linux 靜態庫和動態庫
1. 靜態函式庫
可以使用ar命令來建立和修改靜態庫,這類庫的名字一般是lib***.a;利用靜態函式庫編譯成的檔案比較大,因為整個函式庫的所有資料都會被整合進目標**中,他的優點就顯而易見了,即編譯後的執行程式不需要外部的函式庫支援,因為所有使用的函式都已經被編譯進去了。當然這也會成為他的缺點,因為如果靜態函式庫改變了,那麼你的程式必須重新編譯。
2. 動態函式庫
這類庫的名字一般是lib***.so;相對於靜態函式庫,動態函式庫在編譯的時候 並沒有被編譯進目標**中,你的程式執行到相關函式時才呼叫該函式庫裡的相應函式,因此動態函式庫所產生的可執行檔案比較小。由於函式庫沒有被整合進你的程式,而是程式執行時動態的申請並呼叫,所以程式的執行環境中必須提供相應的庫。動態函式庫的改變並不影響你的程式,所以動態函式庫的公升級比較方便。
linux系統有幾個重要的目錄存放相應的函式庫,如/lib /usr/lib
3. 靜態庫使用
靜態庫的操作工具:gcc和ar 命令
編譯鏈結選項
-l 及-l 引數放在後面.其中,-l 載入庫檔案路徑,-l 指明庫檔案名字.
4.動態庫使用
生成動態庫
編譯生成動態庫的命令為:gcc (-fpic) -shared -o libmyfunction.somyfunction.c
-fpic 使輸出的物件模組是按照可重定位位址方式生成的。
-shared指定把對應的原始檔生成對應的動態鏈結庫檔案。
5設定優先載入本地動態庫
ld_library_path=./和 export ld_library_path
1、臨時修改,logout之後就失效
在terminal中執行:export ld_library_path=./
2、讓當前帳號以後都優先載入當前目錄的動態庫
修改~/.bash_profile在檔案末尾加上兩行: ld_library_path=./ 和 export ld_library_path
3、讓所有帳號從此都優先載入當前目錄的動態庫
修改/etc/profile在檔案末尾加上兩行: ld_library_path=./ 和 export ld_library_path
首先回答前面的問題,一共有多少種方法來指定告訴linux共享庫鏈結器ld.so已經編譯好的庫libbase.so的位置呢?答案是一共有五種,它們都可以通知ld.so去哪些地方找下已經編譯好的c語言函式動態庫,它們是:
1)elf可執行檔案中動態段中dt_rpath所指定的路徑。即在編譯目標**時, 對gcc加入鏈結引數「-wl,-rpath」指定動態庫搜尋路徑,eg:gcc-wl,-rpath,/home/arc/test,-rpath,/lib/,-rpath,/usr/lib/,-rpath,/usr/local/libtest.c
2)環境變數ld_library_path 指定的動態庫搜尋路徑
3)/etc/ld.so.cache中所快取的動態庫路徑,這個可以通過先修改配置檔案/etc/ld.so.conf中指定的動態庫搜尋路徑,然後執行ldconfig命令來改變。
4)預設的動態庫搜尋路徑/lib
5)預設的動態庫搜尋路徑/usr/lib
另外:在嵌入式linux系統的實際應用中,1和2被經常使用,也有一些相對簡單的的嵌入式系統會採用4或5的路徑來規範動態庫,3在嵌入式系統中使用的比較少, 因為有很多系統根本就不支援ld.so.cache。
那麼,動態鏈結器ld.so在這五種路徑中,是按照什麼樣的順序來搜尋需要的動態共享庫呢?答案這裡先告知就是按照上面的順序來得,即優先順序是:1-->2-->3-->4-->5。我們可以寫簡單的程式來證明這個結論。
首先,寫成5個函式,這5個函式名稱都叫pt,但是裡面的內容不一樣:
pt1.c
#include
void pt()
pt2.c
#include
void pt()
pt3.c
#include
void pt()
pt4.c
#include
void pt()
pt5.c
#include
void pt()
然後,分別編譯這5個函式,然後將它們分別移到上面5種情況對應的5個不同目錄下:
gcc -fpic -c pt1.c -o pt.o
gcc -shared pt.o -o libpt.so
mv libpt.so /tmp/st/1/
gcc -fpic -c pt2.c -o pt.o
gcc -shared pt.o -o libpt.so
mv libpt.so /tmp/st/2/
gcc -fpic -c pt3.c -o pt.o
gcc -shared pt.o -o libpt.so
mv libpt.so /tmp/st/3/
gcc -fpic -c pt4.c -o pt.o
gcc -shared pt.o -o libpt.so
mv libpt.so /lib/
gcc -fpic -c pt5.c -o pt.o
gcc -shared pt.o -o libpt.so
mv libpt.so /usr/lib/
再次,編寫乙個main函式m,讓它來呼叫函式pt:
m.c#include
int main()
最後,準備環境,讓ld都知道這5個路徑:
(a) 往/etc/ld.so.conf總增加一行,內容:/tmp/st/3,然後執行 ldconfig 命令
(b) export ld_library_path=/tmp/st/2
另外3中路徑,ld都可以得到,請接著看下面。
之後測試:
gcc m.c -o m1 -l/tmp/st/1 -lpt-wl,-rpath,/tmp/st/1
./m1
start....
1 path on the gcc give
......end
這裡在可執行檔案中動態段中dt_rpath所指定的路徑,因此需要在編譯m.c的時候就指定路徑,由於其他路徑都也告訴了ld,很明顯,此種方法優先順序最高了。
gcc m.c -o m -l/tmp/st/1 -lpt
./mstart....
2 path on the ld_library_path
......end
這裡很顯然呼叫了ld_library_path指定了路徑中的共享庫,因此此種情況優先順序第二。
mv /tmp/st/2/libpt.so /tmp/st/2/libpt2.so
/mstart....
3 path on the /etc/ld.so.conf
......end
這裡是呼叫了/etc/ld.so.cache中所快取的動態庫路徑中的共享庫,因此此種情況優先順序第三。
mv /tmp/st/3/libpt.so /tmp/st/3/libpt3.so
./mstart....
4 path on the /lib
......end
這裡是呼叫/lib中的共享庫,優先順序第四。
rm /lib/libpt.so
./mstart....
5 path on the /usr/lib
......end
這裡是呼叫/lib中的共享庫,優先順序第五。
故證明這五種路徑指定方法的優先順序是1-->2-->3-->4-->5!
pkg_config_path從字面意思上翻譯,就是「軟體包的配置路徑」,這不很明顯了麼,編譯軟體時如果出現找不到所依賴的動態庫時都全靠pkg_config_path了;
ld_library_path也很直白了「裝載器的庫路徑」,ld是loader的簡寫,在博文「段錯誤到底是何方妖孽」裡我也曾提到過,在linux系統啟動乙個程式的過程就叫做裝載,乙個程式要執行時它或多或少的會依賴一些動態庫(靜態編譯的除外)。當你用「ldd 可執行程式名」檢視乙個軟體啟動時所依賴的動態庫,如果輸出項有「lib***.so.y=>not found」一項,你這個軟體100%執行不起來。
# exportld_library_path=/home/other/test/lib:$ld_library_path 像設定其他環境變數一樣,可以寫在 .bashrc 中 source 使其生效。
關於動態庫靜態庫的一些事
首先先對編譯器中關於對原檔案,標頭檔案,庫等編譯相關的理解。其次理解靜態庫和動態庫的。最後在windows和linux下編譯靜態和動態庫,以及相應的使用。編譯器要編譯原始檔,標頭檔案,當然要將原始檔標頭檔案置入工程專案中 標頭檔案不一定,標頭檔案不一定放進工程中,只要保證原始檔include的時候能...
linux 靜態庫和動態庫
1.生成方式 靜態庫 首先將原始檔編譯成目標檔案 gcc c test.c o test.o 然後生成靜態庫 ar rc libstatic.a test.o 共享庫 首先將原始檔編譯成目標檔案 gcc c test.c o test.o 生成共享庫 gcc fpic shared o libsha...
Linux 靜態庫和動態庫
庫有兩種,一種是靜態鏈結庫,一種是動態鏈結庫,不管是哪一種庫,要使用它們,都要在程式中包含相應的include標頭檔案。我們先來回顧一下程式編譯的過程。如下圖 庫 本質乙個目標檔案,這個檔案的字尾有兩種格式,對應兩種庫 缺點是 檔案太大。多次拷貝庫程式,不僅浪費空間,而且檔案體積大 下面實現乙個靜態...