Linux 中動態連結庫的版本號以及ldconfig
動態連結庫的三個名字
1. realname, 真正的名字,一般情況下如果你有版本,應該在後面加上lib[libraryname].so.[version] eg: libtest.so.1.0.0
2. soname, 在編譯動態庫的時候指定的名字,這個名字將會被新增到動態庫的頭部,通過readelf -d 可以檢視, 這個名字是可以沒有的。一般為lib[libraryname].so.i 或 lib[libraryname].so.i.i.
3. linkname, 可執行檔案在載入動態庫的時候查詢的名字,lib[libraryname].so, 後面沒有版本號,若soname存在,最後動態庫連線到的是soname,若soname不存在,而linkname直接軟連線到真正的庫名稱上面, 可執行檔案就將linkname當作soname.
lrwxrwxrwx 1 root root 28 Aug 1 15:59 /usr/local/lib/libopencv_xfeatures2d.so -> libopencv_xfeatures2d.so.3.4 lrwxrwxrwx 1 root root 30 Aug 1 15:59 /usr/local/lib/libopencv_xfeatures2d.so.3.4 -> libopencv_xfeatures2d.so.3.4.2 -rw-r--r-- 1 root root 3090824 Aug 1 22:07 /usr/local/lib/libopencv_xfeatures2d.so.3.4.2
上面的例子就闡述了opencv的連線關係 libopencv_xfeatures2d.so 是linkname, 是編譯可執行檔案的時候查詢的名字,
libopencv_xfeatures2d.so.3.4 是 soname, 這個名字也被嵌入在libopencv_xfeatures2d.so.3.4.2頭部,我們通過readelf -d 檢視一下
readelf -d /usr/local/lib/libopencv_xfeatures2d.so.3.4.2 | grep soname 0x000000000000000e (SONAME) Library soname: [libopencv_xfeatures2d.so.3.4]
這樣的做法允許了動態庫真正的realname更新的時候(小版本更新,原有介面不變), soname本身的名字不需要改變,linkname一直不需要改變,而linkname軟連線的soname物件也不需要改變,只需要改變soname軟連線的realname動態庫就可以了
1. 可以通過手動改變軟連線
2. 可以通過執行ldconfig操作,前提是動態庫路徑在xx.conf檔案中, 或者在LD_LIBRARY_PATH中
若兩個realname在頭部有同樣的soname,ldconfig會選取版本更高的進行軟連線。
libtestuser.so libtestuser.so.1.0 libtestuser.so.1.0.0
假設現在有這三個檔案,分別是我們前面所說的三個linkname, soname, realname,
現在有一個main.cpp, 依賴這個動態庫,編譯它
注意我已經在/etc/ld.so.conf.d/xx.conf裡面添加了這裡的路徑並且更新了ldconfig,這樣linker才能查詢到這個庫。
g++ main.cpp -o main -L./build -ltestuser
通過兩種方式檢視一下main的依賴
1.
[email protected]:~/gitlab/test$ ldd main
linux-vdso.so.1 => (0x00007ffd9c98f000)
libtestuser.so.1.0 => /home/blindfind/gitlab/test/build/libtestuser.so.1.0 (0x00007f380cd1b000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f380ca0c000)
2.
readelf -d main | grep NEEDED
0x0000000000000001 (NEEDED) Shared library: [libtestuser.so.1.0]
0x0000000000000001 (NEEDED) Shared library: [libstdc++.so.6]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
可以看見實際上依賴找的是soname,而soname是嵌入在真正的動態庫裡面的。
再說明一下動態庫依賴動態庫的問題
如果liba.so 依賴 libb.so, 而main依賴liba.so, 如何做到編譯main的時候不指定libb.so的路徑?
雖然編譯動態庫並不需要指定依賴路徑,但是這時候指定可以不再main編譯的時候再次指定liba依賴的動態庫了
[email protected]:~/gitlab/test$ g++ -shared -fPIC -Wl,-soname,libtestuser.so.1 -o libtestuser.so.1.0.0 testUser.cpp -L. -ltest
[email protected]:~/gitlab/test$ ls
build CMakeLists.txt libtest.so libtest.so.1 libtest.so.1.0.1 libtestuser.so.1.0.0 main main.cpp test.cpp test.h testmore test.o testUser.cpp testUser.h
[email protected]:~/gitlab/test$ ldd libtestuser.so.1.0.0
linux-vdso.so.1 => (0x00007ffc9d3e2000)
libtest.so.1 (0x00007ffae2802000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007ffae24d5000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ffae210a000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007ffae1e02000)
/lib64/ld-linux-x86-64.so.2 (0x00007ffae2c08000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007ffae1bec000)
這時候進行指定,可以看見libtestuser依賴了libtest
看一下libtestuser的soname.
readelf -d libtestuser.so.1.0.0 | grep soname
0x000000000000000e (SONAME) Library soname: [libtestuser.so.1]
執行ldconfig,可以看見多了libtestuser.so.1 的軟連線,這是通過檢視libtestuser.so.1.0.0 的soname決定的
[email protected]:~/gitlab/test$ sudo ldconfig
[sudo] password for blindfind:
[email protected]:~/gitlab/test$ ls
build CMakeLists.txt libtest.so libtest.so.1 libtest.so.1.0.1 libtestuser.so.1 libtestuser.so.1.0.0 main main.cpp test.cpp test.h testmore test.o testUser.cpp testUser.h
然後編譯main函式,不指定libtest.so,光指定libtestuser.so, 別忘了先新增linkname的軟連線 ln -s libtesetuser.so.1 libtestuser.so
[email protected]:~/gitlab/test$ g++ main.cpp -o main -L. -ltestuser
[email protected]:~/gitlab/test$ ldd main
linux-vdso.so.1 => (0x00007ffe03917000)
libtestuser.so.1 (0x00007f86d92e1000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f86d8fb4000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f86d8be9000)
libtest.so.1 (0x00007f86d89e7000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f86d86df000)
/lib64/ld-linux-x86-64.so.2 (0x00007f86d94e5000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f86d84c8000)
[email protected]:~/gitlab/test$ ./main
4
[email protected]:~/gitlab/test$
main執行成功,而且ldd檢視以後,發現libtest.so自動被添加了進來,因為libtestuser.so依賴libtest.so