举例说明Linux下make命令及makefile
笔者这几天正在学习linux基础,前几天碰到了make指令,以及如何编写makefile文件,听了老师的视频在自己写又总是报错,最后经过多次尝试和查阅资料终于解决了问题,下面给大家看一下我做的一道题目:
编写一个拥有main_jj.c,fun_jj.c ,head_jj.h的makefile工程,fun_jj实现一个求和函数,main_jj调用求和函数并将结果打印出来,头文件声明求和函数。若在main_jj中修改两个加数后,观察make命令的执行情况。 |
那么我就以这个题目为例,给大家介绍一下Linux下的make指令和makefile文件,如果各位大佬觉得我写的有不妥之处,欢迎大家在评论区留言,我会努力改正,给大家呈现最好的内容。
注意:笔者用的是Ubuntu18.04版本的,别的版本也大同小异。
首先我们来编写函数,为了不干扰主目录下面的文件和目录,我在主目录下新建了一个名为test的目录(mkdir test),下面我用ls命令查看了主目录下的内容,新建成功。
然后我进入到test目录里面(cd test),新建了四个文本文件(touch main_jj.c fun_jj.c head_jj.h makefile),分别是main_jj.c,fun_jj.c ,head_jj.h,makefile,然后再用ls命令查看,新建成功。
然后开始编辑文本文件main_jj.c,fun_jj.c ,head_jj.h,可以用vim编辑器,或者直接用gedit命令,下面是我写好并已经保存在文件里的内容:
//main_jj.c
#include<stdio.h>
int main()
{
int a=2,b=3;
fun(a,b);
return 0;
}
//fun_jj.c
void fun(int a,int b)
{
printf("a = %d\nb = %d\na + b = %d\n",a,b,a+b);
}
//head_jj.h
void fun(int a,int b);
下面来到了最重要的写makefile文件的时候了,我写的makefile文件的内容如下,咱们一句一句来解释。
my_result:fun_jj.o main_jj.o head_jj.h
gcc fun_jj.o main_jj.o head_jj.h -o my_result
fun_jj.o:fun_jj.c
gcc fun_jj.c -c
main_jj.o:main_jj.c
gcc main_jj.c -c
clear:
rm -f *.o
首先我们要知道,在写makefile文件的时候,有的行前面会空上一截,注意,这一截要用Tab键,不能用空格代替。
第一行中的my_result是我为程序编译后产生的可执行文件的文件名
看前两行:
my_result:fun_jj.o main_jj.o head_jj.h
gcc fun_jj.o main_jj.o head_jj.h -o my_result
这两行是说my_result这个文件是由fun_jj.o main_jj.o head_jj.h这三个文件产生的可执行文件,是怎么产生的呢?
噢!原来是执行gcc fun_jj.o main_jj.c head_jj.h -o my_result这一条命令产生的!
那么问题来了:
Ubuntu说:我怎么知道你这个fun_jj.o是怎么来的?快告诉我! |
我:好吧!我告诉你fun_jj.o文件是fun_jj.c编译但不链接来的!,fun_jj.c你直接在当前目录下自己找,找不到的话就报错告诉我,你只要乖乖的按我的指令做就好了,记住了,我给你的指令是:gcc fun_jj.c -c |
Ubuntu说:好吧,我执行gcc fun_jj.c -c了,哇,我生成了fun_jj.o!!!太神奇了,不可思议,我要继续执行指令gcc fun_jj.o main_jj.o head_jj.h -o my_result了。咦?这个 main_jj.o我也不知道怎么来的! |
我:你怕不是个傻子吧! |
我:我再告诉你一遍,同理,main_jj.o文件是main_jj.c编译但不链接来的!给你的指令是:gcc fun_jj.c -c |
Ubuntu说:懂了懂了,谢谢! |
…
通过我和Ubuntu的对话,大家应该知道,makefile文件里的内容就是告诉Ubuntu应该怎么做的,这个题目里面有一个我觉得很怪异的地方,就是文件head_jj.h,他只是一个函数的声明,我试过,如果把makefile文件的内容写成下面这个,结果是一样的:
my_result:fun_jj.o main_jj.o
gcc fun_jj.o main_jj.o -o my_result
fun_jj.o:fun_jj.c
gcc fun_jj.c -c
main_jj.o:main_jj.c
gcc main_jj.c -c
clear:
rm -f *.o
所以我觉得这个文件可写可不写,我们还是暂时把它写上吧。
写完了各个相互关联的语句之后,我们来看看最后的语句:
clear:
rm -f *.o
这两条语句,从rm -f *.o就可以看出,它是删除以.o结尾的文件,这个指令方便我们删去以.o结尾的指令,只需要执行make clear就行了。
下面俺来演示一下,现在命令行输入:
zhaole@zhaole-virtual-machine:~/test$ make my_result
gcc fun_jj.c -c
fun_jj.c: In function ‘fun’:
fun_jj.c:3:2: warning: implicit declaration of function ‘printf’ [-Wimplicit-function-declaration]
printf("a = %d\nb = %d\na + b = %d\n",a,b,a+b);
^~~~~~
fun_jj.c:3:2: warning: incompatible implicit declaration of built-in function ‘printf’
fun_jj.c:3:2: note: include ‘<stdio.h>’ or provide a declaration of ‘printf’
gcc main_jj.c -c
main_jj.c: In function ‘main’:
main_jj.c:5:2: warning: implicit declaration of function ‘fun’ [-Wimplicit-function-declaration]
fun(a,b);
^~~
gcc fun_jj.o main_jj.o head_jj.h -o my_result
再用ll命令查看一下(这里用ll更好,因为ll可以看到文件最后一次修改的时间)
总用量 44
drwxr-xr-x 2 zhaole zhaole 4096 2月 23 21:28 ./
drwxr-xr-x 18 zhaole zhaole 4096 2月 23 20:33 ../
-rw-r--r-- 1 zhaole zhaole 75 2月 21 19:06 fun_jj.c
-rw-r--r-- 1 zhaole zhaole 1592 2月 23 21:28 fun_jj.o
-rw-r--r-- 1 zhaole zhaole 23 2月 21 19:21 head_jj.h
-rw-r--r-- 1 zhaole zhaole 69 2月 21 20:00 main_jj.c
-rw-r--r-- 1 zhaole zhaole 1440 2月 23 21:28 main_jj.o
-rw-r--r-- 1 zhaole zhaole 177 2月 23 21:28 makefile
-rwxr-xr-x 1 zhaole zhaole 8368 2月 23 21:28 my_result*
果然,生成了.o文件
我们再打开my_result查看:
zhaole@zhaole-virtual-machine:~/test$ ./my_result
a = 2
b = 3
a + b = 5
此时我们改变main_jj.c里面a,b的值:
//main_jj.c
#include<stdio.h>
int main()
{
int a=11,b=9;
fun(a,b);
return 0;
}
再重复上面的指令:
zhaole@zhaole-virtual-machine:~/test$ make my_result
gcc main_jj.c -c
main_jj.c: In function ‘main’:
main_jj.c:5:2: warning: implicit declaration of function ‘fun’ [-Wimplicit-function-declaration]
fun(a,b);
^~~
gcc fun_jj.o main_jj.o head_jj.h -o my_result
zhaole@zhaole-virtual-machine:~/test$ ./my_result
a = 11
b = 9
a + b = 20
显然,a,b的值更新了,再用ll命令查看一下:
zhaole@zhaole-virtual-machine:~/test$ ll
总用量 44
drwxr-xr-x 2 zhaole zhaole 4096 2月 23 22:00 ./
drwxr-xr-x 18 zhaole zhaole 4096 2月 23 20:33 ../
-rw-r--r-- 1 zhaole zhaole 75 2月 21 19:06 fun_jj.c
-rw-r--r-- 1 zhaole zhaole 1592 2月 23 21:28 fun_jj.o
-rw-r--r-- 1 zhaole zhaole 23 2月 21 19:21 head_jj.h
-rw-r--r-- 1 zhaole zhaole 70 2月 23 21:59 main_jj.c
-rw-r--r-- 1 zhaole zhaole 1440 2月 23 22:00 main_jj.o
-rw-r--r-- 1 zhaole zhaole 177 2月 23 21:28 makefile
-rwxr-xr-x 1 zhaole zhaole 8368 2月 23 22:00 my_result*
敲黑板!!!
大家看两次ll命令main_jj.c,main_jj.o,my_result这三个文件的修改时间变了,而我只修改了main_jj.c中参数的值,出现这样的原因是因为Ubuntu会检测到和main_jj.c的修改时间是在main_jj.o之后的,就说明在生成main_jj.o之后,main_jj.c有改变了,所以说,也要修改main_jj.o。而在执行gcc fun_jj.o main_jj.o -o my_result的时候,Ubuntu又发现main_jj.o最后一次修改的时间在my_result之后,所以又对my_result进行了修改。
大家可以发现,使用makefile给我们免去了很多繁琐的步骤。
下面我们在不修改数值的情况下,第三次执行make my_result:
zhaole@zhaole-virtual-machine:~/test$ make my_result
make: “my_result”已是最新。
zhaole@zhaole-virtual-machine:~/test$ ./my_result
a = 11
b = 9
a + b = 20
显示已是最新!再用ll命令查看一下:
zhaole@zhaole-virtual-machine:~/test$ ll
总用量 44
drwxr-xr-x 2 zhaole zhaole 4096 2月 23 22:00 ./
drwxr-xr-x 18 zhaole zhaole 4096 2月 23 20:33 ../
-rw-r--r-- 1 zhaole zhaole 75 2月 21 19:06 fun_jj.c
-rw-r--r-- 1 zhaole zhaole 1592 2月 23 21:28 fun_jj.o
-rw-r--r-- 1 zhaole zhaole 23 2月 21 19:21 head_jj.h
-rw-r--r-- 1 zhaole zhaole 70 2月 23 21:59 main_jj.c
-rw-r--r-- 1 zhaole zhaole 1440 2月 23 22:00 main_jj.o
-rw-r--r-- 1 zhaole zhaole 177 2月 23 21:28 makefile
-rwxr-xr-x 1 zhaole zhaole 8368 2月 23 22:00 my_result*
显然,时间没有改变。
下面,我们来演示一下make clear的作用:
zhaole@zhaole-virtual-machine:~/test$ make clear
rm -f *.o
zhaole@zhaole-virtual-machine:~/test$ ll
总用量 36
drwxr-xr-x 2 zhaole zhaole 4096 2月 23 22:12 ./
drwxr-xr-x 18 zhaole zhaole 4096 2月 23 20:33 ../
-rw-r--r-- 1 zhaole zhaole 75 2月 21 19:06 fun_jj.c
-rw-r--r-- 1 zhaole zhaole 23 2月 21 19:21 head_jj.h
-rw-r--r-- 1 zhaole zhaole 70 2月 23 21:59 main_jj.c
-rw-r--r-- 1 zhaole zhaole 177 2月 23 21:28 makefile
-rwxr-xr-x 1 zhaole zhaole 8368 2月 23 22:00 my_result*
发现.o文件全部都没有了,makefile再一次给我们提供了方便!
好了,今天就写到这了,欢迎在评论区对不当的地方进行指正,一起进步。
对了,原创不易,最后如果觉得本文对你有帮助的话,请: