linux的链接库


概述

程序函数库可分为3种类型:静态函数库(static libraries)、共享函数库(shared libraries)、动态加载函数库(dynamically loaded libraries)

程序函数库可分为下面几种类型:

  1. 静态函数库(static libraries):在编译期间(compile-time)静态链接库会全部拷贝进编译对象中,一般以.a文件的存在
  2. 动态函数库(shared libraries):在程序启动的时候加载到程序中,它可以被不同的程序共享,一般以.so文件存在
    • 动态加载函数库(dynamically loaded libraries),在进程运行期间,使用dlfcn.h中的函数加载、调用、关闭动态库

注意: LD_LIBRARY_PATH这个也是很关键的环境变量,一般的linux系统里都没设置这个 export LD_LIBRARY_PATH=/usr/local/lib/:/usr/lib/

如何指定链接的是动态库还是静态库?

如果我们在gcc中使用参数-l来链接某个库,gcc会首先查找动态库,动态库没有再查找静态库,当然我们可以通过-Wl,-Bstatic的方式使用静态库,使用完成之后记得加上-Wl,-Bdynamic收尾,否则所有-Wl,-Bstatic之后的库都变成静态库了

在CMake中,如果一个库既有动态版本,又有静态版本,可以在CMake里面指定target_link_libraries(xxx.a),指向静态库

链接库的顺序

GCC在链接过程中,对参数中的库的顺序是有要求的,参数右侧的库会先于左侧的库加载,也就是说参数的解析是从右往左的。

假设库B依赖与库A,则链接的时候要写为:

gcc -o bin -lB -lA

如果写为:

gcc -o bin -lA -lB

则在B中引用的A中的内容就会无法链接通过。

静态库链接问题

静态库本质上就是使用ar命令打包一堆.o文件

但是静态库和.o文件有不同的地方:

  1. 编译命令里连接了.o文件,那么一定会连接进最后的可执行文件。.o文件中的静态变量、被__attribute__((constructor))修饰的函数,也会正常的在main函数前被调用
  2. 静态库.a文件,如果编译到它发现没有被之前的文件调用,则编译器会忽略这个静态库文件,这会导致一些静态变量错误的没有被初始化。

gcc链接参数

  1. -L:告诉编译器搜索库的时候可以去哪个目录去找,如-L/usr/local/lib
  2. -l:指定链接某动态库或静态库,如-ltcmalloc,也可以显式指定链接库的名字-l:libtest.so
  3. -I:告诉编译器搜索头文件的目录,如-I/usr/local/include

库链接参数

--whole-archive

调整库的链接顺序可以解决大部分问题,但当静态库之间存在环形依赖时,则无法通过调整顺序来解决。

使用--whole-archive可以告诉编译器把静态库中的所有.o .a都进行链接、

--no-whole-archive
  • 这个参数是跟在–whole-archive之后,作用是告诉编译器,后面的库不需要全部都链接了
  • 也就是说只有跟在这两个语句中的参数才会全部被链接
# 例子
g++ -o program main.o \
    -Wl,--whole-archive -lmylib \
    -Wl,--no-whole-archive -llib1 -llib2
--wrap

-Wl,–wrap -Wl,free

--wrap=symbol
    Use a wrapper function for symbol.  Any undefined reference to
    symbol will be resolved to "__wrap_symbol".  Any undefined
    reference to "__real_symbol" will be resolved to symbol.

    This can be used to provide a wrapper for a system function.  The
    wrapper function should be called "__wrap_symbol".  If it wishes to
    call the system function, it should call "__real_symbol".

    Here is a trivial example:

            void *
            __wrap_malloc (size_t c)
            {
                printf ("malloc called with %zu/n", c);
                return __real_malloc (c);
            }

    If you link other code with this file using --wrap malloc, then all
    calls to "malloc" will call the function "__wrap_malloc" instead.
    The call to "__real_malloc" in "__wrap_malloc" will call the real
    "malloc" function.

    You may wish to provide a "__real_malloc" function as well, so that
    links without the --wrap option will succeed.  If you do this, you
    should not put the definition of "__real_malloc" in the same file
    as "__wrap_malloc"; if you do, the assembler may resolve the call
    before the linker has a chance to wrap it to "malloc".
–start-group --end-group

位于--start-group --end-group中的所有静态库将被反复搜索,而不是默认的只搜索一次,直到不再有新的unresolved symbol产生为止。也就是说,出现在这里的.o如果发现有unresolved symbol,则可能回到之前的静态库中继续搜索。

ld

  • ld 命令是二进制工具集 GNU Binutils 的一员,是 GNU 链接器,用于将目标文件与库链接为可执行文件或库文件。相当于编译里面的链接环节

  • gcc里面使用-Wl,开头的参数都是传递给ld的参数,如果直接调用ld,则不需要加-Wl,

常用参数:

  1. -WL,–verbose 打印所有的过程
  2. -Wl,-Bdynamic 后面所有的库都使用动态版本
  3. -Wl,-Bstatic 后面所有的库使用静态版本
  4. -Wl,-soname 加动态链接库的版本号如1.0
  5. -Wl,–as-needed 只链接需要的库,不需要的不链接,gcc中默认打开,因为ld的顺序是从右到左的,所以如果链接顺序有问题,会导致某些库没有链接进去,导致后面的依赖库找不到没有导入的前面库的符号,因而编译失败
  6. -Wl,–version-script 指定库的输出符号,spdk使用如spdk_event.map之类的文件导出函数符号

cc

在linux下,cc就是gcc,之所以搞了个cc,是为了和unix兼容,cc在unix下是c语言的编译器

动态链接库

LD_PRELOAD可以作为参数,增加动态链接库的指向,例如:LD_PRELOAD=/data/tools/lib/libzookeeper_mt.so:/data/tools/lib/libprotobuf.so

参考链接

  1. 浅析静态库链接原理好文,并且介绍了一些编译连接测参数
  2. ld linker question: the --whole-archive option
  3. How to force gcc to link an unused static library
  4. 解压静态库.a文件
  5. linux动态链接库的加载顺序 rpath > LD_LIBRARY_PATH > ldconfig > 系统默认位置/lib /usr/lib
  6. 动态库(.so)链接静态库(.a)的情况总结
  7. gcc 链接库的顺序问题
  8. 深入理解LINUX下动态库链接器/加载器ld-linux.so.2
  9. linux 热替换so文件 热替换需要先dlclose,然后再换掉动态库,切换的过程中不能调用动态库中的函数
  10. Linux下g++编译与使用静态库和动态库
  11. How static library in c++ work with name mangle?C++编译动态库文件,会遇到因为c++对函数改名,而产生name mangling问题
  12. 2.1 Command-line Options ld所有的选项
  13. When and why would the C linker exclude unused symbols?
  14. C 多个动态库存在同名函数问题处理方法:-fvisibility=hidden
  15. gcc编译参数-fPIC的一些问题
  16. GCC选项_-Wl,-soname 及 DT_NEEDED 的解释
  17. 链接脚本(Linker Scripts)语法和规则解析(翻译自官方手册) GROUP(file, file, …) / GROUP(file file …) AS_NEEDED(file, file, …) / AS_NEEDED(file file …)
  18. LD上文是对这个LD文档的部分翻译
  19. LD --version-script及脚本文件控制符号输出
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值