参考资料:GNU make
recipe语法
makefile有一个不同寻常的特性,即在一个文件中实际上有两种不同的语法。
大多数makefile使用make语法,但recipe是由shell解释的,因此使用shell语法编写。make程序并不试图理解shell语法:在将recipe交给shell之前,它只对recipe的内容执行很少的特定翻译。
recipe中的每一行都必须以制表符开头,除了recipe的第一行除外,该行可以附加到目标和先决条件行,中间使用一个分号。
recipe 回显
通常情况下,make会在执行之前打印recipe 的每一行,称为回显(echoing),因为它给人的感觉是自己在输入这些行。当一行以@
开头时(在制表符后),该行的回显将被抑制,@
在该行传递给shell之前被丢弃。
当给make设置-n
或--just-print
标志时,它只回显大多数recipe,而不执行它们;在这种情况下,即使是以@
开头的recipe行也会被打印出来。这个标志有助于找出哪些recipe是必要的,而不需要实际去执行它们。-s
或--silent
标志防止所有的回显,就好像所有的recipe都以@
开头一样;在makefile中为特殊的目标.SILENT
设置一条不带先决条件的规则也有同样的效果。
recipe的执行
当需要执行recipe来更新目标时,它们将通过为recipe的每一行调用新的子shell来执行,除非.ONESHELL
特殊目标在生效。这意味着,设置shell变量和调用shell命令(例如cd
)在每个进程的本地设置内容,不会影响recipe中的后续行。
recipe中的错误
每次shell调用返回后,make查看其退出状态:如果shell成功完成(退出状态为0),recipe中的下一行将在新的shell中执行,当最后一行结束后,规则也就结束了。如果出现错误(退出状态是非零),则放弃当前规则,也许还放弃所有规则。
有时,某个recipe行失败并不表明有问题。例如,使用mkdir
命令来确保目录存在。如果该目录已经存在,mkdir
将报告一个错误,但我们希望make不管怎样都继续。
要忽略recipe行中的错误,请在该行文本的开头(在初始制表符之后)写一个-
。在将行传递给shell执行之前,-
将被丢弃。例如,下面的规则中,即使rm
不能删除一个文件,make也会继续执行。
clean:
-rm -f *.o
当使用-i
或--ignore-errors
标志运行make时,所有规则的所有recipe中的错误都会被忽略。如果没有先决条件,则makefile中针对特殊目标.IGNORE
的规则也有同样的效果。
打断或终止make
如果make在shell执行过程中收到一个致命信号(a fatal signal),它可能会删除recipe本应更新的目标文件。如果目标文件的最后修改时间在make第一次检查之后发生了变化,则执行此操作。