根据包含版本定义的共享库创建动态库时,可以指示链接编辑器将绑定仅限于特定版本定义。实际上,利用链接编辑器可以控制目标文件到特定接口的绑定。
可以使用文件控制指令来控制目标文件的绑定需求。此指令通过链接编辑器的 -M 选项以及关联的 mapfile 提供。可以使用以下文件控制指令语法:
name - version [ version ... ] [ $ADDVERS=version ]; |
name-表示共享库依赖项的名称。此名称应该与链接编辑器所使用的共享库的编译环境名称相匹配。请参见库命名约定。
version-表示应该可用于绑定的共享库内的版本定义名称。可以指定多个版本定义。
此绑定控制在下面的情况下很有用:
当共享库定义独立的、唯一的版本时。定义不同的标准接口时可以进行此版本控制。可以通过绑定控制生成目标文件,以确保该目标文件只绑定到特定接口。
已经在多个软件发行版中对共享库进行版本化时。可以通过绑定控制生成目标文件,从而将该目标文件限制为绑定到上一个软件发行版中提供的接口。这样,使用共享库的最新发行版生成的目标文件仍可以与共享库依赖项的旧发行版一起运行。
以下示例说明了版本控制机制的用法。此示例使用包含以下版本接口定义的共享库 libfoo.so.1:
$ pvs -dsv libfoo.so.1 libfoo.so.1: _end; _GLOBAL_OFFSET_TABLE_; _DYNAMIC; _edata; _PROCEDURE_LINKAGE_TABLE_; _etext; SUNW_1.1: foo1; foo2; SUNW_1.1; SUNW_1.2: {SUNW_1.1}: bar; |
版本定义 SUNW_1.1 和 SUNW_1.2 表示 libfoo.so.1 内的接口,这些接口分别在软件 Release X 和 Release X+1 中提供。
可以使用以下版本控制 mapfile 指令来生成应用程序,使其只绑定到 Release X 中提供的接口:
$ cat mapfile libfoo.so - SUNW_1.1; |
例如,假设您开发一个应用程序 prog,并且要确保此应用程序可以在 Release X 中运行。这样此应用程序只能使用此发行版中提供的接口。如果应用程序错误地引用了符号 bar,便会与所需接口不兼容。链接编辑器会将此情形报告为未定义的符号错误:
$ cat prog.c extern void foo1(); extern void bar(); main() { foo1(); bar(); } $ cc -o prog prog.c -M mapfile -L. -R. -lfoo Undefined first referenced symbol in file bar prog.o (symbol belongs to unavailable \ version ./libfoo.so (SUNW_1.2)) ld: fatal: Symbol referencing errors. No output written to prog |
为了与 SUNW_1.1 接口兼容,必须删除对 bar 的引用。可以对应用程序重新进行处理以删除对 bar 的需求,也可以在创建应用程序时添加 bar 的实现。
缺省情况下,还会根据任意文件控制指令来检验链接编辑过程中遇到的共享库依赖项。使用环境变量 LD_NOVERSION 可抑制任何共享库依赖项的版本验证。
要使记录的版本依赖项多于从目标文件的正常符号绑定中生成的版本依赖项,请使用 $ADDVERS 文件控制指令。本节介绍此附加绑定可能有用的情况。
在一个 libfoo.so.1 示例中,假设在 Release X+2, 中,版本定义 SUNW_1.1 分为两个标准发行版:STAND_A 和 STAND_B。要保持兼容性,必须维护 SUNW_1.1 版本定义。在本示例中,此版本定义表示为继承两个标准定义:
$ pvs -dsv libfoo.so.1 libfoo.so.1: _end; _GLOBAL_OFFSET_TABLE_; _DYNAMIC; _edata; _PROCEDURE_LINKAGE_TABLE_; _etext; SUNW_1.1: {STAND_A, STAND_B}: SUNW_1.1; SUNW_1.2: {SUNW_1.1}: bar; STAND_A: foo1; STAND_A; STAND_B: foo2; STAND_B; |
如果应用程序 prog 的唯一需求是接口符号 foo1,则此应用程序将仅依赖于版本定义 STAND_A。这将阻止在 libfoo.so.1 小于 Release X+2 的系统上运行 prog。尽管早期的发行版具有接口 foo1,但没有版本定义 STAND_A。
生成应用程序 prog 时,可以通过创建对 SUNW_1.1 的依赖性来使其要求与早期发行版一致:
$ cat mapfile libfoo.so - SUNW_1.1 $ADDVERS=SUNW_1.1; $ cat prog extern void foo1(); main() { foo1(); } $ cc -M mapfile -o prog prog.c -L. -R. -lfoo $ pvs -r prog libfoo.so.1 (SUNW_1.1); |
此显式依赖性足以涵盖实际的依赖性要求。此依赖性可满足与旧发行版的兼容性。
创建弱版本定义 (weak version definition)介绍了如何使用弱版本定义 (weak version definition) 标记内部实现更改。这些版本定义非常适用于指示针对目标文件所做的错误修复以及性能改善。如果需要弱版本,可以生成对此版本定义的显式依赖性。当错误修复或性能改善对于目标文件的正常工作至关重要时,创建此类依赖性非常重要。
在上一个 libfoo.so.1 示例中,假设在软件 Release X+3 中以弱版本定义 (weak version definition) SUNW_1.2.1 引入了错误修复:
$ pvs -dsv libfoo.so.1 libfoo.so.1: _end; _GLOBAL_OFFSET_TABLE_; _DYNAMIC; _edata; _PROCEDURE_LINKAGE_TABLE_; _etext; SUNW_1.1: {STAND_A, STAND_B}: SUNW_1.1; SUNW_1.2: {SUNW_1.1}: bar; STAND_A: foo1; STAND_A; STAND_B: foo2; STAND_B; SUNW_1.2.1 [WEAK]: {SUNW_1.2}: SUNW_1.2.1; |
通常,如果根据此共享库生成应用程序,则生成的应用程序将记录与版本定义 SUNW_1.2.1 的弱依赖性。此依赖性仅用于提供信息。如果运行时使用的 libfoo.so.1 中不存在此版本定义,则此依赖性不会导致终止应用程序。
文件控制指令 $ADDVERS 可用于生成版本定义的显式依赖性。如果此定义为弱定义,则此显式引用还会导致版本定义提升为强依赖性。
可以使用以下文件控制指令生成应用程序 prog,以强制满足 SUNW_1.2.1 接口在运行时可用的需求:
$ cat mapfile libfoo.so - SUNW_1.1 $ADDVERS=SUNW_1.2.1; $ cat prog extern void foo1(); main() { foo1(); } $ cc -M mapfile -o prog prog.c -L. -R. -lfoo $ pvs -r prog libfoo.so.1 (SUNW_1.2.1); |
生成 prog 时创建了与接口 STAND_A 的显式依赖性。由于版本定义 SUNW_1.2.1 提升为强版本,因此它也会通过依赖性 STAND_A 进行标准化。在运行时,如果找不到版本定义 SUNW_1.2.1,则会产生致命错误。
如果处理少量的依赖项,可以使用链接编辑器的 -u 选项显式绑定到某个版本定义。使用此选项可以引用版本定义符号。但是,符号引用是不可选择的。如果是处理多个依赖项(包含多个类似命名的版本定义)时,则此方法可能不足以创建显式绑定。