文章目录
一、库
库就是一个二进制文件,是将.c文件编译生成的二进制文件,
里面存放的就是函数实现的二进制的机器指令,库又分为静态库和动态库。
windows:
静态库: xxx.lib
动态库: xxx.dll
linux:
静态库: libxxx.a
动态库: libxxx.so
(一)静态库
1. 概念
静态库是以 libxxx.a
格式命名的 lib 是前缀 .a 是后缀 xxx 是库名
如果在编译时使用的是静态库,会将静态库中的机器指令编译到可执行文件中,
可执行文件的体积相对较大,执行效率相对较高。
静态库更新操作比较麻烦,需要重新编译生成可执行文件,否则拿不到新的库里的指令
2. 制作
#首先,生成.o文件
gcc -c xxx1.c -o xxx1.o
gcc -c xxx2.c -o xxx2.o
....
#ar -cr 目标文件 依赖文件
ar -cr libxxx.a xxx1.o xxx2.o ....
3. 使用(编译)
(1)生成可执行文件
gcc 参数
-I 指定头文件的路径
-L 指定库文件的路径
-l (小写的L)指定链接哪个库
(2)运行
无需指定库文件路径
(二)动态库(共享库)
1. 概念
动态库又叫共享库,是以 libxxx.so
命名的 lib 是前缀 .so 是后缀 xxx 是库名
如果在编译时使用的是动态库,只会将动态库中的 函数符号表 编译到可执行文件中,
可执行文件的体积相对较小,执行时需要去动态库中找到对应的机器指令执行,效率相对较低。
动态库更新操作非常方便,只需要替换库即可,执行时自动就执行了新的库里的指令
2. 制作
gcc -c -fPIC xxx1.c -o xxx1.o #-fPIC表示忽略相对位置
gcc -c -fPIC xxx2.c -o xxx2.o
...
gcc -shared xxx1.o xxx2.o ... -o libxxx.so #这种更常用
或者可以直接把.c编译成动态库
gcc -fPIC -shared xxx1.c xxx2.c -o libxxx.so
- 补充:将
-fPIC
选项应用于库编译时,编译器会生成额外的位置无关代码和数据布局,以确保生成的库可以在不同的内存地址上加载
3. 生成可执行文件
与静态库类似
-I 指定头文件的路径
-L 指定库文件的路径
-l (小写的L)指定链接哪个库
4. 基于动态库的可执行文件的执行过程
如果直接执行,会报错 找不到库文件。
运行前需要指定库的路径,指定库的路径可以用下面的方式:
方式1(相对更常用):通过修改环境变量来实现----最常用的方式,必须会用
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:新的库的路径
//如果相对整个用户生效 可以把上面的指令放在 ~/.bashrc
中
方式2:可以把自己的库放在系统默认的库的路径中----需要sudo权限
sudo cp libxxx.so /lib
或者
sudo cp libxxx.so /usr/lib
方式3:可以通过修改系统的配置文件来实现----需要sudo权限
sudo vi /etc/ld.so.conf.d/libc.conf
在后面添加自己的库文件的路径即可
保存退出后 使用 sudo ldconfig
重新加载配置
(三)静态库使用实例
将数据结构的相关函数封装为静态库
1.文件结构
2. 首先生成.o文件
- 注:因为此时loop_queue.c引用的头文件不在当前目录下,因此需要使用
-I
指出头文件路径,(如果在当前路径下就不需要指定路径了)
3. 生成静态库文件
- 注:使用ar -cr生成静态库文件,然后将其移动到lib目录下(此时无需指定头文件)
4. 使用静态库
使用静态库进行编译时,如果头文件不在当前目录,也需要-I
来指定头文件路径,否则会报错。
无论静态库文件是否存在于当前路径下,都需要使用-L
指定静态库文件路径,并且使用-l
指定静态库(注意:无需加前缀和后缀,只需写库名即可,-l
和库名之间也无需空格分隔)
(四)动态库使用实例
1. 文件结构
2. 首先生成.o文件
- 注:
- 如果头文件不在当前目录下,必须指定头文件路径(如果在当前路径下就不需要指定路径了)
-fPIC
和-c
两个参数顺序可以颠倒
3. 生成动态库文件
- 注:生成动态库文件(此时无需指定头文件)
4. 使用动态库编译生成可执行文件
如果头文件不在当前路径下,需要指定头文件路径
必须指定库文件路径以及库文件
5. 运行使用动态库编译生成的可执行文件
使用动态库,必须指定库的路径(且使用-L
和-l
都不行)
通过修改环境变量来指定库文件路径
此处使用的相对路径,如果可执行文件换个目录就不再生效。