gcc编译生成静态及动态链接库步骤

时间:2022-04-17 06:54:06

http://my.oschina.net/u/1270343/blog/167137


这两天在看《Linux C程序设计大全》,吴岳编著,清华大学出版社。这本书是在一个培训机构看到的,在网上查了下该书的相关信息。从目录而言,该书涵盖了Linux下C程序设计的较多内容,包括C语言基础(主要讲解C语法结构)、C语言开发环境(主要介绍VIM使用、GCC使用、makefile编写、gdb使用)、Linux进程操作、Linux文件操作、Linux网络编程这几部分。阅读了该书几个小章节,总体而言,书的部分内容较充实,但是存在较多编辑错误,部分样例实际运行时与书中内容不符。

      这里使用该书P192-P199的例子,总结下gcc编译静态及动态链接库的方法及步骤。

    程序清单如下:

test.c文件内容:

01 int add(int a, int b)
02 {
03     return a + b;
04 }
05  
06 int sub(int a, int b)
07 {
08     return a - b;
09 }
10  
11 int mul(int a, int b)
12 {
13     return a * b;
14 }
15  
16 int div(int a, int b)
17 {
18     return a / b;
19 }
test.h文件内容:
01 #ifndef
_TEST_H_
02  
03 #define
_TEST_H_
04  
05 extern int add(int a, int b);
06 extern int sub(int a, int b);
07 extern int mul(int a, int b);
08 extern int div(int a, int b);
09  
10 #endif
main.c文件内容:
01 #include
<stdio.h>
02 #include
"test.h"
03  
04 int main ()
05 {
06     int a, b;
07     printf("please input a and b\n");
08     scanf("%d%d", &a, &b);
09  
10     printf("The add : %d\n", add(a, b));
11     printf("The sub : %d\n", sub(a, b));
12     printf("The mul : %d\n", mul(a, b));
13     printf("The div : %d\n"div(a, b));
14  
15     return 0;
16 }
    1. 首先总结使用gcc生成静态库及使用静态库的方法:

    在此例中,test.c用于编译生成静态库libtest.a,test.h为libtest.a对应的头文件。

    step 1: 生成test.o目标文件,使用如下命令:

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

    step 2: 使用ar将test.o打包成libtest.a静态库,使用如下命令:

1 [xgqin@xgqin-desktop
so]$ ar rcs -o libtest.a 
test.o
2 [xgqin@xgqin-desktop
so]$ 
ls
3 libtest.a 
main.c  
test.c  test.h  test.o
    step 3:生成libtest.a静态库后,可以使用ar t参数查看libtest.a文件中包含哪些文件:
1 [xgqin@xgqin-desktop
so]$ ar t libtest.a
2 test.o
3 [xgqin@xgqin-desktop
so]$
    step 4: 编译main.c,并使用libtest.a静态库,链接时-l参数后不加空格指定所需链接的库,这里库名是libtest.a,但是只需要给出-ltest即可,ld会以libtest作为库的实际名字(例如-lm参数,实际表示链接libm库,也就是数学库):
1 [xgqin@xgqin-desktop
so]$ gcc -o app_static main.c -L. -ltest
2 [xgqin@xgqin-desktop
so]$ 
ls
3 app_static 
libtest.a  main.c  
test.c  test.h  test.o

    或使用如下方式编译main.c,并使用libtest.a静态库:

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

 step 5: 运行app_static:

