1. 程式人生 > >淺談GCC/Clang生成和連結靜態庫/動態庫

淺談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 中的檔案就能明白些許。