31-库文件的制作与使用——静态库文件与动态库文件
一、库文件介绍
库文件是在计算机编程中用来存放变量、函数和类的文件,提供给开发者开箱即用
的资源。库文件分为静态库
和动态库
两种,二者在程序链接阶段的行为不同:
- 静态库:在程序的链接阶段被复制到程序中。每次程序运行时,静态库内容都被完整复制,因此占用更多的内存,但无需依赖外部文件,适合独立分发。
- 动态库:在程序的链接阶段不被复制,而是程序运行时由系统
动态加载
到内存中。多个程序可以共享一个动态库实例,节省内存并便于模块化更新。
1.1 静态库和动态库的区别
-
静态库:
- 在编译时将库的内容复制到程序中。
- 优点:无需担心运行时缺失库文件。
- 缺点:占用更多内存,不便于更新。
- 类似于书店,只卖不借。
-
动态库:
- 在运行时加载,不在编译时复制到程序中。
- 优点:节省内存,提高程序执行效率。
- 缺点:需要运行时动态库的支持。
- 类似于图书馆,只借不卖。
1.2 库文件的命名规则
- 前缀
lib
:例如libDeployPkg.so.0
- 静态库后缀
.a
- 动态库后缀
.so
- 版本号在后缀之后:例如
libc.so.1.0.3
1 libc.so.1.0.3
lib 库文件的前缀
c 库的名字(链接库文件时 ,只需要写上该名字)
.so 后缀(so为动态库/共享库 a 则是静态库)
.1 库文件的版本号
.0.3 修正号
二、制作库文件
制作静态库和动态库的原材料都是 .o
文件(可重定位文件),这些文件不能包含主函数 main
。
2.1 静态库的制作
-
生成
.o
文件:gcc -c -fPIC -I../inc swap.c -o swap.o gcc -c -fPIC -I../inc max.c -o max.o
-c
:生成可重定位文件后停止。-fPIC
:生成与地址无关的可执行文件。
fPIC 选项《动态链接库》的说法:如果不加-fPIC,则加载.so文件的代码段时,代码段引用的数据对象需要重定位, 重定位会修改代码段的内容,这就造成每个使用这个.so文件代码段的进程在内核里都会生成这个.so文件代码段的copy.每个copy都不一样,取决于 这个.so文件代码段和数据段内存映射的位置(地址)
-
生成静态库文件:
ar -rcs libmy_lib.a swap.o max.o
rcs是生成静态库文件
三个参数,分别表示:
- r:替换已存在的文件。
- c:创建新的库文件。
- s:生成索引,加快库文件的查找速度。
-
使用静态库文件:
gcc src/*.c -I./inc -L./lib -lmy_lib -o bin/main
-I
是指定头文件的路径,-L
是指定库文件的路径,-l
是指定库文件的名字,-o
是生成可执行文件的名字(路径)。
2.2 动态库的制作
-
生成
.o
文件:gcc -c -fPIC -I../inc swap.c -o swap.o gcc -c -fPIC -I../inc max.c -o max.o
-
生成动态库文件:
gcc -shared -fPIC -o libmy_lib.so.0 swap.o max.o
-shared
表示生成动态库文件
-fPIC
表示生成与地址无关的可执行文件
-o
表示生成动态库文件的名字(路径)
-
生成动态库文件的软链接:
ln -s libmy_lib.so.0 libmy_lib.so
注意:软链接是非必须的,但是在版本管理中,我们通常需要为每个版本的库文件创建一个软链接,以便于管理。
为什么需要生成软链接?
- 版本管理:动态库的版本会不断更新,例如从 libmy_lib.so.0 更新到 libmy_lib.so.1。通过软链接,你可以将 libmy_lib.so 指向最新的版本,无需修改代码或重新编译。
- 编译方便:编译器和链接器通常会查找没有版本号的库文件名称(例如 libmy_lib.so),然后自动链接到相应的库文件。如果没有软链接,编译器可能会找不到库文件,导致编译失败。
- 简化使用:软链接可以让你在编写 Makefile 或其他编译脚本时更加简洁,不需要关注具体的库文件版本号。
- 使用动态库文件:
-
编译:
gcc src/*.c -I./inc -L./lib -lmy_lib -o bin/main
-
运行:
./main
-
2.2.1 动态库加载问题及解决方法
直接使用会报错:
./mian: error while loading shared libraries: libmy_lib.so:cannot open shared object file: No such file or directory
原因是:
因为动态库在我们运行程序的时候需要加载到内存中,加载的动作由系统来完成。系统并不知道我们的库在哪里,因此加载失败。
-
方法一:将库文件放入系统默认路径(推荐)。–> /usr/lib/或者/lib
sudo cp lib/libmy_lib.so /usr/lib/
-
方法二:将库路径添加到环境变量。
vim ~/.bashrc
在末尾添加:
export LD_LIBRARY_PATH=/home/even/my_lib:$LD_LIBRARY_PATH
LD_LIBRARY_PATH
是一个环境变量,用于指定动态链接库的搜索路径。当程序运行时,系统会按照这个路径来查找动态链接库。:
为分隔符,$LD_LIBRARY_PATH
表示原来的路径。
重新加载配置文件:
source ~/.bashrc
-
方法三:在系统默认路径下添加新的路径。
sudo vim /etc/ld.so.conf.d/libc.conf
添加库路径:
/home/even/my_lib
重新生效配置文件:
sudo ldconfig
注意:
如果动态库于静态库名字一样,而且放一起,则编译器==默认使用动态链接==
如何指定让编译器使用静态库-static
2.3 静态编译选项
-
指定使用静态库:
gcc src/*.c -o bin/main -L./lib -I./inc -lmy_lib -static
三、 隐藏命令行路径
前面得路径太长了,可以进行隐藏:
-
编辑
.bashrc
:vim ~/.bashrc
-
添加以下内容:
export PS1='[\u@\h \W]\$ '
-
重新加载配置文件:
source ~/.bashrc