当我们在Linux系统下面编写C程序的时候,经常用到gcc编译器对源文件进行编译,平时学习时写的源文件可能不多。
在工程项目中一般会有比较多的模块分交给每个人写,这样的源文件也比较多,所以想在工程编程中更方便编译代码文件,我们常常会用到Make file文件。
在Windows下可能不需要做这么多,但要是想要成为一个合格的软件工程师就必须学会这项技能。
下面用一个实际的例子说明一下。
一、创建写好的头文件和源文件
sub.c
1 int sub(int var1,int var2) 2 { 3 return var1 - var2; 4 }
div.c
1 int div(int var1,int var2) 2 { 3 4 return var1 / var2; 5 }
add.c
1 int add(int var1, int var2) 2 { 3 return var1 + var2; 4 5 }
mul.c
1 int mul(int var1,int var2) 2 { 3 return var1 * var2; 4 }
mod.c
1 int mod(int var1, int var2) 2 { 3 return var1 % var2; 4 }
cal.h
1 #ifndef cal_h 2 #define cal_h 3 4 int add(int,int); 5 int sub(int,int); 6 int mul(int,int); 7 int div(int,int); 8 int mod(int,int); 9 10 #endif
testcal.c
1 #include <stdio.h> 2 #include "cal.h" 3 4 int main(int argc, char **argv) 5 { 6 int var1; 7 int var2; 8 printf("please input var1:"); 9 scanf("%d",&var1); 10 printf("please input var2:"); 11 scanf("%d",&var2); 12 13 printf("%d add %d is %d ",var1, var2, add(var1,var2)); 14 printf("%d sub %d is %d ",var1, var2, sub(var1,var2)); 15 printf("%d mul %d is %d ",var1, var2, mul(var1,var2)); 16 printf("%d div %d is %d ",var1, var2, div(var1,var2)); 17 printf("%d mod %d is %d ",var1, var2, mod(var1,var2)); 18 19 return 0; 20 21 }
利用对两个数的乘除加减创建以上五个源文件和一个头文件。
下面我们开始编写Makefile文件
1 OBJ = testcal.o add.o div.o sub.o mul.o mod.o 2 testcxm: $(OBJ) cal.h 3 gcc $(OBJ) -o testcxm 4 testcal.o:testcal.c 5 add.o:add.c 6 div.o:div.c 7 sub.o:sub.c 8 mul.o:mul.c 9 mod.o:mod.c 10 11 .PHONY:cleanA clean 12 claenA: 13 rm testcxm $(OBJ) 14 clean: 15 rm $(OBJ)
Makefile文件中的.o后缀文件都是对应着相应的.c文件,会有相互依赖的关系,make有着很强大的功能,及时不用编写gcc -o *.c源文件它也会依据前面的
依赖关系自己补全做这个事情,可以给我们节省编写,也让相应的源文件与之一一对应,更加易读,一目了然。
我们在这里面创建的库文件名称是以我名字首字母testcxm,OBJ类似于C文件里面的宏定义,以这一个代替多个中间目标文件,写.PHONY是为了提醒系统
这是个伪文件,想要运行后面命令应该要在使用make cleanA或者make claen命令进行清除相应的库文件和中间目标文件。
这些源文件和头文件应该在一个文件夹下面,然后运行make命令。
cc -c -o testCal.o testCal.c cc -c -o add.o add.c cc -c -o sub.o sub.c cc -c -o mul.o mul.c cc -c -o div.o div.c cc -c -o mod.o mod.c gcc -o testcxm testCal.o add.o sub.o mul.o div.o mod.o
进行make命令后生成中间目标文件和库文件
查看文件的大小命令ls -l:
total 36 -rwxrwxrwx 1 booker booker 237 Mar 22 22:07 Makefile -rwxrwxrwx 1 booker booker 71 Mar 22 22:11 add.c -rwxrwxrwx 1 booker booker 1232 Mar 22 22:11 add.o -rwxrwxrwx 1 booker booker 127 Mar 22 22:09 cal.h -rwxrwxrwx 1 booker booker 68 Mar 22 13:48 div.c -rwxrwxrwx 1 booker booker 1232 Mar 22 22:00 div.o -rwxrwxrwx 1 booker booker 68 Mar 22 13:48 mod.c -rwxrwxrwx 1 booker booker 1240 Mar 22 22:00 mod.o -rwxrwxrwx 1 booker booker 68 Mar 22 22:10 mul.c -rwxrwxrwx 1 booker booker 1232 Mar 22 22:11 mul.o -rwxrwxrwx 1 booker booker 67 Mar 22 23:14 sub.c -rwxrwxrwx 1 booker booker 1232 Mar 22 23:51 sub.o -rwxrwxrwx 1 booker booker 496 Mar 22 13:48 testcal.c -rwxrwxrwx 1 booker booker 2736 Mar 22 22:00 testcal.o -rwxrwxrwx 1 booker booker 8696 Mar 22 23:51 testcxm
可以看到我们的生成的可执行文件testcxm大小为8696字节,8K大小左右。
运行后:
[booker@TBB6LFOV9OI82DY Design]$ ./testcxm please input var1:10 please input var2:20 10 add 20 is 30 10 sub 20 is -10 10 mul 20 is 200 10 div 20 is 0 10 mod 20 is 10
二、使用静态库文件,生成静态库。静态库文件一般的形式为libname.a,其中lib为前缀,.a后缀扩展名,生成静态库的命令为ar,我将静态库name设为我名字首字母:
ar rcs libcxml.a add.o sub.o mul.o div.o mod.o
生成静态库后,使用一下的命令进行编译:
gcc -o testcxm testcal.c -static -L. -lcxm
其中上面的命令表示:
① gcc -o testcxm:表示使用gcc进行编译,-o指定文件名,后面的为生成的文件名。
② -static:表示使用静态库。
③ -L:表示指明使用库,-lcxm:-l表示lib是缩写,cxm:表示文件名。
查看文件的大小ls -l:
[booker@TBB6LFOV9OI82DY Design]$ ls -l total 972 -rwxrwxrwx 1 booker booker 237 Mar 22 22:07 Makefile -rwxrwxrwx 1 booker booker 71 Mar 22 22:11 add.c -rwxrwxrwx 1 booker booker 1232 Mar 22 22:11 add.o -rwxrwxrwx 1 booker booker 127 Mar 22 22:09 cal.h -rwxrwxrwx 1 booker booker 68 Mar 22 13:48 div.c -rwxrwxrwx 1 booker booker 1232 Mar 22 22:00 div.o -rwxrwxrwx 1 booker booker 6580 Mar 23 00:00 libcxm.a -rwxrwxrwx 1 booker booker 68 Mar 22 13:48 mod.c -rwxrwxrwx 1 booker booker 1240 Mar 22 22:00 mod.o -rwxrwxrwx 1 booker booker 68 Mar 22 22:10 mul.c -rwxrwxrwx 1 booker booker 1232 Mar 22 22:11 mul.o -rwxrwxrwx 1 booker booker 67 Mar 22 23:14 sub.c -rwxrwxrwx 1 booker booker 1232 Mar 22 23:51 sub.o -rwxrwxrwx 1 booker booker 496 Mar 22 13:48 testcal.c -rwxrwxrwx 1 booker booker 2736 Mar 22 22:00 testcal.o -rwxrwxrwx 1 booker booker 958552 Mar 23 00:01 testcxm
从上面我们可以看到使用静态库的可执行文件的大小为958552字节,大概在900多k,运行一下可执行文件:
[booker@TBB6LFOV9OI82DY Design]$ ./testcxm please input var1:5 please input var2:13 5 add 13 is 18 5 sub 13 is -8 5 mul 13 is 65 5 div 13 is 0 5 mod 13 is 5
三、使用动态文件:生成动态库文件。库文件一般的形式为libname.so,其中lib为前缀,.so为后缀扩展名,在此以我名字的首字母为名创建一个动态文件库。
make之后的文件,运行下面的命令:
[booker@TBB6LFOV9OI82DY Design]$ gcc -shared -fPIC -o libcxm.so add.o sub.o mul.o div.o mod.o
-shared指生成动态库,-fPIC对位置进行引用,方便进行地址链接。
再运行一下命令进行编译:
[booker@TBB6LFOV9OI82DY Design]$ gcc -o testcxm testcal.c -L. -lcxm
没有使用-static说明该库文件为动态库。
查看文件的大小:
[booker@TBB6LFOV9OI82DY Design]$ ls -l total 44 -rwxrwxrwx 1 booker booker 237 Mar 22 22:07 Makefile -rwxrwxrwx 1 booker booker 71 Mar 22 22:11 add.c -rwxrwxrwx 1 booker booker 1232 Mar 22 22:11 add.o -rwxrwxrwx 1 booker booker 127 Mar 22 22:09 cal.h -rwxrwxrwx 1 booker booker 68 Mar 22 13:48 div.c -rwxrwxrwx 1 booker booker 1232 Mar 22 22:00 div.o -rwxrwxrwx 1 booker booker 7664 Mar 23 00:18 libcxm.so -rwxrwxrwx 1 booker booker 68 Mar 22 13:48 mod.c -rwxrwxrwx 1 booker booker 1240 Mar 22 22:00 mod.o -rwxrwxrwx 1 booker booker 68 Mar 22 22:10 mul.c -rwxrwxrwx 1 booker booker 1232 Mar 22 22:11 mul.o -rwxrwxrwx 1 booker booker 67 Mar 22 23:14 sub.c -rwxrwxrwx 1 booker booker 1232 Mar 22 23:51 sub.o -rwxrwxrwx 1 booker booker 496 Mar 22 13:48 testcal.c -rwxrwxrwx 1 booker booker 2736 Mar 22 22:00 testcal.o -rwxrwxrwx 1 booker booker 8544 Mar 23 00:23 testcxm
可以看到文件的大小为8544字节,在8k左右,比不打包成库大了一点点,不过要比静态库小很多。
从上面可以看到,Makefile文件的书写并不复杂,这个编辑的顺畅在于make的强大功能,而静态库和动态库的选择很重要,因为这两种库的空间大小相差很多。