创建动态目标文件时,如果该动态目标文件基于包含版本定义的共享目标文件进行链接,则可以指示链接编辑器将绑定仅限于特定版本定义。实际上,使用链接编辑器可以控制目标文件到特定接口的绑定。
使用 DEPEND_VERSIONS mapfile 指令可以控制目标文件的绑定要求。此指令通过链接编辑器的 –M 选项和关联的 mapfile 来提供。DEPEND_VERSIONS 指令使用以下语法。
$mapfile_version 2 DEPEND_VERSIONS objname { ALLOW = version_name; REQUIRE = version_name; .... };
objname 代表共享目标文件依赖项的名称。此名称应当与链接编辑器所使用的共享目标文件编译环境名称一致。请参见库命名约定。
ALLOW 属性用于指定共享目标文件内应设为可用于绑定的版本定义名称。可以指定多个 ALLOW 属性。
REQUIRE 属性允许记录新增的版本定义。可以指定多个 REQUIRE 属性。
在以下情况中,版本绑定的控制非常实用。
当共享目标文件定义了独立的、具有唯一性的版本时。在定义不同标准接口时可以使用这种版本控制方法。可以使用绑定控制生成目标文件,以确保目标文件仅绑定到特定的接口。
当共享目标文件经过了若干软件发行版的版本化时。可以使用绑定控制生成目标文件,以将其绑定限定到之前的软件发行版中可用的接口。这样,目标文件在使用最新发行版的共享目标文件生成之后,仍可以与旧发行版的共享目标文件依赖项一起运行。
以下示例说明了版本控制机制的使用。此示例使用共享目标文件 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 $mapfile_version 2 DEPEND_VERSIONS libfoo.so { ALLOW = SUNW_1.1; }
例如,假定您开发一个应用程序 prog,并希望确保该应用程序可以运行于 Release X。该应用程序必须仅使用 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
要符合 SUNW_1.1 接口,必须删除对 bar 的引用。您可以重新编写应用程序,删除对 bar 的要求,或向应用程序的创建添加一个 bar 的实现。
要记录目标文件的正常符号绑定可能生成的更多版本依赖项,可以将 REQUIRE 属性用于 DEPEND_VERSIONS mapfiile 指令。以下各节说明了可以使用这种额外绑定的情形。
情形之一是,将特定于 ISV 的接口转换为公共标准接口。
在之前的 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 的依赖项。这将使 prog 无法运行在 libfoo.so.1 小于 Release X+2 的系统上。版本定义 STAND_A 在之前的发行版中不存在,尽管接口 foo1 在之前的发行版中存在。
通过创建对 SUNW_1.1 的依赖项,可以生成应用程序 prog,使其要求与之前的发行版一致。
$ cat mapfile $mapfile_version 2 DEPEND_VERSIONS libfoo.so { ALLOW = SUNW_1.1; REQUIRE = 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);
此显式依赖项足以封装真实的依赖项要求。此依赖项可以满足与旧发行板的兼容性。
创建弱版本定义描述了如何使用弱版本定义标记内部实现更改。这些版本定义非常适合指示对目标文件所做的错误修复和性能改进。如果弱版本的存在是必需的,可以生成一个对此版本定义的显式依赖项。当某项错误修复或性能改进对于目标文件的正常工作至关重要时,创建这类依赖项是非常重要的。
在之前的 libfoo.so.1 示例中,假定一项错误修复作为弱版本定义 SUNW_1.2.1 纳入软件 Release X+3 中:
$ 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;
通常,如果应用程序依据此 libfoo.so.1 进行生成,将记录一个对版本定义 SUNW_1.2.1 的弱依赖项。此依赖项仅用于提供信息。如果在运行时使用的 libfoo.so.1 的实现中不存在版本定义,此依赖项不会导致应用程序终止。
使用 DEPEND_VERSIONS mapfile 指令的 REQUIRE 属性可以生成对版本定义的显式依赖项。如果此定义是一个弱定义,则此显式引用同时也是要提升为强依赖项的版本定义。
使用以下文件控制指令,可以将应用程序 prog 生成为强制要求 SUNW_1.2.1 接口在运行时可用。
$ cat mapfile $mapfile_version 2 DEPEND_VERSIONS libfoo.so { ALLOW = SUNW_1.1; REQUIRE = 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 提升为强版本,所以版本 SUNW_1.2.1 使用依赖项 STAND_A 进行标准化。在运行时,如果无法找到版本定义 SUNW_1.2.1,将生成一条致命错误。