6

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.

olebole
  • 521
  • 4
  • 17

1 Answers1

4

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.

Stanislav Pankevich
  • 11,044
  • 8
  • 69
  • 129
  • To me, this sounds not unintended: if one does not link a library member that defines a symbol - even if it is uninitialized there -, then the symbol remains undefined and causes a linker error. What is the rationale behind this? And why is this different between MacOS and Linux (GNU binutils)? – olebole Jun 04 '17 at 19:31
  • I can't say what is the rationale, unfortunately, and don't know why is the difference. I was also surprised by your example code and just did a research on how I could make it work. – Stanislav Pankevich Jun 04 '17 at 20:36
  • Our of curiosity, why don't you use a normal `foo.h` with a normal `extern char foo[];` in it? Is it just for the scope of this question or do you write a production code like that? – Stanislav Pankevich Jun 04 '17 at 20:59
  • The code is not mine (it is old K&R code), and I also rewrote to keep the question as short as possible. An additonal `.h` file would habe make it more complicated for the example. – olebole Jun 05 '17 at 11:44