原文链接:Linux下静态库、动态库的创建和使用
发布时间:2015-08-25 20:26:24
Linux下静态库、动态库的创建和使用
Linux库文件名由:前缀lib、库名和后缀3部分组成,静态库通常以.a作为后缀,动态库以.so作为后缀,
Linux下把动态库叫做共享库,so即shared object的缩写。
静态库是程序编译链接时使用,动态库是程序运行时使用。
预备知识:
a) 2个重要的环境变量:
LIBRARY_PATH : 库文件(静态库或者动态库)搜索路径,编译器链接时,需要去这些路径搜索相应的库,当然系统默认的库文件搜索路径是/usr/lib和/lib。
LD_LIBRARY_PATH :动态库文件搜索路径,程序运行时,需要去这些路径搜索相应的动态库,程序运行时,默认的搜索动态库的路径也是/usr/lib和/lib。
b) 2个重要的系统文件:
/etc/ld.so.conf :里面可以加上动态库的搜索路径,绝对路径,(/usr/lib和/lib默认包含其中)
/etc/ld.so.cache :保存/etc/ld.so.conf里所有路径的所有的动态库文件的缓存,保存了已排好序的动态链接库名字列表,有一个命令:ldconfig 会根据/etc/ld.so.conf生成或者更新/etc/ld.so.cache,执行这个命令需要root权限。(关于这个cache文件里面具体实现哪些东西,笔者也不是很清楚,待后续研究)
程序在运行时,如果都要搜索/etc/ld.so.conf里目录下库文件,效率会很低,因此Linux采用了类似高速缓存制,程序先去查找缓存文件/etc/ld.so.cache ,因此当/usr/lib或者/lib下放入新的动态库后,也要执行sudo ldconfig 重新生成缓存文件,否则程序无法运行,报错提示,找不到共享库。当往/etc/ld.so.conf里添加目录时,或者后来在这些目录下添加新的库,都需要执行 sudo ldconfig 生成新的缓存文件。
==================================================================================
假设有如下文件:mylib.h mylib.c depend.h depend.c
一、创建静态库
1 | gcc -c mylib.c -o mylib.o |
ar 其实就是将*.o文件打包归档而已,主要参数说明:
r --- 在库中加入成员文件,若存在,则替换
c --- 创建一个静态库
s --- 无论ar命令是否修改了库的内容,都强制重新生成库符号表
d --- 从库中删除成员文件
二、使用静态库(3种方法)
1、把库文件放入/usr/lib或者/lib目录下
1 | gcc main.c -o main -lmylib |
2、链接时指定库的目录,假设库文件放在/home/user/lib/下
1 | gcc main.c -o main -L/home/user/lib -lmylib |
3、修改环境变量,将库文件所在目录/home/user/lib/加入到LIBRARY_PATH
1 | export LIBRARY_PATH=/home/user/lib/:$LIBRARY_PATH |
三、创建动态库(2种方法)
1 | # 方法1 |
四、使用动态库(4种方法)
假设libmylib.so库文件在/home/user/lib/下,以下4种方法:
1、把动态库放入 /usr/lib或者/lib下,然后执行sudo ldconfig
1 | gcc main.c -o main -lmylib |
2、修改环境变量
1 | export LD_LIBRARY_PATH=/home/user/lib/:$LD_LIBRARY_PATH |
注意这种方式,不能编译通过,因为LD_LIBRARY_PATH只和运行时有关,所以正确的做法是:
1 | # 编译 + 运行时路径 |
或者将/home/user/lib加入到LIBRARY_PATH中:
1 | export LIBRARY_PATH=/home/user/lib/:$LIBRARY_PATH |
3、将/home/user/lib/加入到/etc/ld.so.conf中,执行sudo ldconfig
1 | gcc main.c -o main -lmylib |
4、在编译时,设置动态库运行时寻找路径
1 | gcc main.c -o main -L/home/user/lib -lmylib -Wl,-rpath=/home/user/lib |
-Wl,-rpath= 指定程序在运行时,搜索动态库会第一个搜索这个指定目录,然后是LD_LIBRARY_PATH,再是/etc/ld.so.conf中的路径。
结论:程序运行时,动态库搜索路径顺序:
- 编译时 -Wl,-rpath= 指定的路径
- LD_LIBRARY_PATH
- /etc/ld.so.cache,即/etc/ld.so.conf中的路径。
根据笔者的实践经验,笔者推荐使用第4种方法,原因如下:
1、对于方法1,诚然简单方便,易于批量部署,但是假如我使用动态库在目标机器也存在,比如 libcurl.so, boost库,如果我使用的libcurl.so比目标机器上的libcurl.so库版本高,那么就等于升级了目标机器的libcurl.so库文件,虽然Linux约定了动态库版本兼容的规则,但是对于随意升级目标机器上的库文件,有时候会造成一些问题,显然污染了系统文件的纯洁。
2、对方法2和方法3都需要修改配置文件,比较麻烦,不易于批量部署,而且也容易污染系统文件的纯洁。
3、方法4的库文件路径可以自己定义,与系统库文件隔离了,解决了方法1,2,3存在的问题。
然而在实践过程中,使用方法4会出现一些莫名其妙的问题。
比如我的程序依赖这个库libcurl.so.4.3.0(一个有名的开源库),并且放在/home/user/lib下,
1 | # 无法编译 —— libcurl.so 不存在,实际文件是 libcurl.so.4.3.0 |
为什么会出现这种问题呢?该如何解决呢?请参见下一篇博客《再谈Linux下的动态库》。
以上内容是笔者在工作中,使用动态库、静态库的个人总结,今作记录于此,由于笔者的水平有限,出错在所难免,恳请读者拍砖指正,谢谢阅读。