由一個(gè)問(wèn)題談起,linux下的動(dòng)態(tài)鏈接庫(kù)的名字后綴是so,但是我們有時(shí)候也會(huì)遇到下面的報(bào)錯(cuò)
./a.out: error while loading shared libraries: libtest.so.1: cannot open shared object file: No such file or directory
動(dòng)態(tài)鏈接庫(kù)的后綴不是so嗎?怎么會(huì)提示鏈接不到libtest.so.1呢?再看第一個(gè)例子,在linux下查看下bash的依賴(lài)庫(kù),可以發(fā)現(xiàn)bash依賴(lài)的動(dòng)態(tài)庫(kù)是libxxx.so.x的,不是常見(jiàn)的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)
第二個(gè)例子,再比如OpenCV的so,可以看到,libopencv_aruco.so是libopencv_aruco.so.4.5的軟鏈接,libopencv_aruco.so.4.5是libopencv_aruco.so.4.5.4的軟鏈接,為什么會(huì)這樣設(shè)計(jì)呢?
$ ls -alh libopencv_*
lrwxrwxrwx 1 root root 22 9月 16 00:41 libopencv_aruco.so -> libopencv_aruco.so.4.5
lrwxrwxrwx 1 root root 24 9月 16 00:41 libopencv_aruco.so.4.5 -> libopencv_aruco.so.4.5.4
-rw-r--r-- 1 root root 428K 9月 16 00:41 libopencv_aruco.so.4.5.4
lrwxrwxrwx 1 root root 24 9月 16 00:41 libopencv_barcode.so -> libopencv_barcode.so.4.5
lrwxrwxrwx 1 root root 26 9月 16 00:41 libopencv_barcode.so.4.5 -> libopencv_barcode.so.4.5.4
-rw-r--r-- 1 root root 124K 9月 16 00:41 libopencv_barcode.so.4.5.4
lrwxrwxrwx 1 root root 23 9月 16 00:41 libopencv_bgsegm.so -> libopencv_bgsegm.so.4.5
lrwxrwxrwx 1 root root 25 9月 16 00:41 libopencv_bgsegm.so.4.5 -> libopencv_bgsegm.so.4.5.4
其實(shí)這是linux下的動(dòng)態(tài)庫(kù)的版本管理方式引起的,這篇文章簡(jiǎn)單討論下。根據(jù)網(wǎng)上查的資料,linux下的動(dòng)態(tài)鏈接庫(kù)有下面三種:
第一個(gè),real name,字如其名意思就是鏈接的真實(shí)的so名字,一般形式為:libname.so.x.y.z,具體的解釋引用鏈接的解釋
x是主版本號(hào)(Major Version Number),y是次版本號(hào)(Minor Version Number),z是發(fā)布版本號(hào)(Release Version Number), 并且它們具有以下要求。
主版本號(hào)(不兼容):重大升級(jí),不同主版本的庫(kù)之間的庫(kù)是不兼容的,所以如果要保證向后兼容就不能刪除舊的動(dòng)態(tài)庫(kù)的版本。
次版本號(hào)(向下兼容): 增量升級(jí),增加一些新的接口但保留原有接口,高次版本號(hào)的庫(kù)向后兼容低次版本號(hào)的庫(kù)。
發(fā)布版本號(hào)(相互兼容):庫(kù)的一些諸如錯(cuò)誤修改、性能改進(jìn)等,不添加新接口,也不更改接口,主版本號(hào)和次版本號(hào)相同的前提下,不同發(fā)布版本之間完全兼容。
第二個(gè),soname就是linux版本管理的重要機(jī)制了。在編譯動(dòng)態(tài)鏈接庫(kù)的時(shí)候,可以設(shè)置一個(gè)soname參數(shù)(通過(guò)-Wl,-soname設(shè)置),通過(guò)這個(gè)參數(shù),編譯器在鏈接的時(shí)候會(huì)根據(jù)這個(gè)SONAME去找對(duì)應(yīng)的動(dòng)態(tài)庫(kù)。以庫(kù)的形式如下libtest.so.x.y.z來(lái)舉例,如果兩個(gè)庫(kù)可以兼容,,那么他們的x是一樣的,比如說(shuō)libtest.so.1.0.0、libtest.so.1.0.1、libtest.so.1.1.1它們?nèi)齻€(gè)動(dòng)態(tài)庫(kù)是互相兼容的,而libtest.so.1.0.0、libtest.so.2.0.1則是不兼容的。
設(shè)置soname的方式以及查看某個(gè)庫(kù)是否設(shè)置soname的方法, 如下命令
# 設(shè)置soname參數(shù)
$ 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]
第三個(gè),link name,就是用gcc或者g++編譯的時(shí)候,-l指定的so名字,比如說(shuō)下面例子的-ltest
g++ main.cpp -L. -ltest
上面介紹了三類(lèi)so,那么我們?cè)賮?lái)看下他們之間的關(guān)系,以及編譯器如何鏈接的。假如我們編譯一個(gè)OpenCV的程序,編譯命令
# 編譯出可執(zhí)行文件 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依賴(lài)
$ 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
編譯階段,編譯的時(shí)候制定鏈接的so,-lopencv_core.so(link name),鏈接的時(shí)候會(huì)根據(jù)軟鏈接關(guān)系找到libopencv_core4.5.4,讀取soname寫(xiě)入到可執(zhí)行文件中。
運(yùn)行時(shí)候,鏈接器讀取可執(zhí)行文件的soname,就是libopencv_core.4.5,再根據(jù)軟鏈接的關(guān)系,最終找到libopencv_core4.5.4(real name)
如果使用了這種動(dòng)態(tài)庫(kù)管理方式,以O(shè)penCV為例,如果小版本升級(jí),比如說(shuō)4.5.4要升級(jí)到4.5.5,可以直接把libopencv_core.so.4.5重新指向libopencv_core.so.4.5.5,不需要重新編譯庫(kù)。如果大版本升級(jí),因?yàn)榇蟀姹镜慕涌诳赡懿患嫒荩源蟀姹旧?jí)要重新編譯。
如果一些比較簡(jiǎn)單的so,可以不用soname這種機(jī)制,直接編譯出libtest.so鏈接上,這樣做事很方便,但是缺點(diǎn)是看不出版本的信息。
審核編輯:劉清
-
OpenCV
+關(guān)注
關(guān)注
32文章
642瀏覽量
42432 -
LINUX內(nèi)核
+關(guān)注
關(guān)注
1文章
317瀏覽量
22186 -
gcc編譯器
+關(guān)注
關(guān)注
0文章
78瀏覽量
3648
發(fā)布評(píng)論請(qǐng)先 登錄
Linux動(dòng)態(tài)鏈接庫(kù)的基本概念
關(guān)于使用動(dòng)態(tài)鏈接庫(kù)及圖像采集的問(wèn)題
labview調(diào)用動(dòng)態(tài)鏈接庫(kù)問(wèn)題
LabVIEW之動(dòng)態(tài)鏈接庫(kù)
關(guān)于labview'的動(dòng)態(tài)鏈接庫(kù)的問(wèn)題
基于動(dòng)態(tài)鏈接庫(kù)技術(shù)的感應(yīng)器非線性特性校正
C++中動(dòng)態(tài)鏈接庫(kù)的創(chuàng)建和調(diào)用
LINUX環(huán)境下CLIPS動(dòng)態(tài)鏈接庫(kù)的實(shí)現(xiàn)方法
虛擬儀器中動(dòng)態(tài)鏈接庫(kù)的應(yīng)用

VC++動(dòng)態(tài)鏈接庫(kù)編程深入淺出

由MATLAB的.m文件生成動(dòng)態(tài)鏈接庫(kù)的方法說(shuō)明
英創(chuàng)信息技術(shù)WinCE設(shè)備動(dòng)態(tài)鏈接庫(kù)的制作與調(diào)用

單片機(jī)高階技能之動(dòng)態(tài)鏈接庫(kù)技術(shù)實(shí)現(xiàn)

Linux下的靜態(tài)鏈接庫(kù)和動(dòng)態(tài)鏈接庫(kù)的區(qū)別是什么?

深入探討Linux系統(tǒng)中的動(dòng)態(tài)鏈接庫(kù)機(jī)制

評(píng)論