类unix的Linux操作系统的静态库和动态库的使用

静态库

1.mkdir staticdir

2.cd staticdir/

3.vi add.h

#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;
}

4.gcc -c *.c 编译不链接

生成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;
}

5.静态库的调用

在.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     //拷贝并重命名了一份刚刚写的文件夹和内容

1.创建动态库

.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直接运行

2.使用动态库

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可以检测,从而达到目的
上一篇:ODOO时差相差8小时解决方案


下一篇:jenkin 镜像构建错误 INFO: Retrying request to {}->unix://localhost:80 org.apache.maven.plugin.M