gcc編譯生成靜態及動態連接庫步驟

       這兩天在看《Linux C程序設計大全》,吳嶽編著,清華大學出版社。這本書是在一個培訓機構看到的,在網上查了下該書的相關信息。從目錄而言,該書涵蓋了Linux下C程序設計的較多內容,包括C語言基礎(主要講解C語法結構)、C語言開發環境(主要介紹VIM使用、GCC使用、makefile編寫、gdb使用)、Linux進程操做、Linux文件操做、Linux網絡編程這幾部分。閱讀了該書幾個小章節,整體而言,書的部份內容較充實,可是存在較多編輯錯誤,部分樣例實際運行時與書中內容不符。 linux

      這裏使用該書P192-P199的例子,總結下gcc編譯靜態及動態連接庫的方法及步驟。 shell

    程序清單以下: 編程

test.c文件內容: 網絡

int add(int a, int b)
{
	return a + b;
}

int sub(int a, int b)
{
	return a - b;
}

int mul(int a, int b)
{
	return a * b;
}

int div(int a, int b)
{
	return a / b;
}
test.h文件內容:
#ifndef _TEST_H_

#define _TEST_H_

extern int add(int a, int b);
extern int sub(int a, int b);
extern int mul(int a, int b);
extern int div(int a, int b);

#endif
main.c文件內容:
#include <stdio.h>
#include "test.h"

int main ()
{
	int a, b;
	printf("please input a and b\n");
	scanf("%d%d", &a, &b);

	printf("The add : %d\n", add(a, b));
	printf("The sub : %d\n", sub(a, b));
	printf("The mul : %d\n", mul(a, b));
	printf("The div : %d\n", div(a, b));

	return 0;
}
    1. 首先總結使用gcc生成靜態庫及使用靜態庫的方法:

    在此例中,test.c用於編譯生成靜態庫libtest.a,test.h爲libtest.a對應的頭文件。 app

    step 1: 生成test.o目標文件,使用以下命令: 函數

[xgqin@xgqin-desktop so]$ ls
main.c  test.c  test.h
[xgqin@xgqin-desktop so]$ gcc -c test.c -o test.o
[xgqin@xgqin-desktop so]$ ls
main.c  test.c  test.h  test.o
    在第一步中使用gcc -c test.c -o test.o首先生成test.o目標文件。

    step 2: 使用ar將test.o打包成libtest.a靜態庫,使用以下命令: 工具

[xgqin@xgqin-desktop so]$ ar rcs -o libtest.a test.o 
[xgqin@xgqin-desktop so]$ ls
libtest.a  main.c  test.c  test.h  test.o
    step 3:生成libtest.a靜態庫後,可使用ar t參數查看libtest.a文件中包含哪些文件:
[xgqin@xgqin-desktop so]$ ar t libtest.a 
test.o
[xgqin@xgqin-desktop so]$
    step 4: 編譯main.c,並使用libtest.a靜態庫,連接時-l參數後不加空格指定所需連接的庫,這裏庫名是libtest.a,可是隻須要給出-ltest便可,ld會以libtest做爲庫的實際名字(例如-lm參數,實際表示連接libm庫,也就是數學庫):
[xgqin@xgqin-desktop so]$ gcc -o app_static main.c -L. -ltest
[xgqin@xgqin-desktop so]$ ls
app_static  libtest.a  main.c  test.c  test.h  test.o

    或使用以下方式編譯main.c,並使用libtest.a靜態庫: ui

[xgqin@xgqin-desktop so]$ gcc -o app_static main.c libtest.a
[xgqin@xgqin-desktop so]$ ls
app_static  libtest.a  main.c  test.c  test.h  test.o

 step 5: 運行app_static: google

[xgqin@xgqin-desktop so]$ ./app_static 
please input a and b
4 2
The add : 6
The sub : 2
The mul : 8
The div : 2
[xgqin@xgqin-desktop so]$

    step 6: 使用readelf 查看app_static的符號表,觀察sub, add, mul, div等函數是否處於app_static的.text段中。注意,section headers中指出 .text代碼段的編號是13,而再symbol table '.symtab'中則顯示add, div, mul, sub均處於13段中,也就是.text代碼段中。所以libtest.a靜態庫通過連接後對應的函數代碼已加入app_static程序代碼段中,此爲靜態連接。 spa

[xgqin@xgqin-desktop so]$ readelf -a app_static 
    .... 
Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  ....
  [13] .text             PROGBITS         0000000000400520  00000520
       0000000000000274  0000000000000000  AX       0     0     16
  [14] .fini             PROGBITS         0000000000400794  00000794
       0000000000000009  0000000000000000  AX       0     0     4
  [15] .rodata           PROGBITS         00000000004007a0  000007a0
       0000000000000062  0000000000000000   A       0     0     8
    ....
  [29] .strtab           STRTAB           0000000000000000  00001fb8
       000000000000027b  0000000000000000           0     0     1  
Symbol table '.symtab' contains 72 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
    ....
    49: 00000000004006c4    20 FUNC    GLOBAL DEFAULT   13 add
    ....
    53: 0000000000400701    19 FUNC    GLOBAL DEFAULT   13 div
    ....
    64: 0000000000400610   179 FUNC    GLOBAL DEFAULT   13 main
    65: 00000000004006ee    19 FUNC    GLOBAL DEFAULT   13 mul
    ....
    70: 00000000004006d8    22 FUNC    GLOBAL DEFAULT   13 sub
    ....

    注:《Linux C程序設計大全》中給出的三種連接靜態庫的方法在實際使用時均出現報錯,以下所示:

