编译一个程序不是你所要编写规则的唯一目的。
makefiles通常除了编译一个程序之外还说明了如何做一些其他事情:
例如,如何删除所有的目标文件以及可执行文件,以至于目录是清空的。
这里是我们如何编写一个make规则去清空我们的示例编辑器。
clean:
\t rm edit $(objects)
实践中,我们可能想要用一种稍微复杂一些的方式编写规则来处理未曾预料的情况。
我们可以如下:
.PHONY : clean
clean:
\t -rm edit $(objects)
这样不会让make因为有一个真正的叫做clean的文件而困惑,也不会导致make继续进行
而不管rm产生的错误。
像这样的这个规则不应该被放在makefile的起始处,因为我们不想要默认地方式运行它。
因此,在这个示例makefile中,我们希望edit的规则,保持为默认的目标。
因为clean不是edit文件的一个先决条件,这条规则不会运行,如果我们不带参数而运行make的话。
为了使得规则运行,我们必须输入make clean。
告诉make如何编译一个系统的信息来自于读取一个叫做makefile的数据库。
makefiles包含了5种东西,显式规则,隐式规则,变量定义,指令和命令。
规则,变量和指令后续章节会详细描述。
- 一个显式规则指示何时以及如何重新编译一个或多个文件,叫做规则的目标。
它列出了目标所依赖的其他的文件,叫做目标的先决条件,并且也给出了一个处方去用来创建和更新目标。
- 一个隐式规则指示何时以及如何重新编译一类文件基于他们的名字。
它描述了目标可能如何依赖一个类似于目标的名称的文件,并且给出了一个创建和更新这个目标的处方。
- 一个变量定义是一个为一个变量指定一个文本字符串的行,这个变量在后续的文本可以被替代。
这个简单的makefile示例展示了一个objects变量定义作为一系列的目标文件。
- 一个指令时一个让make在读取makefile的时候做一些特殊的事情的指令。
这包括了:
-
读取其他makefile
-
决定是否使用或者忽略makefile中的一部分
-
从一个包含多行的字面字符串定义一个变量。
-
在一行中的#表示注释的开始。它以及它后面的部分都被忽略,除了没有被另外的反斜杠所转义的反斜杠将会
继续跨行注释。
只包含一个注释的行事实上是空白,并且被忽略掉。
如果你想要一个#字符,可以用反斜杠转移它。
注释可能存在于makefile的所有地方,尽管他们在特定的情况被特殊地对待。
你不能使用带有变量引用或者函数调用的注释:
任何#的实例将会被字面对待,如果#在一个变量引用或者函数调用中。
在处方中的注释将会被传递给shell中,就像其他处方文本一样。
shell决定如何转译它:它是否是一个注释取决于shell。
在一个定义指令中,在变量定义阶段,注释不能被忽略,而是保持变量的值不变。
当变量被扩展时,他们将会被或者作为make注释或者作为处方文本,取决于变量被评估的上下文。
makefiles使用“基于行”的语法,在这个语法中,新行这个字符是特殊的,并且标志着一个语句的结束。
GNU make没有对一个语句行的长度做限制,取决于你的而电脑的内存数量。
然而,阅读很长且没有折叠或者滚动的行是很困难的。
因此,你可以将你的makefile格式化为可读性好的,方式是在行的中间增加新行:
你可以通过“\”转义内部换行符的方式来实现。
我们将物理换行表示makefile中的换行符表示,而逻辑换行表示一个语句的换行。
反斜杠和换行符的组合的处理方式取决于该语句是否是一个处方行或者是非处方行。
在一个处方中的反斜杠和换行符的处理方式后续在讨论。
在处方行之外,反斜杠以及换行符只表示空格。
一旦完成,所有的在反斜杠和换行符周