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文件内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
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;
}
|
1
2
3
4
5
6
7
8
9
10
|
#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
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
#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;
}
|
在此例中,test.c用于编译生成静态库libtest.a,test.h为libtest.a对应的头文件。
step 1: 生成test.o目标文件,使用如下命令:
1
2
3
4
5
|
[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
|
step 2: 使用ar将test.o打包成libtest.a静态库,使用如下命令:
1
2
3
|
[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
|
1
2
3
|
[xgqin@xgqin-desktop so]$ ar t libtest.a
test
.o
[xgqin@xgqin-desktop so]$
|
1
2
3
|
[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静态库:
1
2
3
|
[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:
1
2
3
4
5
6
7
8
|
[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程序代码段中,此为静态链接。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
[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程序设计大全》中给出的三种链接静态库的方法在实际使用时均出现报错,如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
[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参数,该参数用于生成位置无关代码已共生成动态库使用:
1
2
3
4
5
|
[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参数生成动态库,使用如下命令:
1
2
3
4
5
|
[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
|
上述两个命令可以合在一块,如下所示:
1
2
3
|
[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动态库:
1
2
3
4
5
6
7
8
|
[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,则出现如下错误:
1
2
|
[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
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
[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文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
[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]$
|