日期:2014-05-16 浏览次数:20778 次
使用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,以防止使用老版本的库连接的程序因加载新库不能正常运行。这时系统中,新老版本的库将共存,而不相互影响,使用老版本的库连接的程序加载老库,使用新版本的库连接的程序加载新库。
在库目录下,对应一个库一般存在三个文件:
现在我们对这三个文件做一下总结:在编译时,我们指定-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
每次对搜索路径配置文件做出更改后,需要以root身份运行ldconfig命令。这个命令不仅会更新/etc/ld.so.cache文件,同时,还会更新以库的soname命名的软连接,使其指向最新版本的库。
具体可参见man手册:
man 8 ld.so