Reputation: 190799
I'm trying to generate a static library and link it with an execution binary.
This is a library function:
#include <stdio.h>
int hello() {
return 10;
}
With these commands, I could get a static library.
gcc -c io.c
ar -crv libio.a io.o
With lip -info
, I checked it is x86_64
architecture.
ar> lipo -info libio.a
input file libio.a is not a fat file
Non-fat file: libio.a is architecture: x86_64
This is the main function that uses the library.
#include <stdio.h>
extern int hello();
int main(int argc, char *argv[]) {
printf("%d", hello());
}
However, when I link the object with the static library, I have errors.
gcc main.c -lio -o main -L.
Error messages are:
ld: warning: ignoring file ./libio.a, file was built for archive which is not the architecture being linked (x86_64): ./libio.a
Undefined symbols for architecture x86_64:
"_hello", referenced from:
_main in main-2c41a0.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I use the ar
as in /bin/ar
, and Mac OS X is 10.10.2 with clang-602.0.53.
ar> clang -v
Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
Target: x86_64-apple-darwin14.3.0
Thread model: posix
What might be wrong?
Upvotes: 8
Views: 10685
Reputation: 1204
I started getting the linker error symbol(s) not found for architecture x86_64
due to an improperly built static .lib
file after I upgraded my macOS system to Catalina (this also upgraded the version of Xcode and Apple Clang). These failures would only occur trying to link to one particular static library (my application builds and links to several dozen C++ static libs -- all with nearly identical CMake settings).
After each build I could verify whether the static library was built properly or not by running ar -t /path/to/mystatic.lib
. I'd either get a list of functions in the archive, or an error. Funny enough, sometimes the library built fine and other times it was corrupt -- using the same build configuration. This same library always built fine when my macOS system ran Mojave. But I was not about to downgrade.
The following addition to the CMakeLists.txt
file resolved the issue:
if(APPLE)
set(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> -r -LS <TARGET> <LINK_FLAGS> <OBJECTS>")
endif()
The -r -LS
parameters run ar
without creating an archive symbol table. After running ar
CMake automatically runs ranlib
(actually libtool
on macOS) in a manner that creates the symbol table. Somehow this ensures the static library is always built reliably.
My other static libraries do not require the above CMake setting. I have no idea why only one library was affected.
Upvotes: 0
Reputation: 190799
From hacking CMake generate make file (CMakeFiles/test.dir/link.txt), the ar in /usr/local/ar
which is used in default does not seem to be working correctly.
This is the content of the link.txt
.
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ar qc libtest.a CMakeFiles/test.dir/test.c.o
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib libtest.a
From the script, /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ar
is the one that I had to use.
smcho@macho ar> ls -alF /usr/bin/ar
-rwxr-xr-x 1 root wheel 18160 Oct 17 18:49 /usr/bin/ar*
smcho@macho ar> ls -alF /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ar
-rwxr-xr-x 1 root wheel 33472 Oct 29 16:36 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ar*
Likewise, the ranlib that should be used is /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib
not the default one.
smcho@macho ar> ls -alF `which ar`
-rwxr-xr-x 1 root wheel 18160 Oct 17 18:49 /usr/bin/ar*
smcho@macho ar> ls -alF /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib
lrwxr-xr-x 1 root wheel 7 Nov 10 21:10 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib@ -> libtool
Other than that -qc
option needed to be used (from the cmake generated script)
-c Whenever an archive is created, an informational message to that
effect is written to standard error. If the -c option is speci-
fied, ar creates the archive silently.
-q (Quickly) append the specified files to the archive. If the ar-
chive does not exist a new archive file is created. Much faster
than the -r option, when creating a large archive piece-by-piece,
as no checking is done to see if the files already exist in the
archive.
These are commands for getting correct library file:
clang -c hellolib.cpp -o hellolib.o
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ar -qc libhello.a hellolib.o
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib libhello.a
The usage is:
clang usehello.cpp -lhello -L.
nm and lipo show the correct library file information:
smcho@macho ar> nm libhello.a
libhello.a(hellolib.o):
0000000000000000 T __Z3addii
smcho@macho ar> lipo -info libhello.a
input file libhello.a is not a fat file
Non-fat file: libhello.a is architecture: x86_64
Upvotes: 4
Reputation: 190799
The library should have generated with libtool -static
.
gcc -c io.c
libtool -static -o libio.a io.o
gcc main.c -lio -o main -L.
main
Returns
10
ar> lipo -info libio.a
input file libio.a is not a fat file
Non-fat file: libio.a is architecture: x86_64
ar> file libio.a
libio.a: current ar archive
ar> nm libio.a
io.o:
0000000000000000 T _hello
Hints from this page.
Upvotes: 13