库就是目标文件的集合,我们把不需要升级更新维护的代码打包合并在一起方便使用,也可以对源代码进行保密
静态库在使用时是把被调用的代码复制到调用模块中,然后再执行程序时,静态库就不需要了
静态库的执行速度快,但占用空间大,当库中的内容发生变化时,需要重新编译出新的程序,不能轻易修改库的内容
而共享库只是在调用模块中嵌入调用代码的在库的相对位置的地址,当执行程序时,共享库会和程序一起加载到内存中,当执行到调用共享库中代码的指令时跳转到共享库中执行,执行完毕后再跳转回来
共享库占用空间小,方便更新(共享库发生变化后,程序不需要再次编译),相对于静态库执行效率略低
静态库的扩展名.a,共享库(动态库)的扩展名为.so
静态库
1、 创建静态库
编写源代码: vi .c/.h
编译源代码: gcc -c xxx.c -> xxx.o
打包生成静态库: ar -r libxxx.a x1.o x2.o…
ar命令的一些参数:
-r 把目标文件添加到静态库中,已经存在的更新
-q 把目标文件追加到静态库的末尾
-d 从静态库中删除目标文件
-t 显示静态库中有哪些目标文件
-x 把静态库拆分成目标文件
2、 调用静态库
1、直接调用:调用者和库在同一路径下
gcc main.c libxxx.a
2、设置环境变量:设置方法与C_INCLUDE类似
打开 vi ~/.bashrc 文件
在文件末尾添加一行
export LIBRARY_PATH = $LIBRARY_PATH:库文件的路径
重新加载配置文件 source ~/.bashrc
3、编译时要指定库名
gcc main.c -lmath(math是库名)
设置编译参数:-L路径
gcc main.c -L路径 -lmath
3、 运行
在编译时已经把被函数的二进制复制到可执行文件中了,再执行时不再需要静态库文件
共享库
1、 创建共享库
编写源代码:vi .c/.h
编译出位置无关目标文件:
gcc -c -fpic xxx.c ->xxx.o
链接生成共享库
gcc -shared x1.o x2.o x3.o … -o libxxx.so
2、 调用共享库
1、直接调用:调用者和库在同一路径下
gcc main.c libxxx.so
2、设置环境变量:设置方法与C_INCLUDE类似
打开 vi ~/.bashrc 文件
再文件末尾添加一行
export LD_LIBRARY_PATH = $LIBRARY_PATH:库文件的路径
重新加载配置文件 source ~/.bashrc
3、编译时要指定库名
gcc main.c -lmath(math是库名)
设置编译参数:-L路径
gcc main.c -L路径 -lmath
3、 运行
在使用共享库时,调用者只是记录了被代码在库的位置,因此在执行时需要共享库同时被加载
操作系统会根据LD_LIBRARY_PATH环境变量的设置来加载共享库
动态加载共享库
1、 加载共享库
Void *dlopen(const char *filename,int flag);
Filename:共享库的库名,或路径
Flag:
RTLD_LAZY 使用时才加载
RTLD_NOW 立即加载
返回值:共享库的句柄
2、 获取标识符地址并使用
Void *dlsym(void *handle,const char *symbol);
Handle:共享库的句柄
Symbol:标识符的名字
返回值:标识符在共享库中的位置(地址,可以解引用,或跳转过去)
3、 卸载共享库
Int dlclose(void *handle);
Handle:共享库的句柄
返回值:成功返回0,失败返回-1
4、 获取错误信息
Char *dlerror(void);
返回值:会把在使用共享库的过程中出现的错误,以字符串形式返回
辅助工具
nm:查看目标文件、可执行文件、静态库、共享库中的符号列表
ldd’:查看可执行程序所依赖的共享库有哪些
strip:去除掉目标文件、可执行文件、静态库和共享库中的符号列表、调试信息
objdump:显示二进制模块的反汇编信息 objdump -S a.out