Linux之生成和使用静态库与动态库
本文介绍了Linux环境下如何生成和使用静态库和动态库。
动态库 vs 静态库
| 特性 | 动态库(.so) | 静态库(.a) |
|---|---|---|
| 链接方式 | 运行时动态加载 | 编译时直接嵌入可执行文件 |
| 文件大小 | 可执行文件较小 | 可执行文件较大 |
| 更新方式 | 替换 .so 文件即可生效 |
需重新编译程序 |
| 加载速度 | 稍慢(需运行时加载) | 更快(代码已在二进制中) |
| 适用场景 | 多进程共享、热更新 | 独立部署、无依赖 |
静态库
在 Linux/Unix 系统中,静态库(Static Library)是一种包含多个目标文件(.o 文件)的归档文件,通常以 .a 结尾(Archive)。静态库在编译时会被直接链接到可执行文件中,使得程序运行时不再依赖外部库文件。以下是生成静态库的详细步骤:
准备源文件
假设有两个源文件:
file1.cfile2.c
示例代码
// file1.c
#include <stdio.h>
void func1() {
printf("This is func1()\n");
}
// file2.c
#include <stdio.h>
void func2() {
printf("This is func2()\n");
}
编译生成目标文件(.o 文件)
使用 gcc 或 clang 编译源文件,生成位置无关的目标文件:
gcc -c file1.c -o file1.o
gcc -c file2.c -o file2.o
-c:只编译不链接,生成.o文件。-o:指定输出文件名。
🔍 注意:静态库不需要
-fPIC(位置无关代码),因为代码会被直接嵌入可执行文件。
使用 ar 打包成静态库
静态库的命名规范为 lib<name>.a(例如 libmylib.a)。
使用 ar(归档工具)的 rcs 选项:
ar rcs libmylib.a file1.o file2.o
r:替换或添加文件到库中。c:静默创建库(不显示警告)。s:生成索引(加快链接速度)。
验证静态库
查看库中包含的 .o 文件
ar -t libmylib.a
输出:
file1.o
file2.o
查看导出的符号(函数/变量)
nm libmylib.a
输出示例:
file1.o:
0000000000000000 T func1
file2.o:
0000000000000000 T func2
T表示该符号在库中定义。
使用静态库
编译并链接静态库
gcc main.c -L. -lmylib -o myprogram
-L.:指定库的搜索路径(.表示当前目录)。-lmylib:链接libmylib.a(省略lib和.a)。
运行程序
静态库已嵌入可执行文件,直接运行即可:
./myprogram
高级操作
添加新文件到静态库
ar rcs libmylib.a newfile.o
从静态库中删除文件
ar d libmylib.a file1.o
更新库中的文件
ar r libmylib.a file1.o # 重新添加 file1.o
完整示例流程
# 1. 编译源文件
gcc -c file1.c -o file1.o
gcc -c file2.c -o file2.o
# 2. 打包静态库
ar rcs libmylib.a file1.o file2.o
# 3. 使用静态库
gcc main.c -L. -lmylib -o myprogram
# 4. 运行
./myprogram
常见问题
Q1:静态库和动态库能否混合使用?
可以,但需确保符号冲突已解决。例如:
gcc main.c -L. -lmylib -ldynamiclib -o myprogram
Q2:如何查看可执行文件依赖的库?
对静态库编译的程序:
ldd myprogram # 静态库部分不会显示,动态库会列出
Q3:为什么静态库不需要 -fPIC?
因为静态库代码会被直接复制到可执行文件中,地址在链接时固定。
总结
- 编译
.o文件:gcc -c file1.c -o file1.o - 打包静态库:
ar rcs lib<name>.a *.o - 使用静态库:
gcc main.c -L. -l<name> -o program
静态库适合需要 独立部署、避免外部依赖 的场景,而动态库更适合 节省空间和多进程共享。
动态库
在 Linux/Unix 系统中,动态库(Dynamic Library,也称为共享库,Shared Library)通常以 .so(Shared Object)结尾。动态库在程序运行时被加载,而不是在编译时静态链接到可执行文件中,这使得它们更节省磁盘和内存空间,并支持热更新。以下是生成和使用动态库的详细步骤。
准备源文件
假设有两个源文件:
file1.cfile2.c
示例代码
// file1.c
#include <stdio.h>
void func1() {
printf("This is func1()\n");
}
// file2.c
#include <stdio.h>
void func2() {
printf("This is func2()\n");
}
编译生成位置无关代码(PIC)
动态库需要编译为 位置无关代码(Position-Independent Code, PIC),以便在运行时加载到任意内存地址。使用 -fPIC 选项:
gcc -c -fPIC file1.c -o file1.o
gcc -c -fPIC file2.c -o file2.o
-fPIC:生成位置无关代码(必须加,否则链接时会报错)。
生成动态库(.so 文件)
使用 gcc 的 -shared 选项将 .o 文件打包成动态库:
gcc -shared file1.o file2.o -o libmylib.so
-shared:告诉gcc生成动态库。-o libmylib.so:指定输出文件名(通常格式为lib<name>.so)。
验证动态库
查看动态库的符号(导出的函数)
nm -D libmylib.so
输出示例:
0000000000001110 T func1
0000000000001125 T func2
T表示该符号在库中定义。
检查动态库的依赖
ldd libmylib.so
输出示例:
linux-vdso.so.1 (0x00007ffd3a3f0000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8c3a3f0000)
/lib64/ld-linux-x86-64.so.2 (0x00007f8c3a3f0000)
使用动态库
编译可执行文件并链接动态库
gcc main.c -L. -lmylib -o myprogram
-L.:告诉编译器在当前目录查找库文件。-lmylib:链接libmylib.so(-l后接库名,省略lib和.so)。
运行程序
由于动态库在运行时加载,需要确保系统能找到它:
方法 1:临时设置 LD_LIBRARY_PATH
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
./myprogram
LD_LIBRARY_PATH指定动态库的搜索路径。
方法 2:永久配置(推荐)
将库文件复制到标准库路径(如 /usr/local/lib),然后更新动态库缓存:
sudo cp libmylib.so /usr/local/lib
sudo ldconfig
然后直接运行:
./myprogram
高级用法
指定动态库版本
gcc -shared file1.o file2.o -o libmylib.so.1.0
ln -s libmylib.so.1.0 libmylib.so # 创建软链接
- 版本号格式通常为
libname.so.major.minor。
控制符号导出
在代码中使用 __attribute__((visibility("hidden"))) 隐藏符号:
// file1.c
void __attribute__((visibility("hidden"))) internal_func() {
// 该函数不会导出,仅在库内部使用
}
动态库的加载卸载(dlopen / dlclose)
在程序运行时手动加载动态库:
#include <dlfcn.h>
int main() {
void *handle = dlopen("./libmylib.so", RTLD_LAZY);
if (!handle) {
fprintf(stderr, "Error: %s\n", dlerror());
return 1;
}
void (*func1)() = dlsym(handle, "func1");
func1();
dlclose(handle);
return 0;
}
编译时需要链接 -ldl:
gcc main.c -ldl -o myprogram
总结
- 编译 PIC 代码:
gcc -c -fPIC file1.c -o file1.o - 生成动态库:
gcc -shared *.o -o lib<name>.so - 使用动态库:
- 编译时:
gcc main.c -L. -l<name> - 运行时:确保
LD_LIBRARY_PATH包含库路径,或复制到/usr/local/lib并运行ldconfig。
- 编译时:
动态库适合需要 多进程共享、减少磁盘占用、支持热更新 的场景。

浙公网安备 33010602011771号