1. 程式人生 > >Linux 中動態連結庫的版本號以及ldconfig

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