库的本质:预编译代码的集合,提供可重用的功能模块
特性 | 静态库(.a) | 动态库(.so) |
---|---|---|
文件扩展名 | libxxx.a | libxxx.so |
链接时机 | 编译链接阶段 | 运行时动态加载 |
内存占用 | 多副本 | 单副本共享 |
更新影响 | 需重新编译程序 | 替换库文件即可 |
执行速度 | 稍快(无加载开销) | 稍慢(首次加载需时间) |
典型应用场景 | 嵌入式系统、独立工具 | 大型应用、系统级库 |
gcc -E main.c -o main.i
#include
、#define
等指令gcc -S main.i -o main.s
gcc -c main.s -o main.o
gcc main.o -L. -lmath -o app
# 编译源文件
gcc -c add.c sub.c mult.c
# 打包为静态库
ar rcs libmath.a add.o sub.o mult.o
# 查看库内容
ar -t libmath.a
# 输出:add.o sub.o mult.o
// main.c
#include "mathlib.h"
int main() {
printf("3+5=%d\n", add(3, 5));
return 0;
}
编译命令:
gcc main.c -L. -lmath -o static_app
libmath.a
├── 文件头 (标识/索引)
├── add.o
│ ├── 代码段(.text)
│ ├── 数据段(.data)
│ └── 符号表
├── sub.o
└── mult.o
# 编译位置无关代码(PIC)
gcc -fPIC -c shared.c
# 创建动态库
gcc -shared -o libshared.so shared.o
# 设置运行时库路径
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
// main.c
#include
int main() {
void *handle = dlopen("./libshared.so", RTLD_LAZY);
if (!handle) {
fprintf(stderr, "%s\n", dlerror());
return 1;
}
// 获取函数指针
int (*add_func)(int, int) = dlsym(handle, "add");
printf("3+5=%d\n", add_func(3, 5));
dlclose(handle);
return 0;
}
编译命令:
gcc main.c -ldl -o dynamic_app
# 查看动态库依赖
ldd dynamic_app
# 查看导出符号
nm -D libshared.so
# 修改动态库路径
patchelf --set-rpath /custom/lib dynamic_app
# 静态库
add_library(math_static STATIC add.cpp sub.cpp)
# 动态库
add_library(math_shared SHARED add.cpp sub.cpp)
# 可执行文件
add_executable(app main.cpp)
# 链接库
target_link_libraries(app math_shared)
CC = gcc
CFLAGS = -fPIC -Wall
all: static_app dynamic_app
# 静态库规则
libmath.a: add.o sub.o
ar rcs $@ $^
static_app: main.c libmath.a
$(CC) main.c -L. -lmath -o $@
# 动态库规则
libmath.so: add.o sub.o
$(CC) -shared -o $@ $^
dynamic_app: main.c libmath.so
$(CC) main.c -L. -lmath -o $@ -Wl,-rpath=.
clean:
rm -f *.o *.a *.so *_app
// 使用静态链接隐藏符号
__attribute__((visibility("hidden")))
void internal_func() { /* ... */ }
// 编译时控制
gcc -fvisibility=hidden -c module.c
# 带版本号的动态库
libmath.so -> libmath.so.1.2.3
libmath.so.1 -> libmath.so.1.2.3
libmath.so.1.2.3
# 链接时指定版本
gcc -Wl,-soname,libmath.so.1 -o libmath.so.1.2.3
未定义引用(undefined reference)
-L
设置nm
检查符号是否存在动态库加载失败
ldd
检查依赖LD_DEBUG=libs
调试ABI不兼容
/* version.lds */
MATH_1.0 {
global: add; sub;
local: *;
};
编译:
gcc -shared -Wl,--version-script=version.lds ...
本指南全面覆盖了C/C++库开发的核心技术和实践技巧,从基础概念到高级优化策略,帮助开发者构建高效、稳定的软件库。无论是嵌入式系统还是大型分布式应用,都能从中获得实用的解决方案。
原创技术笔记,转载需注明出处。更多系统编程内容持续更新中…