Makefile模式规则要么忽略虚假规则,要么自动删除输出文件
我正在尝试编写一个makefile,使用模式规则为多个源中的每个源生成多个输出文件 我有以下Makefile模式规则要么忽略虚假规则,要么自动删除输出文件,makefile,wildcard,gnu-make,Makefile,Wildcard,Gnu Make,我正在尝试编写一个makefile,使用模式规则为多个源中的每个源生成多个输出文件 我有以下Makefile(GNU Make 3.8.1): 由于*.all不代表实际的输出文件,我尝试将它们标记为。但是,运行make则不起作用: $ ls Makefile $ make make: Nothing to be done for `all'. 根据make-d: No implicit rule found for `all'. Considering target file `foo.
Makefile
(GNU Make 3.8.1):
由于*.all
不代表实际的输出文件,我尝试将它们标记为。但是,运行make
则不起作用:
$ ls
Makefile
$ make
make: Nothing to be done for `all'.
根据make-d
:
No implicit rule found for `all'.
Considering target file `foo.all'.
File `foo.all' does not exist.
Finished prerequisites of target file `foo.all'.
Must remake target `foo.all'.
Successfully remade target file `foo.all'.
Considering target file `bar.all'.
File `bar.all' does not exist.
Finished prerequisites of target file `bar.all'.
Must remake target `bar.all'.
Successfully remade target file `bar.all'.
Finished prerequisites of target file `all'.
Must remake target `all'.
Successfully remade target file `all'.
make: Nothing to be done for `all'.
它似乎在假装运行%.所有的规则,但跳过主体
但是在注释掉.PHONY
行后,Make运行目标,但随后自动决定删除输出文件:
$ make
touch foo.pdf
touch foo.svg
Made foo
touch bar.pdf
touch bar.svg
Made bar
rm foo.pdf foo.svg bar.pdf bar.svg
根据make-d
,它说:
Removing intermediate files...
最小示例
给出异常行为的最小示例:
%.all: %.out
@echo Made $*
%.out:
touch $@
我希望运行makesomefile.all
使其创建文件somefile.out
,但它会被删除:
$ make somefile.all
touch somefile.out
Made somefile
rm somefile.out
GNU make会考虑您的somefile.out
文件,这就是在您的示例中自动删除这些文件的原因。您可以指示GNU make使用.PRECIOUS
特殊目标保存这些文件,如下所示:
%.all: %.out
@echo Made $*
%.out:
touch $@
.PRECIOUS: %.out
阻止make删除中间文件
我建议不要使用.PRECIOUS
(原因见下文)。使用.SECONDARY
将保留.out
文件:
TARGETS=foo bar
all: $(TARGETS:=.all)
%.all: %.out
@echo Made $*
%.out:
touch $@
.SECONDARY: $(TARGETS:=.out)
$(TARGETS:=.all)
只需将.all
附加到目标中的所有名称<代码>$(目标:=.out)
附加.out
。显然,我们不能将%.out
用作.SECONDARY
的目标。这样就不用单独重新列出所有目标
我不想用.PRECIOUS
来做这个,因为
如果make在其配方执行过程中被终止或中断,则不会删除目标
这会在文件系统中留下损坏的文件。这里有一个例子
all: foo.all bar.all
%.all: %.out
@echo Made $*
%.out:
sh -e -c 'echo "{1, 2, 3" > $@; FAIL!; echo "}" >> $@'
.PRECIOUS: %.out
失败!命令模拟在其工作中间崩溃的工具。下面是一个shell会话,使用上面的Makefile:
$ ls
Makefile
$ make
sh -e -c 'echo "{1, 2, 3" > foo.out; FAIL!; echo "}" >> foo.out'
sh: 1: FAIL!: not found
make: *** [foo.out] Error 127
$ cat foo.out
{1, 2, 3
哎呀。。。我的foo.out
文件不完整。让我们再试一次:
$ make
Made foo
sh -e -c 'echo "{1, 2, 3" > bar.out; FAIL!; echo "}" >> bar.out'
sh: 1: FAIL!: not found
make: *** [bar.out] Error 127
$ cat *.out
{1, 2, 3
{1, 2, 3
Make对于以前运行时留下的文件一点也不明智,因此当您再次运行Make时,它将按面值接收损坏的文件<代码>foo.out
没有重新生成(尽管有“makefoo”消息),因为它已经存在,并且生成文件直接尝试生成bar
.SECONDARY
使其能够:
.SECONDARY所依赖的目标被视为中间文件,只是它们不会自动删除
这意味着它们永远不会因为是中间文件而被自动删除。如果重建目标的工具崩溃,则删除正在重建的目标的默认生成行为不受影响
使用带有模式规则的.PHONY
似乎.PHONY
只适用于明确的目标,而不是推断的目标。我还没有找到证实这一点的文件。然而,这是可行的:
TARGETS:=foo bar
TARGETS_all:=$(TARGETS:=.all)
.PHONY: all
all: $(TARGETS_all)
.PHONY: $(TARGETS_all)
$(TARGETS_all): %.all: %.out
@echo Made $*
%.out:
touch $@
.SECONDARY: $(TARGETS:=.out)
在此规则中,$(TARGETS\u all):%.all:%.out
$(TARGETS\u all):
给出了可应用模式的目标列表。它使foo.all
和bar.all
成为明确的目标。如果没有这一点,它们将被推断为目标
您可以通过在目录中创建名为foo.all
的文件并反复运行make来测试它是否工作。foo.all
文件对make没有影响。我只能猜测.PHONY
需要明确的目标。我已经用我的发现更新了我的答案。@Louis我们显然不能使用%.out作为.SECONDARY的目标。似乎是对我的答案的另一个确认,这是双冒号target/dep行的文档:这个问题是的重复,尽管不明显。阅读关于使用.PHONY
匹配模式规则的回答。
TARGETS:=foo bar
TARGETS_all:=$(TARGETS:=.all)
.PHONY: all
all: $(TARGETS_all)
.PHONY: $(TARGETS_all)
$(TARGETS_all): %.all: %.out
@echo Made $*
%.out:
touch $@
.SECONDARY: $(TARGETS:=.out)