当创建共享文件时,ld链接器从静态库中删除一个对象文件。

时间:2021-01-18 13:24:05

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

我有许多静态库,我将它们链接到一个共享库中。他们中的一个,说得很好。a包含一个有用的对象文件。o有一个函数,usfunc(),它只在另一个静态库中使用,比如usingFunc(),驻留在usingFunc中。c在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.

问题是链接器把有用的东西扔掉了。o和我得到错误“未定义引用”。我尝试了两个链接的顺序。

I've recreated the situation using the simplest files I could think of:

我用我能想到的最简单的文件重新创建了这种情况:

a.h

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.

是否有一种方法可以告诉链接器不要在不列出所有对象文件的情况下丢弃他认为未使用的对象文件?我知道有一个——全存档选项,但我将库作为Android NDK项目的一部分构建,但没有找到方法将这个选项传递给特定的库1。

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:

更新我已经完全理解了我最初的问题并找到了正确的解决方案。首先来看我上面的例子:链接器从入口点开始,搜索它们使用的所有符号。这些是在当前库中查找的。一旦找到它,它就会将它们使用的符号添加到列表中,从而产生力量。库只是进程一次,并且按照它们在命令行中出现的顺序。因此,如果第二个库使用第一个库中的符号——符号将保持未定义,因为链接器不会返回。所以在我的例子中,我应该告诉他b()将被外部调用,我可以用-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:

在最初的问题中,在两个静态库之间有一个循环引用。就好像我在b归档文件b1。用foo()调用函数foo_b()。对于这种情况,我找到了三种可能的解决办法:

  1. List the b twice: ld -shared -o test.so --undefined=b ./b.a ./a.a ./b.a
  2. 列出b两次:ld -共享-o测试。所以,定义= b / b。一。/。一。/本科
  3. Use --whole-archive
  4. 使用——whole-archive
  5. Use --start-group archives --end-group option. The specified archives are searched repeatedly until no new undefined references are created.
  6. 使用——开始组存档——结束组选项。重复搜索指定的归档文件,直到没有创建新的未定义引用为止。

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

对于Android NDK库,似乎只有第一个和第二个选项可用,因为NDK的makefile没有提供指定归档组的方法

Hope this will be useful to other people as well!

希望这对其他人也有帮助!

3 个解决方案

#1


1  

try with --whole-archive option:

尝试——whole-archive选项:

ld -shared -o test.so --whole-archive ./a.a ./b.a

#2


1  

OK in case it's useful for followers, I have found a very useful (and odd) behavior.

好吧,如果它对追随者有用的话,我发现了一个非常有用的(和奇怪的)行为。

If you have this linking order on your command line:

如果您的命令行上有这个链接顺序:

-lsomething1 -lsomething2

-lsomething1 -lsomething2

if the various .o files contained within libsomething1.a "refer to each another" (have some shared methods or the like, amongst themselves) and also at least one of the .o files has a dependency that is "useful/used" by the program, then all the inter-linking .o files will be loaded "when that library is linked against" (basically, when the linker hits the -lsomething1 command).

如果libsomething1中包含的各种.o文件。是指彼此”(有一些共享的方法或类似的,在自己)和至少一个. o文件有一个依赖“有用/使用”的计划,那么所有的盘根错节. o文件将被载入“当图书馆有关反对“(点击链接器的基本上,当-lsomething1命令)。

The linker then continues on and tries to load library "something2". If there is a dependency in "something2" to a .o file in "something1"

然后链接器继续并尝试加载库“something things 2”。如果"something2"中有对"something1"中。o文件的依赖

a) if there was an inter dependency between the .o files in "something1" then it will load, even if that particular dependency was unused earlier.

a)如果在“something1”中.o文件之间存在相互依赖关系,那么它将会加载,即使这个特定的依赖关系以前没有使用过。

b) if there was no interdependency between .o files in something1 then it is possible the .o file was, as the OP phrased it, "thrown away" at load time, so will not be available.

b)如果.o文件在something1中没有相互依赖,那么.o文件可能在加载时被“抛出”,因此不可用。

So basically its possible to "sometimes" have objects in something1 that satisfy link time dependencies with something2, and the linker is happy, even though they are specified in the "wrong order" (something1 then something2, in this case, the right order is reverse of that, things that satisfy dependencies come later in the link chain). Sooo confusing.

基本上它可能“有时”对象与something2 something1满足链接时依赖关系,和链接器是快乐的,即使他们是在“错误的秩序”中指定(something1 something2,在这种情况下,正确的顺序是相反的事情晚些时候来满足依赖关系链)。太太太混乱。

Apparently if it notices it needs/wants a .o file at load time, it loads the entire .o file, not just the symbols it knows it needs/wants.

显然,如果它在加载时注意到它需要/想要一个.o文件,它会加载整个.o文件,而不仅仅是它知道它需要/想要的符号。

So if you accidentally remove an inter dependency, you can suddenly run into undefined reference failures where none existed before (which you can typically counter act by putting the "-l" commands into the "correct" order). And this also means that you can "accidentally" satisfy forward dependencies, which is not the way ld typically works. Go figure. You can accidentally satisfy forward dependencies [!]

因此,如果您不小心删除了一个相互依赖关系,您可能会突然遇到未定义的引用失败(您通常可以通过将“-l”命令放入“正确”的顺序来进行反操作)。这也意味着您可以“意外地”满足向前依赖,这不是ld通常的工作方式。图。您可能会意外地满足向前依赖项[!]

You can see more precisely what is going on (which .o files are being included or not) by adding -Wl,-verbose to your linking command line.

通过向链接命令行添加-Wl,-verbose,您可以更精确地看到正在发生的事情(包括或不包含.o文件)。

