1. 版本组织
Linux共享库版本组织主要分为共享库版本和符号版本:
1) 共享库版本:
共享库采用x.y.z的方式标识共享库版本,x为主版本号,y为次版本号,z为发布版本号;
当主版本号发生变化时,代表共享库版本发生了不兼容的变化,如函数签名变化、接口数据结构变化、函数行为变化等;
当次版本号发生变化时,代表共享库版本增加了新特性,但已有的函数、数据结构等保持兼容;
当发布版本号发生变化时,代表共享库版本修正了BUG,或改进了性能。
因此,如果应用程序使用的共享库的主版本发生了变化,应用程序可能会无法运行;如果仅是次版本号或发布版本号升级,则应用程序不会受影响。
应用程序依赖的共享库的主版本号相同,但次版本号偏低,则应用程序可能可以运行,也有可能不能运行,这取决于应用程序是否使用了新版本中增加提供的接口或数据结构。
因为在运行应用程序时,操作系统如果发现共享库的次版本号偏低,可能采用不允许程序运行的策略,但实际上应用程序可能根本就没有使用较高次版本号中的接口。
为了解决此问题引入了符号版本。
2) 符号版本:
符号版本,即对于每一个符号都有一个版本号。共享库在发布时,标识出了每个符号的最新版本号。如:
VERS_1.2 {
global:
func2;
local:
*
}
VERS_1.1 {
global:
func1;
local:
*
}
func2的符号版本为1.2,而func1的符号版本为1.1。
在生成应用程序时,将会在应用程序文件中根据使用到的符号记录需要的符号版本。在使用动态链接库时,如果发现符号版本低于应用程序要求的版本,将无法运行。
另外,上图中的global和local关键字的作用时用于标识动态库中哪些符号是全局的,哪些是共享库的内部符号。对于共享库内部符号,则不允许应用程序使用。
2. SO-NAME
应用程序需要指定依赖的共享库,因为相同主版本号的共享库是向后兼容的,因此不需要指定共享库的完整版本,而只需要指定它的主版本。
共享库的名称加上它的主版本号,就构成了共享库的SO-NAME,比如libc.so.1.5.3,它的SO-NAME为libc.so.1。
在通过libconfig安装共享库时,会为共享库创建一个软链接文件,并以它的SO-NAME命名。比如上例中,就会生成一个libc.so.1的链接文件,指向libc.so.1.5.3文件。
3. 共享库的路径
共享库文件通常放在下面三个路径中的一个:
/lib: 存放系统最关键和基础的共享库,比如动态链接器,C运行库等。这些库主要是/bin和/sbin下的程序要用到的库,还有系统启动时需要的库;
/usr/lib:存放非系统运行时需要的关键的共享库,主要是开发时需要的共享库文件;
/usr/local/lib:存放与操作系统无关的共享库,如第三方运行时库。比如在安装python时,python需要的共享库文件就会在/usr/local/lib/python下。
4. 共享库的查找
应用程序在加载时,会到共享库的存放路径下查找共享库文件。查找的顺序为:
1) LD_LIBRARY_PATH中指定的路径
2) /etc/ld.so.cache中指定的路径
再通过ldconfig安装共享库时,ldconfig会自动在/etc/ld.so.cache中加入安装的共享库。这个文件主要是为了提高共享库文件的查找速度。
3) 默认共享库目录,先/usr/lib再/lib