Linux动态库管理

15 篇文章 0 订阅

参考链接
Linux 动态库版本管理
一文读懂Linux下动态链接库版本管理及查找加载方式

由一个问题谈起

linux下的动态链接库的名字后缀是so,但是我们有时候也会遇到下面的报错
./a.out: error while loading shared libraries: libtest.so.1: cannot open shared object file: No such file or directory
动态链接库的后缀不是so吗?怎么会提示链接不到libtest.so.1呢?
再看第一个例子,在linux下查看下bash的依赖库,可以发现bash依赖的动态库是libxxx.so.x的,不是常见的libxxx.so。

$ ldd /bin/bash
	linux-vdso.so.1 (0x00007ffedb129000)
	libtinfo.so.6 => /lib/x86_64-linux-gnu/libtinfo.so.6 (0x00007f135ae6b000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f135ac43000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f135b018000)

第二个例子,再比如OpenCV的so,可以看到,libopencv_aruco.so是libopencv_aruco.so.4.5的软链接,libopencv_aruco.so.4.5是libopencv_aruco.so.4.5.4的软链接,为什么会这样设计呢?

$ ls -alh libopencv_*
lrwxrwxrwx 1 root root   22  916 00:41 libopencv_aruco.so -> libopencv_aruco.so.4.5
lrwxrwxrwx 1 root root   24  916 00:41 libopencv_aruco.so.4.5 -> libopencv_aruco.so.4.5.4
-rw-r--r-- 1 root root 428K  916 00:41 libopencv_aruco.so.4.5.4
lrwxrwxrwx 1 root root   24  916 00:41 libopencv_barcode.so -> libopencv_barcode.so.4.5
lrwxrwxrwx 1 root root   26  916 00:41 libopencv_barcode.so.4.5 -> libopencv_barcode.so.4.5.4
-rw-r--r-- 1 root root 124K  916 00:41 libopencv_barcode.so.4.5.4
lrwxrwxrwx 1 root root   23  916 00:41 libopencv_bgsegm.so -> libopencv_bgsegm.so.4.5
lrwxrwxrwx 1 root root   25  916 00:41 libopencv_bgsegm.so.4.5 -> libopencv_bgsegm.so.4.5.4

其实这是linux下的动态库的版本管理方式引起的,这篇文章简单讨论下。

linux下的动态库管理

根据网上查的资料,linux下的动态链接库有下面三种:

real name

real name,字如其名意思就是链接的真实的so名字,一般形式为:libname.so.x.y.z,具体的解释引用链接的解释

x是主版本号(Major Version Number),y是次版本号(Minor Version Number),z是发布版本号(Release Version Number), 并且它们具有以下要求。

  • 主版本号(不兼容):重大升级,不同主版本的库之间的库是不兼容的,所以如果要保证向后兼容就不能删除旧的动态库的版本。
  • 次版本号(向下兼容): 增量升级,增加一些新的接口但保留原有接口,高次版本号的库向后兼容低次版本号的库。
  • 发布版本号(相互兼容):库的一些诸如错误修改、性能改进等,不添加新接口,也不更改接口,主版本号和次版本号相同的前提下,不同发布版本之间完全兼容。

soname

soname就是linux版本管理的重要机制了。在编译动态链接库的时候,可以设置一个soname参数(通过-Wl,-soname设置),通过这个参数,编译器在链接的时候会根据这个SONAME去找对应的动态库。以库的形式如下libtest.so.x.y.z来举例,如果两个库可以兼容,,那么他们的x是一样的,比如说libtest.so.1.0.0、libtest.so.1.0.1、libtest.so.1.1.1它们三个动态库是互相兼容的,而libtest.so.1.0.0、libtest.so.2.0.1则是不兼容的。

设置soname的方式以及查看某个库是否设置soname的方法, 如下命令

# 设置soname参数
$ g++ -fPIC b.cpp -shared -Wl,-soname,libtest.so.1 -o libtest.so.1.0
# 查看so是否有soname
$ readelf -d libtest.so.1.0 | grep SONAME
0x000000000000000e (SONAME)             Library soname: [libtest.so.1]

link name

link name,就是用gcc或者g++编译的时候,-l指定的so名字,比如说下面例子的-ltest

g++ main.cpp -L. -ltest

三个so的关系

上面介绍了三类so,那么我们再来看下他们之间的关系,以及编译器如何链接的
假如我们编译一个OpenCV的程序,编译命令

# 编译出可执行文件 a.out
$ g++ main.cpp -o a.out -I /usr/local/include/opencv4/ -L /usr/local/lib \
	-lopencv_core -lopencv_videoio \
  -lopencv_imgproc -lopencv_objdetect -lopencv_highgui

# 查看a.out的OpenCV依赖
$ ldd a.out | grep opencv
	libopencv_core.so.4.5 => /usr/local/lib/libopencv_core.so.4.5 (0x00007fe5d629c000)
  ......
# 查看opencv_core.so.4.5.4的soname
$ readelf -d /usr/local/lib/libopencv_core.so.4.5.4 | grep SONAME
 0x000000000000000e (SONAME)             Library soname: [libopencv_core.so.4.5]

以opencv_core.so为例,core.so的软链接是这样的
libopencv_core->libopencv_core.4.5->libopencv_core4.5.4

  • 编译阶段,编译的时候制定链接的so,-lopencv_core.so(link name),链接的时候会根据软链接关系找到libopencv_core4.5.4,读取soname写入到可执行文件中。
  • 运行时候,链接器读取可执行文件的soname,就是libopencv_core.4.5,再根据软链接的关系,最终找到libopencv_core4.5.4(real name)

这种方式的优势

如果使用了这种动态库管理方式,以OpenCV为例,如果小版本升级,比如说4.5.4要升级到4.5.5,可以直接把libopencv_core.so.4.5重新指向libopencv_core.so.4.5.5,不需要重新编译库。如果大版本升级,因为大版本的接口可能不兼容,所以大版本升级要重新编译。

如果一些比较简单的so,可以不用soname这种机制,直接编译出libtest.so链接上,这样做事很方便,但是缺点是看不出版本的信息。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chasentech

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值