静态库(.a)与动态库(.so)的简明介绍

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

使用静态库(-lname -Lpath)

如果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了。

使用动态库(-fPIC -shared)

静态库优点是方便,缺点是每个程序都有一份目标文件的,很多程序会使用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提示加载动态库失败,找不到它。动态库的搜索顺序如下

  1. 编译目标代码时指定的动态库搜索路径;
  2. 环境变量LD_LIBRARY_PATH指定动态库搜索路径,它指定程序动态链接库文件搜索路径;export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:data/home/billchen/lib
  3. 配置文件/etc/ld.so.conf中指定的动态库搜索路径;
  4. 默认的动态库搜索路径/lib;
  5. 默认的动态库搜索路径/usr/lib。

这里简单起见,我们直接将libmod.so移动到/lib

$ sudo mv libmod.so /lib
$ ./resultant
print_mod1
print_mod2

动态库别名(-Wl,-soname,xx)

这里再说说-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别名引入一个中间层,好处是程序运行时可以使用和编译时不一样的兼容库。

最新文章

  1. 解决PHP move_uploaded_file函数移动图片失败
  2. 【分布式】RPC初探
  3. Java 嵌套解析 json
  4. 一个PHP加密脚本,达到一定免杀效果
  5. 实例源码--Android手机狗(防盗)源码
  6. CDOJ 1104 求两个数列的子列的交集 查询区间小于A的数有多少个 主席树
  7. vs2012新建实体数据模型(EF)时无Mysql数据源
  8. 10.20_web编辑器复制粘贴图片
  9. HDU 3018 Ant Trip
  10. ini文件解析c库(iniparser)
  11. 武道释义 &amp;#183; 零散
  12. OpenStreetMap(OSM) for developers
  13. 演练5-6:Contoso大学校园管理系统6
  14. [C++]Hello C++
  15. td里的内容宽度自适应 及 鼠标放上显示标题div title
  16. iOS蓝牙心得
  17. ASP.NET没有魔法——ASP.NET MVC 与数据库大集合
  18. SQL2008数据表空间大小查询脚本
  19. Java多线程(二)关于多线程的CPU密集型和IO密集型这件事
  20. spring @bean 的理解

热门文章

  1. Python中正则表达式对中文的匹配问题
  2. spring中二个重要点
  3. Mongoose 参考手册(转载)
  4. linux tcpdump补充
  5. 图论算法》关于SPFA和Dijkstra算法的两三事
  6. Luogu 3066 [USACO12DEC]逃跑的BarnRunning Away From…
  7. 使用pycharm运行调试scrapy
  8. LoadRunner使用问题
  9. SQL将表中某一类型的一列拼接成一行
  10. 前端mock利器:randomjson