第二部分 静态库和动态库
在C语言中,函数库文件分为两种类型,一种是静态库(库程序是直接注入目标程序的,不分彼此,库文件通常以.a结尾),另一种是动态库(库程序是在运行目标程序时(中)加载的,库文件通常以.so结尾)
2.1静态库
静态库,是因为在链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中。因此对应的链接方式称为静态链接。
静态库可以简单看成是一组目标文件(.o文件)的集合,即很多目标文件经过压缩打包后形成的一个文件。
- 在linux中静态库以lib 作为前缀,以**.a**作为后缀,中间库的名字自己指定,如
libxxx.a
2.1.1静态库的生成
-
先对源文件进行汇编操作(-c参数),得到二进制格式的目标文件(.o格式)
-
使用 ar 工具将目标文件打包得到静态库文件(libxxx.a)
使用ar工具的时实用的三个参数
c
:创建一个库s
创建目标文件索引,可以加快时间r
: 在库职工插入(替换)模块,默认的新成员添加在库的结尾出,若模块名已经在库中存在,则替换同名的模块
演示如下
关于编译时的一些参数可以参考 1. GCC编译器的使用 g++生成可执行文件 编译参数的解析
文件目录:
- 生成 .o 文件
g++ -c *.cpp
-I
指定头文件路径
- 打包.o文件,得到静态库
ar rcs 静态库名称(libxxx.a) 材料(*.o)
- 静态库的发布使用
提供得到的
libxxx.a
文件和头文件
2.1.2 静态库的使用
-L
指定库的路径
-l
指定库的名称(即libxxx.a
中 xxx
部分)
得到可执行文件main
2.2 动态库
动态库是程序在运行的时候才去链接相应的动态库代码的,多个程序共享使用库的代码。一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码。
在可执行文件开始运行前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程称为动态链接。
2.2.1动态库的生成
使用g++或gcc命令,添加 -fpic
以及 -shared
参数
-fpic
: 使得生成的代码与位置无关,即使用的是相对位置
-shared
: 生成动态链接库
示例1:
# 分成两步
# 得到.o文件
g++ -c -fpic add.cpp sub.cpp -I ./Include/
# 将得到的.o文件打包成动态库
g++ --shared add.o sub.o -o libcal.so
示例2:
# 一步 生成 动态库 libcal.so
g++ add.cpp sub.cpp -I ./Include/ -fpic -shared -o libcal.so
2.2.2 动态库的使用
g++ main.cpp -I ./Include/ -L./ -lcal -o main
2.2.3 动态库无法加载
动态库的路径并未被记录到可执行程序中,对应的动态库文件也没有被打包到可执行程序中,只是在可执行程序中记录了库的名字。
当可执行程序执行时,会先检测需要的动态库是否可以被加载到,加载不到则会提示上述错误。
动态库的检测和内存的加载都是由动态链接器
来实现的,的那个动态库中的函数被调用了,这个时候动态库才会加载到内存。
我们可以使用ldd 程序名
来检测动态库是否都能被检测到,如下图所示,可知,无法找到 libcal.so
库。
2.2.4动态链接器
动态链接器按照位置搜索顺序依次查找动态库,查找位置的优先级如下:
- 可执行文件的内部的
DT_RPATH
- 系统的环境变量
LD_LIBRARY_PATH
- 系统的动态库的缓存文件
/etc/ld.so.cache
- 存储动态库/静态库的系统目录
/lib/
,/usr/lib
等
按照上述顺序查找需要的动态库,若找不到则会提示上述错误。
-
第一种解决方案 -程序运行时指定动态库的搜索路径
# 指定搜索路径为 /Desktop/C++\ Code/temp/ LD_LIBRARY_PATH=~/Desktop/C++\ Code/temp/ ./main
-
第二种解决方案 - 将库路径添加到环境变量
- 用户级别:
.bashrc
只对当前用户有效 - 系统级别:
/etc/profile
对所有用户生效
示例:
# 在 ~/.bashrc中添加 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:'/home/dbb/Desktop/C++ Code/temp'
- 用户级别:
然后使之生效,可以通过重新打开终端,或者使用 . ~/.bashrc
或 source ~/.bashrc
来更新环境变量,使之生效。
系统级别的设置与上述例子类似,需要使用管理员权限操作sudo
,可自行尝试。
- 第三种解决方案 - 更新
/etc/ld.so.cache
文件
-
将动态库的绝对路径添加(不包含库的名字)到
/etc/ld.so.conf
文件中# 用vim打开文件 sudo vim /etc/ld.so.cache # 添加路径后退出
-
更新
etc/ld.so.conf
中数据到/etc/ld.so.cache
sudo ldconfig
-
第四种解决方案 - 拷贝动态库文件到库目录或者 创建软链接
# 拷贝到 /lib 或者 /usr/lib 中 sudo cp ./libxxx.so /usr/lib # 创建软链接(推荐) sudo ln -s ./libxxx.so /usr/lib/libxxx.so