Linux 中的靜態庫和動態庫簡介及生成過程示例
在實際的軟體開發專案中,不是每一行程式碼都需要我們親自寫。在我們的軟體產品中,有一些程式碼(尤其是函式)的出現頻率很高,它們可以被當作公共程式碼來反覆使用。為了避免重複勞動,我們就把這些公共程式碼編譯為庫檔案,供需要的程式呼叫。在Linux中,庫分為靜態庫和動態庫兩種。
本文對靜態庫和動態庫進行了詳細的介紹,並用實際的C程式碼演示了這兩種庫的生成過程。
一、靜態庫和動態庫簡介
眾所周知,程式一般需要經過預處理、編譯、彙編和連結這幾個步驟才能變成可執行的程式。在實際的軟體開發中,對於一些需要被許多模組反覆使用的公共程式碼,我們就將它們編譯為庫檔案。
庫是一種可執行程式碼的二進位制形式,可以被作業系統載入記憶體執行。Linux支援的庫分為靜態庫和動態庫,動態庫又稱共享庫。一般說來,Linux中的一些重要的庫是存放在lib目錄下的。
靜態庫檔案的字尾為.a,在Linux下一般命名為libxxx.a。在連結步驟中,聯結器將從靜態庫檔案中取得所需的程式碼,複製到生成的可執行檔案中。因此,整個庫中的所有函式都被編譯進了目的碼中。
動態庫檔案的字尾為.so,在Linux下一般命名為libxxx.so。相對於靜態庫,動態庫在編譯的時候並沒有被編譯進目的碼中,而是程式執行到相關函式時才呼叫庫中對應的函式。
可以看到,靜態庫的優點是編譯後的執行程式不需要外部的函式庫支援,缺點是如果靜態函式庫改變了,那麼你的程式必須重新編譯;而動態庫在多個應用程式都要使用同一函式庫的時候就非常適合,但前提是程式的執行環境中必須提供相應的庫。
不管是靜態庫,還是動態庫,都是由*.o目標檔案生成的。
二、靜態庫生成示例
1.單個檔案生成靜態庫示例
我們編寫如下簡單的三個程式檔案:test.h、test.c和main.c,在main.c中要呼叫test.c中實現的函式test。
test.h檔案內容:
#include <stdio.h> void test();
test.c檔案內容:
#include "test.h" void test() { printf("this is in test....../n"); }
main.c檔案內容:
#include "test.h" int main() { test(); return 0; }
將此三個檔案上傳到Linux機器上,編譯生成靜態庫檔案,之後呼叫庫檔案的整個過程如下所示:
~/zhouzhaoxiong/zzx/mytest/a/single> ll -rw------- 1 zhou dba 53 Nov 4 16:04 main.c -rw------- 1 zhou dba 80 Nov 4 16:04 test.c -rw------- 1 zhou dba 36 Nov 4 16:04 test.h ~/zhouzhaoxiong/zzx/mytest/a/single> gcc -c test.c ~/zhouzhaoxiong/zzx/mytest/a/single> ll -rw------- 1 zhou dba 53 Nov 4 16:04 main.c -rw------- 1 zhou dba 80 Nov 4 16:04 test.c -rw------- 1 zhou dba 36 Nov 4 16:04 test.h -rw-rw-rw- 1 zhou dba 1624 Nov 4 16:06 test.o ~/zhouzhaoxiong/zzx/mytest/a/single> ar -r libtest.a test.o ar: creating libtest.a ~/zhouzhaoxiong/zzx/mytest/a/single> ll -rw------- 1 zhou dba 53 Nov 4 16:04 main.c -rw-rw-rw- 1 zhou dba 1766 Nov 4 16:06 libtest.a -rw------- 1 zhou dba 80 Nov 4 16:04 test.c -rw------- 1 zhou dba 36 Nov 4 16:04 test.h -rw-rw-rw- 1 zhou dba 1624 Nov 4 16:06 test.o ~/zhouzhaoxiong/zzx/mytest/a/single> gcc -o test main.c libtest.a ~/zhouzhaoxiong/zzx/mytest/a/single> ll -rw------- 1 zhou dba 52 Nov 4 16:09 main.c -rwxrwxrwx 1 zhou dba 11876 Nov 4 16:09 test -rw-rw-rw- 1 zhou dba 1766 Nov 4 16:06 libtest.a -rw------- 1 zhou dba 80 Nov 4 16:04 test.c -rw------- 1 zhou dba 36 Nov 4 16:04 test.h -rw-rw-rw- 1 zhou dba 1624 Nov 4 16:06 test.o ~/zhouzhaoxiong/zzx/mytest/a/single> ./test this is in test......
我們可以看到,生成庫檔案的命令是“ar -r libtest.a test.o”,而將靜態庫檔案編譯進程式碼的命令是“gcc -o test main.c libtest.a”。
這樣生成了靜態庫檔案libtest.a之後,如果還有其他程式要呼叫test.c中實現的函式,只需要將test.h和libtest.a拷貝到對應的程式碼工程中,然後執行類似“gcc -o test main.c libtest.a”這樣的命令即可。
2.多個檔案生成靜態庫示例
我們編寫如下簡單的五個程式檔案:test.h、test_1.c、test_2.c、test_3.c和main.c,在main.c中要呼叫test_1.c、test_2.c、test_3.c中實現的函式test_1、test_2、test_3。
test.h檔案內容:
#include <stdio.h> void test_1(); void test_2(); void test_3();
test_1.c檔案內容:
#include "test.h" void test_1() { printf("this is in test_1....../n"); }
test_2.c檔案內容:
#include "test.h" void test_2() { printf("this is in test_2....../n"); }
test_3.c檔案內容:
#include "test.h" void test_3() { printf("this is in test_3....../n"); }
main.c檔案內容:
#include "test.h" int main() { test_1(); test_2(); test_3(); return 0; }
將此五個檔案上傳到Linux機器上,編譯生成靜態庫檔案,之後呼叫庫檔案的整個過程如下所示:
~/zhouzhaoxiong/zzx/mytest/a/more> ll -rw------- 1 zxin10 dba 96 Nov 4 16:11 main.c -rw------- 1 zxin10 dba 70 Nov 4 16:04 test.h -rw------- 1 zxin10 dba 84 Nov 4 16:04 test_1.c -rw------- 1 zxin10 dba 84 Nov 4 16:04 test_2.c -rw------- 1 zxin10 dba 84 Nov 4 16:04 test_3.c ~/zhouzhaoxiong/zzx/mytest/a/more> gcc -c test_1.c test_2.c test_3.c ~/zhouzhaoxiong/zzx/mytest/a/more> ll -rw------- 1 zxin10 dba 96 Nov 4 16:11 main.c -rw------- 1 zxin10 dba 70 Nov 4 16:04 test.h -rw------- 1 zxin10 dba 84 Nov 4 16:04 test_1.c -rw-rw-rw- 1 zxin10 dba 1624 Nov 4 16:15 test_1.o -rw------- 1 zxin10 dba 84 Nov 4 16:04 test_2.c -rw-rw-rw- 1 zxin10 dba 1624 Nov 4 16:15 test_2.o -rw------- 1 zxin10 dba 84 Nov 4 16:04 test_3.c -rw-rw-rw- 1 zxin10 dba 1624 Nov 4 16:15 test_3.o ~/zhouzhaoxiong/zzx/mytest/a/more> ar -r libtest.a test_1.o test_2.o test_3.o ar: creating libtest.a ~/zhouzhaoxiong/zzx/mytest/a/more> ll -rw------- 1 zxin10 dba 96 Nov 4 16:11 main.c -rw-rw-rw- 1 zxin10 dba 5158 Nov 4 16:15 libtest.a -rw------- 1 zxin10 dba 70 Nov 4 16:04 test.h -rw------- 1 zxin10 dba 84 Nov 4 16:04 test_1.c -rw-rw-rw- 1 zxin10 dba 1624 Nov 4 16:15 test_1.o -rw------- 1 zxin10 dba 84 Nov 4 16:04 test_2.c -rw-rw-rw- 1 zxin10 dba 1624 Nov 4 16:15 test_2.o -rw------- 1 zxin10 dba 84 Nov 4 16:04 test_3.c -rw-rw-rw- 1 zxin10 dba 1624 Nov 4 16:15 test_3.o ~/zhouzhaoxiong/zzx/mytest/a/more> gcc -o test main.c libtest.a ~/zhouzhaoxiong/zzx/mytest/a/more> ll -rw------- 1 zxin10 dba 96 Nov 4 16:11 main.c -rwxrwxrwx 1 zxin10 dba 12008 Nov 4 16:16 test -rw-rw-rw- 1 zxin10 dba 5158 Nov 4 16:15 libtest.a -rw------- 1 zxin10 dba 70 Nov 4 16:04 test.h -rw------- 1 zxin10 dba 84 Nov 4 16:04 test_1.c -rw-rw-rw- 1 zxin10 dba 1624 Nov 4 16:15 test_1.o -rw------- 1 zxin10 dba 84 Nov 4 16:04 test_2.c -rw-rw-rw- 1 zxin10 dba 1624 Nov 4 16:15 test_2.o -rw------- 1 zxin10 dba 84 Nov 4 16:04 test_3.c -rw-rw-rw- 1 zxin10 dba 1624 Nov 4 16:15 test_3.o ~/zhouzhaoxiong/zzx/mytest/a/more> ./test this is in test_1...... this is in test_2...... this is in test_3......
我們可以看到,生成靜態庫檔案的命令是“ar -r libtest.a test_1.o test_2.o test_3.o”,而將靜態庫檔案編譯進程式碼的命令是“gcc -o test main.c libtest.a”。
這樣生成了靜態庫檔案libtest.a之後,如果還有其他程式要呼叫test_1.c、test_2.c、test_3.c中實現的函式,只需要將test.h和libtest.a拷貝到對應的程式碼工程中,然後執行類似“gcc -o test main.c libtest.a”這樣的命令即可。
三、動態庫生成示例
1.單個檔案生成動態庫示例
我們編寫如下簡單的三個程式檔案:so_test.h、test_a.c和test.c,在test.c中要呼叫test_a.c中實現的函式test_a。
so_test.h檔案內容:
#include <stdio.h> void test_a();
test_a.c檔案內容:
#include "so_test.h" void test_a() { printf("this is in test_a.../n"); }
test.c檔案內容:
#include "so_test.h" int main() { test_a(); return 0; }
將此三個檔案上傳到Linux機器上,編譯生成動態庫檔案,之後呼叫庫檔案的整個過程如下所示:
~/zhouzhaoxiong/zzx/mylib/so> ll -rw------- 1 zxin10 dba 95 Nov 4 17:37 so_test.h -rw------- 1 zxin10 dba 109 Nov 4 17:37 test.c -rw------- 1 zxin10 dba 84 Nov 4 10:57 test_a.c ~/zhouzhaoxiong/zzx/mylib/so> gcc test_a.c -fPIC -shared -o libtest.so ~/zhouzhaoxiong/zzx/mylib/so> ll -rwxrwxrwx 1 zxin10 dba 8181 Nov 4 17:43 libtest.so -rw------- 1 zxin10 dba 95 Nov 4 17:37 so_test.h -rw------- 1 zxin10 dba 109 Nov 4 17:37 test.c -rw------- 1 zxin10 dba 84 Nov 4 10:57 test_a.c ~/zhouzhaoxiong/zzx/mylib/so> gcc test.c -L. -ltest -o test ~/zhouzhaoxiong/zzx/mylib/so> ll -rwxrwxrwx 1 zxin10 dba 8181 Nov 4 17:43 libtest.so -rw------- 1 zxin10 dba 95 Nov 4 17:37 so_test.h -rwxrwxrwx 1 zxin10 dba 11805 Nov 4 17:44 test -rw------- 1 zxin10 dba 109 Nov 4 17:37 test.c -rw------- 1 zxin10 dba 84 Nov 4 10:57 test_a.c ~/zhouzhaoxiong/zzx/mylib/so> ./test this is in test_a...
注意,“./test”命令執行成功的前提是在環境變數中新增了.so檔案所在的路徑,這個路徑可以在“.bash_profile”檔案的“LD_LIBRARY_PATH”變數的值中新增。
我們可以看到,生成動態庫檔案的命令是“gcc test_a.c -fPIC -shared -o libtest.so”,而將動態庫檔案編譯進程式碼的命令是“gcc test.c -L. -ltest -o test”(-L.表示當前路徑)。
這樣生成了動態庫檔案libtest.so之後,如果還有其他程式要呼叫test_a.c中實現的函式,只需要將so_test.h和libtest.so拷貝到對應的程式碼工程中,然後執行類似“gcc test.c -L. -ltest -o test”這樣的命令即可(前提是libtest.so所在的路徑在環境變數中設定正確)。
2.多個檔案生成動態庫示例
我們編寫如下簡單的五個程式檔案:so_test.h、test_a.c、test_b.c、test_c.c和test.c,在test.c中要呼叫test_a.c、test_b.c、test_c.c中實現的函式test_a、test_b、test_c。
so_test.h檔案內容:
#include <stdio.h> void test_a(); void test_b(); void test_c();
test_a.c檔案內容:
#include "so_test.h" void test_a() { printf("this is in test_a.../n"); }
test_b.c檔案內容:
#include "so_test.h" void test_b() { printf("this is in test_b.../n"); }
test_c.c檔案內容:
#include "so_test.h" void test_c() { printf("this is in test_c.../n"); }
test.c檔案內容:
#include "so_test.h" int main() { test_a(); test_b(); test_c(); return 0; }
將此五個檔案上傳到Linux機器上,編譯生成動態庫檔案,之後呼叫庫檔案的整個過程如下所示:
~/zhouzhaoxiong/zzx/mylib/test_so> ll -rwxrwxrwx 1 zxin10 dba 8309 Nov 5 09:12 libtest -rw------- 1 zxin10 dba 70 Nov 5 13:44 so_test.h -rw------- 1 zxin10 dba 105 Nov 4 15:25 test.c -rw------- 1 zxin10 dba 84 Nov 4 15:25 test_a.c -rw------- 1 zxin10 dba 84 Nov 4 15:25 test_b.c -rw------- 1 zxin10 dba 84 Nov 4 15:25 test_c.c ~/zhouzhaoxiong/zzx/mylib/test_so> gcc test_a.c test_b.c test_c.c -fPIC -shared -o libtest.so ~/zhouzhaoxiong/zzx/mylib/test_so> gcc test.c -L. -ltest -o test ~/zhouzhaoxiong/zzx/mylib/test_so> ll -rwxrwxrwx 1 zxin10 dba 8309 Nov 5 13:46 libtest.so -rw------- 1 zxin10 dba 70 Nov 5 13:44 so_test.h -rwxrwxrwx 1 zxin10 dba 11883 Nov 5 13:46 test -rw------- 1 zxin10 dba 105 Nov 4 15:25 test.c -rw------- 1 zxin10 dba 84 Nov 4 15:25 test_a.c -rw------- 1 zxin10 dba 84 Nov 4 15:25 test_b.c -rw------- 1 zxin10 dba 84 Nov 4 15:25 test_c.c ~/zhouzhaoxiong/zzx/mylib/test_so> ./test this is in test_a... this is in test_b... this is in test_c...
注意,“./test”命令執行成功的前提仍然是在環境變數中新增了.so檔案所在的路徑,這個路徑可以在“.bash_profile”檔案的“LD_LIBRARY_PATH”變數的值中新增。
我們可以看到,多個檔案生成動態庫檔案的命令是“gcc test_a.c test_b.c test_c.c -fPIC -shared -o libtest.so”,而將動態庫檔案編譯進程式碼的命令是“gcc test.c -L. -ltest -o test”(-L.表示當前路徑)。
這樣生成了動態庫檔案libtest.so之後,如果還有其他程式要呼叫test_a.c、test_b.c、test_c.c中實現的函式,只需要將so_test.h和libtest.so拷貝到對應的程式碼工程中,然後執行類似“gcc test.c -L. -ltest -o test”這樣的命令即可(前提是libtest.so所在的路徑在環境變數中設定正確)。
四、總結
有關生成靜態庫和動態庫的命令,說明如下:
第一,在本文中,我們使用的生成靜態庫的命令形如“ar -r test.a test.o”,其中,-r是replace的意思,表示如果當前插入的模組名已經在庫中存在,則替換同名的模組。我們也可以用形如“ar -cr test.a test.o”的命令來生成靜態庫,其中-c是create的意思,表示生成。
第二,在本文中,我們使用的生成動態庫檔案的命令形如“gcc test_a.c -fPIC -shared -o libtest.so”,其中,fPIC表示編譯為位置獨立的程式碼,shared表示生成的庫為共享庫。將動態庫檔案編譯進程式碼的命令是“gcc test.c -L. -ltest -o test”,-L指定庫查詢的位置(注意L後面還有’.'),表示在當前目錄下查詢(如果在當前目錄下的lib目錄下查詢,可以寫成-L./lib);-l則指定函式庫名,其中的lib和.so省略(如這裡的libtest.so就簡寫為test)。
第三,使用ldd命令可以檢視一個可執行程式依賴的共享庫,該命令的使用示例如下所示:
~/zhouzhaoxiong/zzx/mylib/test_so> ldd test linux-vdso.so.1 => (0x00007fff1db6e000) libtest.so => /home/zhou/lib/libtest.so (0x00007fdbfff21000) libc.so.6 => /lib64/libc.so.6 (0x00007fdbffb95000) /lib64/ld-linux-x86-64.so.2 (0x00007fdc00124000)
可以看到,可執行檔案test依賴於四個共享庫,其中libtest.so位於當前使用者的lib目錄下。
參考資料:
1. http://blog.chinaunix.net/uid-26833883-id-3219335.html
2. http://blog.csdn.net/bat603/article/details/1438408
3. http://blog.sina.com.cn/s/blog_795ed1810101789t.html
相關文章
- 簡述Linux下的靜態庫和動態庫Linux
- cmake:生成靜態庫和動態庫
- Linux 靜態庫生成及呼叫Linux
- iOS中的動態庫,靜態庫和framework介紹iOSFramework
- linux下的靜態庫與動態庫Linux
- ios靜態庫和動態庫iOS
- [Linux]動靜態庫Linux
- Linux共享庫、靜態庫、動態庫詳解Linux
- 靜態庫生成
- android下java的靜態庫和動態庫AndroidJava
- iOS動態庫和靜態庫的運用iOS
- linux 動態庫 靜態庫 函式覆蓋Linux函式
- 靜態庫與動態庫
- 封裝動態庫dll與靜態庫lib(原理及簡單例項)封裝單例
- linux下靜態連結庫和動態連結庫的區別有哪些Linux
- 一、靜態庫和動態庫,Makefile專案管理專案管理
- 動靜態庫
- Android NDK祕籍--淺析靜態庫和動態庫Android
- 動態庫的生成和使用(二)
- 靜態庫和動態庫的製作以及Bundle資原始檔的使用
- 動態連結庫與靜態連結庫
- Linux動態庫Linux
- Oracle資料庫啟動過程及狀態詳解Oracle資料庫
- 動態連結庫的生成和使用(二)
- 關於MNN工程框架編譯出來的靜態庫和動態庫的使用框架編譯
- 筆記: 判斷lib庫是動態庫還是靜態庫筆記
- iOS中動/靜態庫支援bitcode的問題iOS
- CMake和靜態庫順序
- Android NDK祕籍--編譯靜態庫、呼叫靜態庫Android編譯
- 偽靜態、靜態和動態的區別
- Java中的靜態代理和動態代理Java
- iOS的Framework靜態庫iOSFramework
- vsstudio中靜態庫lib的除錯除錯
- C靜態庫的建立與使用--為什麼要引入靜態庫?
- iOS 靜態庫 與私有庫iOS
- Android:JNI與NDK(二)交叉編譯與動態庫,靜態庫Android編譯
- iOS - 靜態庫.a 和 framework 詳解iOSFramework
- windows和linux gcc生成動態連結庫DLL和SO並用python呼叫WindowsLinuxGCPython
- BootStrap的動態模態框及靜態模態框boot