我有一个如下所示的目录结构:
$ tree
.
|-- dir
| `-- subdir
| `-- data
`-- makefile
其中data
是一个文件。我的makefile
看起来像这样:
all: dir/analysis
.SECONDEXPANSION:
%/analysis: %/subdir
%/analysis: $(addsuffix /data, $$^)
@echo TARGET: $@ DEPS: $^
touch $@
当我运行make
时,我希望结果如下:
TARGET: dir/analysis DEPS: dir/subdir/data dir/subdir
touch dir/analysis
相反,它只是报告
make: *** No rule to make target `dir/analysis', needed by `all'. Stop.
如果我将第一条规则更改为dir/analysis: dir/subdir
,那么它会按预期工作。因此我怀疑make
忽略了第一条规则,并在第一条规则为%/analysis: %/subdir
时直接跳到第二条规则。当两个规则都以dir/analysis
作为目标而不仅仅是第一个规则时,它也可以按预期工作。 MadScientists对另一个问题here的回答似乎适用于我的问题。我尝试添加像
dummy_target: dir/subdir
mkdir -p dir/subdir
和
dir/subdir:
mkdir -p dir/subdir
到makefile
的末尾,试图使第一个规则的依赖关系成为一个明确的目标,但这并没有改变任何东西。我对make
很陌生,所以我可能错过了一些非常愚蠢的东西,但我不能为我的生活弄清楚。如何按照他们编写的顺序执行第一条和第二条规则?如果重要的话,我使用Make 3.81版。
- 编辑 -
如果我实际在第一条规则之后添加命令,例如@echo RULE 1
,则该命令执行而不是第二条命令。
答案 0 :(得分:5)
我认为您了解makefile:
# Original
all: dir/analysis
.SECONDEXPANSION:
%/analysis: %/subdir
%/analysis: $(addsuffix /data, $$^)
@echo TARGET: $@ DEPS: $^
touch $@
像这样:
dir/analysis
/analysis
取决于 /subdir
。所以
这使dir/subdir
成为dir/analysis
/analysis
取决于我们得到的东西
后缀为/data
/analysis
的先决条件。 (中学
扩展$$^
为我们提供了目标的先决条件)。和
因为dir/analysis
的先前先决条件是dir/subdir
,现在就是dir/subdir dir/subdir/data
使dir/analysis
成为TARGET: dir/analysis DEPS: dir/subdir/data dir/subdir
touch dir/analysis
的新先决条件。因此配方的输出应该是:
# A
xx: xa
xx: xb
xx: xc
touch $@
这种理解是非常错误的。您混淆并混淆了操作 模式规则与操作或普通规则的关系。
如果makefile说,例如:
# B
xx: xa
xx: xb
%x: %c
touch $@
甚至:
xx
然后组合目标xx
的所有空规则的先决条件
当# A
被视为目标时,使用(一)非空规则。所以
xx: xa xb xc
touch $@
相当于:
# B
和xx: xa xb
%x: %c
touch $@
相当于:
xx
并且在这两种情况下xa xb xc
的先决条件都是%x: %a
%x: %b
touch $@
。
然而:
%x: %a %b
touch $@
等同于:
.SECONDEXPANSION:
%/analysis: %/subdir
%/analysis: $(addsuffix /data, $$^)
@echo TARGET: $@ DEPS: $^
touch $@
如果您编写了一个空的模式规则,其效果就是删除 具有相同目标和先决条件模式的任何先前模式规则。如果你 永远写一个非空模式规则,你只需替换 具有相同目标和先决条件模式的任何先前模式规则。看到 10.5.6 Canceling Implicit Rules
所以:
.SECONDEXPANSION:
%/analysis: $(addsuffix /data, $$^)
@echo TARGET: $@ DEPS: $^
touch $@
相当于:
dir/analysis
然后,当考虑$^
的此模式规则时,
有没有之前的先决条件:$$^
将扩展为空字符串,并且
在二次扩展中,# Residual
%/analysis: /data
@echo TARGET: $@ DEPS: $^
touch $@
也是如此。所以最后的配方相当于:
# Original
您可以通过运行# Residual
和{{}}来满足自己的需求
-d
makefile在调试模式下(make: *** No rule to make target 'dir/analysis', needed by 'all'. Stop.
)并比较输出。
这解释了为什么两种情况下的输出都得出结论:
/data
模式规则只会被实例化以制作目标,如果这样做可以为目标提供方法。为什么还要选择它?由于先决条件make foo.o
不存在,因此模式规则
是不可行的,被丢弃了。就像你用makefile尝试%.o: %c
touch $@
:
foo.c
目录中没有.PHONY: all clean
all: dir/analysis
%/analysis: %/subdir %/subdir/data
@echo TARGET: $@ DEPS: $^
touch $@
clean:
rm -f dir/analysis
。
如果你真的想看到你期望的输出,那么你可以从:
获得它%/analysis: %/subdir/data
但很难相信这是你真正想要看到的。这个makefile 使分析依赖于数据,也取决于目录所在的位置 数据驻留。有什么意义呢?
dir/subdir
可能表达了数据与分析之间的理想关系: -
通过使touch dir/subdir
成为一个独立的先决条件,你所实现的就是引入
如果分析变得比中的目录更旧,则需要重新制作分析
数据所在的 - 无论数据如何。所以如果,例如,我跑make
,
这需要make
重新运行分析,即使数据没有改变。
我只能通过假设来理解你的动机
现实你还希望.PHONY: all clean
all: dir/analysis
.SECONDARY:
%/subdir:
mkdir -p $@
%/subdir/data: | %/subdir
touch $@
%/analysis: %/subdir/data
@echo TARGET: $@ DEPS: $^
touch $@
clean:
rm -f dir/analysis dir/subdir/data
制作数据,以及它所在的目录,如果
当需要分析时,它们不存在。如果那就是那种情况
你想要一个makefile:
%/subdir/data: | %/subdir
这里,模式规则:
%/subdir
使%/subdir/data
成为order-only prerequisite
/dir/subdir
。这意味着在确定/dir/subdir/data
是否需要时,/dir/subdir/data
不被视为
要制作,但如果确定要制作/dir/subdir
,则首先制作/dir/subdir
。这个
方式,.SECONDARY
将被创建,如果它不存在,当你需要它将数据放在那里,但没有影响
是否需要进行数据或分析。
特殊目标make
是technicality。它指示make
不自动删除任何后续目标
它推断出来自链式模式规则的中间人工制品。没有它,在这个例子中dir/subdir/data
会推断出dir/subdir/
和dir/analysis
只是制作dir/subdir/data
的废品并自动删除它们
在末尾。
如果您最初运行此makefile而没有dir/subdir/
而没有$ make
mkdir -p dir/subdir
touch dir/subdir/data
TARGET: dir/analysis DEPS: dir/subdir/data
touch dir/analysis
,则会获得:
$ make clean
rm -f dir/analysis dir/subdir/data
$ make
touch dir/subdir/data
TARGET: dir/analysis DEPS: dir/subdir/data
touch dir/analysis
随后:
$ make
make: Nothing to be done for 'all'.
$ touch dir/subdir
$ make
make: Nothing to be done for 'all'.
然后:
{{1}}