知識點
現代連接器在處理動態庫時將鏈接時路徑(Link-time path)和運行時路徑(Run-time path)分開,用戶可以通過-L指定連接時庫的路徑,通過-R(或-rpath)指定程序運行時庫的路徑,大大提高了庫應用的靈活性。
鏈接器ld的選項有 -L,-rpath 和 -rpath-link,看了下 man ld,大致是這個意思:-L: “鏈接”的時候,去找的目錄,也就是所有的 -l 選項里的庫,都會先從 -L 指定的目錄去找,然后是默認的地方。編譯時的-L選項并不影響環境變量LD_LIBRARY_PATH,-L只是指定了程序編譯連接時庫的路徑,并不影響程序執行時庫的路徑,系統還是會到默認路徑下查找該程序所需要的庫,如果找不到,還是會報錯,類似cannot open shared object file。
-rpath-link:這個也是用于“鏈接”的時候的,例如你顯示指定的需要 FOO.so,但是 FOO.so 本身是需要 BAR.so 的,后者你并沒有指定,而是 FOO.so 引用到它,這個時候,會先從 -rpath-link 給的路徑里找。
-rpath: “運行”的時候,去找的目錄。運行的時候,要找 .so 文件,會從這個選項里指定的地方去找。對于交叉編譯,交叉編譯鏈接器需已經配置 –with-sysroot 選項才能起作用。也就是說,-rpath指定的路徑會被記錄在生成的可執行程序中,用于運行時查找需要加載的動態庫。?
知識點2
? -Wa,<options> ? Pass comma-separated <options> on to the assembler
? -Wp,<options> ? Pass comma-separated <options> on to the preprocessor
? -Wl,<options> ? Pass comma-separated <options> on to the linker?the?
-rpath
?option encodes the path in the binary, either as?DT_RPATH
?or?DR_RUNPATH
通常,您不需要它,事實上,最好不要在可執行文件中對庫搜索路徑進行編碼(使用-rpath選項將路徑編碼為二進制,可以是DT_rpath或DR_RUNPATH)
注:我自己的一般方法是在可執行文件位于構建樹中,并依賴于構建樹中的其他庫時,將其與–rpath選項鏈接,以便于調試,但在安裝(make install,building packages)時,需要在不使用–rpath選項的情況下重新鏈接,并將查找共享庫的任務留給目標平臺的適當動態鏈接器配置,例如ld.so.conf。?
知識點3
binutils在2.22版本以后,默認把–no-copy-dt-needed-entries這個選項打開了。當打開了這個選項的時候,編譯器在鏈接的時候是不會遞歸的去獲取依賴動態庫的依賴項的,于是就會出現上述的問題。
? ?--copy-dt-needed-entries
? ?--no-copy-dt-needed-entries
? ? ? ?This option affects the treatment of dynamic libraries referred to by DT_NEEDED tags inside ELF dynamic libraries mentioned on the command line. ?Normally the linker won't add a DT_NEEDED
? ? ? ?tag to the output binary for each library mentioned in a DT_NEEDED tag in an input dynamic library. ?With --copy-dt-needed-entries specified on the command line however any dynamic
? ? ? ?libraries that follow it will have their DT_NEEDED entries added. ?The default behaviour can be restored with --no-copy-dt-needed-entries.? ? ? ?This option also has an effect on the resolution of symbols in dynamic libraries. ?With --copy-dt-needed-entries dynamic libraries mentioned on the command line will be recursively
? ? ? ?searched, following their DT_NEEDED tags to other libraries, in order to resolve symbols required by the output binary. ?With the default setting however the searching of dynamic
? ? ? ?libraries that follow it will stop with the dynamic library itself. ?No DT_NEEDED links will be traversed to resolve symbols.
跟在–no-copy-dt-needed-entries它后面的庫都不會遍歷其依賴項,使用–copy-dt-needed-entries則相反。即可以遍歷所有依賴項目,保證編譯成功。
實例
//a.cc == main.cc
#include <iostream>
#include "b.h"int main()
{bbb();std::cout << "Hello world" << std::endl;return 0;
}//b.h-----
#pragma oncevoid bbb();//b.cc-----
#include <iostream>
#include "ccc.h"void bbb()
{ccc();std::cout << "Hello world" << std::endl;
}// ccc.h-----
#pragma once
void ccc();// ccc.cc-----
#include <iostream>void ccc()
{std::cout << "Hello world" << std::endl;
}
編譯過程1
$ g++ -fPIC -shared ccc.cc -o libccc.so
$ g++ -fPIC -shared b.cc -o libbbb.so -L. -lccc
# g++ a.cc -L. -lb 是不行的,具體看https://blog.csdn.net/zrq293/article/details/105969423
g++ a.cc -L. -lb -Wl,--copy-dt-needed-entries
/usr/bin/ld: warning: libccc.so, needed by ./libb.so, not found (try using -rpath or -rpath-link)
$ g++ a.cc -L. -lb -Wl,--copy-dt-needed-entries,-rpath-link=.
$ ./a.out
./a.out: error while loading shared libraries: libb.so: cannot open shared object file: No such file or directory
$ g++ a.cc -L. -lb -Wl,--copy-dt-needed-entries,-rpath-link=.,-rpath=.
tiantian@DESKTOP-UVN3KRD:~/code$ ./a.out
./a.out: error while loading shared libraries: libccc.so: cannot open shared object file: No such file or directory$ ldd a.outlinux-vdso.so.1 (0x00007ffff5585000)libb.so => ./libb.so (0x00007f44961f0000)libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f4495fc0000)libc.so => ./libc.so (0x00007f4495fb0000)libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f4495d80000)libccc.so => not foundlibm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f4495c80000)/lib64/ld-linux-x86-64.so.2 (0x00007f4496215000)libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f4495c60000)
$ export LD_LIBRARY_PATH=.
$ ./a.out
Hello world
Hello world
Hello world
cmake的擴展
默認cmake設置
set(CMAKE_SKIP_BUILD_RPATH FALSE) ? ? ? ? ? ? ? ? # 編譯時加上RPATH ?
set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) ? ? ? ? # 編譯時RPATH不使用安裝的RPATH ?
set(CMAKE_INSTALL_RPATH "") ? ? ? ? ? ? ? ? ? ? ? # 安裝RPATH為空 ?
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE) ? ? ?# 安裝的執行文件不加上RPATH ?
設置rpathSET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)?
SET(CMAKE_INSTALL_RPATH "\${ORIGIN}/../lib")
- 默認情況下,這個PATH在構建產生的中間文件,是不增加的;而是只對安裝的目標有效。如果你想針對構建的中間文件也有效果,可以加上
- 手動指定添加的RPATH