个人主页:chian-ocean
文章专栏-Linux
前言
动静态库是编程中两种主要的库类型,它们用于帮助开发者复用已有的代码,而不需要每次都从头开始编写。它们的主要区别在于链接和加载的时机、方式以及使用场景

库
库就是一些已经写好并且经过测试的功能模块,你只需要在自己的程序中"借用"这些功能,而无需重新做同样的工作。这样不仅节省了时间,还能提高代码的质量和稳定性。
库的形式
库的形式 主要有两种,分别是 静态库 和 动态库。它们的区别在于程序如何使用这些库,以及库文件在程序中的存储方式。
静态库 (Static Library)
静态库是在程序编译时就被链接到可执行文件中的库,所有的库代码会被嵌入到最终生成的程序中。程序在运行时不再依赖外部的库文件。
文件扩展名:
- Linux/Unix 系统 :
.a
(archive) - Windows 系统 :
.lib
动态库 (Dynamic Library)
动态库是在程序运行时 加载的库,程序并不会将库的代码嵌入到程序中,而是在程序启动时,或者在程序运行时动态加载需要的库文件。
文件扩展名:
- Linux/Unix 系统 :
.so
(Shared Object) - Windows 系统 :
.dll
(Dynamic Link Library)
总结:
特性 | 静态库 | 动态库 |
---|---|---|
链接时机 | 编译时链接,库代码被嵌入到程序中 | 运行时链接,程序在执行时动态加载库 |
可执行文件大小 | 程序文件较大,因为库代码被包含在其中 | 程序文件较小,只包含对库的引用,库的代码在外部 |
依赖关系 | 不依赖外部库文件,所有代码在可执行文件中 | 依赖外部库文件,程序必须确保运行时找到对应的库文件 |
共享 | 每个程序都包含自己需要的库代码,不共享 | 多个程序可以共享同一个库文件,节省内存和磁盘空间 |
更新 | 库文件更新时需要重新编译程序 | 库文件更新时,无需重新编译程序,只需要确保兼容性 |
性能 | 程序启动较快,因为所有代码都已经包含在内 | 程序启动时需要加载库文件,可能稍慢,且可能会有额外的内存管理开销 |
静态库
静态库的制作
**静态库(Static Library)**是一个打包了多个目标文件(.o
文件)或其他库文件的归档文件。它可以在编译时链接到程序中,生成最终的可执行文件。静态库的扩展名通常为 .a
(在 Unix/Linux 系统上)。
编写源文件 : 创建包含函数实现的 .c
文件,例如 math.c
。
- 简单的加减乘除。
cpp
#include "mymath.h"
int errno = 0 ;
int add(int x,int y)
{
return x + y;
}
int sub(int x,int y)
{
return x - y;
}
int mul(int x,int y)
{
return x * y;
}
int div(int x,int y)
{
if(y == 0)
{
errno = -1;
return -1;
}
return x / y;
}
编写头文件: 创建包含函数实现的 .c 函数声明
cpp
#pragma once
#include <stdio.h>
extern int errno;
int add(int x,int y);
int sub(int x,int y);
int mul(int x,int y);
int div(int x,int y);
编写Makefile:创建自动化构建文件
makefile
# 定义静态库的名称
lib=libmath.a
# 生成静态库 libmath.a 的规则
# 依赖 mymath.o 文件,并将其打包成静态库
$(lib): mymath.o
# 使用 ar 命令将目标文件 mymath.o 添加到静态库 libmath.a 中
ar -rc $@ $^
# 编译 mymath.c 文件为 mymath.o 目标文件的规则
mymath.o: mymath.c
# 使用 gcc 编译 mymath.c 文件为目标文件 mymath.o
gcc -c $^
# 定义伪目标 clean,它用于清理构建产生的文件
.PHONY: clean
clean:
# 删除所有目标文件 (.o) 和库文件 (lib*)
rm -rf *.o lib*
# 定义伪目标 output,它用于创建输出目录并复制必要的文件
.PHONY: output
output:
# 创建 lib/include 目录
mkdir -p lib/include
# 创建 lib/libmymath 目录
mkdir -p lib/libmymath
# 将所有头文件复制到 lib/include 目录
cp *.h lib/include
# 将静态库 (.a 文件) 复制到 lib/libmymath 目录
cp *.a lib/libmymath
静态库的使用
cpp
#include "mymath.h" // 包含自定义的头文件 mymath.h
int main() {
printf("add(1 + 1) = %d\n", add(1, 1));
printf("sub(1 + 1) = %d\n", sub(1, 1));
printf("mul(1 + 1) = %d\n", mul(1, 1));
printf("div(1 + 1) = %d\n", div(1, 1));
return 0;
}
写一个代码利用自己写的库;
- 此时的静态库在
/lib/libmymath
的路径下。 - 头文件在
/lib/include
的路径下。 - 可执行程序在
/mian
的目录下。
库路径和头文件路径只有用户知道
bash
gcc main.c -I ../lib/include/ -L ../lib/libmymath/ -lmymath
-
gcc main.c
:使用gcc
编译器来编译main.c
文件。 -
-I ./lib/include/
:这个选项告诉编译器在./lib/include/
目录中查找头文件 (*.h
)。-I
后面跟着的是头文件所在的目录。 -
-L ./lib/libmymath/
:这个选项告诉编译器在./lib/libmymath/
目录中查找库文件 (*.a
或*.so
),-L
后面跟的是库文件所在的目录。 -
-lmymath
:这个选项告诉编译器链接libmymath
库。编译器会自动查找并链接名为libmymath.a
或libmymath.so
的库文件。注意,lib
前缀和.a
后缀会被自动省略。
库路径和头文件路径在系统路径下
bash
/usr/lib64 #库的系统默认路径
bash
/usr/include #头文件的系统默认路径
这时候我们仅仅需要手动连接库就好了。
bash
gcc main.c -lmymath
动态库
动态库的制作
- 把静态库的的方法做成动态库。
编写Makefile:创建自动化构建文件
makefile
# 定义变量dy_mymath,表示生成的动态库文件名
dy_mymath = libmymath.so
# 生成动态库 libmymath.so 目标
# 该目标依赖于 mymath.o 文件
$(dy_mymath): mymath.o
# 使用gcc命令生成动态库,-shared 表示生成共享库,-o 用于指定输出文件
# $@ 代表目标文件(这里是 libmymath.so),$^ 代表所有依赖文件(这里是 mymath.o)
gcc -shared -o $@ $^
# 生成目标文件 mymath.o
# 该目标依赖于 mymath.c 文件
mymath.o: mymath.c
# 使用gcc编译源文件 mymath.c 生成目标文件 mymath.o
# -fPIC 生成位置无关代码(适用于动态库),-c 只编译源文件,不进行链接
# $^ 代表依赖文件(这里是 mymath.c)
gcc -fPIC -c $^
# 声明 clean 为伪目标,表示 make clean 是一个命令,而不是文件
.PHONY: clean
# clean 目标,用于清理生成的目标文件和动态库文件
clean:
# 删除所有目标文件 (.o) 和共享库文件 (.so)
# -rf 强制删除,不询问确认
rm -rf *.o *.so
动态库的使用
库路径和头文件路径只有用户知道

