Static library link issue with Mac OS X: symbol(s) not found for architecture x86_64

10.3k views Asked by At

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?

3

There are 3 answers

0
prosseek On BEST ANSWER

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.

0
MikeOnline On

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.

2
prosseek On

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