背景
最近在做一些golang调用c语言库的工作,但是一直使用动态库,每次部署都要牵扯依赖库的复制,比较麻烦,所以开始选择使用静态库,那么c语言静态库和动态库应该如何编译呢?本篇博客展开一些简单的使用介绍。
库
什么是库?
库是一段编译好的二进制代码,加上头文件就可以供别人使用。什么时候会用到库?一是某些代码需要给别人使用,但又不想暴露源代码,就需要以库的形式进行封装,只暴露出头文件;二是对于某些不需要经常修改的代码,为了减少编译的时间,就可以把它打包成库,因为库已经是编译的文件,编译的时候只需要链接,不会浪费编译时间。
链接的时候就有静态和动态的,于是就有了静态库和动态库。
动态库
-
命名规则:libxxx.so
-
制作步骤:
- 将源文件生成.o文件(例:gcc a.c b.c -c fpic)
- 打包:gcc -shared a.o b.o -o libxxx.so
-
使用方法:
- gcc test.c -I ./ -L ./ -ltest -o app
- -I:指定头文件的路径
- -L:指定库的位置
- -l:指定库的名字(去掉lib和.so)
-
动态库找不到文件问题解决:
-
使用环境变量:
* 临时设置:在终端输入:export LD_LIBRARY_PATH=动态库的路径: L D L I B R A R Y P A T H ∗ 永久设置:用户级别:在 . / b a s h r c 文件中写入 e x p o r t L D L I B R A R Y P A T H = 动态库的路径 : LD_LIBRARY_PATH * 永久设置: 用户级别:在 ~./bashrc 文件中写入 export LD_LIBRARY_PATH=动态库的路径: LDLIBRARYPATH∗永久设置:用户级别:在 ./bashrc 文件中写入 exportLDLIBRARYPATH=动态库的路径:LD_LIBRARY_PATH(配置完成要重启终端,或输入 source ~./bashrc)
系统级别:在 /etc/profile 文件中写入 export LD_LIBRARY_PATH=动态库的路径:$LD_LIBRARY_PATH(配置完成输入 source/etc/profile) -
修改文件列表/etc/ld.so.cache:
* 找到配置文件:/etc/ld.so.conf
* 把动态库的绝对路径加入到文件中
* 执行命令:sudo ldconfig -v
-
静态库
-
命名规则:
- 例:libtest.a
- ①lib ②xxx - 库的名字 ③.a
-
制作步骤:
- 原材料:xxx.c 或 xxx.cpp
- 将生成的.c文件转成.o文件(例:gcc a.c b.c -c)
- 将.o文件打包:
* ar rcs 静态库的名字 原材料(.o文件)
* 例:ar rcs libtest.a a.o b.o(ar意思是将将代码序列化) - 查看静态库的内容:nm libtest.a
-
使用方法:
- gcc test.c -I ./ -L ./lib -lmycalc -o app
- -I(i):指定头文件的路径
- -L:指定库的位置
- -l(L):指定库的名字(去掉lib和.a)
wl rpath含义
其中,有两个单独的部分-Wl和-rpath组成。
-Wl
这个是gcc的参数,表示编译器将后面的参数传递给链接器ld。
-rpath
大体就以下这几个意思:
1. 添加一个文件夹作为运行时库的搜索路径。在将ELF可执行文件与共享对象链接时使用此选项;
2. 在链接时,一些动态库明确的链接了其他动态库, 则-rpath选项也可用于定位这些链接的动态库(没太理解这个);
3. 在运行链接时,会优先搜索-rpath的路径,再去搜索LD_RUN_PATH的路径。