静态库和动态库分析总结

1、库文件的作用:

  简单来说:库文件通过头文件向外导出接口。用户通过头文件找到库文件中头文件中有函数的申明,库文件实现函数的定义。比如,printf函数。使用时应包括stdio.h,打开stdio.h你只能看到,printf这个函数的申明,却看不到printf具体是怎么实现的,而函数的实现在相应的C库中。而库文件一般是以二进制形式而不是C源文件形式提供给用户使用的。程序中包括了stdio.h这个头文件。链接器就能根据头件中的信息找到printf这个函数的实现并链接进这个程序代码段里。函数实现的代码从而把这段代码链接到用户程序中去。
  创建一个库一般处于一下两种目的:

1、把一些相关的代码,打包成一个库,发布给其它的人用。这种情况是最常见的情况,如写 C 语言用到 libgcc。在这种情况下,你除了提供库文件:静态库[ windows 下 .lib,linux .a];动态库:[Windows 下 .dll,Linux 下 .so] 之外,必须提供头文件。头文件是你这个库里面提供了那些接口可以供外界使用。如果没有头文件,其他人无法使用。
2、为某些软件写插件。
很多大的项目,都是模块化设计,留有一些特定的接口,方便定制。当程序运行时,会动态加载制定目录下的动态库,运行时调用动态库里面约定好的方法。这种情况无需提供头文件,但要按照特定的约定来实现这个库。

  库文件和SDK: 一般来说SDK是完全封装好的,提供的是一个二进制的包,C++SDK包含有相应的头文件(这里定义了对外提供的接口)和相应的库文件(由源码编译成的库)。有时C-SDK 以开源方式提供。开发者可以从本文档提供的下载地址查看和下载 SDK 的源代码,并按自己的工程现状进行合理使用,例如编译为静态库或者动态库后进行链接,或者直接将 SDK 的源代码加入到自己的工程中一起编译,以保持工程设置的简单性。API是一个具体的函数,一个确定的功能说明,已经明确了它的作用(比如做加法)。而SDK就像是很多方法的集合体,sdk封装的的就是api,是一个工具。现在很多第三方接口运行是通过远程调用的方式,这样的好处是不需要下载对应的SDK,只需要知道API的接口地址。在某种程度上减少了调用他人接口的难度。

2、静态库

  静态库:在链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中。因此对应的链接方式称为静态链接。静态库与汇编生成的目标文件一起链接为可执行文件,那么静态库必定跟.o文件格式相似。其实一个静态库可以简单看成是一组目标文件(.o/.obj文件)的集合,即很多目标文件经过压缩打包后形成的一个文件。Linux创建静态库过程如下:
[1] 首先,将代码文件编译成目标文件.o(StaticMath.o)g++ -c StaticMath.cpp。
[2] 然后,通过ar工具将目标文件打包成.a静态库文件注意带参数-c,否则直接编译为可执行文件ar -crv libstaticmath.a StaticMath.o(c:创建一个库,r:插入模块若存在同名则替换,v: 程序执行时显示详细的信息)

3、动态库

  在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入。不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例,规避了空间浪费问题。动态库在程序运行是才被载入,也解决了静态库对程序的更新、部署和发布页会带来麻烦。用户只需要更新动态库即可,增量更新。
g++ -fPIC -shared -o libdynmath.so DynamicMath.cpp
  动态库特点总结:
[1] 动态库把对一些库函数的链接载入推迟到程序运行的时期。
[2] 可以实现进程之间的资源共享。(因此动态库也称为共享库)。
[3] 将一些程序升级变得简单。
[4] 甚至可以真正做到链接载入完全由程序员在程序代码中控制(显示调用)。

