makefile用于定义并描述源文件之间的依赖关系,用于说明如何编译各个源文件并生成最终的可执行文件,规则是makefile中的基本组成部分。
一个最基本的依赖规则如下所示:
targets代表这个规则的目标,通常是需要生成的目标文件名,或者是make所需执行的命令名称,例如:all。prerequisites代表该规则的依赖,也即当前目标所依赖的其他目标或者文件。command为规则的命令即完成目标所要执行的命令,也叫动作,可以写为图中command1的形式,即和依赖写在同一行,和依赖之间通过分号隔开。也可以写成command2的形式,即写在依赖的下一行,并以tab键开头,tab字符告诉make解释器此行是一个命令行。可以使用续行符“”将内容分开写到下一行,提高可读性。
targets可以包含多个目标,使用空格对多个目标名进行分隔。prerequisites也可以包含多个依赖,通过空格对多个依赖进行分隔。
一个简单的makefile如下:
上图中,all目标依赖test目标,即需要test的存在,并执行echo "make all"命令才可以完成。而test目标没有依赖,只需要执行echo "make test"即可完成。
运行make命令,得到下图的结果,可以看到test目标先执行,然后才能执行all目标。小技巧:在命令之前加上@符号,可以不输出命令本身,使命令无回显,而只输出命令执行结果。
一个规则被执行需要满足以下条件中的一个:
1、当目标对应的文件不存在,执行对应的命令。
2、当依赖在时间上比目标更新,执行对应的命令。
3、当依赖关系连续发生时,对比依赖链上的每一个目标。
另一个makefile案例:
hello.out需要func.o和main.o文件的存在,并执行对应的命令才能完成。main.o依赖main.c,并执行相应命令才能完成。func.o依赖func.c,并执行相应命令才能完成。执行make后,输出如下所示,可见,只有main.o func.o子目标完成后,才能生成最终的目标hello.out。
修改func.c,再次执行make,输出如下,main.o没有被重新生成,而只有func.o和hello.out的目标对应的命令被执行了,因为main.o存在,且在时间上比 main.c更新,所以该目标对应的命令不会执行,无需重新生成。
将hello.out目标改为all,如下所示:
当我们再次执行make时,gcc -o hello.out main.o func.o,这句命令总会执行,即使依赖文件并没有更新,这是因为在当前目录下并没有一个叫all的文件存在,make在解析makefile时,发现当前路径下没有all文件,而这正符合三个条件中的第一个,因此,命令会被执行。解决技巧如下:
将hello.out和all目标写在一起,当执行make时,make解释器默认的目标是hello.out,当前目录下会存在hello.out文件,因此,当依赖不改变时,多次执行make命令也不会去更新最终的可执行文件了,而是给出文件是最新的提示,如下所示:
欢迎评论、指导以及进一步交流,QQ527635593
本文参考:
狄泰软件教学课件
gun make手册
专业嵌入式软件开发