标签:搜索 链接器 集合 例子 本质 exit 线索 出现 方法
gcc有很多关于静态库,动态库的选项如-l
,-L
,-fPIC
,-shared
-Wl,-soname
,看着很复杂容易混淆,其实静态库和动态库都是应需而生,只要有了一个线索都很容易理解。
假设有三个文件(后面均使用这个例子):
// mod1.c
#include <stdio.h>
void print_mod1(){
printf("%s\n",__func__);
}
// mod2.c
#include <stdio.h>
void print_mod2(){
printf("%s\n",__func__);
}
//main.c
int main(){
print_mod1();
print_mod2();
return 0;
}
我们要想运行这个程序需要先编译mod1.c
,mod2.c
生成目标文件,然后目标文件与main.c
结合完成编译:
$ gcc -c mod1.c mod2.c
$ gcc -o resultant main.c mod1.o mod2.o
$ ./resultant
print_mod1
print_mod2
如果mod再多一点就会出现体力劳动:
$ gcc -o resultant mod1.o mod2.o mod3.o mod4.o mod5.o ... mod1024.o
于是就引入了静态库的概念。静态库又叫归档文件,在linux下是*.a
后缀的文件,本质上就是目标文件(*.o
)的一个集合。
ar -r
命令可以将*.o
打包为一个静态库$ ar r libmod.a mod1.o mod2.o
ar tv libmod.a
查看归档里面有哪些目标文件:$ ar tv libmod.a
rw-r--r-- 0/0 1544 Dec 31 16:00 1969 mod1.o
rw-r--r-- 0/0 1544 Dec 31 16:00 1969 mod2.o
ar d libmod.a mod2.o
删除一个不需要的目标文件打包好后就可以用libmod.a
代替一串目标文件了:
$ gcc -o resultant main.c libmod.a
最常用的链接静态库的方式是添加-lname
选项。-lname
会默认链接名为libname.a
的静态库:
$ gcc -o resultant main.o -lmod
/usr/bin/ld: cannot find -lmod
collect2: error: ld returned 1 exit status
这里我们如果直接使用-lmod
gcc会提示找不到libmod.a
模块,因为gcc只会在标准路径如/usr/lib,/lib
查找,解决方法一是把libmod.a放到标准路径,二是使用-Lpath
选项。
$ gcc -o resultant main.c -L. -lmod
$ ./resultant
print_mod1
print_mod2
-Lpath
把指定路径加入链接器搜索路径,这里我们把当前目录(.
)加入,自然就能找到libmod.a
了。
静态库优点是方便,缺点是每个程序都有一份目标文件的,很多程序会使用printf
,如果每个程序都包含一份printf.o
的实现,会非常浪费磁盘空间和宝贵内存页。还有如果要对静态库中某一个目标文件进行更新,那么应用程序就需要重新链接。
基于这些需求,动态库诞生了。
动态库需要位置独立的代码,所以不能使用前面的mod1.o
,mod2.o
,需要-fPIC
选项重新编译:
$ gcc -c -fPIC mod1.c mod2.c
然后再组合成动态库:
$ gcc -shared -o libmod.so mod1.o mod2.o
最后使用这个动态库:
$ gcc -o resultant main.c libmod.so
$ ./resultant
./resultant: error while loading shared libraries: libmod.so: cannot open shared object file: No such file or directory
好了,不出所料,又出问题了。gcc提示加载动态库失败,找不到它。动态库的搜索顺序如下
这里简单起见,我们直接将libmod.so
移动到/lib
:
$ sudo mv libmod.so /lib
$ ./resultant
print_mod1
print_mod2
这里再说说-Wl,-soname
,该选择告知链接器一个动态库的别名
$ gcc -shared -Wl,-soname,libalias.so -o libmod.so mod1.o mod2.o
$ gcc -o resultant main.c libmod.so
上面命令使用libalias.so
作为libmod.so
的别名,再次运行resultant
会提示找不到libalias.so
错误而不是libmod.so
,-soname别名引入一个中间层,好处是程序运行时可以使用和编译时不一样的兼容库。
标签:搜索 链接器 集合 例子 本质 exit 线索 出现 方法
原文地址:https://www.cnblogs.com/racaljk/p/9591431.html