linux 动态库、静态库
库:可执行的二进制代码,不可以独立执行(没有main函数入口)
库是否兼容:取决于编译器、汇编器、链接器
linux链接静态库(.a):将库中用到的函数的代码指令,写入到可执行文件中、运行时无依赖
linux链接动态库(共享库.so):在可执行程序中记录了库中函数的符号表信息,执行时再找库,找不到,则无法执行。
程序默认使用动态库
1、静态库
静态库命名:libxxx.a,在编译的第4步使用,链接阶段
1.1制作静态库:
(1)gcc -c xxx.c -o xxx.o //.c文件制作成.o文件 gcc -c 只编译,不链接,生成目标文件
(2)ar -rcs libxxxx.a xxx.o aaaa.o //使用ar工具制作静态库。ar是linux压缩备份命令,可以将多个文件打包成一个备份文件
(3)编译链接库 gcc test.c -o a.out libxxxx.a
(4)ar -t 查看libxxxx.a是由哪些.o文件构成。
ar -t 显示静态库的内容 ar -d 从库中删除成员文件 ar -r 在库中加入成员文件,若存在,则替换 ar -c 创建一个库 ar -s 无论ar命令是否修改了库内容,都强制重新生成库符号表
1.2 静态库示例
main.c 源码

[root@localhost test_lib]# cat main.c #include <stdio.h> int main() { int a = 2,b = 3,c = 0; printf("c = %d\n", test_lib_a(a,b)); printf("c = %d\n", test_lib_b(a,b)); printf("c = %d\n", test_lib_c(a,b)); return 0; }
test_lib_a.c、test_lib_b.c、test_lib_c.c源码

[root@localhost test_lib]# cat test_lib_a.c #include <stdio.h> int test_lib_a(int a, int b) { printf("%s\n", __FUNCTION__); return a + b; } [root@localhost test_lib]# [root@localhost test_lib]# cat test_lib_b.c #include <stdio.h> int test_lib_b(int a, int b) { printf("%s\n", __FUNCTION__); return a + b; } [root@localhost test_lib]# cat test_lib_c.c #include <stdio.h> int test_lib_c(int a, int b) { printf("%s\n", __FUNCTION__); return a + b; } [root@localhost test_lib]# cat test_lib_a.c #include <stdio.h> int test_lib_a(int a, int b) { printf("%s\n", __FUNCTION__); return a + b; } [root@localhost test_lib]# [root@localhost test_lib]# cat test_lib_b.c #include <stdio.h> int test_lib_b(int a, int b) { printf("%s\n", __FUNCTION__); return a + b; } [root@localhost test_lib]# cat test_lib_c.c #include <stdio.h> int test_lib_c(int a, int b) { printf("%s\n", __FUNCTION__); return a + b; }
编译.c 查看生成的.o文件
[root@localhost test_lib]# gcc -c *.c [root@localhost test_lib]# ls libtest_lib_all.a main.c main.o test_lib_a.c test_lib_a.o test_lib_b.c test_lib_b.o test_lib_c.c test_lib_c.o [root@localhost test_lib]# ar -rcs libtest_lib.a test_lib_a.o test_lib_b.o test_lib_c.o [root@localhost test_lib]# gcc main.o -o a.out libtest_lib.a [root@localhost test_lib]# ./a.out test_lib_a c = 5 test_lib_b c = 5 test_lib_c c = 5
这三种方式编译也ok

[root@localhost test_lib]# gcc test_lib_a.o test_lib_b.o test_lib_c.o main.o -o a.out //这种编译也ok [root@localhost test_lib]# [root@localhost test_lib]# gcc test_lib_a.o test_lib_b.o test_lib_c.o main.c -o a.out //这种编译也ok [root@localhost test_lib]# gcc main.c -o a.out libtest_lib.a
2、动态库
.so 库 (Shared Object ),共享的目标文件
查看文件(动态库)的依赖 : ldd xxxxx
2.1 制作动态库
[root@localhost test_lib]# gcc -shared -fPIC -c *.c //需要带-shared -fPIC编译,否则无法做成动态库 // gcc -shared -fPIC -o libxxxx.so bbbb.o cccc.o dddd.o [root@localhost test_lib]# gcc -shared -fPIC -o libtest_lib.so test_lib_d.o test_lib_b.o test_lib_c.o
2.2 动态库示例
test_lib_d.c 代码

