库:可执行的二进制代码,不可以独立执行(没有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

最新文章

  1. Linux C编程学习6---字符串处理、数据转换
  2. 这些HTML、CSS知识点,面试和平时开发都需要 No10-No11
  3. Myeclipse 找不到Convert to maven project选项
  4. Ibatis 测试出SQL
  5. archlinux 网络配置
  6. Object Pascal 面向对象的特性
  7. iOS开发——动画OC篇&amp;知识点总结
  8. PHP读取xml方法讲解
  9. QT5删除隐藏目录+隐藏文件(使用Process::start函数调用系统命令,且等待到结束)
  10. 捕获异常 winform
  11. 341. Flatten Nested List Iterator
  12. 【有源汇上下界最大流】ZOJ 3229 Shoot the Bullet
  13. Java实现SOAP协议 之 HelloWorld
  14. Linux 常用命令学习
  15. [Swift]LeetCode781. 森林中的兔子 | Rabbits in Forest
  16. CentOS 7系统初始化
  17. MYSQL: set names utf8是什么意思?
  18. 【面试题】新东方.NET工程师面试题总结
  19. UVa 11167 Monkeys in the Emei Mountain (最大流)
  20. java方法——重载2

热门文章

  1. Module理解及使用
  2. ctf命令执行刷题
  3. 斐讯K2刷华硕固件教程
  4. .net 移动mas短信接口开发
  5. WPF HandyOrg DataGrid 表格内容和标题居中显示
  6. 【Java-01-2】java基础-基本语法(2)(关系运算,if,循环)
  7. Java学习笔记(一)环境安装与java基础
  8. 【研究生学习】SNR、Eb/N0和Es/N0的关系
  9. Kubernetes v1.22 编译 kubeadm 修改证书有效期到 100 年
  10. OOP学习讲义