请考虑以下代码结构:
main.cpp -> depends on libone.a -> depends on libtwo.a
假设在main.cpp
中仅使用libone.a
中的函数。因此,实际上,编写main.cpp
的程序员实际上只关心libone.a
。在这一点上,他们甚至都不知道libone.a
对libtwo.a
有依赖性。
他们试图按如下方式编译其代码并获得链接器错误:
g++ -o main main.cpp -lone
-错误!未定义的符号!
这成为一个问题,因为自libone.a
依赖于libtwo.a
以来,使用libone.a
的任何人都必须了解此依赖关系...正如您可以想象的那样,如果FAR有更多依赖关系,则会出现此问题。而不是单个图书馆,它很快就会成为联系的噩梦。
解决此问题的第一个想法是“很简单,我在编译libone.a
时将libtwo.a
与libone.a
链接起来!
事实证明,它并不像我希望的那么简单...编译libone.a
时,无法链接libtwo.a
。静态库在编译时不会链接到任何东西,而是在将库编译成可执行文件时必须链接所有依赖项。
例如,要编译依赖于静态库而又依赖于另一个静态库的main.cpp
,则必须链接两个库。总是。
g++ -o main main.cpp -lone -ltwo
另一种想法是尝试将libone
编译为链接到libtwo.a
的动态库。
奇怪的是,它确实起作用了!编译并链接libone.so
后,主程序只需要关心libone.so
,就不再需要了解libtwo.a
。
g++ -o main main.cpp -lone
成功!
完成此练习后,仍然缺少一件。我只是似乎无法弄清楚为什么静态库无法链接到其他库,而动态库可以链接的任何原因。实际上,在链接libone.so
之前,动态库libtwo.a
根本不会编译。不过,这很好,因为作为libone.so
的作者,我会知道它对libtwo.a
的依赖性-main.cpp
的作者却不知道。实际上,他们不必知道。
所以要问一个真正的问题...为什么动态库可以像这样链接到其他库,而静态库却不能?动态库比静态库似乎有明显的优势,但我从未见过任何地方提到它!
答案 0 :(得分:5)
静态库只是对象文件的存档,没有依赖的概念,因为它从未链接过。
链接的共享库可以解决符号,并且它们可以具有依存关系。
答案 1 :(得分:1)
由于您的问题涉及gcc和.so / .a文件,因此我假设您使用的是使用ELF文件作为目标代码的Unix。
完成此练习后,仍然缺少一件。我只是 似乎无法找出导致静态库无法链接的任何原因 其他库,但动态库可以。
静态库未链接,如另一个答案中所述。它们只是已编译目标文件的存档。共享库实际上是链接的,这意味着链接器实际上解析任何导出符号可到达的所有符号。将导出的符号视为库的API。完全链接的共享库包含每个符号的定义,或者包含告诉操作系统(特别是动态加载程序)所需的 other 个共享库才能访问该符号所必需的依赖项信息。链接器将所有内容组合成一种特殊的文件格式,称为ELF shared object (动态库)。
事实上,动态库libone.so无法编译 直到我链接libtwo.a。没关系,因为 我是libone.so的作者,我会知道它对libtwo.a的依赖- 但是main.cpp的作者不知道。实际上,他们 不应该知道。
libone.so
可能编译正常,但是由于未解析的符号,如果没有libtwo
,则不会链接。由于链接器在链接共享库时必须解析所有可访问的符号,因此如果找不到链接器,它将失败。由于libone.so
使用libtwo
中的符号,因此链接程序需要了解libtwo.a
才能找到它们。当您将静态库链接到共享库时,可通过将定义直接复制到输出共享库文件中来解析符号,因此,此时libone.so
的用户对于{{ 1}},因为其符号位于libtwo
中。
另一个选择是将共享库链接到其他共享库。如果要将libone.so
链接到libtwo.so
中(请注意.so后缀),则链接器通过在输出共享对象文件中添加一个特殊的节来解析libone.so
所需的符号。在运行时需要libone
。稍后,当操作系统加载libtwo.so
时,它知道还需要加载libone.so
。而且,如果您的应用程序仅直接使用libtwo.so
,那么在构建时就需要告诉链接程序,因为它将在libone
中进行链接,请注意它需要libone
并递归下定决心,直到一切都好为止。
现在,操作系统必须在运行时进行的所有加载都会导致性能损失,而且如果您不小心的话,多个共享对象中都存在一些带有全局静态变量的陷阱。静态链接还有其他一些潜在的性能优势,我不会在这里讨论,但足以说明的是,使用动态库的平均性能并不高,但是对于大多数现实情况而言,这种差异也可以忽略不计。