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。
- 编译时:
动态库适合需要 多进程共享、减少磁盘占用、支持热更新 的场景。
Linux之生成和使用静态库与动态库的更多相关文章
- Linux下Gcc生成和使用静态库和动态库详解(转)
一.基本概念 1.1什么是库 在windows平台和linux平台下都大量存在着库. 本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行. 由于windows和linux的平台不同( ...
- 在Linux下如何使用GCC编译程序、简单生成 静态库及动态库
最近在编写的一个Apache kafka 的C/C++客户端,,在看他写的 example中,他的编译是用librdkafka++.a和librdkafka.a 静态库编译的,,,而我们这 ...
- Linux下Gcc生成和使用静态库和动态库详解
参考文章:http://blog.chinaunix.net/uid-23592843-id-223539.html 一.基本概念 1.1什么是库 在windows平台和linux平台下都大量存在着库 ...
- [转]Linux下用gcc/g++生成静态库和动态库(Z)
Linux下用gcc/g++生成静态库和动态库(Z) 2012-07-24 16:45:10| 分类: linux | 标签:链接库 linux g++ gcc |举报|字号 订阅 ...
- 【转】Linux下gcc生成和使用静态库和动态库详解
一.基本概念 1.1 什么是库 在Windows平台和Linux平台下都大量存在着库. 本质上来说,库是一种可执行代码的二进制形式,可以被操作系统载入内存执行. 由于windows和linux的平台不 ...
- Linux下GCC生成和使用静态库和动态库【转】
本文转载自:http://www.cppblog.com/deane/articles/165216.html 一.基本概念 1.1什么是库 在windows平台和linux平台下都大量存在着库. 本 ...
- Linux下的静态库与动态库的生成与调用
静态库与动态库 静态函数库 这类库的名字一般是libxxx.a,xxx为库的名字.利用静态函数库编译成的文件比较大,因为整个函数库的所有数据都会被整合进目标代码中,他的优点就显而易见了,即编译后的执行 ...
- Linux-Gcc生成和使用静态库和动态库详解
一.基本概念 1.1什么是库 在windows平台和linux平台下都大量存在着库. 本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行. 由于windows和linux的平台不同( ...
- iOS 静态库和动态库的区别&静态库的生成
linux中静态库和动态库的区别 一.不同 库从本质上来说是一种可执行代码的二进制格式,可以被载入内存中执行.库分静态库和动态库两种. 1. 静态函数库 这类库的名字一般是libxxx.a:利用静态函 ...
- makefile生成静态库和动态库
库是一种软件组件技术,库里面封装了数据和函数. 库的使用可以使程序模块化. Windows系统包括静态链接库(.lib文件)和动态链接库(.dll文件). Linux通常把库文件存放在/usr/lib ...
随机推荐
- ChatGPT学习之旅 (2) Hello Prompt
大家好,我是Edison. 上一篇:初步了解ChatGPT 什么是Prompt Prompt又称提示词,它是AI模型的指令.它即可以是一个问题,也可以是一段文字描述,AI模型会基于你给出的Prompt ...
- .NET Core如何通过认证机制访问Kafka?
大家好,我是Edison. 最近有一个ASP.NET Core使用认证机制访问Kafka的需求,加之我们又使用了CAP这个开源项目使用的Kafka,于是网上寻找了一番发现对应资料太少,于是调查了一番, ...
- 16串口服务器在机房监控console口交换机的应用
16串口服务器在机房监控console口交换机的应用 1.应用场景 目前机房中交换机的接口很多是console 口(RS232串口类型),想要实现网络化登录,便于远程控制管理机房中的交换机.如果机房交 ...
- pdf工具类之获取pdf的总页数以及每页的宽度和高度
没啥可说的,毫无技术的水贴 1 /** 2 * 获取pdf的总页数以及每页的宽度和高度 3 * 4 * @param filePath 5 * @return Map<String, List& ...
- 解决Ubuntu上使用fsck命令时遇到的“The superlock could not be read......”的问题
问题产生原因:我也不太清楚,可能是给硬盘分区的时候出的问题. 问题解决方法:依次执行以下的命令,请根据实际情况调整存储设备名称. 注意:下面的操作会清空硬盘所有数据,请根据自己的需求来判断是否需要执行 ...
- Educational Codeforces Round 180 (Rated for Div. 2) C. Coloring Game
C – Coloring Game 思路:不难看出,当 Alice 选完三个数 a b c(其中 a ≤ b ≤ c)后,Bob 能选的只有两种情况: 选择 c,这样只用比较 a+b 和 c 的大小关 ...
- GAMES 103 动画基础作业1 Shape Matching 浅浅解析
简介 作业1简单实现了一个以一定初始速度和角速度的模型和墙壁碰撞的效果. 总共讲解了三种算法 impulse (脉冲法) Shape Matching(基于形状保持的算法, 不包含物理特性) Pena ...
- 低代码开发平台,可零代码发布API
RestCloud低代码开发平台可以快速的开发企业级前后端分离的业务系统以及基于微服务架构的业务系统.平台通过建立数据模型和业务模型能够无代码快速的发布API服务,同时也能基于数据模型快速生成Java ...
- SciTech-EECS-Signal-OpAmp(Operational Amplifier,运算放大器): Gain放大倍数计算公式及其电路中电容的作用 + MCU或OpAmp用 三极管适配 以驱动 高Vgs电压的MOS管 + 分流器采样百安级大电流的微电压信号 + 微电压信号放大
SciTech-EECS-Signal-OpAmp(Operational Amplifier,运算放大器): Gain增益放大倍数计算公式 ## 分流器采样百安级大电流的微电压信号 OpAmp(运算 ...
- SciTech-BigDataAIML-paperswithcode.com-Datasets+Method+Code: 这网站上有丰富的"数据集"+Papers论文+Code代码实现
https://paperswithcode.com/ 这网站上有丰富的"数据集"+Papers论文+Code代码实现