[xgqin@xgqin-desktop so]$ gcc main.c -llibtest.a -o app
/usr/bin/ld: cannot find -llibtest.a
collect2: error: ld returned 1 exit status
[xgqin@xgqin-desktop so]$ gcc main.c -ltest.a -o app
/usr/bin/ld: cannot find -ltest.a
collect2: error: ld returned 1 exit status
[xgqin@xgqin-desktop so]$ gcc main.c -ltest -o app
/usr/bin/ld: cannot find -ltest
collect2: error: ld returned 1 exit status
[xgqin@xgqin-desktop so]$ gcc -L. main.c -o app
/tmp/ccEpq6Fp.o: In function `main':
main.c:(.text+0x37): undefined reference to `add'
main.c:(.text+0x57): undefined reference to `sub'
main.c:(.text+0x77): undefined reference to `mul'
collect2: error: ld returned 1 exit status
[xgqin@xgqin-desktop so]$ gcc main.c -static ./libtest.a -o app
/usr/bin/ld: cannot find -lc
collect2: error: ld returned 1 exit status
[xgqin@xgqin-desktop so]$

    具體出錯緣由,我的推測應與ld相關。

    2. 再總結使用gcc生成動態庫及使用動態庫的方法:

    step 1: 生成test.o目標文件,使用以下命令。此處須要添加-fPIC參數,該參數用於生成位置無關代碼已共生成動態庫使用:

[xgqin@xgqin-desktop so]$ gcc -c -o test.o -fPIC test.c 
[xgqin@xgqin-desktop so]$ ls
app_static  libtest.a  main.c  test.c  test.h  test.o
[xgqin@xgqin-desktop so]$ file test.o 
test.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped



    step 2: 使用-shared參數生成動態庫,使用以下命令:


[xgqin@xgqin-desktop so]$ gcc -shared -o libmyshare.so test.o 
[xgqin@xgqin-desktop so]$ ls
app_static  libmyshare.so  libtest.a  main.c  test.c  test.h  test.o
[xgqin@xgqin-desktop so]$ file libmyshare.so 
libmyshare.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=0x4053caa2d2d48b9b026576a69929a4a44abedcb0, not stripped


    上述兩個命令能夠合在一塊,以下所示:

[xgqin@xgqin-desktop so]$ gcc -shared -fPIC -o libmyshare.so test.c 
[xgqin@xgqin-desktop so]$ file libmyshare.so 
libmyshare.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=0x4053caa2d2d48b9b026576a69929a4a44abedcb0, not stripped

    step 3: 編譯main.c,使用libmyshare.so動態庫:


[xgqin@xgqin-desktop so]$ gcc -o app_share main.c -L. -lmyshare
[xgqin@xgqin-desktop so]$ ls
app_share  app_static  libmyshare.so  libtest.a  main.c  test.c  test.h  test.o
[xgqin@xgqin-desktop so]$ ldd app_share 
	linux-vdso.so.1 =>  (0x00007fff3972c000)
	libmyshare.so => not found
	libc.so.6 => /lib64/libc.so.6 (0x0000003039600000)
	/lib64/ld-linux-x86-64.so.2 (0x0000003039200000)

    使用ldd命令查看app_share使用的動態庫,發現提示libmyshare沒法找到,若是直接執行app_share,則出現以下錯誤:

[xgqin@xgqin-desktop so]$ ./app_share 
./app_share: error while loading shared libraries: libmyshare.so: cannot open shared object file: No such file or directory
    查看相關資料後,提示與LD_LIBRARY_PATH相關,首先使用export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH將當前目錄加入LD_LIBRARY_PATH變量中。再次運行ldd app_share,以下:

[xgqin@xgqin-desktop so]$ gcc -o app_share main.c -L. -lmyshare
[xgqin@xgqin-desktop so]$ ldd app_share 
	linux-vdso.so.1 =>  (0x00007fff26b70000)
	libmyshare.so => not found
	libc.so.6 => /lib64/libc.so.6 (0x0000003039600000)
	/lib64/ld-linux-x86-64.so.2 (0x0000003039200000)
[xgqin@xgqin-desktop so]$ export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
[xgqin@xgqin-desktop so]$ echo $LD_LIBRARY_PATH
.:
[xgqin@xgqin-desktop so]$ ldd app_share 
	linux-vdso.so.1 =>  (0x00007fff55dbe000)
	libmyshare.so => ./libmyshare.so (0x00007fb8c3b18000)
	libc.so.6 => /lib64/libc.so.6 (0x0000003039600000)
	/lib64/ld-linux-x86-64.so.2 (0x0000003039200000)
[xgqin@xgqin-desktop so]$ ./app_share 
please input a and b
4 2
The add : 6
The sub : 2
The mul : 8
The div : 2

 注:注意觀察export先後的兩次ldd執行時,libmyshare.so的指向狀況。

另外一種編譯main.c,並連接libmyshare.so的方式以下(該方式經過./libmyshare.so直接指定使用當前目錄下的libmyshare.so文件:

[xgqin@xgqin-desktop so]$ gcc -o app_share main.c ./libmyshare.so 
[xgqin@xgqin-desktop so]$ ldd app_share 
 linux-vdso.so.1 =>  (0x00007fff066c3000)
 ./libmyshare.so (0x00007f945b6b0000)
 libc.so.6 => /lib64/libc.so.6 (0x0000003039600000)
 /lib64/ld-linux-x86-64.so.2 (0x0000003039200000)
[xgqin@xgqin-desktop so]$ ./app_share 
please input a and b
4 2
The add : 6
The sub : 2
The mul : 8
The div : 2
[xgqin@xgqin-desktop so]$ 
本文中使用到的readelf屬於binutils工具集,感興趣的讀者能夠訪問google或者百度。
相關文章
相關標籤/搜索