#ifndef _ADD_H__ #define _ADD_H__ int add(int n,int m); #endif
vi add.c
#include "add.h" int add(int n,int m){ return n+m; }
vi min.h
#ifndef _MIN_H__ #define _MIN_H__ int min(int n,int m); #endif
vi min.c
#include "min.h" int min(int n,int m){ return n-m; }
生成add.o min.o
ar指令:ar [选项] 静态库文件名 目标文件列表
-r - 将目标文件插入到静态库中,已存在则更新
-q - 将目标文件追加到静态库尾
-d - 从静态库中删除目标文件
-t - 列表显示静态库中的目标文件
-x - 将静态库展开为目标文件
ar -r liboper.a add.o min.o lib是必备的 oper只是个名字 打包成静态库文件:ar -r libxxx.a xxx.o … 生成liboper.a静态库 ar -t liboper.a 查看.o文件的包含 ar -d liboper.a min.o 从静态库中删除min.o ar -q liboper.a min.o 队列式加入 ar -x liboper.a 展开.a 里面的内容,会把.o的文件都展出来,放到当前目录中
main.c
#include "add.h" #include "min.h" #include <stdio.h> int main(){ int a=20,b=20; printf("%d\n",add(a,b));//有了静态库liboper.a没有.h也运行 printf("%d\n",min(a,b)); return 0; }
在.c文件中使用静态库中的函数 需要包含头文件,即头文件目录 gcc -I main.c中包含的头文件的存放位置目录 main.c -l静态库名字(这里是oper)-L 静态库存放位置目录 -I 头文件目录 -l链接静态库/动态库 - L查找静态库/动态库的路径 第一个是大i,第二个是小L 即使是在当前目录,也需要配置 -I 或者 -L 后面加 . ./staticlib/ 这是.h存储的位置 gcc -I ./staticlib/ main.c -loper -L. //.是当前路径 当liboper.a提供出去时,存储目录会变,例如我把.a移动到上层,终端cd到桌面 目录就变成 .桌面/staticdir/ gcc -I .桌面/staticdir/staticlib/ main.c -loper -L ./staticdir/ 也可以通过配置当前终端变量 export CPATH=$CPATH:/目录 export LIBRARY_PATH=$LIBRARY_PATH: /目录 - 链接时查找静态库/共享库的路径 两个都配置后,gcc main.c -loper 就可以直接运行,不需要在输入地址,但是这个配置只对当前终端 有效,在运行一个终端就没用了。 如果是bashrc处添加就是永久 sudo vi ~/.bashrc 永久配置 source ~/.bashrc 保存执行 pwd用于查看当前目录名 gcc -static -c array.c //表明这个文件是用来生成静态库的
cp -rf staticlib sharelib //拷贝并重命名了一份刚刚写的文件夹和内容
.c.h编辑完毕 编译所有的.c文件 gcc -c -fpic x.c 生成动态库 gcc -shared *.o -o lib动态库名.so ;//这是前面所有的.c文件都已经用-fpic编译过的写法 gcc -shared -fpic *.c -o lib动态库名.so ;//另一种 gcc -I ./sharedlib/ main.c -l动态库名 -L ./sharedlib/ 这个时候动态库不能.a.out直接运行
1.编写代码,包含头文件,使用动态库中的函数 2.gcc -I 头文件路径 main.c-l动态库名 -L 动态库路径 3.链接动态库即使生成了可执行文件,该可执行文件依然不能运行 LD_LIBRARY_PATH 的作用是在执行可执行文件程序时,去指定位置链接动态库 动态库必须用这个配置: export LD_LIBRARY_PATH=$ LD_LIBRARY_PATH:./sharedlib/
1. 生成步骤不一样 静态库是ar -r lib静态库名.a *.o 动态库是gcc -shared *.o -o lib动态库名.so 2. 静态库文件没有’x’这个权限,动态库有’x’权限(即可以直接执行,所以最后执行是跑到动态库中) 3. 链接静态库时,是把调用函数的指定用静态库中的二进制代码来替换, 链接动态库时,是直接在函数调用下嵌入函数在动态库中的相对地址 使用静态库生成的可执行程序比较大 使用动态库生成的比较小 4. 链接静态库,编译时比较慢,执行效率高 链接动态库,编译时比较快,执行效率低 5. 链接静态库,生成的执行文件在运行过程中不依赖于静态库文件 链接动态库,生成的执行文件在运行过程中依赖于动态库的LD_LIBRARY_PATH 链接动态库生成的可执行程序在运行时查找动态库的路径 6. 静态库其实本质上是对目标文件进行打包,但是动态库其实是对目标文件进行进一步的编译, 是可以执行的二进制指令 7. 如果liboper.a liboper.so都有 gcc -I main,c -loper -L.//首选链接的是动态库 那么我们如何选择连接静态库: gcc -I -static main,c -loper -L.//强制链接静态库
loadsharedlib.c
#include <stdio.h> #include <dlfcn.h> typedef int (*FUNC)(int,int); int main(){ void *handle = dlopen("liboper.so",RTLD_NOW); if(handle == NULL){ printf("%s\n",dlerror());//获取错误信息 return -1; } FUNC f1,f2,f3,f4; f1 = dlsym(handle,"add");//根据标识符获取该标识符在动态库中的相对地址 if(f1 == NULL){ printf("%s\n",dlerror()); return -1; } int ret = f1(1024,9527); printf("ret = %d\n",ret); f2 = dlsym(handle,"minus"); ret = f2(1024,9527); printf("ret = %d\n",ret); f3 = dlsym(handle,"div"); ret = f3(9527,1024); printf("ret = %d\n",ret); dlclose(handle); return 0; }
编译的时候必须使用-ldl gcc loadsharedlib -ldl
•nm: 查看目标文件、可执行文件、静态库、共享库中的符号列表。
•ldd: 查看可执行文件和共享库的动态依赖。// 例如ldd a.out 查看a.out依赖的动态库
•ldconfig: 共享库管理。
事先将共享库的路径信息写入/etc/ld.so.conf配置文件中,ldconfig根据该配置文件生成/etc/ld.so.cache缓冲文件,并将该缓冲文件载入内存,借以提高共享库的加载效率。
系统启动时自动执行ldconfig,但若修改了共享库配置,则需要手动执行该程序。
•strip: 减肥。去除目标文件、可执行文件、静态库和共享库中的符号列表、调试信息等。
•objdump: 显示二进制模块的反汇编信息。//转为汇编代码
如果在实际开发中,有一个.c文件修改了,需要编译哪些动态库 1.c文件所在的动态库 2.链接了该动态库的所有动态库和可执行程序都需要重新编译 通过ldd可以检测,从而达到目的