Makefile 的一个陷阱
前言(Intro)
问题是这样的,我写了一个 Makefile,大致内容如下,
1 |
|
然而执行 make b
却只打印出 b
;
执行 make c1
的结果却是 make: Nothing to be done for 'c1'
。
为何会无法执行 c1 和 c2?!
找原因
Nothing to be done for
的出现,有可能是因为没有可执行的命令。
但在这里似乎不是这个问题。
为了寻找这个问题,我从最简单的写法开始推:
1 |
|
1 |
|
正常。
1 |
|
1 |
|
正常。
1 |
|
1 |
|
正常。
1 |
|
1 |
|
不正常。
跟之前的相比,变化的是 .PHONY
中添加了 c1 和 c2 项。这个问题一定跟 .PHONY
相关。
原因
参见 GNU - makefile。有这么一行:
The implicit rule search (see Implicit Rules) is skipped for .PHONY targets. This is why declaring a target as .PHONY is good for performance, even if you are not worried about the actual file existing.
所以,当用 %
这种使用通配符的规则(即 Implicit Rule),只要对应的实际项存在于 .PHONY
中,这条规则就会被跳过。
读文档不仔细,就容易踩到坑。
Makefile:怪我咯?
其他
在调试的过程中,还发现其他几点需要注意的地方。
一、
我用 $(warning)
来打印调试变量,奇怪的是在先决条件 (prerequisites) 中使用 warning 无法打印出 % 的值。
比如
1 |
|
make a.c
打印出的是 Makefile:1: %.o
,然而去掉 warning,实际上 make a.c
是可以执行到 %.o
里的命令的。
我猜可能是 a.c
对应的值还没映射到 %, warning 就打印了。或者因为 % 是个特殊的变量,从而 warning 无法打印。具体没有研究过,瞎猜的。
二、
1 |
|
这里虽然 b 不在 .PHONY 里,但是 make b
依然可以无限次执行。原因在于 c 是伪命令,会影响到 b。
只要把 c 从 .PHONY 中去掉,执行 make b
(已经存在 b 文件的情况下),就会得到 make: 'b' is up to date.
的提示。
所以写 Makefile 的时候要注意链式依赖里有没有依赖伪命令,以此提高执行效率。