前兩天寫了乙個動態庫,然後試圖編譯到程式裡面去執行,結果發現編譯的時候通過gcc的-l引數來指定路徑僅僅能讓編譯通過,執行時還是會出問題的。
比如下面這個例子:
main.c是主程式,sum.c中間含有乙個函式add,用來執行加法,**如下:
1/*2* main.c3*/
4 #include 5
6int add(int a, int b);78
int main(int argc,char *argv)
9
1/*2出錯結果如下圖所示:* sum.c3*/
4int add(int a, int b)
5
我在編譯的時候通過-l指定了查詢動態庫的位置,結果執行的時候還是找不到我自己寫的那個libsum.so這個動態庫,後來去查了一下,才明白其中原委。
程式在鏈結動態庫的時候分為2步,編譯時鏈結和執行時鏈結。
1. 編譯時鏈結
這個過程是由ld程式來執行的,所以編譯時找不到動態庫的位置的話,經常就會看到這種錯誤:
這個過程嚴格意義上來說並不能說是鏈結,因為在這裡ld程式並沒有真正的把庫裡面的函式的執行**寫到可執行檔案裡面,只是把一些符號還有其他的必要資訊寫道了可執行檔案裡面,供可執行檔案執行時查詢。
總的來說,ld在這一步裡面就是做了兩個事情:
1. 查詢動態庫中是否含有我們需要的符號(函式和全域性變數),如果都能找到,則鏈結允許通過,生成了可執行檔案。
2. 在可執行檔案中寫入了符號和其他必要的資訊(例如符號的位址),供可執行檔案執行時查詢。
2. 執行時鏈結
(1)ld-linux.so.6在可執行的目標檔案中被指定,可用readelf命令檢視
(2)ld-linux.so.6預設在/usr/lib和lib中搜尋;當glibc安裝到/usr/local下時,它查詢/usr/local/lib
(3)ld_library_path環境變數中所設定的路徑
(4)/etc/ld.so.conf(或/usr/local/etc/ld.so.conf)中所指定的路徑,由ldconfig生成二進位制的ld.so.cache中
(1)ld-linux.so.6由gcc的spec檔案中所設定
(2)gcc --print-search-dirs所列印出的路徑,主要是libgcc_s.so等庫。可以通過gcc_exec_prefix來設定
(3)library_path環境變數中所設定的路徑,或編譯的命令列中指定的-l/usr/local/lib
(4)binutils中的ld所設定的預設搜尋路徑順序,編譯binutils時指定。(可以通過「ld --verbose | grep search」來檢視)
(5)二進位制程式的搜尋路徑順序為path環境變數中所設定。一般/usr/local/bin高於/usr/bin
(6)編譯時的標頭檔案的搜尋路徑順序,與library的查詢順序類似。一般/usr/local/include高於/usr/include
大家注意編譯時查詢的路徑可以通過gcc -l引數或者library_path來指定,但是執行時的查詢路徑卻不包含gcc -l和library_path環境變數指定的路徑,所以這樣就會出現我們剛開始所說的那個問題,編譯時通過-l指定了動態庫的搜尋路徑,編譯也通過了,但是執行時卻會報錯,這是因為執行時查詢動態庫的路徑還沒指定,所以我們自己寫的動態庫就找不到了,而要解決這個問題,通過設定環境變數ld_library_path或者修改/etc/ld.so.conf(記得修改完了執行ldconfi來生成ld.so.cache)就可以了。如下圖所示:
Linux動態庫的查詢路徑
前兩天寫了乙個動態庫,然後試圖編譯到程式裡面去執行,結果發現編譯的時候通過gcc的 l引數來指定路徑僅僅能讓編譯通過,執行時還是會出問題的。比如下面這個例子 main.c是主程式,sum.c中間含有乙個函式add,用來執行加法,如下 1 2 main.c3 4 include 5 6int add ...
Linux動態庫的查詢路徑
上頭需要把專案從windows系統移動到linux下,作為對linux半吊子的我卻無意承擔了這個工作,從此填坑深如海。原專案實在msvc qt開發的,還好qt是跨平台的,但是windows和linux的執行還是有所差距的。以下記錄linux下動態庫的搜尋路徑,多數內容來自csdn中的其他大神。這個過...
GNU GCC查詢路徑
1.標頭檔案 gcc 在編譯時如何去尋找所需要的標頭檔案 header file的搜尋會從 i開始 然後找gcc的環境變數 c include path,cplus include path,objc include path 再找內定目錄 usr include usr local include...