5

我正在尝试使用模式规则编写一个生成文件来为多个源中的每一个生成多个输出文件。

我有以下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. 但是,运行makethen 不起作用:

$ 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
4

2 回答 2

3

防止 make 删除中间文件

我建议不要使用.PRECIOUS(原因见下文)。使用.SECONDARY将保留.out文件:

TARGETS=foo bar
all: $(TARGETS:=.all)

%.all: %.out
    @echo Made $*

%.out:
    touch $@

.SECONDARY: $(TARGETS:=.out)

$(TARGETS:=.all)只是附加.allTARGETS. $(TARGETS:=.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

失败!命令模拟一个在工作过程中崩溃的工具。这是一个使用上述 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

哎呀...我的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 直接尝试制作 bar。

.SECONDARY使之:

.SECONDARY 所依赖的目标被视为中间文件,除了它们永远不会自动删除。

这意味着它们永远不会因为它们是中间文件而被自动删除。如果重建目标的工具崩溃,则删除正在重建的目标的默认 make 行为不受影响。

使用.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 来测试它是否有效。该foo.all文件对 make 没有影响。

于 2013-11-10T16:22:00.623 回答
2

您的somefile.out文件被 GNU make 视为中间文件,这就是在您的示例中它们被自动删除的原因。.PRECIOUS您可以通过使用特殊目标来指示 GNU make 保留这些文件,如下所示:

%.all: %.out
    @echo Made $*

%.out:
    touch $@

.PRECIOUS: %.out
于 2013-11-10T01:35:07.757 回答