我有一些静态库,我将它们链接在一起成为一个共享库。其中一个库,比如说libUsefulFunc.a包含了一个名为usefulFunc()的函数,它只被另一个静态库usingFunc()使用。usingFunc()存储在libUsingFunc.a中的usingFunc.c文件中。
问题是链接器会丢弃usefulFunc.o,并且我会得到"undefined reference"错误。我尝试过链接顺序的不同方式。
我已经用最简单的文件重新创建了这种情况:
a.h
如果我提供的是目标文件而不是归档文件:
有没有一种方法可以告诉链接器不要丢弃他认为未使用的目标文件,而无需列出所有目标文件?我知道有一个--whole-archive选项,但我将库构建为Android NDK项目的一部分,并没有找到一种为特定库传递此选项的方法。 更新:我已经完全理解了我的原始问题并找到了正确的解决方案。首先是我的上面的例子:链接器从入口点开始搜索它们使用的所有符号。这些符号在当前库中查找。一旦找到,它就会将它们使用的符号添加到其列表中,以此类推。库只处理一次,并按照它们在命令行上出现的顺序进行处理。因此,如果第二个库使用来自第一个库的符号,则该符号将保持未定义状态,因为链接器不会返回。因此,在我的示例中,我应该告诉他b()将被外部调用,我可以通过使用--undefined=b来实现。
在我之前遇到的问题中,两个静态库之间存在循环引用。就像在b存档中有一个名为b1.c的文件,其中包含被foo()调用的函数foo_b()。针对这种情况,我找到了3个解决方案:
希望这对其他人也有用!
问题是链接器会丢弃usefulFunc.o,并且我会得到"undefined reference"错误。我尝试过链接顺序的不同方式。
我已经用最简单的文件重新创建了这种情况:
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());
}
构建所有内容:
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 ./b.a ./a.a ./b.a
- 使用--whole-archive选项
- 使用--start-group archives --end-group选项。指定的存档将被重复搜索,直到不再创建新的未定义引用。
希望这对其他人也有用!
ld
不应该是这样的吗:ld -shared -o test.so ./b.a ./a.a
? - alkextern
关键字以及它是否会影响到这里正在发生的事情的人,这个答案:https://dev59.com/I3RA5IYBdhLWcg3wtwSe#856736 或许会有所帮助。 - alkgcc
替换ld
命令(ld
命令显示“未知选项-shared
”,但GCC知道该怎么做)。完成这个步骤后,假设第一个ld
行引用了a.a
和b.a
(而不是问题中写的.o
文件),第一个共享对象为空——没有从任何存档库中复制任何内容。我不确定这是否是意外的行为;根据我的经验,共享库不会直接包含其他库(静态或共享)的材料,尽管它可能包含对它们的引用。 - Jonathan Leffler