如果你是经验老手,只想将已有的静态库文件链接到新的动态库中,直接看第四节。
一、动态库的编译和使用
- a.c
int myadd(int a, int b) {
return a + b;
}
编译生成动态库:
gcc -fpic -shared a.c -o liba.so
- testa.c
#include <stdio.h>
extern int myadd(int a, int b);
int main() {
int a = 1;
int b = 2;
int c;
c = myadd(a, b);
printf("c = %d\n", c);
return 0;
}
编译testa.c并连接liba.so
gcc testa.c -L. -la -Wl,-rpath,\$ORIGIN -o testa.out
-Wl,-rpath,$ORIGIN 优先在当前路径查找动态链接库
- 查看符号
# ./testa.out文件中myadd符号为U(undef),即表示动态连接
$ nm ./testa.out | grep myadd
U myadd
# 查看链接库情况
$ ldd ./testa.out
linux-vdso.so.1 (0x00007ffc2d963000)
liba.so => /home/yuzhiyong/mywork/gitee/hello_samples/c_samples/library_samples/liba/./liba.so (0x00007fab7b332000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fab7b0f0000)
/lib64/ld-linux-x86-64.so.2 (0x00007fab7b33e000)
二、静态库的编译和使用
- a.c
int myadd(int a, int b) {
return a + b;
}
编译生成静态库
gcc -c a.c -o a.o
ar rcs -o liba.a a.o
- testa.c
#include <stdio.h>
extern int myadd(int a, int b);
int main() {
int a = 1;
int b = 2;
int c;
c = myadd(a, b);
printf("c = %d\n", c);
return 0;
}
编译testa.c并连接静态库liba.a
## 注意: 要先把liba.so删掉,因为默认优先动态链接
gcc testa.c -L. -la -o testa.out
- 查看符号
# ./testa.out文件中myadd符号为T,即表示myadd在testa.out文件中实现
$ nm ./testa.out | grep myadd
0000000000001195 T myadd
# 查看链接库情况
$ ldd testa.out
linux-vdso.so.1 (0x00007fff871f1000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6caf95e000)
/lib64/ld-linux-x86-64.so.2 (0x00007f6cafba7000)
三、动态库是否可以链接一个已有的静态库?
- 疑问:动态库编译链接的时候,无法链接一个已有的静态库到自己吗?
为此,我们做一个测试,将静态库liba.a链接到libb.so动态库中 - b.c
extern int myadd(int a, int b);
// 和的平方
int accumulation_square(int a, int b) {
int c = myadd(a, b);
return c * c;
}
- 编译
$ gcc -fpic -shared -L. -la b.c -o libb.so
# 查看libb.so中的符号myadd,未定义
$ nm libb.so | grep myadd
U myadd
这说明, 这么做并不能把liba.a链接到新的动态库libb.so中。
使用下面命令也是一样的。
gcc -fpic -shared -L. `pwd`/liba.a b.c -o libb.so
- testb.c
#include <stdio.h>
int accumulation_square(int a, int b);
int main() {
int a = 1;
int b = 2;
int c;
c = accumulation_square(a, b);
printf("c = %d\n", c);
return 0;
}
编译可执行文件测试
# 仅链接libb.so,编译报错,提示找不到myadd符号
$ gcc testb.c -L. -lb -o testb
/usr/bin/ld: ./libb.so: undefined reference to `myadd'
collect2: error: ld returned 1 exit status
# 同时链接libb.so 和liba.a
$ gcc testb.c -L. -lb -la -Wl,-rpath,\$ORIGIN -o testb.out
# 运行
$ ./testb.out
c = 9
# 查看符号, 可以看到myadd的实现已经被静态链接到testb.out
$ nm testb.out
00000000000011b5 T myadd
U accumulation_square
- 总结
- 静态库只能被链接到可执行文件,动态库编译时不可链接静态库。(别急,还有办法)
四、另辟蹊径(编译动态库,并将已有的静态库链接进来)
- 查看静态库中有哪些目标文件(object文件)。
$ ar -t liba.a
a.o
- 从静态库文件中提取目标文件。
$ mkdir liba
$ cp liba.a liba
$ cd liba/
$ ar x liba.a
$ ls
a.o liba.a
至此就得到的静态库(liba.a)中的目标文件
- 将静态库(liba.a)中的目标文件,和新的代码b.c一起链接生成信息动态库libb.so。
$ cd ..
$ gcc -c b.c -o b.o
$ gcc -fpic -shared b.o ./liba/a.o -o libb.so
- 查看符号, myadd已经被添加的新的动态库中了。
$ nm libb.so | grep myadd
0000000000001145 T myadd