linux的动态库和静态库(c语言)——将已有的静态库文件链接到新的动态库中


如果你是经验老手,只想将已有的静态库文件链接到新的动态库中,直接看第四节。

一、动态库的编译和使用

  • 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
  • 总结
  1. 静态库只能被链接到可执行文件,动态库编译时不可链接静态库。(别急,还有办法)

四、另辟蹊径(编译动态库,并将已有的静态库链接进来)

  1. 查看静态库中有哪些目标文件(object文件)。
$ ar -t liba.a
a.o
  1. 从静态库文件中提取目标文件。
$ mkdir liba
$ cp liba.a liba
$ cd liba/
$ ar x liba.a
$ ls
a.o  liba.a

至此就得到的静态库(liba.a)中的目标文件

  1. 将静态库(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
  1. 查看符号, myadd已经被添加的新的动态库中了。
$ nm libb.so | grep myadd
0000000000001145 T myadd
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值