一、静态库和动态库 1、两种库的介绍与对比 1.1、首先什么是库呢? 库就是已经写好的、具有实现特定功能的、可以重用的代码。 1.2、静态库和动态库的有啥区别呢? 静态库是后缀名为.a的归档文件(格式为:libname.a),在程序编译时会被连接到目标代码中,所以程序运行时将不再需要该静态库。动态库是后缀名为.so的归档文件(格式为:libname.so[主版本号.次版本号.发行号]),在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入。所以,后续运行时需要函数库的支持。 1.3、静态库有什么弊端呢? 第一,因为静态库是在编译时嵌入到使用它的程序中的,所以容易造成资源空间的浪费。第二,当静态库更新时,所有使用它的程序也要重新编译,这就会造成一个小小的改动也变得极其麻烦。所以在一些项目开发中基本上用的都是动态库。 2、 gcc命令的相关库选项 3、 库的生成 3.1 生成静态库 vim Sort_Array.c 内容如下 /****************** 排序代码 *************************/ void Sort_Array(int *Array, int lenth) { int i,j,temp; for(i=0;i<lenth;i++) { for(j=0;j<lenth-1-i;j++) { if(Array[j] > Array[j+1]) { temp = Array[j]; Array[j] = Array[j+1]; Array[j+1] = temp; } } } } vim main.c 内容如下 #include<stdio.h> int main(int argc,char **argv) { int i; int Array[10]={1,5,3,2,7,8,45,62,24,66}; for(i=0;i<10;i++) printf("%d\t",Array[i]);
Sort_Array(Array,10); //排序 printf("\n");
for(i=0;i<10;i++) printf("%d\t",Array[i]); return0; }
第一步:编译源程序Sort_Array.c生成目标文件Sort_Array.o gcc -c Sort_Array.c -o Sort_Array.o 第二步:对目标文件*.o进行归档,生成 lib*.a库文件 ar crsv libSort_Array.a Sort_Array.o 第3步:编译程序的时候链接静态库 gcc -o main main.c -static -L./ -lSort_Array 3.2 生成动态库 第一步:编译源程序Sort_Array.c生成目标文件Sort_Array.o gcc -fPiC -c Sort_Array.c -o Sort_Array.o 第二步:对目标文件*.o进行归档,生成 lib*.so库文件 gcc -shared -o libSort_Array.so Sort_Array.o 第3步:编译并链接动态库 gcc -o main main.c -L./ -lSort_Array 此时已经生成可执行文件main,但是你会发现你直接运行时会出错,因为系统找不到这个库,所以我们要把库文件拷贝到/lib或者/usr/lib(系统默认搜索库路径)下。 二、makefile介绍 1、简介 Make(工程管理器)是一款能够帮助我们自动检查文件的更新情况,并通过makefile(工程管理配置文件)指定相关配置选项来指引其进行编译工作的软件。 2、书写格式 object:source1.o source2.o //这里指明了终极目标项和依赖项 gcc -o object source1.o source2.o //要执行的命令语句 source1.o:source1.c //指明目标和依赖项 gcc -c source1.c -o source1.o //要执行的命令语句
source2.o:source2.c //指明目标和依赖项 gcc -c source2.c -o source2.o //要执行的命令语句 首先我们要知道第一个目标被称为终极目标,也就是当我们执行make的时候要生成的那个文件,其次要知道命令要以TAB制表符开头的。 makefile的执行过程: 因为刚开始的时候终极目标以及其依赖文件都不存在,所以会执行下面两段语句生成source1.o和source2.o,最后再根据这两个生成终极目标。之后若是有哪个源文件(如:source1.c)改变了,执行make时将会发现目标文件(source1.o)比依赖文件(source1.c)旧,这时就会重新生成目标文件,最后通过重新生成的目标文件生成终极目标。 3、变量 3.1 自定义变量 a = hi //定义变量a的值 a += everybody //在变量后面追加一个值 s = $(a) xiao ming //引用变量的值($代表取该变量的值) object: @echo $(s) //打印变量s的值(@代表不打印命令行本身) @echo $(a) ~ 3.2 系统预定义变量(系统提前帮我们定义好的变量) 通过变量的使用上面那段代码可以重写成一下这个样子 OBJ = source1.o source2.o //定义变量 EXE = object $(EXE):$(OBJ) //这里指明了终极目标项和依赖项 $(CC) -o object $(OBJ) //使用系统预定义变量
source1.o:source1.c//生成目标source1.o $(CC) -c source1.c -o source1.o
source2.o:source2.c//生成目标source2.o $(CC) -c source2.c -o source2.o 3.3 自动变量(上面的系统预定义变量,如果你不重新赋值,那它的值就是固定不变,相对而言自动变量是可以自动的变化的) 通过自动变量对上面的代码进一步改写 OBJ = source1.o source2.o //定义变量 EXE = object $(EXE):$(OBJ) //这里指明了终极目标项和依赖项 $(CC) -o $(@) $(^) //使用自动变量代表目标文件和依赖文件
source1.o:source1.c//生成目标source1.o $(CC) -c $(^) -o $(@)
source2.o:source2.c//生成目标source2.o $(CC) -c $(^) -o $(@) 4、规则 4.1、隐式规则(make会根据目标文件去寻找同名的依赖文件,并生成对与的编译语句) OBJ = source1.o source2.o //定义变量 EXE = object $(EXE):$(OBJ) //这里指明了终极目标项和依赖项 $(CC) -o $(@) $(^) //使用系统预定义变量CC 上面的代码改写成这样就可以了,因为make会通过.o目标文件自动去找到同名的.c并生成对应的编译语句。 但是隐式规则业也有不足的地方,就是当我们的目标只是一个动作而不是文件的时候,如下面所示: OBJ = source1.o source2.o //定义变量 EXE = object $(EXE):$(OBJ) //这里指明了终极目标项和依赖项 $(CC) -o $(@) $(^) clean: //清理文件 $(RM) $(OBJ) $(EXE) //执行清理命令 .PHONY:clean //.PHONY明确告诉makefile不要对clean运用隐式规则 clean这个目标只是想执行一个动作而已,但假如刚好有一个clean.c文件的话,那因为隐式操作,则会生成对应的编译语句,从而造成混淆。所以,我们必须通过指示符.PHONY告诉makefile不要对clean运用隐式操作。我们把这种不能进行隐式操作的目标叫做伪目标。 4.2、模式规则(%通配符) OBJ = source1.o source2.o //定义变量 EXE = object $(EXE):$(OBJ) //这里指明了终极目标项和依赖项 $(CC) -o $(@) $(^) //使用系统预定义变量CC
%.o:%.c //模式通配,将所有.c编译成同名的.o文件 $(CC) -c $(^) -o $(@)
模式规则利用通配符一句话可以生成多个目标文件。 4.3、多目标规则 (多个目标具有相同的依赖项) a.o b.o c.o:head.h //多个目标依赖head.h 当head.h头文件一改变,多个目标将都重新进行编译。 4.4、双冒号规则(一个目标可以有多种编译方法,分别通过冒号说明) 当同一个文件作为多个双冒号规则的目标时,这些规则会被独立地处理。可以把他们当成多条不同普通的规则一样。当双冒号规则的每一个依赖文件发生改变时,只执行该规则对应的命令。如下所示: object:a.c cc a.c -o object object:b.c cc b.c -o object object:d.c cc d.c -o object 假如a.c发生改变,则只会编译a.c,而其它的则不编译。 5、条件判断 ifdef VARIABLE //判断定义了VARIABLE这个变量 obj = $(VARIABLE) else obj = EXAMPLE endif
$(obj):object.o ifeq ($(CC),gcc) // 判断变量CC是否跟gcc相等 $(CC) object.o -o $(obj) else gcc object.o -o $(obj) endif
6、make的命令行选项 注:makefile这一块内容比较晦涩我们无需深究,只要能写下简单的makefile以及能够看得懂就好了,因为复杂的makefile都是用工具生成的(如autotools)。 总结:这一篇就介绍到这里,精彩后续! ---------------------------------------------------------------------------------------------------------------------- 我们尊重原创,也注重分享,文章来源于微信公众号:交流基地,建议关注公众号查看原文。如若侵权请联系qter@qter.org。 ---------------------------------------------------------------------------------------------------------------------- |