
2021-01-04
发布日期:2021-05-18 04:38:03
浏览次数:18
分类:精选文章
本文共 2625 字,大约阅读时间需要 8 分钟。
动态库的制作与使用指南
一、动态库的制作步骤
要制作动态库,通常需要遵循以下步骤:
编译源文件生成目标文件
使用gcc编译所有需要打包的源文件,生成与位置无关的.o文件:gcc -c -fPIC t*.c
这里的t*.c
表示将所有以t
开头的C源文件编译为目标文件。生成的目标文件与依赖的位置无关。
打包目标文件生成动态库
将上述生成的目标文件打包成为动态库:gcc -shared -o libt_math.so *.o
这里的*-shared
参数表示生成共享库,*.o
表示将所有的目标文件打包到动态库中。
链接可执行文件
使用动态连接器将动态库链接到可执行文件中:gcc main.c -L. -lt_math
由于使用的是静态连接器,连接器会尝试加载动态库文件。如果找不到动态库,会抛出类似libt_math.so cant open
的错误提示。
二、常见错误处理
在实际操作中,可能会遇到如下的问题:
执行可执行文件时提示libt_math.so cant open
。
ldd a.out
查看依赖关系,可以了解具体哪个动态库无法加载。$ ldd a.out
通过查看依赖关系可以看到:
ldd a.outldd: dynamic /lib/t_math.so: no such file or directory
这表明/lib/t_math.so
、/usr/lib/t_math.so
等常用路径中都不存在动态库文件。
三、常见问题解决方法
要解决上述问题,可以采取以下措施:
手动指定动态库的路径
在运行可执行文件时,通过设置LD_LIBRARY_PATH
环境变量,手动告知动态连接器动态库的位置:export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/lib
适用于临时需要查找动态库的场景。
检查默认搜索路径
动态连接器通常会查找以下路径中的动态库:/lib/usr/lib
你可以手动检查这些路径下是否存在动态库文件。
四、静态库与动态库的区别
1. 关键特性对比
静态库
- 通常被编译到可执行文件中,生成的可执行文件不再依赖静态库。
- 依赖静态库的可执行文件虽然体积较大,但无需额外的动态库支持。
动态库
- 被编译到可执行文件中,生成的可执行文件在运行时依赖动态库。
- 动态连接器会在运行时根据需要加载所需的动态库,减少可执行文件的体积。
2. 管理与使用特点
静态库
- 使用静态库的可执行文件在运行时无需外部动态库支持。
- 但一旦需要修改字月代码,则需要重新编译整个可执行文件。
动态库
- 使用动态库的可执行文件需要动态连接器的支持。
- 动态连接器负责在运行时动态地加载相关动态库文件,保持内核态与用户态的透明度。
五、动态加载的原理与接口
动态加载的核心是通过动态连接器实现的。常见的动态加载接口包括dlopen
、dlclose
、dlsym
等。
#include
1. 动态连接器的功能
dlopen
- 用于打开动态库文件。
- 参数:
filename
(动态库路径) |flags
(lazzy或eager绑定)。 - 返回:成功则为非空指针,失败则为NULL。
dlclose
- 用于关闭已经打开的动态库。
- 返回:若成功则非零,若引用计数减到0则卸载动态库。
dlerror
- 用于获取动态连接器失败的错误信息。
dlsym
- 用于获取特定符号在动态库中的地址。
2. 实际应用示例
#include#include typedef int (*sub_func)(int a, int b);int main(int argc, char *argv) { void *handle = dlopen(argv[1], RTLD_NOW); if (NULL == handle) { printf("dlopen error: %s\n", dlerror()); return -1; } sub_func sub = (sub_func)dlsym(handle, "sub"); if (NULL == sub) { printf("dlsym error: %s\n", dlerror()); return -1; } printf("sub(3-2) = %d\n", sub(3, 2)); dlclose(handle); return 0;}
3. 常用库文件
执行ldd dynamic
时,可以看到常用的动态库文件:
ldd: dynamic /lib/dl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f9debc40000)ldd: dynamic /libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9def0c0000)ldd: dynamic /lib64/ld-linux-x86-64.so.2 => /lib/x86_64-linux-gnu/lib64/ld-linux-x86-64.so.2 (0x00007f9de9b40000)ldd: dynamic /t_math.so => /usr/local/lib/t_math.so (0x00007f9de9d70000)
从依赖关系可知,dynamic
本身依赖于多个动态库,其中/usr/local/lib/t_math.so
是我们的自定义动态库。
4. 动态加载的实现细节
从库文件的符号信息来看:
nm dynamic:...dlsym@GLIBC_2.2.5dlclose@GLIBC_2.2.5dlopen@GLIBC_2.2.5dlerror@GLIBC_2.2.5...
这些符号表明dynamic
程序依赖于动态连接器的核心接口。但是,你会注意到动态库t_math.so
中的符号并没有在这个输出中。
六、总结
动态库能够提供更高的灵活性和可扩展性,但也伴随着一定的使用成本。合理使用动态连接器的接口,能够更好地管理程序的依赖关系。这也是动态加载机制的核心优势所在。
发表评论
最新留言
网站不错 人气很旺了 加油
[***.192.178.218]2025年04月21日 18时39分14秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
Explore Optimization
2019-03-07
解决数据库报ORA-02289:序列不存在错误
2019-03-07
map[]和map.at()取值之间的区别
2019-03-08
【SQLI-Lab】靶场搭建
2019-03-08
【Bootstrap5】精细学习记录
2019-03-08
Struts2-从值栈获取list集合数据(三种方式)
2019-03-08
参考图像
2019-03-09
设计模式(18)——中介者模式
2019-03-09
推荐几篇近期必看的视觉综述,含GAN、Transformer、人脸超分辨、遥感等
2019-03-09
【专题3:电子工程师 之 上位机】 之 【46.QT音频接口】
2019-03-09
一文理解设计模式--命令模式(Command)
2019-03-09
VTK:可视化之RandomProbe
2019-03-09
block多队列分析 - 2. block多队列的初始化
2019-03-09
Java时间
2019-03-09
不编译只打包system或者vendor image命令
2019-03-09
【编程】C语言入门:1到 100 的所有整数中出现多少个数字9
2019-03-09
flink启动(二)
2019-03-09