库
库是指在我们应用中,有一些公用的代码是需要反复的使用,就把这些代码编译为“库”文件;在链接步骤中,链接器将从库文件取得所需代码,复制到生成的可执行文件中。
Linux中常见的库文件有两种,一种.a为后缀,为静态库,一种以.so为后缀,为动态库
目标文件
在解释静态库和动态库之前 ,需要简单了解一下什么是目标文件。目标文件常常按照特定的格式来组织,在Linux下,他是ELF格式(可执行可链接格式)
而通常目标文件有三种形式
-
可执行目标文件(executable)。即我们通常所认识的,可以直接运行的二进制文件
-
可重定位目标文件(relocatable)。包含了二进制的代码和数据,可以与其他可重定位目标文件合并,并船舰一个可执行目标文件
-
共享目标文件(shared object)。它是一种在加载或运行时进行链接的特殊可重定位目标文件。
静态库
什么是静态库:
前面提到的可重定位目标文件以一种特定的方式打包成一个单独的文件,并且在链接生成可执行文件时,从这个单独的文件中“拷贝”它自己需要的内容到最终可执行文件中。这个单独的文件,称为静态库。Linux这类库的名字一般是libxxx.a(archive)。
静态库的制作
我们要将add.c sub.c 创建成静态库文件
add.c
int add(int a, int b) { return a+b; }
sub.cint subtract(int a, int b) { return a-b; }
执行命令
//先编译成可重定位目标文件
gcc -c add.c sub.c
//利用ar工具创建静态库
ar rcs libmath.a add.o sub.o
使用静态链接构建成我们的可执行文件
main.c
#include <stdio.h>
#include "head.h"
int main()
{
int a = 20;
int b = 12;
printf("a = %d, b = %d\n", a, b);
printf("a + b = %d\n", add(a, b));
printf("a - b = %d\n", subtract(a, b));
return 0;
}
head.h
#ifndef _HEAD_H
#define _HEAD_H
// 加法
int add(int a, int b);
// 减法
int subtract(int a, int b);
#endif
代码计算a,b的和差应打印结果,由于代码用到了add和sub函数,他们位于我们自己的库libmath.a中,因此编译的时候需要这样写:gcc main.c -o main -I ./include/ -L ./lib/ -l math。
-I ./include/指定头文件所在位置,-L ./lib/指定库路径,-l math。指定库名。
动态库
什么是动态库
动态库跟静态库类似,但是它并不在链接时将需要的二进制代码都“拷贝”到可执行文件中,而仅仅“拷贝”一些重定位和符号表信息,这些信息可以在程序运行时完成真正的链接过程。Linux中这类库的名字一般libxxx.so。(shared object)
动态库的创建步骤
我们以静态库使用的代码为例
//先编译成可重定位目标文件(生成与位置无关的代码 -fpic)
gcc -c -fpic add.c sub.c mult.c div.c
//使用gcc -shared制作动态库
gcc -shared *.o -o libcalc.so
我们可以通过ldd命令来观察可执行文件链接了哪些动态库
正因为我们没有吧libcalc.so中的二进制代码“拷贝”到可执行文件中,我们的程序在其他没有上面动态库是,将无法正常运行。
找不到动态库
运行可执行程序时 ./main出错 ldd main --> "not found"
原因:
链接器:工作处于链接状态,工作时需要 -l 和 -L
动态链接器: 工作处于程序运行阶段,工作时需要提供动态库所在目录位置。
解决方式:
(1)通过环境变量: export LD_LIBRARY_PATH = 动态库路径
./main 成功(临时生效,启动终端环境变量失效)
(2)永久生效: 写入终端配置文件 .bashrc 建议使用绝对路径。
1) vi ~/.bashrc
2)在末尾写入 export LD_LIBRARY_PATH = 动态库路径 保存
3) ..bashrc 或 source .bashrc 或重启终端。 让修改后的bashrc生效
4)./main 成功
(3)拷贝自定义动态库到/lib(标准C库所在目录下)
(4)配置文件法
1) sudo vi /etc/ld.so.conf
2)写入动态库绝对路径 保存
3)sudo ldconfig 是文件生效
4)./main 成功 ldd main 查看