1.动态库的命名规则
- Linux:libxxx.so
lib:前缀(固定的)
xxx:库的名字(自定义的)
so:后缀(固定的)
在Linux下是一个可执行文件
- Windows:libxxx.dll
2.准备工作
这里用的代码和静态库的制作用的代码是一个,只不过被我分在两个文件夹下了:
3.制作动态库
(1)得到.o文件,得到和位置无关的文件
命令格式:
gcc -c -fpic/-FPIC xxx.c xxx.c xxx.c
解释:
-c —— 编译、汇编指定的源文件,但不进行链接
-fpic/-FPIC —— 生成与位置无关的代码
xxx.c —— 源代码文件
我们先进入带test_code文件夹下,得到.o文件,打开终端,输入以下命令:
gcc -c -fpic add.c div.c mult.c sub.c
执行完该指令后,会生成相应的.o文件,可以用tree命令查看一下:
(2)gcc得到动态库
命令格式:
gcc -shared xxx.o xxx.o -o libxxx.so 或 gcc -shared *.o -o libxxx.so
解释:
-shared —— 生成共享目标文件
xxx.o —— gcc得到的对应的.o文件
-o —— 将文件编译成可执行文件
libxxx.so —— Linux环境下动态库的命名
*.o —— 代表所以.o文件
然后我在test/test_code目录下执行终端命令:
gcc -shared *.o -o libcalc.so
执行完后会生成一个libcalc.so的动态库文件,可以tree查看一下:
4.使用动态库
(1)将动态库复制到test/test_dynamic/lib目录下
(2)编译main.c
gcc main.c -o main -I include/ -L lib/ -l calc
执行该命令后,会生成一个main可执行文件:
(3)执行main文件(会报错)
这时候会发现报错了:
意思就是说加载动态库libcalc.so失败,虽然我们编译main.c的时候指定了动态库的路径和名称,但是生成的可执行文件在运行时找不到动态库文件。
(4)分析报错原因
- 静态库:gcc进行链接时,会把静态库中代码打包带可执行程序中
- 动态库:gcc进行链接时,动态库的代码不会被打包到可执行程序中
- 程序启动之后,动态库会被加载到内存中,可通过ldd(list dynamic dependencies)命令查看动态库依赖关系
- 当系统加载可执行文件时,能够知道其所依赖的库的名字,但是还需要知道绝对路径。此时就需要系统的动态载入器来获取该绝对路径。对于elf格式的可执行程序,是由ld-linux.so来完成的,它先后搜索elf文件的DT-RPATH段——>环境变量LD_LIBRARY_PATH——>/etc/ld.so.cache文件列表——>/lib/ 或 /user/lib目录找到库文件后将其载入内存
通过ldd命令查看动态库依赖关系之后会发现,我们制作的libcalc.so这个动态库文件找不到!我们知道了是因为找不到动态库libcalc.so之后呀,把这个动态库的绝对路径加上不就好了。
5.解决使用动态库时的报错
5.1 法一:给LD_LIBRARY_PATH添加环境变量
(1)查看一下动态库libcalc.so的路径,并复制。使用pwd命令得到路径
(2)开始配置环境变量
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/lhn/test/test_dynamic/lib
这个命令的意思就是配置LD_LIBRARY_PATH环境变量,$LD_LIBRARY_PATH是获取LD_LIBRARY_PATH环境变量之前的一些环境变量,然后用 : 隔开,开始添加新的环境变量路径。
运行这行命令没有报错,则环境变量就配置成功了!
(3)查看环境变量
- 可以直接输入env命令查看环境变量:
这些都是系统环境变量,然后画红框的就是我们刚刚添加的环境变量,这样太多了也不好找可以用下面的方法。
- 只查看LD_LIBRARY_PATH的环境变量
命令:
echo $LD_LIBRARY_PATH
可以看到只显示了LD_LIBRARY_PATH的环境变量,前面没有东西,就代表LD_LIBRARY_PATH之前没有环境变量,我们后来加了一个。
然后我们载查看一下main的动态库依赖关系:
可以看到,我们制作的动态库libcalc.so已经被找到了!
(4)执行main
可以看到,程序执行正确,输出结果!
注意:这是在终端里面配置的环境变量,是一个临时的,如果说我们断开连接,重新打开一个终端运行main可执行文件时,会发现又报错了,之前配置的环境变量没了。临时的还是可以用的😉
5.2 法二:用户级别的配置
(1)进入家目录下,输入ll命令:
可以看到有一个隐藏文件.bashrc,其实我们配置这个文件就可以了,直接编辑她:
- vi .bashrc打开这个文件
- 然后shift+g跳转到最后一行
- 输入o(往下插一行)
- 将配置信息输入
- 保存并退出
(2)使刚刚的修改生效
. .bashrc
或
source .bashrc
这两个命令都可以,执行完不报错就可以:
(3)查看一下main的动态依赖库关系
说明libcalc.so的环境变量已经配好了!
(4)执行程序
5.3 法三:系统级别的配置
(1)配置/etc/profile
sudo vi /etc/profile
同样的操作,直接shift+g(跳转到最后一行),输入o(在下反插入一行),输入配置信息
然后保存并退出!
(2)使刚刚的修改生效
source /etc/profile
或
. /etc/profile
两个命令都可以!
(3)查看main可执行文件的动态库依赖关系
OK!显示配置成功!
(4)执行程序
OK!结束了!动态库的使用比静态库复杂一点!
6.动态库的优缺点
6.1优点
- 可以实现进程间资源共享(共享库)
- 更新、部署、发布简单
- 可以控制何时加载动态库
6.2缺点
- 加载速度比静态库慢
- 发布程序时需要提供依赖的动态库