1. 靜態函數庫
這類庫的名字一般是libxxx.a;利用靜態函數庫編譯成的文件比較大,因為整個 函數庫的所有數據都會被整合進目標代碼中,他的優點就顯而易見了,即編譯后的執行程序不需要外部的函數庫支持,因為所有使用的函數都已經被編譯進去了。當然這也會成為他的缺點,因為如果靜態函數庫改變了,那么你的程序必須重新編譯。
2. 動態函數庫
這類庫的名字一般是libxxx.so;相對於靜態函數庫,動態函數庫在編譯的時候 並沒有被編譯進目標代碼中,你的程序執行到相關函數時才調用該函數庫里的相應函數,因此動態函數庫所產生的可執行文件比較小。由於函數庫沒有被整合進你的程序,而是程序運行時動態的申請並調用,所以程序的運行環境中必須提供相應的庫。動態函數庫的改變並不影響你的程序,所以動態函數庫的升級比較方便。
linux系統有幾個重要的目錄存放相應的函數庫,如/lib /usr/lib。
編譯靜態庫和動態庫 :
無論是靜態庫還是動態庫 ,都是由.o文件組成。因此我們可以先編譯出.o文件 。
下面提供兩個小程序 :
sum.h #ifndef SUM_H_ #define SUM_H_ int add (int ,int ) ; #endif
sum.cpp #include <iostream> #include "auth.h" int add (int x ,int y ) { int sum = x + y ; return sum ; }
#include "sum.h" #include<iostream> int main() { int k = add(8,10); std::cout<<"k= "<< k<<std::endl; return 0 ; }
首先編譯.o文件:
g++ -c sum.cpp ------>生成.o文件
編譯.so 文件 :
g++ -shared -fPIC -o libsum.so sum.o ------>生成libsum.so文件
編譯.a 文件 :
ar rcs libsum.a sum.o - ----> 生成libsum.a 文件
編譯測試文件並測試 :
g++ -c test.cpp
g++ -o test test.o -lauth -L./
ok,測試結果顯示k = 18 ;
然而 在linux64位的系統中,這個問題就出來了 。
如果依然按照上面的命令進行編譯 ,會出現以下錯誤 :
/usr/bin/ld: sum.o: relocation R_X86_64_32 against `a local symbol' can not be used when making a shared object; recompile with -fPIC
auth.o: could not read symbols: Bad value。
auth.o: could not read symbols: Bad value。
碰到這個錯誤 ,你可以去檢查下,對應的文件在編譯的時候是不是用了-fPIC這個參數哦 。
-fPIC:表示編譯為位置獨立的代碼,不用此選項的話編譯后的代碼是位置相關的所以動態載入時是通過代碼拷貝的方式來滿足不同進程的需要,而不能達到真正代碼段共享的目的。
在生成.o文件的時候 加上參數 -fPIC ,這個錯誤就可以搞定了 ,在編譯動態庫時,必須指定這個參數 ,主要是因為代碼的重定向的問題 。如果沒有這個參數 ,編譯的代碼加載的時候不能夠重定向。
g++ -fPIC -c sum.cpp
那么,如果我希望指定執行文件鏈接靜態庫怎么辦呢 ??
默認情況下,如果在某個目錄下.so 和.a 同時存在的時 ,gcc會優先選擇.so 。
我們一般通過 -I引入包含文件 ,-L引入庫目錄 ,-l指定依賴的庫文件。當在靜態庫和動態庫同時存在時,gcc選擇.so ,如果你在能夠將.
so和.a分開的情況下 ,使用-lname (name為lib的名字)來指定庫文件(無論靜態庫還是動態庫都可以),如果靜態庫和動態庫在同一目錄下 ,可以使用 path/libname.a 來指定依賴的庫文件 。
Linux下約定所有庫都以前綴lib開始靜態庫以.a結尾,動態庫以.so結尾。再編譯程式時,無需帶上前綴和后綴。
在編譯過程中,-L指定的路徑是編譯路徑 ,而在運行時需要動態的搜索庫文件 ,這兩個路徑不是一個概念 。因此經常會出現這樣的問題 :
”明明已經將庫的頭文件所在目錄 通過 “-I” include進來了,庫所在文件通過“-L”參數引導,並指定了“-l”的庫名,但通過ldd命令察看時,就是死活找不到你指定鏈接的so文件,這時你 要作的就是通過修改LD_LIBRARY_PATH或者/etc/ld.so.conf文件來指定動態庫的目錄。通常這樣做就可以解決庫無法鏈接的問題 了。