我一直很感兴趣地阅读这篇文章: https://anadoxin.org/blog/control-over-symbol-exports-in-gcc.html/
它有一个名为“共享库问题使用的静态库”的特定部分引起了我的注意。 我已经尝试了一些超出文章描述的内容,并且有些东西我不太明白。
使用本文中的代码片段,假设我首先创建一个简单的静态库:
g++ util.cpp -o util.o -c -fPIC
ar r libutil.a util.o
然后我独立创建一个独立的对象:
g++ code.cpp -o code.o -c -fPIC
最后,我结合两者创建了一个共享库:
g++ code.o libutil.a -shared -o libcode.so
现在,正如文章中所述,如果我查看共享库的导出表,一切都如我所料:
$ nm -CD libcode.so | grep " T "
000000000000124c T _fini
0000000000001000 T _init
0000000000001167 T entry_point()
00000000000011d1 T util_function()
0000000000001145 T function1()
但我不明白的是,如果我从共享库中排除
code.o
并仅从静态存档中构建它:
g++ libutil.a -shared -o libcode.so
那么在这种情况下共享库的导出表完全是空的:
$ nm -CD libcode.so | grep " T "
00000000000010f8 T _fini
0000000000001000 T _init
我发现为了获得预期的行为,我需要构建共享库,如下所示:
g++ -Wl,--whole-archive libutil.a -Wl,--no-whole-archive -shared -o libcode.so
在这种情况下,存档中的符号将按预期导出:
$ nm -CD libcode.so | grep " T "
00000000000011a0 T _fini
0000000000001000 T _init
0000000000001125 T util_function()
在我看来,静态档案只是独立对象的集合。然而,在创建共享库时,静态档案和独立对象的处理方式似乎略有不同。当从静态档案创建的共享库没有任何独立对象时,为什么需要使用
-Wl,--whole-archive
?
静态库仍然是一个库。当您链接到动态库时,您不会期望动态库中的所有现有符号都作为导入符号添加到您的目标(通常是
U
输出中的 nm
)。那么,为什么您期望在链接静态库时添加所有包含的符号呢?如果链接器总是将库(静态或动态)中的每个符号放入目标中,则最终会得到一个包含大量不必要条目的符号表,并且在静态库的情况下,这些条目将显着增大大小不好。
库的目的是提供链接器(在共享库的情况下,还有动态链接器)在需要符号时可以查找的二进制信息。您似乎期望它以相反的方向起作用,但事实并非如此。
如果您向链接器提供对象,则您将给出不同的指令。您告诉链接器目标文件需要成为目标的一部分。传递目标文件可能意味着没有其他合理的意义。
链接器逐一检查命令行选项,将遇到的目标文件链接到最终目标。丢失的符号可以通过参数来解决,这些参数可能是命令行后面出现的其他目标文件或库。这样,您就可以精确控制最终目标中包含的内容。