静态库简介
静态库的本质就是将多个目标文件打包成一个库文件。链接静态库就是将库中被调用代码复制到可执行文件中。使用了静态库的可执行文件占用磁盘空间和内容空间都比较大,静态库中代码被修改后,需重新生成库文件并需重新链接库文件。使用静态库的可执行文件无需依赖静态库,静态库即使被删除,也可照常运行。执行效率比动态库相对要高。
静态库的文件形式为:lib<库名>.a
静态库制作
代码实现
假如我们制定一个数学操作的静态库,在同一个文件夹下,有如下文件:
– add.c
– add.h
– sub.c
– sub.h
add.c为加法操作实现,sub.c为减法操作实现。
代码如下:
add.h
#ifndef C_ADD_H
#define C_ADD_H
int add(int a, int b);
#endif //C_ADD_H
add.c
#include "add.h"
int add(int a, int b) {
return a + b;
}
sub.h
#ifndef C_SUB_H
#define C_SUB_H
int sub(int a, int b);
#endif //C_SUB_H
sub.c
#include "sub.h"
int sub(int a, int b) {
return a - b;
}
创建静态库
首先我们将源代码编译为目标文件:
gcc -c add.c sub.c
执行完毕后会生产add.o和sub.o文件。
静态库创建使用ar
命令;
ar -r libmymath.a add.o sub.o
执行完后,会创建一个libmymath.a文件。
链接使用静态库
我们为了使用上面的静态库,我们在如上相同文件夹下,创建一个main.c文件:
– add.c # 加法实现
– add.h # 加法头文件
– sub.c # 减法实现
– sub.h # 减法头文件
– libmymath.a # 静态库文件
– main.c # 入口主程序
main.c
#include <stdio.h>
#include "add.h"
#include "sub.h"
int main(void) {
int a = 20;
int b = 10;
printf("%d+%d=%d\n", a, b, add(a, b));
printf("%d-%d=%d\n", a, b, sub(a, b));
return 0;
}
我们使用#include预处理指令包含了sub.h和add.h头文件,来使用我们制作的mymath静态库。
如果我们直接gcc -o main main.c
肯定会出错,因为编译器不知道add.h和sub.h是哪里来的,也不知道add和sub函数的定义在哪里。
所以我们需要使用-l
选项,让编译器链接到我们制作的静态库:
gcc -o main -lmymath main.c
执行上面的命令发现还是会报错,是因为编译器默认查找的/usr/lib;/usr/local/lib系统文件夹中的库。而非我们的制作的静态库存放地址,除非将你制作的libmymath.a放到上面的lib文件夹中,那么执行上面的命令就不会有问题。如果不在上述文件夹中,则需要使用-L
来指定附加库文件搜索路径。
此处我的libmymath.a在当前目录,所以执行:
gcc -o main -lmymath -L./ main.c
注意:gcc的
-l
选项后面跟的库名,只需要指定除去lib和.a后缀的中间的实际命名就可以了,编译器会自动按照lib<库名>.a
规则来搜索库文件。
如果预处理指令#include包含的头文件不在当前目录下,则需要在gcc的时候,通过-I
选项来指定头文件附加搜索路径。
此时在当前目录生成了main的可执行文件。
运行得到如下:
20+10=30
20-10=10
静态库如果被删除,不会影响可执行文件的执行。因为静态库的代码被复制到了可执行文件中,作为了可执行文件的一部分,这也是静态库和动态库的部分区别所在。
至此,从静态库的制作到链接使用就结束了。