4、库文件的链接处理

   一个编译单元是指一个.cpp文件以及它所#include的所有.h文件,.h文件里的代码将会被扩展到包含它的.cpp文件里。链接器之库文件处理:其实链接真正的输入只有两类,一类是目标文件,另一类是库文件(包括通常以.a结束的静态库和以so结束的动态库),当然还有链接脚本输入以及响应文件输入等信息。但是事实上一个库文件也是一个所有目标文件以某种形式组成的打包文件。就好像windows下的winrar或者linux下的tar文件,它都是为了把一个操作系统相关的文件夹表示的文件树结构压缩入一个文件,从而便于传输,因为很多工具都是不支持文件夹传递了(因为文件目录结构是操作系统相关组织形式),例如我们常见的ftp协议以及大部分的IM软件。
   所以对于链接器来说,它就执行了对目标文件打包相反的操作,也就是把文件中的符号还原为一些目标文件的组合。但是为了便于链接器更快的知道这个库文件中包含了哪些文件,库文件使用了自己特殊的格式来组织符号,从而可以让链接器尽可能快的确定这个库中的某些文件是否需要。所以库文件的开始列出了自己包含的所有符号的信息(准确的说是已定义符号),在链接器读入库文件的时候,它会决定读取这些信息,决定这个库中符号是否需要。如果当前未定义符号在库文件中有定义,那么就把这个符号所在的目标文件整个作为链接器的目标文件输入。这相当于一个CPU的cache算法,如果有一个cache字节命中,那么整个cache line都被从内存读入CPU cache。

5、库文件的搜索路径

  动态库的搜索路径:编译目标代码时指定的动态库搜索路径;
  • 环境变量LD_LIBRARY_PATH指定的动态库搜索路径;
  • 配置文件/etc/ld.so.conf中指定的动态库搜索路径;
  • 默认的动态库搜索路径/lib,/lib64(64位系统)
  • 默认的动态库搜索路径/usr/lib ,/usr/lib64(64位系统)。
  静态库的搜索路径:
  • ld会去找GCC命令行中的参数-L的目录中是否有该静态库;
  • 再去找GCC的环境变量LIBRARY_PATH
  • 再找默认内定目录/lib /lib64、/usr/lib /usr/lib64、/usr/local/lib /usr/local/lib64是否有该链接库。

6、CMAKE编译链接库文件

   同一二进制(.out文件)在不同环境下执行的时候可能因为环境下具有的动态库不同而不能正常执行,可以用ldd(list, dynamic, dependencies的缩写, 意思是, 列出动态库依赖关系)命令看二进制依赖的动态库文件。使用方法:ldd加 二进制文件可执行文件。
   静态库和动态库共存时,cmake会默认先链接动态库,如果要强制使用静态库,在CMakeLists.txt中如此直接指明:

target_link_libraries(main ${CMAKE_SOURCE_DIR}/libbingitup.a)  #强制使用静态库
target_link_libraries(myProject comm)     # 连接libhello.so库,默认优先链接动态库
target_link_libraries(myProject libcomm.a)  # 显示指定链接静态库
target_link_libraries(myProject libcomm.so) # 显示指定链接动态库
target_link_libraries(myProject libcomm.so)  #这些库名写法都可以。
target_link_libraries(myProject -lcomm) # 连接libhello.so库,默认优先链接动态库

   CMAKE/gcc中库的链接顺序是从右往左进行,所以要把最基础实现的库放在最后,这样左边的lib就可以调用右边的lib中的代码。同时,当一个函数的实现代码在多个lib都存在时,最左边的lib代码最后link,所以也将最终保存下来。

   target_link_libraries里库文件的顺序符合gcc链接顺序的规则,即被依赖的库放在依赖它的库的后面,比如target_link_libraries(hello A B.a C.so)

   在上面的命令中,libA.so可能依赖于libB.a和libC.so,如果顺序有错,链接时会报错。还有一点,B.a会告诉CMake优先使用静态链接库libB.a,C.so会告诉CMake优先使用动态链接库libC.so,也可直接使用库文件的相对路径或绝对路径。使用绝对路径的好处在于,当依赖的库被更新时,make的时候也会重新链接。在链接命令中给出所依赖的库时,需要注意库之间的依赖顺序,依赖其它库的库一定要放到被依赖库的前面,这样才能真正避免undefined reference的错误。

   gcc默认只载入c/c++语言使用的标准库,如标准io库(如printf)和标准模板库(stl,g++),其它库必须用-l显示指定。g++: gcc 的一个版木,默认语言设置为C++,而且在连接的时候自动包含标准 C++ 库。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值