You can see which .o files (and their symbols) are included in your .a file (all together) by using the nm command (ex: nm libmylib.a) or if you're cross compiling its something like i686-mingw-nm libmylib.a or its like. GL!

通过使用nm命令(例如:nm libmylib.a)或者交叉编译它的i686-mingw-nm libmylib之类的东西,您可以看到在a文件中包含了哪些.o文件(及其符号)。或者它的样子。GL !

#3


0  

Avoid linking static objects into a shared library, because a shared library should preferably contain position independent code (to avoid too much relocation at dynamic link time).

避免将静态对象链接到共享库中,因为共享库应该最好包含位置无关的代码(以避免在动态链接时重定位过多)。

In practice, recompile every source file like foo.c with gcc -fPIC -O -Wall -c foo.c -o foo.pic.o and link them all to make your shared library, e.g. gcc -shared *.pic.o -o libshared.so (and you may link needed libraries into your .so)

在实践中,重新编译每个源文件,比如foo。用gcc -fPIC -O -Wall -c foo。c - o foo.pic。o并将它们链接到共享库中,例如gcc -shared *.pic。o - o libshared。所以(你可以将需要的库链接到。so中)

#1


1  

try with --whole-archive option:

尝试——whole-archive选项:

ld -shared -o test.so --whole-archive ./a.a ./b.a

#2


1  

OK in case it's useful for followers, I have found a very useful (and odd) behavior.

好吧,如果它对追随者有用的话,我发现了一个非常有用的(和奇怪的)行为。

If you have this linking order on your command line:

如果您的命令行上有这个链接顺序:

-lsomething1 -lsomething2

-lsomething1 -lsomething2

if the various .o files contained within libsomething1.a "refer to each another" (have some shared methods or the like, amongst themselves) and also at least one of the .o files has a dependency that is "useful/used" by the program, then all the inter-linking .o files will be loaded "when that library is linked against" (basically, when the linker hits the -lsomething1 command).

如果libsomething1中包含的各种.o文件。是指彼此”(有一些共享的方法或类似的,在自己)和至少一个. o文件有一个依赖“有用/使用”的计划,那么所有的盘根错节. o文件将被载入“当图书馆有关反对“(点击链接器的基本上,当-lsomething1命令)。

The linker then continues on and tries to load library "something2". If there is a dependency in "something2" to a .o file in "something1"

然后链接器继续并尝试加载库“something things 2”。如果"something2"中有对"something1"中。o文件的依赖

a) if there was an inter dependency between the .o files in "something1" then it will load, even if that particular dependency was unused earlier.

a)如果在“something1”中.o文件之间存在相互依赖关系,那么它将会加载,即使这个特定的依赖关系以前没有使用过。

b) if there was no interdependency between .o files in something1 then it is possible the .o file was, as the OP phrased it, "thrown away" at load time, so will not be available.

b)如果.o文件在something1中没有相互依赖,那么.o文件可能在加载时被“抛出”,因此不可用。

So basically its possible to "sometimes" have objects in something1 that satisfy link time dependencies with something2, and the linker is happy, even though they are specified in the "wrong order" (something1 then something2, in this case, the right order is reverse of that, things that satisfy dependencies come later in the link chain). Sooo confusing.

基本上它可能“有时”对象与something2 something1满足链接时依赖关系,和链接器是快乐的,即使他们是在“错误的秩序”中指定(something1 something2,在这种情况下,正确的顺序是相反的事情晚些时候来满足依赖关系链)。太太太混乱。

Apparently if it notices it needs/wants a .o file at load time, it loads the entire .o file, not just the symbols it knows it needs/wants.

显然,如果它在加载时注意到它需要/想要一个.o文件,它会加载整个.o文件,而不仅仅是它知道它需要/想要的符号。

So if you accidentally remove an inter dependency, you can suddenly run into undefined reference failures where none existed before (which you can typically counter act by putting the "-l" commands into the "correct" order). And this also means that you can "accidentally" satisfy forward dependencies, which is not the way ld typically works. Go figure. You can accidentally satisfy forward dependencies [!]

因此,如果您不小心删除了一个相互依赖关系,您可能会突然遇到未定义的引用失败(您通常可以通过将“-l”命令放入“正确”的顺序来进行反操作)。这也意味着您可以“意外地”满足向前依赖,这不是ld通常的工作方式。图。您可能会意外地满足向前依赖项[!]

You can see more precisely what is going on (which .o files are being included or not) by adding -Wl,-verbose to your linking command line.

通过向链接命令行添加-Wl,-verbose,您可以更精确地看到正在发生的事情(包括或不包含.o文件)。

You can see which .o files (and their symbols) are included in your .a file (all together) by using the nm command (ex: nm libmylib.a) or if you're cross compiling its something like i686-mingw-nm libmylib.a or its like. GL!

通过使用nm命令(例如:nm libmylib.a)或者交叉编译它的i686-mingw-nm libmylib之类的东西,您可以看到在a文件中包含了哪些.o文件(及其符号)。或者它的样子。GL !

#3


0  

Avoid linking static objects into a shared library, because a shared library should preferably contain position independent code (to avoid too much relocation at dynamic link time).

避免将静态对象链接到共享库中,因为共享库应该最好包含位置无关的代码(以避免在动态链接时重定位过多)。

In practice, recompile every source file like foo.c with gcc -fPIC -O -Wall -c foo.c -o foo.pic.o and link them all to make your shared library, e.g. gcc -shared *.pic.o -o libshared.so (and you may link needed libraries into your .so)

在实践中,重新编译每个源文件,比如foo。用gcc -fPIC -O -Wall -c foo。c - o foo.pic。o并将它们链接到共享库中,例如gcc -shared *.pic。o - o libshared。所以(你可以将需要的库链接到。so中)