库文件基础
- 什么是函数库?
- 存放函数的仓库就是函数库
- 系统提供了标准库和一些其他的库文件
- 用户也可以自定义函数库
- 根据链接方式的不同, 将函数库分为动态库(共享库)和静态库两种
- 库函数的命名规则
- 动态库命名规则 lib库名.so
- 静态库命名规则 lib库名.a
静态库的制作和使用
-
1. 将所有要加入库中的源文件编译为目标文件(gcc -c *.c)
-
2. 将第一步生成的所有目标文件打包为静态库文件(ar -r lib库名.a *.o )
-
3. 使用静态库文件链接生成可执行文件(gcc main.o -L库的路径 -l库名)
-
使用静态库生成可执行文件, 静态链接的原理
-
#include <> 和 “” 的区别
- 系统路径PATH和当前路径
p_math.h (定义各个模块间的接口)
// 如果没有定义了这个宏, 就定义这个宏,紧接着进行函数声明, 最后endif. 如果定义过, 就直接跳到endif
#ifndef P_MATH_H_ //为了避免头文件重复包含
#define P_MATH_H_
//函数声明
int t_add(int, int);
int t_sub(int, int);
int t_mul(int, int);
int t_div(int, int);
#endif
add.c (加法模块)
#include "p_math.h"
int t_add(int x, int y){
return x + y;
}
int t_sub(int x, int y){
return x - y;
}
mul.c (乘法模块)
#include "p_math.h"
int t_mul(int x, int y) {
return x * y;
}
int t_div(int x, int y) {
return x / y;
}
main.c
#include "p_math.h"
#include <stdio.h>
int main(void){
int val_x = 6, val_y = 2;
printf("%d + %d = %d\n", val_x, val_y, t_add(val_x, val_y));
printf("%d * %d = %d\n", val_x, val_y, t_mul(val_x, val_y));
}
# 1. 源文件编译为目标文件
$ gcc -c add.c mul.c main.c
# 2.将 目标文件打包为静态库文件 libpmath.a, 生成库名叫做pmath的静态库
$ ar -r libpmath.a add.o mul.o
ar: creating libpmath.a
#看下这个库里有啥
$ ar -t libpmath.a
add.o
mul.o
# 3. 使用静态库文件链接生成可执行文件
# -L后接路径, -l后接路径下的库名 pmath
$ gcc main.o -L. -lpmath
$ ./a.out
6 + 2 = 8
6 * 2 = 12
$ nm libpmath.a
add.o:
0000000000000000 T t_add
0000000000000014 T t_sub
mul.o:
0000000000000013 T t_div
0000000000000000 T t_mul
# 将main.c 中的 t_mul 所在语句注释掉
$ gcc -c add.c mul.c main.c
$ gcc *.o
# 多个目标文件链接, 会把多个模块的内容都放一块得到可执行文件
$ nm a.out
....
0000000000400430 T _start
0000000000400526 T t_add
00000000004005a4 T t_div
0000000000601038 D __TMC_END__
0000000000400591 T t_mul
000000000040053a T t_sub
....
# 但静态库就不一样了, 用到那个就把哪个链接进来
$ gcc main.o -L. -lpmath
# 因为main.c中只用到add.o模块里的内容, 所以只把add.o里的内容链接进来了
# 链接进来以后 a.out 就是一个独立的可执行程序, 不在依赖静态库
$ nm a.out
....
0000000000400430 T _start
000000000040056b T t_add
0000000000601038 D __TMC_END__
000000000040057f T t_sub
....
$ rm libpmath.a
$ a.out
6+2=8
除了静态库编译, 还有之前两种编译方式,回顾
# 之前的两种生成可执行文件的方法
# 1.
$ gcc *.c #编译链接一步到胃(开个小车)
$ ./a.out
6 + 2 = 8
6 * 2 = 12
# 2.
$ gcc -c *.c #编译生成目标文件
$ gcc *.o #链接目标文件成可执行文件
$ ./a.out
6 + 2 = 8
6 * 2 = 12