目錄
找不到.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”是需要省略的。