淺談GCC/Clang生成和連結靜態庫/動態庫
為了方便下面的講解,先寫兩個C++原始檔,程式碼如下:
1 2 3 4 5 |
//add.cpp
int add( int a, int b)
{
return a + b;
}
|
1 2 3 4 5 6 7 8 9 10 11 |
//main.cpp
#include <iostream>
int add( int a, int b);
int main( int argc, const char *argv[])
{
std::cout << add(1, 2) << std::endl;
return 0;
}
|
筆者的開發平臺: Mac OS X 10.9.2 / Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn)
生成靜態庫
靜態庫檔案的命名規則是:lib****.a(將****替換成自定義名字),將 add.cpp 編譯成一個目標檔案,然後打包成為一個靜態庫,具體操作如下:
1.先將 add.cpp 編譯成目標檔案 add.o
clang++ -c add.cpp
2.然後使用 ar 命令將目標檔案 add.o 打包成為靜態庫檔案 libadd.a
ar -r libadd.a add.o
從上面這些操作中可以看出,生成靜態庫檔案其實就是使用 ar 命令將目標檔案打包一下,ar 是 archive 的縮寫,意思是歸檔,有關 ar 的部分引數解釋如下:
-r :新增或替換指定的檔案到歸檔中;
ar -r libtest.a test.o
-v :顯示冗餘的資訊;
ar -rv libtest.a test.o
-t :按順序顯示歸檔中的檔名;
ar -t libtest.a
-d :從歸檔裡刪除指定的檔案;
ar -d libtest.a test.o
從 ar 命令的引數中可以得知,可以將多個目標檔案打包到一個靜態庫中,並可以隨時的新增和刪除。
連結靜態庫
生成完靜態庫了,然後該如何使用這個生成的靜態庫檔案呢?看下面的具體操作:
1.將 main.cpp 模組編譯成為目標檔案 main.o
clang++ -c main.cpp
2.將目標檔案 main.o 和靜態庫檔案 libadd.a 連結成為可執行檔案 main
clang++ main.o -L. -ladd -o main
3.執行可執行檔案 main
./main
執行結果:
3
連結靜態庫時,在 clang++ 連結命令後添加了兩個引數,下面具體解釋一下:
L. :將當前目錄新增至編譯器庫搜尋目錄中,如果動態庫和靜態庫同時存在,會優先選擇動態庫;
-ladd :表示查詢靜態庫名是:libadd.a 或 動態庫名是:libadd.so 的庫檔案進行連結,優先選擇動態庫;
將這兩個引數泛化來講解:
Ldir :將 dir 新增編譯器的庫查詢路徑中,編譯器預設僅僅搜尋 /usr/lib 和 /usr/local/lib 這兩個資料夾;
-lname :查詢靜態庫名是:libname.a 或 動態庫名是:libname.so 的庫檔案進行連結,優先選擇動態庫;
生成動態庫
相比靜態庫,使用動態庫生成的可執行檔案更小,看下面如何生成一個動態庫:
clang++ test.o -shared -fPIC -o libtest.so
執行完上面的操作後,會生成一個動態庫檔案:libtest.so,動態庫檔案的命名規則和靜態庫一樣,只是副檔名變成了 .so,下面具體解釋一下生成動態庫使用的引數的意義:
-shared :表明生成的檔案是動態庫檔案;
-fPIC :表明生成的動態庫是位置獨立的程式碼(Position-independent Code),這個引數筆者也解釋不太清楚,可以自己 man 一下或者 Google 一下。
-o :指定生成的檔名;
連結動態庫
clang++ main.o -L. -ltest -o main
動態庫的連結和靜態庫一樣,見上文。
靜態庫和動態庫的區別:
1.使用靜態庫生成的可執行檔案比動態庫大;
2.使用靜態庫生成的可執行檔案執行時可以脫離靜態庫執行,而使用動態庫生成的可執行檔案在執行時需要動態庫檔案(所以它比較大)。
3.動態庫可以同時被多個程式共享,節省記憶體和外存。
.
.
思考:
有沒有想過靜態庫和動態庫有什麼用?其實看看 /usr/lib 和 /usr/local/lib 中的檔案就能明白些許。