我们在linux下开发项⽬,有时会对外提供动态库,像***.so.1.0.0这样⼦的⽂件,另外提供相应的头⽂件。⽤户拿到动态库和头⽂件说明,就可以使⽤动态库⾥的function。
那随之⽽来的⼀个问题是,动态库的升级问题,我们的动态库更改了⼀个bug,升级了⼀个版本,那使⽤我们动态库的应⽤程序需要重新编译吗?运⾏时会产⽣异常吗?linux下是怎么规范这些内容的呐?⼤家⼀定听说过windows下的dll hell。
Linux中的.so⽂件 是动态链接的产物
共享库理解为提供各种功能函数的集合,对外提供标准的接⼝Linux中命名系统中共享库的规则
主版本号:不同的版本号之间不兼容次版本号:增量升级 向后兼容
发⾏版本号:对应次版本的错误修正和性能提升,不影响兼容性下⾯说说linux下动态库的命名规范。
为⽅便管理依赖关系,创建或部署共享库时,必须遵循统⼀约定的规则才⾏,其中包括动态库的命名规则及其部署⽅式。共享库命名约定
1) 每个动态库有⼀个包含了真正的库代码的⽂件名,通常被称为库的 realname ,命名格式通常为
libxxx.so.x.y.z,其中so后缀中的x为主版本号,y为副版本号,z为发⾏版本号。例如,我的linux系统机器上zlib共享库的realname为 libz.so.1.2.8,这个⽂件是含有可执⾏的⼆进制代码的。
2) 每个动态库都有⼀个以\"lib\"为前缀且以\".so.x\"为结尾的被称为 soname
的特定名称,其中x为主版本号,soname命名格式通常为libxxx.so.x。例如,我的linux系统机器上zlib共享库的soname为libz.so.1。这个soname包含了动态库的主版本号,这个doname⼀般会包含在库代码的头⽂件中,这个可以使⽤ readelf -d 读取出来,使⽤这个动态库的程序的⼆进制ELF的头⽂件中包含有这个动态库的soname。程序运⾏时会按照这个名称去找真正的库⽂件。
3) 此外,编译链依赖了共享库的应⽤模块时,链接器只认不带任何版本号的共享库名, 可以将库名称作\" linker name。
例如,我的linux系统机器上zlib共享库的linkername为libz.so。也即,链接使⽤了动态库的程序时查找的动态库名称。例如:gcc -o testtest.o -lz , 链接时就会找libz.so 。若没有这个⽂件,链接器就报错。
以实际例⼦的形式,详细地阐述了realname soname linkername 之间的关系。
添加动态链接库路径
1. 连接和运⾏时库⽂件搜索路径到设置
库⽂件在连接(静态库和共享库)和运⾏(仅限于使⽤共享库的程序)时被使⽤,其搜索路径是在系统中进⾏设置的。⼀般 Linux 系统把/lib 和 /usr/lib 两个⽬录作为默认的库搜索路径,所以使⽤这两个⽬录中的库时不需要进⾏设置搜索路径即可直接使⽤。对于处于默认库搜索路径之外的库,需要将库的位置添加到库的搜索路径之中。设置库⽂件的搜索路径有下列两种⽅式,可任选其⼀使⽤:
(1). 在 /etc/ld.so.conf ⽂件中添加库的搜索路径。(或者在/etc/ld.so.conf.d 下新建⼀个.conf⽂件,将搜索路径⼀⾏⼀个加⼊-junziyang)将⾃⼰可能存放库⽂件的路径都加⼊到/etc /ld.so.conf中是明智的选择添加⽅法也极其简单,将库⽂件的绝对路径直接写进去就OK了,⼀⾏⼀个。例如:1/usr/X11R6/lib2/usr/local/lib3/opt/lib
需要注意的是:这种搜索路径的设置⽅式对于程序连接时的库(包括共享库和静态库)的定位已经⾜够了,但是对于使⽤了共享库的程序
的执⾏还是不够的。这是因为为了加快程序执⾏时对共享库的定位速度,避免使⽤搜索路径查找共享库的低效率,所以是直接读取库列表⽂件 /etc/ld.so.cache 从中进⾏搜索的。/etc/ld.so.cache 是⼀个⾮⽂本的数据⽂件,不能直接编辑,它是根据 /etc/ld.so.conf 中设置的搜索路径由 /sbin/ldconfig 命令将这些搜索路径下的共享库⽂件集中在⼀起⽽⽣成的(ldconfig 命令要以 root 权限执⾏)。
因此,为了保证程序执⾏时对库的定位,在 /etc/ld.so.conf 中进⾏了库搜索路径的设置之后,还必须要运⾏ /sbin/ldconfig 命令更新
/etc/ld.so.cache ⽂件之后才可以。ldconfig ,简单的说,它的作⽤就是将/etc/ld.so.conf列出的路径下的库⽂件缓存到/etc/ld.so.cache 以供使⽤。因此当安装完⼀些库⽂件,(例如刚安装好glib),或者修改ld.so.conf增加新的库路径后,需要运⾏⼀下 /sbin/ldconfig使所有的库⽂件都被缓存到ld.so.cache中,如果没做,即使库⽂件明明就在/usr/lib下的,也是不会被使⽤的,结果编译过程中抱错,缺少xxx库,去查看发现明明就在那放着,搞的想⼤骂computer蠢猪⼀个。
在程序连接时,对于库⽂件(静态库和共享库)的搜索路径,除了上⾯的设置⽅式之外,还可以通过 -L 参数显式指定。因为⽤ -L 设置的路径将被优先搜索,所以在连接的时候通常都会以这种⽅式直接指定要连接的库的路径。
这种设置⽅式需要 root 权限,以改变 /etc/ld.so.conf ⽂件并执⾏ /sbin/ldconfig 命令。⽽且,当系统重新启动后,所有的基于 GTK2 的程序在运⾏时都将使⽤新安装的 GTK+ 库。不幸的是,由于 GTK+ 版本的改变,这有时会给应⽤程序带来兼容性的问题,造成某些程序运⾏不正常。为了避免出现上⾯的这些情况,在 GTK+ 及其依赖库的安装过程中对于库的搜索路径的设置将采⽤另⼀种⽅式进⾏。这种设置⽅式不需要 root 权限,设置也简单。
(2). 在环境变量 LD_LIBRARY_PATH 中指明库的搜索路径。
设置⽅式:
1export LD_LIBRARY_PATH=/opt/gtk/lib:$LD_LIBRARY_PATH可以⽤下⾯的命令查看 LD_LIBRAY_PATH 的设置内容:1echo $LD_LIBRARY_PATH
⾄此,库的两种设置就完成了。
查看程序使⽤的动态库ldd <可执⾏程序>
因篇幅问题不能全部显示,请点此查看更多更全内容