make 错误被忽略为哪般?

在使用 make 编译时常常出现类似这样的提示:

make[6]: [copyapi] Error 1 (ignored)

找到目标 copyapi 的定义,发现使用了 $(RM)$(CP) 两个变量,而这两个变量定义如下:

RM               = -@rm -f
CP               = -@cp

rmcp 两个命令前都加了减号(-),表示忽略错误(加 @ 表示不打印命令本身)。

在学习 makefile 时一定学过命令前加减号表示忽略错误,但看到 Error 1 (ignored) 这样的提示时,却没有想到是什么原因导致的,逆向思维有待提高。

看看 GNU make 手册 5.5 Errors in Recipes 对此的描述:

After each shell invocation returns, make looks at its exit status. If the shell completed successfully (the exit status is zero), the next line in the recipe is executed in a new shell; after the last line is finished, the rule is finished.

If there is an error (the exit status is nonzero), make gives up on the current rule, and perhaps on all rules.

Sometimes the failure of a certain recipe line does not indicate a problem. For example, you may use the mkdir command to ensure that a directory exists. If the directory already exists, mkdir will report an error, but you probably want make to continue regardless.

To ignore errors in a recipe line, write a ‘-’ at the beginning of the line’s text (after the initial tab). The ‘-’ is discarded before the line is passed to the shell for execution.

When errors are to be ignored, because of either a ‘-’ or the ‘-i’ flag, make treats an error return just like success, except that it prints out a message that tells you the status code the shell exited with, and says that the error has been ignored.

而在调用 make 时传入 -i--ignore-errors 标志将忽略所有的错误,没有前置条件的特殊目标 .IGNORE 也具有同样效果。但使用 - 具有更好的扩展性。

上述特性需要与另一标志 -k--keep-going 区别开来。-k 并不会忽略遇到的错误,而是继续其它目标的编译,直到所有目标都执行之后再返回错误。这有助于一次性发现所有错误、做出相应修改并再次编译。这也是 Emacs 的 compile 命令默认使用 -k 标志的原因。

最后需要注意的是,即使编译出现错误,目标文件的时间戳还是会更新。假如源文件没有修改就再次编译,出错的目标文件将不会更新,也就是不会重新编译。此时需要手动删除此目标文件再次编译解决,也可通过增加 .DELETE_ON_ERROR 目标实现自动删除的目的。

关于 @ 符号可参考 5.2 Recipe Echoing 的描述。


comments powered by Disqus