我正在尝试编写一个makefile,使用模式规则为多个源生成多个输出文件。
我有以下Makefile
(GNU Make 3.8.1):
all : foo.all bar.all
%.all : %.pdf %.svg
@echo Made $*
%.pdf :
touch $@
%.svg :
touch $@
.PHONY: foo.all bar.all
由于*.all
不代表实际的输出文件,我尝试将它们标记为.PHONY
。但是,运行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'.
似乎假装运行%.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 $@
我希望运行make somefile.all
使其创建文件somefile.out
,但会被删除:
$ make somefile.all
touch somefile.out
Made somefile
rm somefile.out
答案 0 :(得分:3)
我建议不要使用.PRECIOUS
(请参阅下面的原因)。使用.SECONDARY
会保留.out
个文件:
TARGETS=foo bar
all: $(TARGETS:=.all)
%.all: %.out
@echo Made $*
%.out:
touch $@
.SECONDARY: $(TARGETS:=.out)
$(TARGETS:=.all)
只需将.all
附加到TARGETS
中的所有姓名即可。 $(TARGETS:=.out)
追加.out
。我们显然无法将%.out
用作.SECONDARY
的目标。这些只是单独存放所有目标。
我更喜欢不使用.PRECIOUS
,因为the documentation says
如果make在执行配方期间被杀死或中断,则不会删除目标。
这可能会在文件系统中留下损坏的文件。这是一个例子。
all: foo.all bar.all
%.all: %.out
@echo Made $*
%.out:
sh -e -c 'echo "{1, 2, 3" > $@; FAIL!; echo "}" >> $@'
.PRECIOUS: %.out
失败!命令模拟在其工作过程中崩溃的工具。这是一个使用上面Makefile的shell会话:
$ 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
Yikes ...我的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
没有被重新制作(尽管有“Made foo”消息),因为它已经存在并且Makefile直接试图制作吧。
.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_all): %.all: %.out
$(TARGETS_all):
中,列出了可应用模式的目标列表。它使foo.all
和bar.all
显式目标成为可能。如果没有这个,它们将成为推断目标。
您可以通过在目录中创建名为foo.all
的文件来测试它是否有效,并运行make over over。 foo.all
文件对make没有影响。
答案 1 :(得分:2)
您的somefile.out
文件被GNU make视为intermediate,这就是为什么它们会在您的示例中自动删除的原因。您可以使用.PRECIOUS
特殊目标来指示GNU make保留这些文件,如下所示:
%.all: %.out
@echo Made $*
%.out:
touch $@
.PRECIOUS: %.out