I have a number of static libraries which I link together into one shared library. One of them, say libUsefulFunc.a contains an object file usefulFunc.o with a function, usefulFunc() that is only used from another static library, let's say usingFunc(), residing in usingFunc.c hosted in libUsingFunc.a
The problem is that the linker throws away the usefulFunc.o and I get error " undefined reference ". I tried both orders of linking.
I've recreated the situation using the simplest files I could think of:
a.h
extern int foo();
a.c
#include "a.h"
int foo()
{
return 13;
}
b.c
#include "a.h"
extern int b()
{
return print("a = %d\n", foo());
}
Building it all:
gcc -c a.c -o a.o
gcc -c b.c -o b.o
ar q b.a b.o
ar q a.a a.o
ld -shared -o test.so ./b.a ./a.a
nm ./test.so
00001034 A __bss_start
00001034 A _edata
00001034 A _end
If I provide the object files instead of archives:
ld -shared -o test.so ./a.o ./b.o
nm ./test.so
00001220 a _DYNAMIC
00000000 a _GLOBAL_OFFSET_TABLE_
00001298 A __bss_start
00001298 A _edata
00001298 A _end
000001a0 T b
00000194 T foo
U print
Is there a way to tell the linker not to throw away the object files he thinks are unused without having to list all object files? I know there is a --whole-archive option, but I build the library as a part of Android NDK project and did not find a way to pass this option for specific library one.
An update I've fully understood my original problem and found the correct solution. First to my example above: the linker starts from the entry points and searches for all symbols they use. These are looked up in the current library. Once found it adds the symbols they use to its list and so force. The libraries are processes only once and in the order they appear on the command line. So if the second library uses a symbol from the first one - the symbol will remain undefined, as the linker does not go back. So in my example I should have told him that b() will be called externally, I could do it by using --undefined=b:
ld -shared -o test.so --undefined=b ./b.a ./a.a
In the original problem I had there was a circular reference between two static libraries. as if I had in the b archive a file b1.c with function foo_b() that is called from foo(). For such cases there are 3 possible solutions I have found:
- List the b twice: ld -shared -o test.so --undefined=b ./b.a ./a.a ./b.a
- Use --whole-archive
- Use --start-group archives --end-group option. The specified archives are searched repeatedly until no new undefined references are created.
For Android NDK libraries, only the first and the second options seem to be available, as NDK's makefiles don't provide a way to specify the archive group
Hope this will be useful to other people as well!