gcc在鏈接時通常用到的鏈接選項“-l”和“-L”分別用來指明需要鏈接的動態庫名字及搜索路徑,但是當使用的“-l”選項指定的庫還有另外的依賴關系時,“-L”選項的參數無法提供對依賴庫路徑的包含。
假設我們有如下文件和自定義庫文件:
./main.c
./lib/libtest.so
./lib/libtest2.so
其中 main.c依賴libtest.so
libtest.so又依賴libtest2.so
當我們如下編譯鏈接時:
gcc -o test main.o -ltest -L./lib
編譯器按照如下順序尋找庫文件:
- 首先會去找-L指定的參數目錄
- 再找gcc的環境變量LIBRARY_PATH指定的參數
- 再找內定默認目錄 /lib:/usr/lib: /usr/local/lib
在以上目錄中找到需要的庫文件之后,編譯器將找到庫文件的信息傳遞給鏈接器進行鏈接。
接着在調用鏈接器時,由於libtest.so又依賴libtest2.so,所以鏈接器接着去尋找libtest2.so文件,尋找順序如下:
- 所有由'-rpath-link'選項指定的搜索路徑
- 所有由'-rpath'指定的搜索路徑
- 如果'-rpath'和'rpath-link'選項沒有被使用, 會搜索環境變量'LD_RUN_PATH'的內容(它也只對本地連接器起作用)
- 對於一個本地連接器,環境變量'LD_LIBRARY_PATH'的內容被搜索.
- 對於一個本地ELF連接器,共享庫中的`DT_RUNPATH'和`DT_RPATH'操作符會被需要它的共享庫搜索. 如果'DT_RUNPATH' 存在了, 那'DT_RPATH'就會被忽略.
- 缺省目錄, 常規的,如'/lib'和'/usr/lib'.
- 對於ELF系統上的本地連接器, 如果文件'/etc/ld.so.conf'存在, 這個文件中有的目錄會被搜索.
如果需要的共享庫沒有被找到, 那連接器會發出一條警告信息
ld: warning: libtest2.so need by libtest.so not found (try using -rpath or -rpath-link)
說明鏈接器鏈接時,並未找到libtest.so需要的lianlibtest2.so文件。
這就說明鏈接器鏈接時尋找依賴庫的路徑里不包含“-L"指定的路徑,“-L”只是單純的增加一個尋找指定庫文件的路徑。
顯然如果指定的庫文件還依賴另外的庫文件(例如libtest2.so),“-L"已經完成使命,則不會在尋找-L指定的目錄。
ld --help 也可以看到關於“-L”的解釋
-L DIRECTORY, --library-path DIRECTORY
Add DIRECTORY to library search path
遇到這種情況,有幾種方法
- 在環境變量LD_LIBRARY_PATH中添加搜索路徑(不建議使用,因為是全局變量)
- 在/etc/ld.so.conf'.d/目錄中增加conf文件(ldconfig)
- 根據鏈接器警告提示,使用'-rpath'跟'-rpath_link'
- 其他(我不知道的....)
這里學習一下'-rpath'跟'-rpath_link'的用法,
ld --help中關於-rpath和-rpath-link的解釋是:
-rpath PATH Set runtime shared library search path
-rpath-link PATH Set link time shared library search path
即在連接時,鏈接器需要依賴庫時還會去搜索-rpath-link指定的路徑。
-rpath為設置程序運行時搜索依賴庫的路徑,可以設置相對路徑。
編譯器中使用-rpath和-rpath-link 的格式如下:
gcc -Wl,rpath=/home/test:../lib:/usr/lib64
-Wl(小寫L),<選項> 將逗號分隔的 <選項> 傳遞給鏈接器
不使用-Wl 編譯器無法識別-rpath等選項。
-rpath和-rpath-link可以指定多個目錄,目錄與目錄之間用冒號分割
參考:http://blog.csdn.net/youhaipeng/article/details/8213702
參考:http://www.laogu.com/wz_2754.htm