【linux】程序找不到動態庫.so的解決辦法|查看.so動態庫信息|.so動態庫加載順序


目錄

找不到.so解決方法

方法一:添加環境變量

方法二:復制so文件到lib路徑

方法三:(推薦)添加ldconfig尋找路徑

方法四:在編譯目標代碼時指定該程序的動態庫搜索路徑

其他命令

查看程序依賴的.so庫

查看動態庫連接過程

查看一個so鏈接庫的版本

查看So文件中的字符串信息(最常見是版本號)

動態庫查找順序

動態庫[鏈接時]路徑和[運行時]路徑

修改efl文件(程序、庫文件)的庫依賴路徑

鏈接靜態庫/動態庫

 


找不到.so解決方法

Linux 動態庫的默認搜索路徑是 /lib 和 /usr/lib,除了默認的搜索路徑外,還可以通過以下幾種方法來指定。

原文:https://www.it610.com/article/1295147005911310336.htm

方法一:添加環境變量

添加環境變量三種方式

1. 添加當前用戶當前終端的環境變量(臨時)

export LD_LIBRARY_PATH=/home/czd/...  #.so file path

2. 添加當前用戶的環境變量

修改~/.bashrc文件,在其末尾,添加環境變量

vim ~/.bashrc
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/czd/...  #.so file path

使其生效,

source ~/.bashrc

如不能生效,請重啟

3. 添加所有用戶的環境變量

修改profile文件,在其末尾添加環境變量

vim /etc/profile
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/czd/...  #.so file path

使其生效

source /etc/profile

如不能生效,請重啟

方法二:復制so文件到lib路徑

linux系統的so庫一般存儲與“/usr/lib/”路徑中,可將動態庫復制到該路徑中。

sudo cp liblibtest.so /usr/lib/

即時生效

方法三:(推薦)添加ldconfig尋找路徑

步驟1. 編輯鏈接配置文件

vim /etc/ld.so.conf,確認內容是否為如下,不是則修改為如下:

