引文
库文件是计算机上的一类文件,可以理解为一种代码仓库,提供给使用者一些可以直接使用的变量、函数或类。
库文件分为两类:
- 静态库:在链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中。因此对应的链接方式称为静态链接。
- 动态库:动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入。不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例,规避了空间浪费问题。
1. 静态库
1.1 静态库的制作
- 命名规则:
- Linux:libxxx.a
- lib: 前缀,固定
- xxx:库的名称,自起
- .a: 后缀,固定
- Windows:libxxx.lib
- 静态的制作
- gcc 获得 .o 文件
- 将 .o 文件打包,使用 ar(archive) 工具
命令:ar rcs libxxx.a xxx.o xxx.o
eg: arc rcs libsuanshu.a sub.o add.o mult.o div.o
1.2 静态库的使用
ydh@ubuntu:~/static_lib$ gcc main.c -o dest -I include/ -l calc -L lib/
解释如下:
-I include/:生成目标文件所需头文件路径
-l calc:调用的库的名称
-L lib/:调用的库的路径
注:调用静态库依旧需要附带头文件,比如上述例子中的静态库calc包含了add.o、sub.o、mult.o、div.o的函数体,但是我们依旧需要头文件 head.h 来告诉我们有哪些函数。
head.h 的内容如下:
#ifndef _HEAD_H
#define _HEAD_H
// 加法
int add(int a, int b);
// 减法
int subtract(int a, int b);
// 乘法
int multiply(int a, int b);
// 除法
double divide(int a, int b);
#endif
2. 动态库
2.1 动态库的制作
- 命名规则
- Linux:libxxx.so
- lib:前缀,固定
- xxx:库的名称,自定
- .so :后缀,固定
- Windows:libxxx.dll
- 动态库的制作
- gcc 得到和位置无关的代码
gcc -c -fpic/-fPIC a.c b.c
- gcc 得到动态库
gcc -shared a.o b.o -o libcalc.so
2.2 动态库的使用
报错原因:动态库是程序运行期间动态加载到程序中的,当找不到依赖的文件时报错
此时,可以通过 ldd(list dynamic dependencies)命令查看动态库依赖关系
2.3 动态库加载失败的解决方法
既然上述问题是因为无法找到动态(共享)库的位置,那我们如何定位动态库呢?
当系统加载可执行代码时,能够知道其所依赖的库的名字,但是还需要知道绝对路径。此时就需要系统的动态载入器来获取该绝对路径。对于elf格式的可执行程序,是由ld-linux.so来完成的,它先后搜索elf文件的DT_RPATH段–>环境变量LD_LIBRARY_PATH–>/etc/ld.so.cache文件列表–>/lib/,/usr/lib目录找到库文件后将其载入内存。
- 方式一:直接在终端进行配置。这种配置方式只在当前终端有效。
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:动态库路径
注:$ 为取值,:为拼接,上述命令表示将原来的动态库路径加上新的动态库路径
- 方式二:用户级别的,修改 .bashrc 文件,并重启该文件配置
vim .bashrc // 在文件的最后一行加上方式一的配置语句并退出(ESC + :wq)
. .bashrc // 第一个点相当于source,即source bashrc
- 方式三:系统级别,修改 /etc/profile 文件,并重启该文件配置
vim /etc/profile // 在文件的最后一行加上方式一的配置语句并退出(ESC + :wq)
. /etc/profile // 第一个点相当于source,即source /etc/profile
3. 静态库与动态库的区别
- 静态库优缺点
- 优点
- 静态库被打包到应用程序中加载速度快
- 发布程序无需提供静态库,移植方便
- 缺点
- 消耗系统资源、浪费内存
- 更新、部署、发布麻烦
- 动态库优缺点
- 优点
- 可以实现进程间资源共享
- 更新、部署、发布简单
- 可以控制何时加载动态库
- 缺点
- 加载速度比静态库慢
- 发布时需要提供依赖的动态库
说明: 参考视频https://www.nowcoder.com/study/live/504