能够对可执行内部版本控制的共享目标文件进行的唯一更改就是兼容更改。请参见接口兼容性。任何不兼容的更改都要求使用新的外部版本化名称生成一个新的共享目标文件。请参见协调版本化文件名。
通过内部版本控制便可进行的兼容更新分为以下三种基本类别:
添加新符号
从现有符号创建新接口
内部实现更改
前两个类别可以通过将接口版本定义与相应符号关联来实现。后一个类别可以通过创建不具有任何关联的弱版本定义 (weak version definition) 来实现。
任何包含新全局符号的新的共享目标文件兼容发行版都应将这些符号指定给新的版本定义。此新版本定义应继承上一个版本定义。
以下 mapfile 示例将新符号 foo3 指定给新接口版本定义 SUNW_1.2。此新接口继承原始接口 SUNW_1.1。
$ cat mapfile $mapfile_version 2 SYMBOL_VERSION SUNW_1.2 { # Release X+1. global: foo3; } SUNW_1.1; SYMBOL_VERSION SUNW_1.1 { # Release X. global: foo2; foo1; local: *; };
版本定义的继承可减少所有共享目标文件用户必须记录的版本信息量。
任何包含目标文件实现更新(例如错误修复或性能改进)的新的共享目标文件兼容发行版都应带有一个弱版本定义。此新版本定义应继承发生更新时所用的最新版本定义。
以下 mapfile 示例生成弱版本定义 (weak version definition) SUNW_1.1.1。此新接口指明对上一个接口 SUNW_1.1 提供的实现进行了内部更改。
$ cat mapfile $mapfile_version 2 SYMBOL_VERSION SUNW_1.1.1 { } SUNW_1.1; # Release X+1. SYMBOL_VERSION SUNW_1.1 { # Release X. global: foo2; foo1; local: *; };
如果在同一个发行版中发生了内部更改并添加了新接口,则应创建弱版本定义 (weak version definition) 和接口版本定义。以下示例显示了添加版本定义 SUNW_1.2 和接口更改 SUNW_1.1.1 的情况,它们是在同一个发行周期内添加的。两个接口都继承原始接口 SUNW_1.1。
$ cat mapfile $mapfile_version 2 SYMBOL_VERSION SUNW_1.2 { # Release X+1. global: foo3; } SUNW_1.1; SYMBOL_VERSION SUNW_1.1.1 { } SUNW_1.1; # Release X+1. SYMBOL_VERSION SUNW_1.1 { # Release X. global: foo2; foo1; local: *; };
注 - SUNW_1.1 和 SUNW_1.1.1 版本定义的注释指明它们应用于同一个发行版。
有时,新的行业标准中会采用供应商接口提供的符号。创建新标准接口时,请务必维护共享目标文件提供的原始接口定义。创建一些中间版本定义,以便根据它们生成新标准定义和原始接口定义。
以下 mapfile 示例显示了添加新的行业标准接口 STAND.1。此接口包含新符号 foo4 以及现有符号 foo3 和 foo1,它们最初分别通过接口 SUNW_1.2 和 SUNW_1.1 提供。
$ cat mapfile $mapfile_version 2 SYMBOL_VERSION STAND.1 { # Release X+2. global: foo4; } STAND.0.1 STAND.0.2; SYMBOL_VERSION SUNW_1.2 { # Release X+1. global: SUNW_1.2; } STAND.0.1 SUNW_1.1; SYMBOL_VERSION SUNW_1.1.1 { } SUNW_1.1; # Release X+1. SYMBOL_VERSION SUNW_1.1 { # Release X. global: foo2; local: *; } STAND.0.2; # Subversion - providing for SYMBOL_VERSION STAND.0.1 { # SUNW_1.2 and STAND.1 interfaces. global: foo3; }; # Subversion - providing for SYMBOL_VERSION STAND.0.2 { # SUNW_1.1 and STAND.1 interfaces. global: foo1; };
符号 foo3 和 foo1 被引入各自的中间接口定义(用于创建原始接口定义和新接口定义)中。
SUNW_1.2 接口的新定义引用了自身的版本定义符号。如果没有此引用,SUNW_1.2 接口将不包含任何即时符号引用,从而将归类为弱版本定义 (weak version definition)。
将符号定义迁移到标准接口中时,任何原始接口定义都必须继续表示相同符号列表。可以使用 pvs(1) 验证此要求。以下示例显示了软件发行版 X+1 中存在的 SUNW_1.2 接口的符号列表。
$ pvs -ds -N SUNW_1.2 libfoo.so.1 SUNW_1.2: foo3; SUNW_1.1: foo2; foo1;
尽管新标准接口在软件发行版 X+2 中的引入更改了可用的接口版本定义,但每个原始接口提供的符号列表均保持不变。以下示例显示了接口 SUNW_1.2 仍然提供符号 foo1、foo2 和 foo3。
$ pvs -ds -N SUNW_1.2 libfoo.so.1 SUNW_1.2: STAND.0.1: foo3; SUNW_1.1: foo2; STAND.0.2: foo1;
应用程序可能只引用新的子版本中的一个。在这种情况下,尝试在上一个发行版中运行此应用程序将导致运行时版本控制错误。请参见绑定到版本定义。
通过直接引用现有的版本名称,可以提升应用程序的版本绑定。请参见绑定到额外的版本定义。例如,如果一个应用程序只引用共享目标文件 libfoo.so.1 的符号 foo1,则其版本引用为 STAND.0.2。要使此应用程序能够在以前的发行版上运行,可以使用版本控制指令 mapfile 将版本绑定提升到 SUNW_1.1。
$ cat prog.c extern void foo1(); main() { foo1(); } $ cc -o prog prog.c -L. -R. -lfoo $ pvs -r prog libfoo.so.1 (STAND.0.2); $ cat mapfile $mapfile_version 2 DEPEND_VERSIONS libfoo.so { ALLOW = SUNW_1.1; REQUIRE = SUNW_1.1; }; $ cc -M mapfile -o prog prog.c -L. -R. -lfoo $ pvs -r prog libfoo.so.1 (SUNW_1.1);
实际上,很少需要按这种方式提升版本绑定。因为很少会引入新的标准二进制接口,而且大多数应用程序都引用一个接口系列中的许多符号。