链接程序和库指南

协调版本化文件名

在链接编辑过程中,输入共享库的最常见方法是使用 -l 选项。此选项使用链接编辑器的库搜索机制来查找带有 lib 前缀以及 .so 后缀的共享库。

但是,在运行时,所有共享库依赖项都应该以其版本化名称形式存在。可以创建两个文件名之间的文件系统链接,而不是维护遵循这些命名约定的两个不同的共享库。

要使运行时共享库 libfoo.so.1 可用于编译环境,请提供从编译文件名到运行时文件名的符号链接。 例如:


$ cc -o libfoo.so.1 -G -K pic foo.c

$ ln -s libfoo.so.1 libfoo.so

$ ls -l libfoo*

lrwxrwxrwx  1 usr grp          11 1991 libfoo.so -> libfoo.so.1

-rwxrwxr-x  1 usr grp        3136 1991 libfoo.so.1

符号链接和硬链接都可使用。但是,符号链接在文档和诊断辅助方面更有用。

已经针对运行时环境生成共享库 libfoo.so.1。通过生成符号链接 libfoo.so,可以在编译环境中使用此文件。 例如:


$ cc -o prog main.o -L. -lfoo

链接编辑器处理具有共享库 libfoo.so.1(通过符号链接 libfoo.so 即可找到)所描述的接口的可重定位目标文件 main.o

针对多个软件发行版,可以分发具有已更改接口的此共享库的新版本。可以将编译环境构建为通过更改符号链接即可使用适用的接口。 例如:


$ ls -l libfoo*

lrwxrwxrwx  1 usr grp          11 1993 libfoo.so -> libfoo.so.3

-rwxrwxr-x  1 usr grp        3136 1991 libfoo.so.1

-rwxrwxr-x  1 usr grp        3237 1992 libfoo.so.2

-rwxrwxr-x  1 usr grp        3554 1993 libfoo.so.3

此共享库提供三个主要的版本。其中两个共享库 libfoo.so.1libfoo.so.2 为现有应用程序提供依赖项。libfoo.so.3 则为创建和运行新应用程序提供最新主发行版。

使用此符号链接机制本身并不足以保证在编译环境中使用了正确的共享库绑定,就能满足运行时环境对此绑定的需求。如示例目前所示,链接编辑器将在动态可执行文件 prog 中记录其已处理的共享库的文件名。在这种情况下,此文件名即是编译环境文件名。


$ dump -Lv prog



prog:

 **** DYNAMIC SECTION INFORMATION ****

.dynamic:

[INDEX] Tag      Value

[1]     NEEDED   libfoo.so

.........

执行应用程序 prog 后,运行时链接程序将搜索依赖项 libfoo.soprog 将绑定到此符号链接所指向的文件。

要提供记录为依赖项的正确运行时名称,应该生成共享库 libfoo.so.1(通过 soname 定义生成)。此定义标识共享库的运行时名称。链接此共享库的任何目标文件将此名称用作依赖项的名称。在共享库本身的链接编辑过程中,可以使用 -h 选项提供此定义。 例如:


$ cc -o libfoo.so.1 -G -K pic -h libfoo.so.1 foo.c

$ ln -s libfoo.so.1 libfoo.so

$ cc -o prog main.o -L. -lfoo

$ dump -Lv prog



prog:

 **** DYNAMIC SECTION INFORMATION ****

.dynamic:

[INDEX] Tag      Value

[1]     NEEDED   libfoo.so.1

.........

此符号链接和 soname 机制已经在编译和运行时环境的共享库命名约定之间建立了很强的协调。将在生成的输出文件中准确记录链接编辑过程中处理的接口。此记录可确保在运行时提供目标接口。


注意 – 注意 –

创建新的外部版本化共享库是一项主要的更改。请务必了解使用此共享库的所有进程的全部依赖项。

例如,应用程序可能依赖于 libfoo.so.1 以及从外部传送的目标文件 libISV.so.1。后者也可能依赖于 libfoo.so.1。如果重新设计应用程序,使其使用 libfoo.so.2 中的新接口,而不对外部目标文件 libISV.so.1 的使用做任何更改,则 libfoo.so 的两个主要版本都会引入正在运行的进程。由于更改 libfoo.so 版本的唯一原因是标记不兼容的更改,因此在一个进程中具有该目标文件的两个版本可能会导致错误的符号绑定并由此导致不需要的交互。