[root@localhost test_lib]# cat test_lib_d.c #include <stdio.h> int test_lib_a(int a, int b) { printf("%s but this test_lib_c.c\n", __FUNCTION__); return a + b; }
编译 .o 编译 .so
[root@localhost test_lib]# gcc -shared -fPIC -c *.c //编译.o 文件 [root@localhost test_lib]# gcc -shared -fPIC -o libtest_lib.so test_lib_d.o test_lib_b.o test_lib_c.o //编译动态库 // 查看编译生成的动态库.so和.o文件 [root@localhost test_lib]# ls a.out lib_path libtest_lib.so main.c main.o test_lib_a.c test_lib_a.o test_lib_b.c test_lib_b.o test_lib_c.c test_lib_c.o
运行可执行文件
[root@localhost test_lib]# cp lib_path/libtest_lib.so /lib64/ //将库拷贝到动态库默认搜索路径/lib64下 [root@localhost test_lib]# ./a.out test_lib_a but this test_lib_c.c c = 5 test_lib_b c = 5 test_lib_c c = 5
3、链接库、链接头文件
-I(大写i):指定include包含文件的搜索路径.
-L :指定链接所需库所在路径
-l(小写L):指定所需链接库的库名(比如链接libastatic.a) -lastatic
-static: :静态链接,但会导致所有的库都使用静态连接
-Wl,-Bdynamic:指明为动态链接
-Wl,-Bstatic:指明为静态链接
-Wl,-rpath=:指定文件搜索库路径
混合链接时:动态库在静态库前面链接时,必须在命令行最后使用动态连接的命令。(系统的运行库使用动态链接方式,结尾不是动态链接,会导致后面链接系统的库,去找到的是静态库)
混合链接时:优先链接动态库
如下为证明优先链接动态库
//编译生成静态库、动态库 [root@localhost test_lib]# ar -rcs libtest_lib_b.a test_lib_b.o [root@localhost test_lib]# ar -rcs libtest_lib_c.a test_lib_c.o [root@localhost test_lib]# gcc -shared -fPIC -o libtest_lib_a.so test_lib_d.o // 动态库、静态库混合链接,且证明优先链接动态库 [root@localhost test_lib]# gcc main.c -o a.out -L lib_path/ -Wl,-Bdynamic -ltest_lib_a -Wl,-Bstatic -ltest_lib_b -ltest_lib_c -Wl,-Bdynamic [root@localhost test_lib]# [root@localhost test_lib]# ./a.out ./a.out: error while loading shared libraries: libtest_lib_a.so: cannot open shared object file: No such file or directory [root@localhost test_lib]# mv lib_path/libtest_lib_a.so /lib64/ [root@localhost test_lib]# [root@localhost test_lib]# ./a.out test_lib_a but this test_lib_c.c c = 5 test_lib_b c = 5 test_lib_c c = 5 //静态链接放在结尾,是有问题的 [root@localhost test_lib]# gcc main.c -o a.out -L lib_path/ -Wl,-Bdynamic -ltest_lib_a -Wl,-Bstatic -ltest_lib_b -lte st_lib_c /usr/bin/ld: cannot find -lgcc_s collect2: error: ld returned 1 exit status [root@localhost test_lib]# [root@localhost test_lib]# gcc main.c -o a.out -L lib_path/ -Wl,-Bstatic -ltest_lib_b -ltest_lib_c -Wl,-Bdynamic -lte st_lib_a
3.1、解决动态库链接问题
./a.out: error while loading shared libraries: libtest_lib.so: cannot open shared object file: No such file or directory
上面问题核心原因是,编译时候能链接到动态库,可执行文件执行时找链接不到库。
解决办法1:
1、拷贝库到默认链接路径下,即拷贝库到/lib、/lib64、/usr/lib下 |
2、编译时,指定库运行时库搜索路径。即加上前缀-Wl(小写L), -R(或-rpath)。-Wl,-rpath=./lib_path -L./lib_path |
3、环境变量LD_LIBRARY_PATH指定的动态库搜索路径。export LD_LIBRARY_PATH=./lib_path |
4、配置文件/etc/ld.so.conf中指定的动态库搜索路径 |
[root@localhost test_lib]# gcc main.c -o a.out -Wl,-rpath=./lib_path -L./lib_path -ltest_lib
3.2、库链接顺序
注意:库的链接顺序为从左到右,即A依赖B,则-lA -lB。越基础的库越放在右边
4、查看库的属性:
(1)ldd xxxx //查看xxx文件的依赖库
(2)已经启动的,查看进程号,cat /proc/PID/maps //可以查看到可执行文件已加载的库
(3)xxx-linux-objdump -x file-name | grepp NEEDED
(4)xxx-linux-readelf -a file-name | grep Shared
参考:
https://www.cnblogs.com/xingmuxin/p/11416518.html
https://zhuanlan.zhihu.com/p/349122842
https://blog.csdn.net/JoshYueby/article/details/105528682
https://blog.csdn.net/yueguangmuyu/article/details/117655920
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异