- 在程序编译的最后一个阶段也就是链接阶段 , 在 gcc 命令中虽然指定了库路径,但是这个路径并没有被记录到可执行程序中,只是检查了这个路径下的库文件是否存在 。同样对应的动态库文件也没有被打包到可执行程序中 , 只是在可执行程序中记录了库的名字 。
- 当可执行程序被执行起来之后:
- 程序会先检测所需的动态库是否可以被加载,加载不到就会提示上边的错误信息 。
- 当动态库中的函数在程序中被调用了,这个时候动态库才加载到内存,如果不被调用就不加载 。
动态库的检测和内存加载操作都是由动态链接器来完成的动态链接器是一个独立于应用程序的进程,属于操作系统 。当用户的程序需要加载动态库的时候动态连接器就开始工作了,很显然动态连接器根本就不知道用户通过 gcc 编译程序的时候通过参数 -L 指定的路径 。
那么动态链接器是如何搜索某一个动态库的呢,在它内部有一个默认的搜索顺序 , 按照优先级从高到低的顺序分别是:
- 可执行文件内部的 DT_RPATH 段 。
- 系统的环境变量 LD_LIBRARY_PATH 。
- 系统动态库的缓存文件 /etc/ld.so.cache 。
- 存储「静态库 / 动态库」的系统目录 /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
打开并修改该文件:文章插图
修改后,使用
$ source ~/.bashrc
使修改立即生效 。经过上述操作 , 就不用每次开启终端都需要修改环境变量了 。当然这种永久生效的方式仅适用于动态库路径唯一的情况 , 如果你每次使用的动态库都在不同的位置,那么这么设置也没啥用2.4 动态库与静态库的比较2.4.1 静态库的特点
- 静态库对函数库的链接是在编译期完成的 。
- 静态库在程序编译时会链接到目标代码中,因此使可执行文件变大 。
- 当链接好静态库后,在程序运行时就不需要静态库了 。
- 对程序的更新、部署与发布不方便,需要全量更新 。
- 如果某一个静态库更新了,所有使用它的应用程序都需要重新编译、发布给用户 。
- 动态库把对一些库函数的链接载入推迟到程序运行时期 。
- 可以实现进程之间的资源共享,因此动态库也称为共享库 。
- 将一些程序升级变得简单,不需要重新编译,属于增量更新 。
- 为了使程序更加简洁不需要在项目中维护太多的源文件 。
- 另一方面是为了源代码保密,毕竟不是所有人都想把自己编写的程序开源出来 。
参考资料
- GCC | 爱编程的大丙 (subingwen.cn)
- GCC编译的四个阶段
- Linux 静态库和动态库 | 爱编程的大丙 (subingwen.cn)
- linux命令之ar—创建静态库.a文件
- 静态库和动态库 - 简书 (jianshu.com)
- linux中 ldd命令简介
- collect2: error: ld returned 1 exit status(解决方案大总结)
推荐阅读
- java中GC的日志认识详解
- 我的世界指令附魔攻略(我的世界附魔1000级的指令)
- JUC中的AQS底层详细超详解
- 图文详解 微服务 Zipkin 链路追踪原理
- 唐人街探案3剧情详解_唐人街探案3讲了什么剧情
- C++之值传递&指针传递&引用传递详解
- 非常全面 Dubbo 原理和机制详解
- 未知暗殿走法路线详解(未知暗殿怎么走视频)
- JWT基础概念详解
- Go | 基本数据类型详解