11-共享库版本和命名规则
41.6 共享库版本和命名规则
下面考虑在共享库的版本化过程中需要做的事情。一般来讲,一个共享库相互连续的两个版本是相互兼容的,这意味着每个模块中的函数对外呈现出来的调用接口是一致的,并且函数的语义是等价的(即它们能取得同样的结果)。这种版本号不同但相互兼容的版本被称为共享库的次要版本。但有时候需要创建创建一个库的新主版本——即与上一个版本不兼容的版本。(在41.8节中将会更加明确地看到哪些方面会引起不兼容性。)同时,必须要确保使用老版本的库的程序仍然能够运行。
为了满足这些版本化的要求,共享库的真实名称和soname必须要使用一种标准的命名规范。
真实名称、soname以及链接器名称
共享库的每个不兼容版本是通过一个唯一的主要版本标识符来区分的,这个主要版本标识符是共享库的真实名称的一部分。根据惯例,主要版本标识符由一个数字构成,这个数字随着库的每个不兼容版本的发布而顺序递增。除了主要版本标识符之外,真实名称还包含一个次要版本标识符,它用来区分库的主要版本中兼容的次要版本。真实名称的格式规范为libname.so.major-id.minor-id。
与主要版本标识符一样,次要版本标识符可以是任意字符串。但根据惯例,它要么是一个数字,要么是两个由点分隔的数字,其中第一个数字标识出了次要版本,第二个数字表示该次要版本中的补丁号或修订号。下面是一些共享库的真实名称。
共享库的soname包括相应的真实名称中的主要版本标识符,但不包含次要版本标识符。因此soname的形式为libname.so.major-id。
通常,会将soname创建为包含真实名称的目录中的一个相对符号链接。下面是一些soname的例子以及它们可能通过符号链接指向的真实名称。
对于共享库的某个特定的主要版本来讲,可能存在几个库文件,这些库文件是通过不同的次要版本标识符来区分的。通常,每个库的主要版本的soname会指向在主要版本中最新的次要版本(如上面的libdemo.so例子所示)。这种配置使得在共享库的运行时操作期间版本化语义能够正确工作。由于静态链接阶段会将soname的副本(独立于次要版本)嵌入到可执行文件中并且soname符号链接后面可能会被修改指向一个更新的(次要)版本的共享库,因此可以确保可执行文件在运行时能够加载库的最新的次要版本。此外,由于一个库的不同的主要版本的soname不同,因此它们能够和平地共存并且被需要它们的程序访问。
除了真实名称和soname之外,通常还会为每个共享库定义第三个名称:链接器名称,将可执行文件与共享库链接起来时会用到这个名称。链接器名称是一个只包含库名同时不包含主要或次要版本标识符的符号链接,因此其形式为libname.so。有了链接器名称之后就可以构建能够自动使用共享库的正确版本(即最新版本)的独立于版本的链接命令了。
一般来讲,链接器名称与它所引用的文件位于同一个目录中,它既可以链接到真实名称,也可以连接到库的最新主要版本的soname。通常,最好使用指向soname的链接,因此对soname所做的变更会自动反应到链接器名称上。(在41.7节中会看到ldconfig程序将保持soname最新的任务自动化了,因此如果使用了刚才介绍的规范的话就是隐式地维护链接器名称。)
如果需要将一个程序与共享库的一个较老的主要版本链接起来,就不能使用链接器名称。相反,在链接命令中需要通过制定具体的真实名称或soname来标示出所需要的版本(主要版本)。
下面是一些链接器名称的例子。
表41-1对共享库的真实名称、soname以及链接器名称进行了总结,图41-3描绘了这些名称之间的关系。

| 名 称 | 格 式 | 描 述 | | :----- | :----- | :----- | :----- | :----- | | 真实名称 | libname.so.maj.min | 保存库代码的文件;每个库的major-plus-minor版本都存在一个真实名称 | | soname | libname.so.maj | 库的每个主要版本都存在一个soname;在链接时被嵌入到可执行文件中;在运行时用来找出指向相应的(最新的)真实名称的同名符号链接所引用的库 | | 链接器名称 | libname.so | 指向真实名称或最新的(更常见的做法)soname的符号链接;只存在一个实例;允许构建版本独立的链接命令 |
使用标准规范创建一个共享库
根据上面介绍的相关知识,下面开始介绍如何遵循标准规范来构建一个演示库。首先需要创建目标文件。
接着创建共享库,其真实名称为libdemo.so.1.0.1,soname为libdemo.so.1。
接着为soname和链接器名称创建恰当的符号链接。
接着可以使用ls来验证配置(使用awk来选择感兴趣的字段)。
接着可以使用链接器名称来构建可执行文件(注意链接命令不会用到版本号),并照常运行这个程序。