include /etc/ld.so.conf.d/*.conf

步驟2. 進入/etc/ld.so.conf.d目錄內,創建*.conf文件,文件名隨意,擴展名必須為.conf

cd /etc/ld.so.conf/
vim libmy.conf 

步驟4. 在文件內部,添加so的路徑,保存並退出

/home/czd/eclipse-workspacee/calllib/Debug

步驟5. 執行命令時期生效

sudo ldconfig

程序在運行時尋找so庫就會到添加的目錄中尋找。

 

https://blog.csdn.net/qq_38350702/article/details/106128030

方法四:在編譯目標代碼時指定該程序的動態庫搜索路徑

 

解決辦法有兩種,第一程序鏈接時指定鏈接庫的位置,就是使用-wl,-rpath=<link_path>參數,<link_path>就是鏈接庫的路徑。如:

gcc -o foo foo.c -L. -lfoo -Wl,-rpath=/usr/mylib

上面就是指定了鏈接的位置在/usr/mylib,執行./foo時,foo會去/usr/mylib找libfoo.so庫。

不過一般情況我們使用如下格式

gcc -o foo foo.c -L$(prefix)/lib -lfoo -Wl,-rpath=$(prefix)/lib

 

其他命令

查看程序依賴的.so庫

查看可以執行程序需要哪些動態庫,以及是否能找到

ldd  /usr/bin/mount

[root@rdma64 lcx]# ldd ./ceph_perf_msgr_server_normal
        linux-vdso.so.1 =>  (0x00007ffc24dec000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f6f9a6ee000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007f6f9a4ea000)
        libmymalloc.so => not found
        libjemalloc.so.1 => not found

        libsnappy.so.1 => /lib64/libsnappy.so.1 (0x00007f6f9a0e2000)
        libceph-common.so.0 => ./bak/libceph-common.so.0 (0x00007f6f912d5000)

 

查看可以執行程序需要哪些動態庫,使用命令:
readelf   -d  [可執行程序]   

 

查看動態庫連接過程

查keep

ldconfig -v | grep keep

ldconfig -p | grep keep

查看一個so鏈接庫的版本

如果要准確的版本,看看這個庫文件鏈接到那個具體文件:

/lib# file libhandle.so

libhandle.so: symbolic link to `libhandle.so.1'

lib# file libhandle.so.1

libhandle.so.1: symbolic link to `libhandle.so.1.0.3'

可以看到經過兩次鏈接,最終文件名中1.0.3是版本號,其它方法只能得出主版本號

查看So文件中的字符串信息(最常見是版本號)

strings libc.so | grep Version

 

動態庫查找順序

 

綜合以上結果可知,動態庫的搜索路徑搜索的先后順序是:

1.編譯目標代碼時指定的動態庫搜索路徑; //-L、-rpath和-rpath-link

2.環境變量LD_LIBRARY_PATH指定的動態庫搜索路徑;

3.配置文件/etc/ld.so.conf中指定的動態庫搜索路徑;

4.默認的動態庫搜索路徑/lib;

5.默認的動態庫搜索路徑/usr/lib。

在上述1、2、3指定動態庫搜索路徑時,都可指定多個動態庫搜索路徑,其搜索的先后順序是按指定路徑的先后順序搜索的。

http://blog.csdn.net/21aspnet/article/details/6724457

 

動態庫[鏈接時]路徑和[運行時]路徑

http://blog.csdn.net/q1302182594/article/details/42102961( -L、-rpath和-rpath-link的區別)

現代連接器在處理動態庫時將鏈接時路徑(Link-time path)和運行時路徑(Run-time path)分開。用戶可以

  • 通過-L 指定編譯連接時庫的路徑
  • 通過-R(或-rpath)指定程序運行時庫的路徑,

大大提高了庫應用的靈活性。

比如我們在編譯環境 gcc -o target -L /work/lib/zlib/  -llibz-1.2.3 (work/lib/zlib下是編譯環境的動態庫目錄),將target編譯好后我們只要把zlib下的庫文件拷貝到運行環境的系統默認路徑下即可。或者通過-rpath(或-R )、LD_LIBRARY_PATH指定查找路徑。

 

鏈接器ld的選項有 -L,-rpath 和 -rpath-link,大致是這個意思:

-L: “鏈接”的時候,去找的目錄,也就是所有的 -lxxx 選項里的庫,都會先從 -L 指定的目錄去找,然后是默認的地方。-L只是指定了程序編譯連接時庫的路徑,並不影響程序執行時庫的路徑。

-rpath和-rpath-link都可以在鏈接時指定庫的路徑;但是運行可執行文件時,-rpath-link指定的路徑就不再有效(鏈接器沒有將庫的路徑包含進可執行文件中),

而-rpath指定的路徑還有效(因為鏈接器已經將庫的路徑包含在可執行文件中了。)

 

修改efl文件(程序、庫文件)的庫依賴路徑

工具:patchelf
(RHEL 已經自帶了chrpath工具,直接使用即可. ( yum install chrpath)不過chrpath 有個缺陷,如果當前系統為x86_64,則修改i386 elf會報錯,patchelf則無此問題!)

 

rpath全稱是run-time search path。Linux下所有elf格式的文件都包含它,特別是可執行文件。它規定了可執行文件在尋找.so文件時的第一優先位置。用patchelf修改它的信息。https://www.cnblogs.com/ar-cheng/p/13225342.html

查看demo依賴的庫:

$ readelf -d demo
 

更改程序或庫運行時搜索依賴庫的路徑(多個路徑用冒號隔開)

$ patchelf  --set-rpath   /opt/my-libs/lib:/other-libs   my-program

去掉冗余的依賴庫路徑(Shrink the RPATH of executables and libraries:)

$ patchelf  --shrink-rpath  my-program

去掉冗余的依賴庫路徑,但保留/usr/lib:/foo/lib前綴的路徑

$ patchelf  --shrink-rpath  --allowed-rpath-prefixes  /usr/lib:/foo/lib  my-program

刪除一些設置的依賴

$ patchelf  --remove-needed  libfoo.so.1 my-program 

增加依賴
$ patchelf  --add-needed        libfoo.so.1 my-program  

更換依賴。原本是依賴 liboriginal.so.1,改為依賴 libreplacement.so.1

$ patchelf  --replace-needed  liboriginal.so.1  libreplacement.so.1  my-program 

更改動態庫的短名(SONAME) :
$ patchelf  --set-soname  libnewname.so.3.4.5  path/to/libmylibrary.so.1.2.3 
關於SONAME,見:https://blog.csdn.net/bandaoyu/article/details/115307641

Change the dynamic loader ("ELF interpreter") of executables
$ patchelf  --set-interpreter /lib/my-ld-linux.so.2 my-program 

教程:https://blog.csdn.net/juluwangriyue/article/details/108617283

官網使用說明:

README.md
PatchELF is a simple utility for modifying existing ELF executables and libraries. In particular, it can do the following:

Change the dynamic loader ("ELF interpreter") of executables:
$ patchelf --set-interpreter /lib/my-ld-linux.so.2 my-program

Change the RPATH of executables and libraries:
$ patchelf --set-rpath /opt/my-libs/lib:/other-libs my-program

Shrink the RPATH of executables and libraries:
$ patchelf --shrink-rpath my-program

This removes from the RPATH all directories that do not contain a library referenced by DT_NEEDED fields of the executable or library. For instance, if an executable references one library libfoo.so, has an RPATH /lib:/usr/lib:/foo/lib, and libfoo.so can only be found in /foo/lib, then the new RPATH will be /foo/lib.

In addition, the --allowed-rpath-prefixes option can be used for further rpath tuning. For instance, if an executable has an RPATH /tmp/build-foo/.libs:/foo/lib, it is probably desirable to keep the /foo/lib reference instead of the /tmp entry. To accomplish that, use:

$ patchelf --shrink-rpath --allowed-rpath-prefixes /usr/lib:/foo/lib my-program

Remove declared dependencies on dynamic libraries (DT_NEEDED entries):
$ patchelf --remove-needed libfoo.so.1 my-program

This option can be given multiple times.
Add a declared dependency on a dynamic library (DT_NEEDED):
$ patchelf --add-needed libfoo.so.1 my-program

This option can be give multiple times.
Replace a declared dependency on a dynamic library with another one (DT_NEEDED):

$ patchelf --replace-needed liboriginal.so.1 libreplacement.so.1 my-program

This option can be give multiple times.

Change SONAME of a dynamic library:
$ patchelf --set-soname libnewname.so.3.4.5 path/to/libmylibrary.so.1.2.3

 

鏈接靜態庫/動態庫

鏈接靜態庫

鏈接靜態庫libadd_minus.a

方式一

gcc -o main2 main.o -L./ -ladd_minus

說明1:-L./表明庫文件位置在當前文件夾

說明2: -ladd_minus 表示鏈接 libadd_minus.a 文件,使用“-l”參數時,前綴“lib”和后綴“.a”是需要省略的。

方式二、

-L/your/library/path  -l:libmylib.a

如果-l:filename格式指定一個文件名,連接程序直接去找這個文件名了,不會再像使用-lname時將name擴展成lib<name>.a格式的文件名.

當然如果庫的位置不在gcc默認搜索路徑中,要用-L參數另外指定搜索庫的路徑

 

在gcc編譯鏈接時強制使用lib.a

當一個庫文件既有.a又有.so時,如果這么寫,gcc會優先鏈接.so文件:

gcc -L/path/to/library/ -ljemalloc -o run

有一種寫法可以強制鏈接.a庫文件:

gcc -L/path/to/library/ -l:libjemalloc.a -o run

這種寫法也能解決當依賴庫不是以libxxx.a或者libxxx.so規范命名時,可以通過指定庫文件全名來解決。

鏈接動態庫

 

gcc -o main4 main.o -L./ -ladd_minus -lmulti_div

說明1:-L./表明庫文件位置在當前文件夾

說明2: -ladd_minus 表示鏈接 libadd_minus.so 文件,使用“-l”參數時,前綴“lib”和后綴“.so”是需要省略的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM