Linux高并发服务器开发项目| part-1.Linux系统编程入门(1.6 动态库的制作和使用 /1.7 动态库加载失败的原因 /1.8 解决动态库加载失败问题/ 1.9 静态库和动态库的对比)
1.6 动态库的制作和使用
【步骤】
◼ 命名规则:
◆ Linux :== libxxx.so==
lib : 前缀(固定)
xxx : 库的名字,自己起
.so : 后缀(固定)
在Linux下是一个可执行文件
◆ Windows : libxxx.dll
◼ 动态库的制作:
◆ gcc 得到 .o 文件,得到和位置无关的代码
gcc -c –fpic/-fPIC a.c b.c
◆ gcc 得到动态库
gcc -shared a.o b.o -o libcalc.so
【补充】
(1)生成的动态库文件是可执行文件。
(2)-fpic 用于编译阶段,产生的代码没有绝对地址,全部用相对地址,这正好满足了共享库的要求,共享库被加载时地址不是固定的。如果不加-fpic ,那么生成的代码就会与位置有关,当进程使用该.so文件时都需要重定位,且会产生成该文件的副本,每个副本都不同,不同点取决于该文件代码段与数据段所映射内存的位置。
1.7 动态库加载失败的原因
【工作原理】
◼ 静态库:GCC 进行链接时,会把静态库中代码打包到可执行程序中。因此静态库不需要查找路径,只要运行程序就将静态库中的代码加载到内存中了。
◼ 动态库:GCC 进行链接时,动态库的代码不会被打包到可执行程序中。因此需要查找动态库的路径,然后将动态库文件加载到可内存中。
◼ 程序启动之后,动态库会被动态加载到内存中,通过 ==ldd (list dynamic dependencies)==命令检查动态库依赖关系。当用到动态库中的API时,就需要去查找动态库的绝对路径,将动态库加载到内存中,才能使用该API。
◼ 如何定位共享库文件呢?
当系统加载可执行代码时候,能够知道其所依赖的库的名字,但是还需要知道绝对路
径。此时就需要系统的动态载入器来获取该绝对路径。对于elf格式的可执行程序,是
由ld-linux.so来完成的,它先后搜索elf文件的 DT_RPATH段 ——> 环境变量LD_LIBRARY_PATH ——> /etc/ld.so.cache文件列表 ——> /lib/,/usr/lib
目录找到库文件后将其载入内存。都找不到就会出现动态库查找不到的错误。
1.8 解决动态库加载失败问题
【解决方法1:修改环境变量LD_LIBRARY_PATH】
◼ elf文件的 DT_RPATH段改变不了,先从环境变量LD_LIBRARY_PATH开始修改。
方式一:在终端配置环境变量
(1)输入指令export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/nowcoder/Linux/lesson06/library/lib
◼ export :添加环境变量
◼ LD_LIBRARY_PATH:要添加的环境变量名称
◼ $LD_LIBRARY_PATH:获取原先的环境变量的值
◼ /home/nowcoder/Linux/lesson06/library/lib:环境变量的绝对路径
(2)echo $LD_LIBRARY_PATH
◼ echo $LD_LIBRARY_PATH:查看环境变量的路径
(3)ldd 动态库名
◼ ldd 动态库名:再次查看动态依赖项就可以看到,动态库所对应的绝对路径
方式二:用户级别配置环境变量
(1)进入用户根目录,找到.bashrc文件.
(2)编辑.bashrc文件,在最后换行,并输入export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/nowcoder/Linux/lesson06/library/lib
(3)使路径生效:. .bashrc 或 source .bashrc(. 就是source)
方式三:系统级别配置环境变量
(1)编辑系统文件/etc/profile
sudo vim /etc/profile
(2)在最后一行添加export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/nowcoder/Linux/lesson06/library/lib
(3)使路径生效:source /etc/profile
(4)查看环境变量的路径:echo $LD_LIBRARY_PATH
【小结】
(1)当使用方式一:终端配置环境变量时,关闭配置的终端,重新打开新的终端,之前配置的环境变量就失效了,因为该环境变量只是临时的。再次执行动态库配置的可执行文件还是会出现找不到动态库绝对路径的错误。
【解决方法2:/etc/ld.so.cache文件列表】
步骤:
(1)因为没有对/etc/ld.so.cache的修改权限,所以只能间接修改/etc/ld.so.cache文件
(2)通过修改/etc/ld.so.conf,从而间接修改/etc/ld.so.cache
(3)编辑/etc/ld.so.conf:sudo vim /etc/ld.so.conf
(4)在最后一行输入/home/nowcoder/Linux/lesson06/library/lib
(5)更新 /etc/ld.so.conf文件:sudo ldconfig
【解决方法3:修改/lib/或/user/lib/文件】
步骤:
(1)只需要将动态库文件放到/lib/或/user/lib文件下就可以了
【总结】
(1)不推荐解决方法3,因为系统中的动态库都放在/lib/或/user/lib/中,如果将动态库文件放到上述两文件中可能会覆盖同名的系统自带的动态库文件,系统可能会出现问题。
1.9 静态库和动态库的对比
【两者差异】
(1)创建方式不同
(2)链接时,静态库保存到目标文件中,动态库不保存到目标文件中。
【两者优缺点】
(1)静态库的优缺点
◼ 优点:
◆ 静态库被打包到应用程序中加载速度快
◆ 发布程序无需提供静态库,移植方便
◼ 缺点:
◆ 消耗系统资源,浪费内存
◆ 更新、部署、发布麻烦
(2)动态库的优缺点
◼ 优点:
◆ 可以实现进程间资源共享(共享库)
◆ 更新、部署、发布简单
◆ 可以控制何时加载动态库
◼ 缺点:
◆ 加载速度比静态库慢
◆ 发布程序时需要提供依赖的动态库
【使用时机】
◼ 库比较小 ——> 静态库
◼ 库比较大 ——> 动态库