为什么.PHONY隐式模式规则没有被触发?

时间:2010-06-22 17:31:04

标签: makefile

我有以下递归makefile:

.PHONY: all clean

%.subdir:
    $(MAKE) -C src $*
    $(MAKE) -C dict $*

all: all.subdir

clean: clean.subdir

并且工作正常:

$ make all
make -C src all
make[1]: Entering directory `/or-1.3.6-fix/src'
make[1]: Nothing to be done for `all'.
make[1]: Leaving directory `/or-1.3.6-fix/src'
make -C dict all
make[1]: Entering directory `/or-1.3.6-fix/dict'
make[1]: Nothing to be done for `all'.
make[1]: Leaving directory `/or-1.3.6-fix/dict'

但将%.subdir规则定义为虚假更为合乎逻辑:

.PHONY: all clean all.subdir clean.subdir

现在让我停止工作:

$ make all
make: Nothing to be done for `all'.
$ make -d all
...
Updating goal targets....
Considering target file `all'.
 File `all' does not exist.
  Considering target file `all.subdir'.
   File `all.subdir' does not exist.
   Finished prerequisites of target file `all.subdir'.
  Must remake target `all.subdir'.
  Successfully remade target file `all.subdir'.
 Finished prerequisites of target file `all'.
Must remake target `all'.
Successfully remade target file `all'.
make: Nothing to be done for `all'.

有人可以解释一下为什么(或者更好地指出我制作文档)?

3 个答案:

答案 0 :(得分:22)

你是对的,将子网规则定义为PHONY会更有意义。但Make不考虑PHONY目标的隐含规则,因此您必须重写该规则。我建议如下:

SUBDIR_TARGETS = all.subdir clean.subdir
.PHONY: all clean $(SUBDIR_TARGETS) 

$(SUBDIR_TARGETS): %.subdir:
    $(MAKE) -C src $*
    $(MAKE) -C dict $*

all: all.subdir
clean: clean.subdir

答案 1 :(得分:9)

来自制作手册的this section

  

为.PHONY目标跳过隐式规则搜索(请参阅隐式规则)。这就是为什么将目标声明为.PHONY有利于提高性能,即使您不担心实际存在的文件。

因此,永远不会搜索隐式目标,因为它们是虚假的。

您可以通过其他方式实现您想要做的事情。试试这个:

SUBDIRS := all clean
.PHONY: $(SUBDIRS)

$(SUBDIRS):
    echo $(MAKE) -C src $@
    echo $(MAKE) -C dict $@

答案 2 :(得分:9)

GNU使得声明为.PHONY的必需目标明确已经在其他答案中说明,这也为此提供了一些补救措施。

在这个额外的答案中,我想添加一个替代品,当我测试时结合了“虚假”行为,即每次无论是否存在同名文件(都被忽略),都会触发目标。替代方案如下:

.PHONY: phony_explicit

phony_explicit: 

%.subdir: phony_explicit
    $(MAKE) -C src $*
    $(MAKE) -C dict $*

它的前提是,虽然只有明确的目标可以设置为.PHONY,但是依赖于明确的伪目标的任何东西本身都会继承很多(据我所知)虚假属性。 一个隐式的,即模式匹配目标,例如上面的%.subdir,就好像被添加到.PHONY一样(这是不可能的,因为它本身并不是明确的),但是通过它的先天假的虚假变成了假的{{ 1}}。

归结为每个规则 - 也通过模式匹配隐含 - 在其先决条件中具有明确的虚假目标(即添加到phony_explicit的目标)是通过这种依赖也以虚假的方式执行(每次,无条件地文件系统错误地拥有一个具有恰好名称的文件)。

实际上,GNU make文档提到了.PHONY target,在某些版本的GNU中,不提供FORCE目标会部分模仿.PHONY行为。此处提供的替代方法使用此.PHONY目标approuch,但由于使用了GNU make,它还将FORCE目标设置为FORCE,以避免与实际存在的同名文件发生潜在冲突。

使用此解决方案甚至

.PHONY

将产生所需的

调用
touch clean.subir; make clean.subdir

这个替代方案的潜在优点是它不需要明确声明make -C src clean make -C dist clean clean.subdir,但实际上是使用隐式all.subdir模式匹配。