繁体   English   中英

为什么动态库可以链接到其他库,而静态库不能?

[英]Why can dynamic libraries link to other libraries, but static ones can't?

考虑以下代码结构:

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人都必须知道这个依赖......正如你想象的那样,这个问题可能发生在比单个库更多的依赖中,并且可以很快成为一个连接噩梦。


尝试 1 解决此问题:

解决这个问题的第一个想法是“这很简单,当我编译libone.a时,我只需将libone.alibtwo.a链接!

事实证明它并不像我希望的那么简单......在编译libone.a ,无法链接libtwo.a 静态库在编译时不会链接到任何内容,而是在将库编译为可执行文件时必须链接所有依赖项。

例如,要编译依赖于另一个静态库的静态库的main.cpp ,您必须链接这两个库。 总是。

g++ -o main main.cpp -lone -ltwo


尝试 2 解决此问题:

另一个想法是尝试将libone编译为链接到libtwo.a的动态库。

奇怪的是,这刚刚奏效! 编译链接libone.so ,主程序只需要关心libone.so ,不再需要关心libtwo.a

g++ -o main main.cpp -lone

成功!


完成此练习后,仍然缺少一件。 我似乎无法弄清楚为什么静态库不能链接到其他库,而动态库可以。 事实上,在我链接libtwo.a之前,动态库libone.so根本不会编译。 不过这很好,因为作为libone.so的作者,我会知道它对libtwo.a依赖 - main.cpp的作者,但是不知道。 实际上,他们不应该知道。

所以回到真正的问题......为什么动态库可以链接到其他这样的库而静态库不能? 这似乎是动态库相对于静态库的明显优势,但我从未在任何地方看到过它!

静态库只是目标文件的存档,没有依赖的概念,因为它从未链接过。

共享库是链接的、解决符号的,因此它们可以具有依赖关系。

由于您的问题涉及 gcc 和 .so/.a 文件,我假设您使用的是某种将 ELF 文件用于目标代码的 Unix。

完成此练习后,仍然缺少一件。 我似乎无法弄清楚为什么静态库不能链接到其他库,而动态库可以。

正如另一个答案中提到的那样,静态库没有链接。 它们只是已编译目标文件的存档。 共享库实际上是链接的,这意味着链接器实际上解析了任何导出符号可访问的所有符号。 将导出的符号视为库的 API。 一个完全链接的共享库要么包含每个符号的定义,要么包含告诉操作系统(特别是动态加载器)需要哪些其他共享库来访问符号所需的依赖信息。 链接器将所有这些组合成一种称为ELF 共享对象(动态库)的特殊文件格式。

事实上,在我链接 libtwo.a 之前,动态库 libone.so 根本不会编译。 不过这很好,因为作为 libone.so 的作者,我会知道它对 libtwo.a 的依赖——但是 main.cpp 的作者不知道。 实际上,他们不应该知道。

libone.so可能编译得很好,但由于未解析的符号,没有libtwo将无法链接。 因为链接器在链接共享库时必须解析所有可访问的符号,所以如果找不到任何符号,它将失败。 由于libone.so在使用符号libtwo ,链接器需要了解libtwo.a找到他们。 当您将静态库链接到共享库时,通过将定义直接复制到输出共享对象文件中来解析符号,因此此时, libone.so用户可能对libone.so的使用libtwo因为它的符号只是在libone.so

另一种选择是将共享库链接到其他共享库。 如果您将libtwo.so链接到libone.so (注意 .so 后缀),则链接器通过向输出共享对象文件添加一个特殊部分来解析libone所需的符号,该部分表明它在运行时需要libtwo.so 稍后,当操作系统加载libone.so ,它知道它还需要加载libtwo.so 而且,如果您的应用程序仅直接使用libone ,那么您只需要在构建时告诉链接器即可,因为它将在libone链接,看到它需要libtwo ,并递归解析直到一切正常。

现在,操作系统必须在运行时加载的所有内容都会导致性能成本,并且如果您不小心,多个共享对象中存在全局静态变量的一些问题。 静态链接还有一些其他潜在的性能优势,我不会在这里介绍,但可以说使用动态库的平均性能并不那么好,但对于大多数现实世界情况,这种差异也可以忽略不计。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM