Symbol not found when static linking on MacOSX

2019-05-27 07:58发布

问题:

I am trying to create a static library and link it on MacOS X (several versions): File foo.c:

char foo[111];

File bar.c:

#include <string.h>

extern char foo[];

int bar(char *src) {
  strcpy(foo, src);
  return strlen(foo);
}

Create a library:

$ cc -c foo.c bar.c
$ ar r libfoobar.a foo.o bar.o
ar: creating archive libfoobar.a
$ ranlib libfoobar.a 
$ nm libfoobar.a 

libfoobar.a(foo.o):
000000000000006f C _foo

libfoobar.a(bar.o):
                 U ___strcpy_chk
0000000000000000 T _bar
                 U _foo
                 U _strlen

Create a small test program:

File main.c:

#include <stdio.h>

int bar(char *);

int main(void) {
  printf("foobarbar = %i\n", bar("123"));
  return 0;
}

Compile and link:

$ cc -c main.c
$ cc -o m main.o -L. -lfoobar
Undefined symbols for architecture x86_64:
  "_foo", referenced from:
      _bar in libfoobar.a(bar.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Why is the symbol not found? It is defined in foo.c? Shouldn't at least ranlib create an index in the library that allows a random order of the files there?

The same code works well under Linux (gcc), and also when the symbol in foo.c is not a char array, but an int.

回答1:

There is a similar question: Object files not properly added to archive on mac which has this answer:

Option 1:

ar -rs my_archive.a foo.o bar.o other_object_files.o
ranlib -c my_archive.a

Option 2:

libtool -c -static -o my_archive.a foo.o bar.o other_object_files.o

It is -c flag that makes a difference for both options on ranlib and libtool respectively:

-c

Include common symbols as definitions with respect to the table of contents. This is seldom the intended behavior for linking from a library, as it forces the linking of a library member just because it uses an uninitialized global that is undefined at that point in the linking. This option is included only because this was the original behavior of ranlib. This option is not the default.