sh
gcc main.c -I ../ -L ../ -lmymath
-
-I../
:此选项指定了头文件路径,告诉编译器去../
目录下查找头文件。 -
-L../
:此选项指定了库文件路径,告诉链接器去../
目录下查找库文件。 -
-lmymath
:告诉编译器链接libmymath.so
动态库。链接器会自动在路径中查找名为libmymath.so
的动态库文件。
库路径和头文件路径在系统路径下
bash
/usr/lib64 #库的系统默认路径
bash
/usr/include #头文件的系统默认路径
这时候我们仅仅需要手动连接库就好了。
bash
gcc main.c -lmymath
执行可执行程序的时候就会报错:

vb
./a.out: error while loading shared libraries: libmymath.so: cannot open shared object file: No such file or directory
这个错误表明 动态库 libmymath.so
无法被加载,通常是因为系统在运行时无法找到该动态库。
动态库的加载
-
将动态库加载到
lib64
系统路径下,拷贝到系统默认搜索的路径的下面 -
软链接到
lib64
的系统路径下。
bash
sudo ln -s /home/ocean/linux/file/lib_dyn/libmymath.so /lib64

将其软连接到系统路径下。

- 运行程序时指定动态库路径: 如果运行时无法找到动态库,使用
LD_LIBRARY_PATH
来指定动态库的位置(临时)。
bash
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/ocean/linux/file/lib_dyn

- 在
/etc/ld.so.conof.d
建立自己的动态库的路径配置文件,然后执行ldconfig
进行刷新。

- 同样也可以进行动态库的加载。