背景

最近在做一些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=动态库的路径:Android编译静态库可以链接动态库吗 编译动态库依赖静态库_头文件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的路径。