linux库的制作
一、库文件介绍
| 维度 | 内容 |
|---|---|
| 定义 | 一组预先编译好的函数、类或数据的集合,以文件形式存在,用于被其他程序调用 |
| 本质 | 可执行代码的二进制形式,是代码复用的一种方式,将常用功能封装起来,方便开发者在不同项目中使用 |
| 作用 | 1.提高开发效率:避免重复编写相同功能的代码,减少开发时间 2.便于代码维护:集中管理功能模块,修改和升级库时只需更新库文件,无需修改使用库的程序 3.保护代码隐私:将核心代码封装在库中,只提供接口供外部使用,隐藏实现细节 |
| 分类 | 说明 |
|---|---|
| 库的分类 | 静态库和共享库(动态库) |
| 跨平台问题 | 不同平台(如 Linux vs Windows)的指令集、二进制格式、系统调用不同,导致库无法跨平台直接使用(如 Linux 的 .so 不能在 Windows 上运行) |
| Linux平台静态库命名 | libxxx.a(以 lib 为前缀 + 自定义库名 + .a 后缀) |
| Linux平台动态库命名 | libxxx.so(以 lib 为前缀 + 自定义库名 +.so 后缀) |
| 动态库版本命名 | libxxx.so.x.y.z,其中x 为主版本号(不兼容旧版),y 为次版本号(兼容旧版),z 为发行版本号(修复问题不影响接口) |
二、静态库介绍及制作
2.1 静态库介绍
在静态链接方式下,最终生成的可执行文件不仅包含程序本身的编译后代码,还包含了所依赖的静态库1和静态库2的全部被使用到的代码。
| 维度 | 内容 |
|---|---|
| 定义 | 静态库在程序编译链接阶段,其代码会被完整地“复制”到最终生成的可执行文件中,成为可执行文件的一部分。编译完成后,静态库与可执行文件“绑定”,运行时无需额外依赖 |
| 特点 | 1.可执行文件独立运行,不依赖外部库文件 2.静态库会使可执行文件体积较大,但效率比较高 3.若静态库更新,需重新编译链接程序 |
| 文件格式 | Windows平台为 .lib,Linux平台为 .a,Mac平台为 .a |
2.2 静态库制作及使用
| 步骤 | 说明 | 示例命令 |
|---|---|---|
| 准备源文件 | 编写实现库功能的源文件(如 .c 或 .cpp) | - |
| 编译生成目标文件 | 使用编译器将源文件编译成目标文件(如 .o 或 .obj) | gcc -c 源文件.c -o 目标文件.o |
| 打包生成静态库 | 使用归档工具将目标文件打包成静态库 | ar -cr 静态库.a 目标文件.o |
| 编译主程序并链接静态库 | 编译主程序并链接静态库,生成可执行文件。 若库名为 libmyadd.a,则库名写 myadd,编译器自动拼接 lib 前缀和 .a 后缀查找库文件 | gcc 目标文件.o -l库名 -L库路径 -o 可执行文件 |
最后一步可执行文件不需要加后缀
2.3 静态库所用核心选项
| 工具 | 选项 | 作用 | 示例命令 |
|---|---|---|---|
| GCC | -c | 只编译不链接,生成目标文件(.o) | gcc -c add.c -o add.o |
| GCC | -o | 指定输出文件名称 | gcc -c main.c -o main.o |
| GCC | -l | 指定要链接的库名(省略lib前缀和.a后缀) | gcc main.c -lmyadd -o main |
| GCC | -L | 指定库文件搜索路径 | gcc main.c -L./lib -lmyadd -o main |
| AR | -c | 创建新的归档文件(静态库) | ar -cr libmyadd.a add.o |
| AR | -r | 将目标文件添加到归档文件中(替换已存在的文件) | ar -cr libmyadd.a add.o |
三、动态库介绍及制作
3.1 动态库介绍
动态链接仅在运行时调用动态库,可执行文件体积小且便于库更新,但需确保运行时库文件存在且版本兼容。调用动态库的时候是用库的符号表进行调动
| 维度 | 内容 |
|---|---|
| 定义 | 动态库也称之为共享库,是在程序运行时才被加载到内存中,可以被多个可执行文件共享使用,为它们提供函数、数据等资源 |
| 特点 | 1.可执行文件运行时,需依赖系统中存在的动态库 2.可执行文件体积小(只记录的动态库的引用,没有记录全部的库)有效节省磁盘和内存空间 3.更新灵活,只要接口不变,无需重新编译依赖它的可执行文件 |
| 文件格式 | Windows平台为 .dll,Linux平台为 .so,Mac平台为 .dylib |
3.2 动态库制作及使用
| 步骤 | 说明 | 示例命令 |
|---|---|---|
| 准备源文件 | 编写实现库功能的源文件(如 .c 或 .cpp) | - |
| 编译生成与位置无关的目标文件 | 使用编译器编译源文件时,添加 -fPIC 选项生成位置无关代码(PIC)的目标文件 | gcc -c -fPIC 源文件.c -o 目标文件.o |
| 链接生成动态库 | 使用编译器将目标文件链接为动态库,多个程序可共享同一份动态库文件,节省内存 | gcc -shared 目标文件.o -o 动态库.so |
| 编译时链接动态库 | 编译时通过 -L 指定路径、-l 指定库名生成可执行文件 库名不包含前缀和后缀 | gcc 源文件.c -l库名 -L库路径 -o 可执行文件 |
可能还需要创建符号链接,动态库版本管理中的可选步骤,用于为带版本号的动态库(如 libxxx.so.1.0.0)创建简化的符号链接(如 libxxx.so),方便编译时查找。
3.3 加载动态库方法
| 运行时加载动态库方法 | 说明 | 示例操作 |
|---|---|---|
| LD_LIBRARY_PATH环境变量 | 通过环境变量临时指定库搜索路径 | export LD_LIBRARY_PATH=$PWD |
| /etc/ld.so.conf配置文件 | 编辑配置文件添加库路径,然后更新缓存 | sudo vim /etc/ld.so.conf(添加路径),然后sudo ldconfig |
| 系统默认路径 | 将库放入系统默认目录,更新缓存 | 通过mv命令:系统级库放/usr/lib,用户自定义库放/usr/local/lib,然后sudo ldconfig |
| 运行时加载动态库方法 | 优点 | 缺点 |
|---|---|---|
| LD_LIBRARY_PATH环境变量 | 方便临时测试,无需修改系统配置 | 仅对当前终端生效,不持久,可能被滥用 |
| /etc/ld.so.conf配置文件 | 系统级生效,永久有效,影响所有用户 | 需要 root 权限 |
| 系统默认路径 | 简单直接,无需额外配置 | 可能污染系统库目录,与包管理器管理的库冲突 |
3.4 动态库所用核心选项
| 工具 | 选项 | 作用 | 示例 |
|---|---|---|---|
| gcc(编译阶段) | -c | 只编译不链接,生成目标文件(.o),不生成可执行程序 | gcc -c add.c -o add.o |
| gcc(编译阶段) | -fPIC | 生成位置无关代码(PIC),确保动态库可被加载到内存任意地址并正常运行(动态库必需) | gcc -c -fPIC add.c -o add.o |
| gcc(编译阶段) | -o | 指定输出文件名称(如目标文件.o或动态库.so) | gcc -c -fPIC add.c -o add.o |
| gcc(链接阶段) | -shared | 将目标文件(.o)链接为动态库(.so),是生成动态库的核心选项 | gcc -shared add.o -o libmyadd.so |
| gcc(使用阶段) | -L | 指定动态库的搜索路径(编译时用于查找 .so 文件) | gcc main.c -lmyadd -L./lib -o main |
| gcc(使用阶段) | -l | 指定要链接的动态库名称(省略lib前缀和.so后缀,如 libmyadd.so 对应 -lmyadd) | gcc main.c -lmyadd -L. -o main |
| 系统工具 | ldconfig | 更新系统动态库缓存,使新添加的动态库(如放入/usr/lib)被系统识别(需sudo权限) | sudo ldconfig |
-static 表示静态链接
四、静态库与动态库的区别
| 对比维度 | 静态库 | 动态库 |
|---|---|---|
| 链接方式 | 编译时链接 | 运行时链接 |
| 可执行文件体积 | 体积大 | 体积小 |
| 内存占用 | 多个程序使用时,每个程序都有一份库的副本,占用内存多 | 多个程序共享同一份库,内存中只有一份副本,节省内存 |
| 更新维护 | 库更新需重新编译链接程序 | 库更新只需替换库文件,无需重新编译链接程序 |
| 依赖性 | 无运行时依赖 | 有运行时依赖,库缺失程序无法运行 |
| 适用场景 | 适合对程序独立性要求高、库不常更新、且对可执行文件启动速度有要求的场景 | 适合库需要频繁更新、多个程序共享库功能、且希望减小可执行文件体积的场景 |
静态库在程序运行的时候不需要在系统中,因为静态库编译时已链接到程序,运行时无需依赖
静态库与动态库的核心差异在于链接时机。
五、库制作常见问题及解决方案
| 问题类型 | 可能原因 | 解决方法 |
|---|---|---|
| 静态库链接时提示未定义的引用 | 库文件路径错误、库名拼写错误、库中确实不存在该函数或变量的定义 | 检查库路径和库名是否正确,确认库中是否实现了所需功能 |
| 动态库运行时提示无法找到库文件 | 库文件路径未加入系统默认搜索路径或未通过环境变量指定 | 将动态库复制到系统默认库路径(如 /usr/local/lib),或设置相应的环境变量(如 Linux 的 LD_LIBRARY_PATH) |
| 动态库版本冲突 | 程序依赖的动态库版本与系统中安装的版本不一致 | 安装程序所需版本的动态库,或重新编译程序使其适配系统中的库版本 |
