ldd工具
使用ldd工具用户可以查看可执行文件依赖的共享库,以及共享库的加载目录。可执行文件中包含了运行时所需的共享库列表。当可执行文件被运行时,系统负责装载所需的库文件。对《linux 动态库的创建和使用》生成的可执行程序使用ldd,输出结果如下:
[wayz11@linux]$ ldd main
linux-gate.so.1 => (0x00fea000)
libhelloworld.so.1 => /home/wayz11/lib_test/libhelloworld.so.1 (0x007ff000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x4fba2000)
libm.so.6 => /lib/libm.so.6 (0x4ea71000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x4eab6000)
libc.so.6 => /lib/libc.so.6 (0x4e8b2000)
/lib/ld-linux.so.2 (0x4e88f000)
共享库的简称soname
soname的功能
如前所述,可执行文件中包含了共享库依赖列表,列表中列出的是共享库的soname。
soname的主要用于共享库的版本兼容性控制。当我们升级共享库库时,如果新版本兼容老版本,则soname不用升级,使用老版本的库连接的程序,不用重新编译就能使用新库正常运行。如果新版本的库不兼容老版本,则我们必须升级soname,以防止使用老版本的库连接的程序因加载新库不能正常运行。这时系统中,新老版本的库将共存,而不相互影响,使用老版本的库连接的程序加载老库,使用新版本的库连接的程序加载新库。
共享库的三个文件
在库目录下,对应一个库一般存在三个文件:
- 主文件包含了库的代码,包含库的全部版本号。例如《linux 动态库的创建和使用》中生成的libhelloworld.so.1.0.0。
- 第二个文件和库的soname具有相同的名字,它是到主文件的一个软连接。例如《linux 动态库的创建和使用》中生成的libhelloworld.so.1。这个文件是必须的,共享库装载器使用这个文件加载共享库。
- 第三个文件为库的名字。例如《linux 动态库的创建和使用》中生成的libhelloworld.so。这个文件只用于编译程序,有了这个文件,我们就可以使用-lhelloword选项指明连接libhelloworld.so.1.0.0库。
现在我们对这三个文件做一下总结:在编译时,我们指定-lhelloword选项,连接器ld知道需要连接libhelloworld.so文件,而libhelloworld.so又是libhelloworld.so.1.0.0的软连接,进而连接libhelloworld.so.1.0.0。连接器从libhelloworld.so.1.0.0中读取soname,写入可执行程序main的共享库依赖列表中。当main运行时,共享库装载器从main中读取依赖共享库的soname列表,其中就有我们的libhelloworld.so.1。于是共享库装载器加载libhelloworld.so.1文件,而这个文件又是到libhelloworld.so.1.0.0的软连接,进而共享库装载器加载libhelloworld.so.1.0.0共享库文件。
共享库的升级
兼容性升级
假定我们要升级我们的libhelloworld.so.1.0.0库,新库完全兼容老库。假定新库的版本号为libhelloworld.so.1.8.3。由于是兼容升级,则soname仍为libhelloworld.so.1。这时我们只需重新指定libhelloworld.so.1和libhelloworld.so连个文件连接到libhelloworld.so.1.8.3。注:使用老的库的程序,需要重启才能重新加载新库。
非兼容性升级
假定我们又要升级,新库不兼容老库,新库的版本号为libhelloworld.so.2.0.0,新库的soname为libhelloworld.so.2。则我们需要重新生成libhelloworld.so软连接,指向libhelloworld.so.2.0.0,这样新编译的程序将连接新库。我们还需要重新生成libhelloworld.so.2软连接,指向libhelloworld.so.2.0.0库。这样将使得新老库并存,使用老库连接的程序和使用新库的程序都能加载对应的库运行。
共享库装载器
共享库装载器,也被称为动态链接器。在程序运行时,共享库装载器替程序加载合适版本的共享库到内存。共享库装载的器的名字为ld.so或ld-linux.so,这取决于Linux libc的版本。
共享库搜索路径配置文件
文件 /etc/ld.so.conf 定义了共享库装载程序的搜索路径。一般这个文件只包含一行内容,如下:
include /etc/ld.so.conf.d/*.conf
这是说这个文件包含/etc/ld.so.conf.d中所有以.conf结尾的文件。通常为了好管理,我们在/etc/ld.so.conf.d目录下生成一个新conf文件,包含我们欲添加的库目录即可。
每次对搜索路径配置文件做出更改后,需要以root身份运行ldconfig命令。这个命令不仅会更新/etc/ld.so.cache文件,同时,还会更新以库的soname命名的软连接,使其指向最新版本的库。
共享库装载器使用的环境变量
具体可参见man手册:
man 8 ld.so