Makefile 为什么不触发虚假的隐式模式规则?

Makefile 为什么不触发虚假的隐式模式规则?,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'. mak

我有以下递归生成文件:

.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'
但将
%定义为虚假规则更符合逻辑:

.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'.
有人能给我解释一下原因吗(或者更好地告诉我制作文档)?

来自制作手册:

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

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

你可以通过另一种方式实现你想做的事情。试试这个:

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

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

你说得对,将细分规则定义为虚假规则更有意义。但不考虑伪目标的隐式规则,所以必须改写该规则。我建议如下:

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

GNU将要求的目标声明为
.PHONY
明确,这一点在其他答案中已经说明,这也提供了一些补救措施

在这个附加答案中,我想添加一个替代选项,在我测试时,它结合了“虚假”行为,即无论是否存在同名文件(它们被忽略),每次都会触发目标。另一种选择是:

.PHONY: phony_explicit

phony_explicit: 

%.subdir: phony_explicit
    $(MAKE) -C src $*
    $(MAKE) -C dict $*
它工作的前提是,虽然只有显式目标可以设置为.PHONY,但依赖于显式虚假目标的任何东西本身都继承了很多(据我所知)虚假属性。 一个隐式的,即模式匹配目标,如上面的
%.subdir
,就像将其添加到
.PHONY
(这是不可能的,因为它本身不是显式的),但通过其prerequesite PHONY
PHONY_explicit
,它却变得虚假

归根结底,每一条规则——也是通过模式匹配隐式的——其先决条件中都有一个显式的虚假目标(即添加到
.phony
)的目标——都是通过这种依赖关系以虚假的方式执行的(每次,无条件地,文件系统错误地拥有一个同名文件)

事实上,GNU make文档提到了
强制力
,在一些不提供
.PHONY
目标的GNU版本中,它部分模拟了
.PHONY
行为。这里介绍的替代方法使用此
FORCE
target方法,但由于使用了GNU make,因此它还将
FORCE
target设置为
.PHONY
,以避免与同名的实际存在的文件发生潜在冲突

使用此解决方案,即使是

touch clean.subir; make clean.subdir
将产生所需的

make -C src clean
make -C dist clean

此替代方案的潜在优点是,它不需要明确声明
clean.subdir
all.subdir
,而是使用隐式
%.subdir
模式匹配。

谢谢您的回答。我已经读过文档,所以如果你给我指出文档中的确切引用,我可以给你的答案打分。关于非虚假默认目标的更多建议是错误的。答案已更新,其中包含关于虚假规则和隐式目标的特定部分,以及解决问题的另一种方法。谢谢,现在看起来好多了。谢谢你的提示!很好。我宁愿稍微修饰一下,然后说
PHONY_TARGETS:=all clean
。PHONY:$(PHONY_TARGETS)$(addsuffix.subdir,$(PHONY_TARGETS))
找到了两个冒号目标/dep行的文档,如果有人感兴趣的话: