天天看點

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。

#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");
}           
#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");
}           
#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。

#include <stdio.h>

void test_a();
void test_b();
void test_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");
}           
#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目錄下。

linux中.o,.a,.o,.so檔案的意義和程式設計實作

繼續閱讀