我试图了解 Solaris 上的链接器如何/为什么动态加载某些库文件。我正在使用 ldd 来查看这一点(使用 -s 开关查看链接器尝试了哪些路径)。例如,如果我运行“ldd /usr/local/bin/isql -s”,我会注意到被搜索的库之一被称为“libodbc.so.1”。我注意到这与它沿途找到的名为“libodbc.so”的文件不匹配。因此,它最终解析为“libodbc.so.1.0.0”和“libodbc.so.1”之间存在符号链接的地方。我的问题是 - “.1”在这里的意义是什么?是表示版本号吗?为什么有些安装程序会创建这些符号链接,而有些则不会?
aut*_*iej 12
此问题并非特定于 Solaris。
当您安装共享库(或提供共享库的软件)时,您会得到三个文件,它们看起来都相似但用途不同。
libfoo.so.1.0.0? 这是(常规)数据文件。它包含库本身。您可以有多个这些,具有不同的版本。在此文件中,有一个名为 SONAME的ELF 字段,该字段设置为libfoo.so.1. 在 Linux 上,运行objdump -p libfoo.so.1.0.0 | grep SONAME以找出答案。libfoo.so? libfoo.so.1.0.0? 这是在针对 libfoo 编译软件时使用的符号链接。当您-lfoo向链接器指定时,它将准确查找libfoo.so. 通常,libfoo.so它永远不是常规文件,它始终是指向要用于链接的 libfoo 版本的符号链接。在复杂的构建环境中,您可能有多个版本的库,您可以使用此符号链接来选择要链接的版本。libfoo.so.1? libfoo.so.1.0.0? 这也是一个符号链接,在您运行需要库的二进制文件时使用。还记得我提到的 SONAME 字段吗?当您针对 libfoo 链接二进制文件时,二进制文件将记录库的 SONAME 并将在运行时使用它。此设置允许您同时安装同一库的多个版本。不同的二进制文件可能需要不同版本的库,每个二进制文件都会找到正确版本的库。通常,当存在向后不兼容的 API 更改时,库的 SONAME 会由上游更改。所有旧的二进制文件仍然使用旧的 API,而新链接的二进制文件使用新的 API。
一些打包项目,Debian 就是一个例子,对不同版本的库使用不同的包名。这允许您独立安装和卸载共享库的每个版本。
有一些边缘情况。例如,共享库之间的依赖关系可能导致同时拉入两个版本。考虑:
foo ? libbar.so.1, libbaz.so.1
libbar.so.1 ? libbaz.so.1
Run Code Online (Sandbox Code Playgroud)
想象一下,我们安装了一个新版本的 libbaz 并重新编译了 foo。现在我们有:
foo ? libbar.so.1, libbaz.so.2
libbar.so.1 ? libbaz.so.1
Run Code Online (Sandbox Code Playgroud)
在运行时, foo 将加载libbaz.so.2和libbar.so.1,libbar.so.1并将加载libbaz.so.1。看到问题了吗?同时加载两个版本的 libbaz。我不完全确定内存中代码布局的确切后果是什么,但实际上这会导致崩溃。