很多linux新手经常是直接用gcc/g++命令来编译程序的,因为对于linux新手,他们的源文件数目少得可怜,他们仅仅用gcc/g++也是可以的,但通常一个项目是拥有非常多的源文件的,而这些源文件直接也有着复杂的关系(编译的先后顺序等),如果此时仍然用gcc/g++命令来直接编译的话,那将会是一个极其痛苦的事情。
make是一条命令,makefile是一个文件。
执行make命令时,makefile会告诉make命令以什么样的规则来编译程序。
而makfile文件里的内容(也就是编译规则),是需要我们自己来写的!
来一个简单的例子:
这里有四个文件:makefile、add.h、add.c、main.c
makefile里编写了编译add.c、main.c的规则
接下来,我们只需要执行一条命令make,即可完成makefile里的编译规则。
现在我们再回想一下,如果不用make/makefile的话,我们是如何编译这两个源文件的呢?
我们应该是用gcc -o main main.c add.c 这一条命令来编译的。如果我们想要编译十次,我们就需要输入十次这样的命令,但如果有了make/makefile,我们只需要十次make。如果来一百个源文件,并且编译十次,我们直接用gcc会极其的麻烦,但是make仍然只需要十次就ok。
看到这里,想必大家已经认识到了make/makefile的重要性!
target ...:prerequisites ...
command
...
...
target是一个目标文件,prerequisites是生成target所需要的文件,commmand是make所需要执行的命令(shell命令)。
而这就是一种依赖关系:target依赖于prerequisites,而生成target的规则(命令)定义在command中。
值得注意的是:如果prerequisites中如果存在一个文件的时间要比target新,则command才能够执行。
看下面例子:
当main已存在,并且main比main.c、add.c时间都要新的话,makefile中的command是无效的。
那么我们如何证实呢?
可以看到,main的modify时间是要比main.c、add.c的modify时间要新的,然后执行make的时候出现提示。
那么我们现在改一下main.c的modify时间(需要对main.c里的文本内容作修改),看看会发生什么。
我们打开文件,在里面添加了若干行空格,就改变了main.c的modify时间,导致main.c的modify时间比main的要新,所以后续执行make命令时能够执行成功。
这里有一个疑问,那就是要比较target和prerequisites的日期新旧,为什么只比较modify时间?
因为modify时间只有修改了文件里的内容时,才会跟着改变。
执行make时,会默认执行makefile里的第一个target。当第一个target成功生成(执行)之后,则停止下面的规则。如果当生成第一个target时发现所需的依赖文件不存在,则按从上到下的顺序依次执行规则直到找到依赖文件使得第一个target生成成功。
直接执行make时,会为了makefile里的第一个target而从上往下寻找依赖文件。那么如果我们不想生成第一个target呢?假设我们这里只想生成add.o,该怎么办?这时我们需要make加上我们要生成(执行的)那个target。
看上图,我们只想生成main.o,所以我们make main.o,而main.o的依赖文件是不存在的,所以向下寻找,直到生成main.o停止,所以也并没有执行makefile里面的add.o add.s add.i等操作。
上面我们说过target和prerequisites会根据modify的时间新旧来决定是否执行command。
那么为什么要这样做呢?
这是因为,根据prerequisites而生成的target没必要再次编译生成,并且大型项目编译的时间是很长的,只有当prerequisites发生变化时target才需要再次编译生成最新的。
那么如果我们就是想要每次重新编译生成target而不受时间新旧的约束,这时该怎么做呢?我们可以给target前面修饰一个.PHONY
,经过.PHONY
修饰的名词就变为来伪目标,该目标下的command每次都可以执行而不受时间约束。