我有许多静态库,我将它们链接到一个共享库中。其中一个,比如说 libUsefulFunc.a 包含一个目标文件 usefulFunc.o,它带有一个函数,有用的Func(),它只能从另一个静态库中使用,比如说 usingFunc(),驻留在 libUsingFunc.a 中的 usingFunc.c
问题是链接器丢弃了有用的Func.o,我得到错误“未定义的引用”。我尝试了两种链接顺序。
我使用我能想到的最简单的文件重新创建了这种情况:
啊
extern int foo();
交流
#include "a.h"
int foo()
{
return 13;
}
公元前
#include "a.h"
extern int b()
{
return print("a = %d\n", foo());
}
构建一切:
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
如果我提供目标文件而不是档案:
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
有没有办法告诉链接器不要丢弃他认为未使用的目标文件而不必列出所有目标文件?我知道有一个 --whole-archive 选项,但是我将库构建为 Android NDK 项目的一部分,并且没有找到一种方法为特定库传递此选项。
更新我已经完全理解了我原来的问题并找到了正确的解决方案。首先是我上面的示例:链接器从入口点开始并搜索它们使用的所有符号。这些在当前库中查找。一旦找到,它就会将他们使用的符号添加到其列表中,从而强制执行。这些库仅是一次进程,并且按照它们在命令行中出现的顺序。因此,如果第二个库使用第一个库中的符号 - 该符号将保持未定义,因为链接器不会返回。所以在我的例子中,我应该告诉他 b() 将被外部调用,我可以使用 --undefined=b 来做到这一点:
ld -shared -o test.so --undefined=b ./b.a ./a.a
在最初的问题中,我遇到了两个静态库之间的循环引用。就好像我在 b 存档中有一个文件 b1.c,它具有从 foo() 调用的函数 foo_b()。对于这种情况,我发现了 3 种可能的解决方案:
- 列出 b 两次: ld -shared -o test.so --undefined=b ./ba ./aa ./ba
- 使用 --whole-archive
- 使用 --start-group archives --end-group 选项。重复搜索指定的档案,直到没有创建新的未定义引用。
对于 Android NDK 库,似乎只有第一个和第二个选项可用,因为 NDK 的 makefile 不提供指定存档组的方法
希望这对其他人也有用!