在Linux开发中,库是预编译的代码集合,供程序调用;链接则是将库代码与程序代码结合的过程。根据库的存储和链接方式,分为静态库( .a )和动态库( .so ),对应的链接方式为静态链接和动态链接。
一、基本概念
- 静态库(Static Library)
- 以 .a 为后缀,是目标文件( .o )的归档包。
- 静态链接:编译时,链接器会将静态库中被程序调用的代码完整复制到可执行文件中。
- 特点:可执行文件独立运行,不依赖外部库;文件体积大;库更新后,程序需重新编译链接。
- 动态库(Shared Library)
- 以 .so 为后缀(Shared Object),是可被多个程序共享的代码库。
- 动态链接:编译时,链接器仅记录程序对动态库的引用(如库名、函数地址),不复制库代码;程序运行时,由动态链接器加载动态库到内存并完成链接。
- 特点:可执行文件体积小;多个程序共享同一份动态库,节省内存;库更新后,无需重新编译程序(只要接口兼容)。
二、代码示例(C语言)
准备工作:编写库的源文件
创建两个文件, math.c (库实现)和 math.h (库头文件):
c
// math.h 头文件
#ifndef MATH_H
#define MATH_H
int add(int a, int b);
int sub(int a, int b);
#endif
c
// math.c 库实现
#include "math.h"
int add(int a, int b) {
return a + b;
}
int sub(int a, int b) {
return a - b;
}
- 制作并使用静态库
步骤1:编译生成目标文件 .o
c
bash
gcc -c math.c -o math.o # -c 表示只编译不链接,生成目标文件
步骤2:打包生成静态库 .a
c
bash
ar rcs libmath.a math.o # ar是归档工具,rcs:创建、替换、索引
步骤3:编写主程序并静态链接
创建主程序 main.c :
c
#include <stdio.h>
#include "math.h"
int main() {
printf("3+2=%d\n", add(3, 2));
printf("3-2=%d\n", sub(3, 2));
return 0;
}
步骤4:编译主程序并链接静态库
c
bash
gcc main.c -o main_static -L. -lmath # -L. 指定库路径(当前目录),-lmath 链接libmath.a
步骤5:运行与验证
c
bash
./main_static
输出:
plaintext
3+2=5
3-2=1
- 验证静态链接:删除静态库 libmath.a ,程序仍可正常运行(代码已复制到可执行文件中)。
- 制作并使用动态库
步骤1:编译生成位置无关的目标文件 .o
c
bash
gcc -c -fPIC math.c -o math.o # -fPIC 生成位置无关代码,用于动态库
步骤2:生成动态库 .so
c
bash
gcc -shared -o libmath.so math.o # -shared 表示生成动态库
步骤3:编译主程序并动态链接
c
bash
gcc main.c -o main_dynamic -L. -lmath # 编译命令与静态链接一致,链接器自动优先找动态库
步骤4:运行与验证
直接运行可能报错(系统找不到动态库),需指定动态库路径:
bash
方式1:临时指定环境变量
export LD_LIBRARY_PATH=./:$LD_LIBRARY_PATH
./main_dynamic
方式2:将动态库复制到系统库路径(如/usr/lib)
cp libmath.so /usr/lib
./main_dynamic
输出与静态链接一致:
plaintext
3+2=5
3-2=1
- 验证动态链接:删除动态库 libmath.so ,程序运行时会报错(依赖外部库)。