1 [xgqin@xgqin-desktop
so]$ ./app_static
2 please
input a and b
3 4
2
4 The
add : 6
5 The
sub : 2
6 The
mul : 8
7 The
div : 2
8 [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程序代码段中,此为静态链接。

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

    注:《Linux C程序设计大全》中给出的三种链接静态库的方法在实际使用时均出现报错,如下所示:

01 [xgqin@xgqin-desktop
so]$ gcc main.c -llibtest.a -o app
02 /usr/bin/ld:
cannot 
find -llibtest.a
03 collect2:
error: ld returned 1 
exit status
04 [xgqin@xgqin-desktop
so]$ gcc main.c -ltest.a -o app
05 /usr/bin/ld:
cannot 
find -ltest.a
06 collect2:
error: ld returned 1 
exit status
07 [xgqin@xgqin-desktop
so]$ gcc main.c -ltest -o app
08 /usr/bin/ld:
cannot 
find -ltest
09 collect2:
error: ld returned 1 
exit status
10 [xgqin@xgqin-desktop
so]$ gcc -L. main.c -o app
11 /tmp/ccEpq6Fp.o:
In 
function `main':
12 main.c:(.text+0x37):
undefined reference to `add'
13 main.c:(.text+0x57):
undefined reference to `sub'
14 main.c:(.text+0x77):
undefined reference to `mul'
15 collect2:
error: ld returned 1 
exit status
16 [xgqin@xgqin-desktop
so]$ gcc main.c -static ./libtest.a -o app
17 /usr/bin/ld:
cannot 
find -lc
18 collect2:
error: ld returned 1 
exit status
19 [xgqin@xgqin-desktop
so]$

    具体出错原因,个人推测应与ld相关。

    2. 再总结使用gcc生成动态库及使用动态库的方法:

    step 1: 生成test.o目标文件,使用如下命令。此处需要添加-fPIC参数,该参数用于生成位置无关代码已共生成动态库使用:

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



    step 2: 使用-shared参数生成动态库,使用如下命令:


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


    上述两个命令可以合在一块,如下所示:

1 [xgqin@xgqin-desktop
so]$ gcc -shared -fPIC -o libmyshare.so 
test.c
2 [xgqin@xgqin-desktop
so]$ 
file libmyshare.so
3 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动态库:


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

    使用ldd命令查看app_share使用的动态库,发现提示libmyshare无法找到,如果直接执行app_share,则出现如下错误:

1 [xgqin@xgqin-desktop
so]$ ./app_share
2 ./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,如下:

01 [xgqin@xgqin-desktop
so]$ gcc -o app_share main.c -L. -lmyshare
02 [xgqin@xgqin-desktop
so]$ ldd app_share
03     linux-vdso.so.1 =>  (0x00007fff26b70000)
04     libmyshare.so => not found
05     libc.so.6 => /lib64/libc.so.6 (0x0000003039600000)
06     /lib64/ld-linux-x86-64.so.2 (0x0000003039200000)
07 [xgqin@xgqin-desktop
so]$ 
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
08 [xgqin@xgqin-desktop
so]$ 
echo $LD_LIBRARY_PATH
09 .:
10 [xgqin@xgqin-desktop
so]$ ldd app_share
11     linux-vdso.so.1 =>  (0x00007fff55dbe000)
12     libmyshare.so => ./libmyshare.so (0x00007fb8c3b18000)
13     libc.so.6 => /lib64/libc.so.6 (0x0000003039600000)
14     /lib64/ld-linux-x86-64.so.2 (0x0000003039200000)
15 [xgqin@xgqin-desktop
so]$ ./app_share
16 please
input a and b
17 4
2
18 The
add : 6
19 The
sub : 2
20 The
mul : 8
21 The
div : 2

 注:注意观察export前后的两次ldd执行时,libmyshare.so的指向情况。

另一种编译main.c,并链接libmyshare.so的方式如下(该方式通过./libmyshare.so直接指定使用当前目录下的libmyshare.so文件:

01 [xgqin@xgqin-desktop
so]$ gcc -o app_share main.c ./libmyshare.so 
02 [xgqin@xgqin-desktop
so]$ ldd app_share 
03  linux-vdso.so.1 =>  (0x00007fff066c3000)
04  ./libmyshare.so (0x00007f945b6b0000)
05  libc.so.6 => /lib64/libc.so.6 (0x0000003039600000)
06  /lib64/ld-linux-x86-64.so.2 (0x0000003039200000)
07 [xgqin@xgqin-desktop
so]$ ./app_share 
08 please
input a and b
09 4
2
10 The
add : 6
11 The
sub : 2
12 The
mul : 8
13 The
div : 2
14 [xgqin@xgqin-desktop
so]$ 
本文中使用到的readelf属于binutils工具集,感兴趣的读者可以访问google或者百度。