1. 搜索路径
1.1 链接时搜索路径
-L path
,-rpath-link
,LD_LIBRARY_PATH
1.2 运行时搜索路径
-Wl
,-rpath path
,LD_LIBRARY_PATH
运行搜索路径优先级:- 可执行程序的RUNPATH段
- 可执行程序的RPATH段
- LD_LIBRARY_PATH
- /etc/ld.so.cache
- /usr/lib/、/lib/
1.3 使用 ldd 命令找不到对应的共享库文件
可能是两种情况引起的:
- 共享库没有安装在该系统中;
- 共享库保存在 /etc/ld.so.conf 文件列出的搜索路径之外的位置;
通常情况下,许多开放源代码的程序或函数库都会默认将自己安装到
/usr/local
目录下的相应位置, 如:/usr/local/bin
或/usr/local/lib
, 以便与系统自身的程序或函数库相区别; 而许多 Linux 系统的/etc/ld.so.conf
文件中默认又不包含/usr/local/lib
。因此,往往会出现已经安装了共享库,但是却无法找到共享库的情况。具体解决办法如下:
检查 /etc/ld.so.conf 文件,如果其中缺少 /usr/local/lib 目录,就添加进去;
!!! 注意 !!!: 在修改了/etc/ld.so.conf
文件或者在系统中安装了新的函数库之后,需要运行ldconfig
命令 ,该命令用来刷新系统的共享库缓存(为了减少共享库系统的库搜索时间,共享库系统维护了一个共享库 soname 的缓存文件/etc/ld.so.cache
)。
2. 版本兼容和soname机制
2.1 创建so:
% gcc –shared –Wl,-soname,libname.so.x –o libname.x.y.z x.o
可以在编译动态库的同时给动态库创建soname(libname.so.x)
, libname.x.y.z
是动态库的realname,其中:
- x表示主版本号,在改变库里的任何函数接口时才进行改变,接口变以后,前面用到这个函数的程序就不能运行了,
- y表示次版本号,是不改变任何函数的接口,只加了几个新的函数,这样前面的程序也能运行,
- z表示维护号,是修改现有函数的bug时才改变。
如果你没有改大版本号,这时只需要把新动态库库覆盖掉旧动态库就行了;
但如果大版本号改了,那新旧动态库要同时存在,新程序需要新soname,旧程序需要旧soname。
2.2 链接so:
% gcc test.c –lname –L .
-L . 指定linkname(libname.so)
所在的目录,它是到实际的库文件的一个软链接,libname.x.y.z
文件中会有soname的信息(libname.x)
, ld把soname的信息保存在生成的可执行代码中; 链接时一般是链接到最新的库文件,但不需要知道具体的版本号。
2.3 运行时加载:
程序执行的时候就会加载soname(libname.x)
–>realname(libname.x.a.b)
并运行。
2.4 相关文件汇总
#lib 目录中每个库文件一般会有以下几个相关文件
#链接的时候用,把实际文件的soname信息包含到可执行文件中
lrwxrwxrwx 1 root root 22 2014-09-17 17:46 libname.so -> libname.so.0.0.0
#运行的时候用,根据可执行文件中的soname信息查找实际的库文件
lrwxrwxrwx 1 root root 22 2014-09-17 17:46 libname.so.0 -> libname.so.0.0.0
#实际的库文件
-rwxr-xr-x 1 root root 18572 2009-06-05 17:28 libname.so.0.0.0
3. 一些实用的小技巧
只要在gcc上指定连接库的名字,ld默认就会把它连接到目标程序中去,然而一些无意义的动态库链接到可执行程序只会使程序的启动速度变慢:
- 使用ldd -u xxx查看xxx中不需要链接的so
- 使用-Wl,–as-needed编译选项让编译器来决定链接哪些必要的so(注意-Wl,和后面选项之间不能有空格)