一、库:
库文件是目标文件的集合,可以被其他代码调用,把代码封装成库文件后方便使用、方便管理,安全性高、保密性强
静态库:
就是目标文件的集合,当调用静态库时,编译器会把静态库的所有的二进制指令拷贝到最后的可执行文件中
-
优点:
运行速度比共享库要快,运行时不需要依赖静态库文件。(它把通用功能模块的多个目标文件打包在一起,用到它的程序只需要在链接时指定这个库文件,链接器就会从这个库中抽取出用到的功能代码拷贝到目标程序中,而不需要每次都对这些通用功能代码重新编译。)
-
缺点:
1、可执行文件相对较大,当静态库有修改后,所有使用了该静态库的可执行文件都需要重新编译;
2、磁盘和内存空间占用大。静态库虽然加快了编译速度,提高了不同部门间的协作效率,但是在每个与静态库链接的程序中,都会保存一份引用到的通用功能代码的拷贝,而且在运行时,每一份拷贝都要占用相应的物理内存。
共享库:
就是带入口的可执行文件,当调用共享库时,调用语句处会记录该函数在共享库中的位置,并且共享库文件要与运行的可执行文件一起加载到内存中,当执行到调用共享库代码的语句时,就会跳转到共享库二进制指令的内存中执行,执行完后会跳转回调用语句处,其次,每个共享库在物理内存中只有一份副本,多个应用会在各自的虚拟地址空间内映射这同一份可执行文件,因此可以节省可观的内存空间。
-
优点:可执行文件相对较小,当共享库有修改,可执行文件不需要重新编译
-
缺点:运行速度比静态库慢一些,运行时需要依赖于共享库文件
二、静态库 .a
制作静态库:
1、编译出目标文件
gcc -c xxx.c ...
2、打包目标文件生成静态库文件
ar -r libxxx.a a.o b.o c.o...
使用静态库:
1、直接使用
gcc xxx.c libxxx.a
2、指定库文件的位置
gcc xxx.c -Lpath -lxxx
-L指定库的路径 -l库名 指定要加载的库(库名不包括前缀lib 后缀.a .so)
3、通过修改配置文件中的环境变量来指定库的查找路径
- 打开系统配置文件:
vim ~/.bashrc
- 在配置文件末尾添加:
export LIBRARY_PATH=$LIBRARY_PATH:新路径(绝对路径)
- 保存退出并重新加载配置文件
source ~/.bashrc
- 使用静态库:
gcc xxx.c -lxxx
三、共享库 .so
制作共享库:
1、编译生成目标文件
gcc -fpic -c xxx.c
-fpic 生成与位置无关的文件
2、生成共享库文件
gcc -shared -fpic a.o b.o c.o ... -o libxxx.so
使用共享库:
编译时:
1、直接使用
gcc xxx.c libxxx.so
2、指定库文件的位置
gcc xxx.c -Lpath -lxxx
-L指定库的路径 -l库名 指定要加载的库(库名不包括前缀lib 后缀.a .so)
3、通过修改配置文件中的环境变量来指定库的查找路径
- 打开系统配置文件:
vim ~/.bashrc
- 在配置文件末尾添加:
export LIBRARY_PATH=$LIBRARY_PATH:新路径(绝对路径)
- 保存退出并重新加载配置文件
source ~/.bashrc
- 使用共享库:
gcc xxx.c -lxxx
运行时:
运行时,系统会去默认指定的共享库加载路径进行加载共享库,一般通过修改配置文件的环境变量进行设置
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:共享库的加载路径
注意:
1、如果指定路径下有同名的静态库文件、共享库文件,gcc编译器会默认优先加载共享库文件
如果想要优先使用同名静态库文件 增加 -static编译参数实现
2、对配置文件中的环境变量进行删除修改时,最好重启终端才生效
动态使用共享库:
作用:在代码中决定使用哪些共享库,编译时不需要指定,执行时还是需要依赖共享库
dlopen\dlerror\dlsym
库文件相关辅助命令:
-
ldd 查看可执行文件依赖哪些共享库 ldd ./a.out
-
nm 查看目标文件、可执行文件、静态库、共享库文件的符号列表
-
strip 减肥 删除目标文件、可执行文件、静态库、共享库文件的符号列表