命令
make命令实质上是一个单行shell脚本。实际的执行过程是:make先检查命令中是否有特殊字符(可能影响当前程序的行为),如果没有,就直接执行;如果有,就将其传递给subshell执行(使用fork/exec)。
make命令默认会交给/bin/sh
执行,这由SHELL
变量指定,出于可移植性的考虑,一般不建议修改。(不过改成bash还是可以接受的)
命令的解析
在工作目标之后,凡是第一个字符是tab的文本一律被视为命令(触发上一行结尾是反斜线)。因此,以tab开头的注释(# …)为shell注释,也会出现在console中。而以空格(无论多少个)开头的注释则为make注释,会被直接忽略。
make可以识别命令末尾的反斜线,已将其视为同一个命令,如:
1 | .INTERMEDIATE: file_list |
这里补充一点,上一篇中提到过.INTERMEDIATE生成的文件最后会被删除,但是如果运行make file_list,这个规则就不是中间过程,生成的文件也不会被删除。
再举一个cd的例子:
1 | TAGS: |
命令修饰符
修饰符 | 解释 |
---|---|
@ |
不要输出命令 |
- |
忽略命令中的错误 |
+ |
要求make执行命令,就算用户是以–just-print命令行选项来执行make的 |
错误与中断
使用--keep-going
或-k
选项可以让make编译完所有文件,以尽可能多的输出错误信息。在调试程序时,我们倾向于将复杂命令拆分成独立命令,而不是使用&&
,因为这样可读性强,make还能在错误发生时提供更多的信息。
在使用-k
选项运行程序时,如果命令出错导致一个文件没有被成功建立,而其时间戳已经被更新,那么随后的动作就会引用错误的数据,这时我们就可以使用.DELETE_ON_ERROR
来标记,表示一旦出错就删除该文件。参考第一篇。
当make的执行被信号中断时,如果文件被更改,当前工作目标文件就会被删除,这时可以使用.PRECIOUS
来保护该文件不被删除。
命令行大小有长度限制(32k~128k,因系统而异)。这里说的长度不是命令本身的长度,而是运行后的长度,比如在一个有几千个文件的文件夹里面执行ls。
递归式make
当使用make来编译一个大型项目时,可以先为每个目录编写一个简单的、各自独立的makefile,然后使用make来分别执行它们。
调试技术
warning函数
warning函数会被扩展成空字符串,所以它可以被放在任何地方输出变量。
命令行选项
–just-print, -n
使得make读进makefile并且输出将要执行的命令而不去执行它们
–print-data-base, -p
运行makefile,显示GNU版权信息以及make所运行的命令,然后输出它的内部数据库。这会打印出大量debug信息,比如当前变量、使用的模式等
–warn-undefined-variables
使得make在未定义的变量被扩展时显示警告信息
–debug选项
使用–debug=option选项,可以获得最详细的一个方法。有五个调试选项可选:(实际使用时可以简写为首字母)
调试选项 | 解释 |
---|---|
basic |
最不详细的基本调试功能,时–debug的默认选项 |
verbose |
除了basic,还提供了“哪些文件被分析、哪些必要添加不需要重建”等信息 |
implicit |
除了verbose,还提供了关于“为每个工作目标搜索隐含规则”的额外信息 |
jobs |
输出被make调用的子进程的细节,不会启用basic选项的功能 |
all |
启用前面所有的选项,使用-d时,启用的就是这个功能 |
此外还有一个修饰符:makefile
,即使用--debug=makefile
。这样做不会启用调试信息,直到makefile被更新。
系列导航