GCC 指令详解及动态库、静态库的使用( 五 )

  • 在程序编译的最后一个阶段也就是链接阶段 , 在 gcc 命令中虽然指定了库路径,但是这个路径并没有被记录到可执行程序中,只是检查了这个路径下的库文件是否存在 。同样对应的动态库文件也没有被打包到可执行程序中 , 只是在可执行程序中记录了库的名字 。
  • 当可执行程序被执行起来之后:
    • 程序会先检测所需的动态库是否可以被加载,加载不到就会提示上边的错误信息 。
    • 当动态库中的函数在程序中被调用了,这个时候动态库才加载到内存,如果不被调用就不加载 。
动态库的检测和内存加载操作都是由动态链接器来完成的
动态链接器是一个独立于应用程序的进程,属于操作系统 。当用户的程序需要加载动态库的时候动态连接器就开始工作了,很显然动态连接器根本就不知道用户通过 gcc 编译程序的时候通过参数 -L 指定的路径 。
那么动态链接器是如何搜索某一个动态库的呢,在它内部有一个默认的搜索顺序 , 按照优先级从高到低的顺序分别是:
  1. 可执行文件内部的 DT_RPATH 段 。
  2. 系统的环境变量 LD_LIBRARY_PATH 。
  3. 系统动态库的缓存文件 /etc/ld.so.cache 。
  4. 存储「静态库 / 动态库」的系统目录 /lib、/usr/lib 等 。
按照以上四个顺序,依次搜索,找到之后结束遍历 。若检索到最终还是没找到,那么动态连接器就会提示动态库找不到的错误信息 。一般情况下,我们都是通过修改系统的环境变量的方式设置动态库的地址 。
将动态库路径追加到环境变量 LD_LIBRARY_PATH 中:$ LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:动态库的绝对路径
比如,我所需要的动态库的绝对路径为 /mnt/hgfs/SharedFolders/DynamicLibrary , 那么:
$ LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/mnt/hgfs/SharedFolders/DynamicLibrary
这样的话,我在运行 main,就不会报错了 。
但是通过这种方式设置的环境变量尽在当前的终端中有效,那么怎样才能让这个设置永久生效呢?
通过指令$ vim ~/.bashrc打开并修改该文件:
GCC 指令详解及动态库、静态库的使用

文章插图
修改后,使用$ source ~/.bashrc使修改立即生效 。
经过上述操作 , 就不用每次开启终端都需要修改环境变量了 。当然这种永久生效的方式仅适用于动态库路径唯一的情况 , 如果你每次使用的动态库都在不同的位置,那么这么设置也没啥用
2.4 动态库与静态库的比较2.4.1 静态库的特点
  1. 静态库对函数库的链接是在编译期完成的 。
  2. 静态库在程序编译时会链接到目标代码中,因此使可执行文件变大 。
  3. 当链接好静态库后,在程序运行时就不需要静态库了 。
  4. 对程序的更新、部署与发布不方便,需要全量更新 。
  5. 如果某一个静态库更新了,所有使用它的应用程序都需要重新编译、发布给用户 。
2.4.2 动态库的特点
  1. 动态库把对一些库函数的链接载入推迟到程序运行时期 。
  2. 可以实现进程之间的资源共享,因此动态库也称为共享库 。
  3. 将一些程序升级变得简单,不需要重新编译,属于增量更新 。
2.5 使用库的目的在项目中使用库一般有两个目的:
  1. 为了使程序更加简洁不需要在项目中维护太多的源文件 。
  2. 另一方面是为了源代码保密,毕竟不是所有人都想把自己编写的程序开源出来 。
当我们拿到了库文件(动态库、静态库)之后要想使用还必须有这些库中提供的 API 函数的声明 , 也就是头文件 , 把这些都添加到项目中,就可以快乐的写代码了 。
参考资料
  • GCC | 爱编程的大丙 (subingwen.cn)
  • GCC编译的四个阶段
  • Linux 静态库和动态库 | 爱编程的大丙 (subingwen.cn)
  • linux命令之ar—创建静态库.a文件
  • 静态库和动态库 - 简书 (jianshu.com)
  • linux中 ldd命令简介
  • collect2: error: ld returned 1 exit status(解决方案大总结)

推荐阅读