目录
1.为什么要使用make
假设我们的执行文件里面包含2个源文件,分别是main.c , test.c ,
如果想要这个程序运行起来,那么就需要先编译:
# 先对源文件进行编译,产生test.o,main.o文件
[sjp@iZwz97d32td9ocseu9tkn4Z ~]$ gcc -c test.c
[sjp@iZwz97d32td9ocseu9tkn4Z ~]$ gcc -c main.c
# 将test.o main.o文件进行链接,将生成的可执行程序文件定为mytest
[sjp@iZwz97d32td9ocseu9tkn4Z ~]$ gcc test.o main.o -o mytest
[sjp@iZwz97d32td9ocseu9tkn4Z ~]$ ./mytest <==> 执行可执行文件 结果如下
hello sjp
hello sjp
hello sjp
hello sjp
hello sjp
hello sjp
编译过程需要进行好多操作,如果有更多的源文件,那么我们就需要输入更多 gcc -c 源文件 的操作,而且如果要对源文件进行重新编译,则上诉的操作需要在操作一遍,光是要找出这些命令就够烦人了,那么有没有一个步骤就完成上面所有操作?make就可以帮我们完成以上所有的操作。
我必须先说明的是make是一条命令。makefile文件。
要想使用make这条命令,就需要在当前目录下创建一个makefile或者Makefile文件,内容如下:
1 mytest:main.o test.o
2 gcc -o mytest main.o test.o # 前面的空格必须以【Tab】键开头
3
4 main.o:main.c
5 gcc -c main.c
6 test.o:test.c
7 gcc -c test.c
当我们执行make指令后,make会去当前目录下去找makefile或Makefile文件,并根据makefile或Makefile中的内容去执行相关的命令
[sjp@iZwz97d32td9ocseu9tkn4Z ~]$ make
gcc -c main.c
gcc -c test.c
gcc -o mytest main.o test.o
# 不修改源文件中的任何内容,再执行make指令,则不会再继续对源文件进行编译
[sjp@iZwz97d32td9ocseu9tkn4Z ~]$ make
make: `mytest' is up to date.
我们只写了mytest需要的目标文件,结果make会主动的去判断每个目标文件相关的源代码文件,并直接进行编译,最后在执行链接的操作。
编译完成后,如果我们再去修改源文件中的代码,那么make会主动的去判断哪一个源目标文件被修改了,并仅重新编译该文件, 如此这样,可以节省很多的编译时间,某些程序在进行编译操作时,会消耗很多的cpu资源。
例如:我们将test.c中的代码修改了一下,那么我们在执行一次make命令,则只会重新编译更新test.c文件产生test.o文件,不会对main.c文件进行重新编译,最后再将main.o和test.o重新链接,
[sjp@iZwz97d32td9ocseu9tkn4Z ~]$ make
gcc -c test.c
gcc -o mytest main.o test.o
执行make命令后,没有将main.c重新编译。
总结make的好处:
- make可以简化编译所需要执行的命令。
- 若在编译完成后,修改了某个源文件中的内容,我们再执行make命令,则make只会去编译更新那个被修改的源文件,其它的目标文件不会被修改。
- 最后可以依照依赖性来更新执行文件
2.makefile的基本语法与变量
基本的makedile规则:
目标:依赖文件列表
<Tab>依赖方法
第一行 为依赖关系。
例如;
1 mytest:main.o test.o
2 gcc -o mytest main.o test.o # 前面的空格必须以【Tab】键开头
mytest:main.o test.o 是依赖关系
上面中的第一行中的mytest是目标,main.o test.o是依赖文件
gcc -o mytest main.o test.o 是生成mytest文件的方法,也就是依赖方法。
mytest依赖main.o和test.o的链接才能生成mytest。
如果我们想要一个命令直接清理掉所有的目标文件(.o文件)与执行文件(.exe文件),那么我可以需要建立clean目标,如下:
1 mytest:main.o test.o
2 gcc -o mytest main.o test.o
3
4 main.o:main.c
5 gcc -c main.c
6 test.o:test.c
7 gcc -c test.c
8
9 .PHONY:clean
10 clean:
11 rm -f test.o main.o mytest
其中.PHONY是修饰clean的,使clean可以一直重复使用,当然.PHONY:clean去掉也是可以的。
当我们要将生成的test.o main.o mytest删掉时,用make clean命令即可。
[sjp@iZwz97d32td9ocseu9tkn4Z ~]$ make clean
rm -f test.o main.o mytest
在makefile文件中重复的变量有很多,那么我们是否可以将它们简化呢?
例子;
1 mytest:main.o test.o
2 gcc -o mytest main.o test.o
上面的命令可以改成:
1 mytest:main.o test.o
2 gcc -o $@ $^
$@:表示目标,代表上面的 mytest
$^:表示依赖文件列表中的所有依赖文件。代表上面的 main.o test.o
当我们执行make,效果是一样的,如下:
[sjp@iZwz97d32td9ocseu9tkn4Z ~]$ make
gcc -c main.c
gcc -c test.c
gcc -o mytest main.o test.o
使用$^好处:
如果是依赖文件列表中有几十个文件甚至更多,那么在依赖方法中直接使用$^可以直接取代依赖文件列表中所有的文件,不需要将所有的依赖文件一 一列出来 所以使用$^是非常方便的。
使用$^和$@的好处:
如果我们修改(删除,添加)依赖关系中的目标或依赖列表中的依赖文件时,我们可以不用修改(删除添加)依赖方法中的文件。
make和makefile说完之后,我们还需要解决一个问题。
问题:
我们知道,生成可执行文件有两种方法:
方法一;将源文件进行编译并链接形成可执行文件,没有保存其中的编译产生的目标文件(.o文件)。如下;
gcc main.c test.c -o mytest 直接将main.c和test.c文件编译并链接形成mytest文件,没有保存其中编译产生的目标文件(.o文件)
方法二:将源文文件进行编译产生目标文件,将它保存下来,然后再将目标文件进行链接。
gcc -c test.c
gcc -c main.c
gcc test.o main.o -o mytest
先将test.c main.c 编译产生目标文件(.o文件),然后再将目标文件进行链接。
请问方法二相对于方法一有什么优势?
方法二是将编译生成的目标文件给保存起来,我们生成可执行文件时,将目标文件链接起来,如果我们其中有一个文件修改了代码后,我们只需要
对被修改的源文件进行编译即可,不用再将所有的源文件进行编译。例如:如果有一个项目有100多个源文件,如果我们将它编译链接后
形成可执行程序后,发现功能并没有符合我们的预期,我们在将其中的几个源文件进行修改,那么我们只需要对那几个被修改的源文件再进行编译即可。
而方法一由于没有保存相关的目标文件,就需要将所有的源文件进行再一次编译。而将所有的源文件在一次编译可能需要等上几个小时等,所以为了能减少时间,我们在编译的时候需要将其目标文件进行保存。
好啦,今天的分享就到这里了,如果这篇文章帮到你的话,记得给笔者一个赞哦,关注我,我将不断分享知识出来,感谢你的支持。
记得点个赞哦(●'◡'●)。