Makefile模式规则要么忽略虚假规则,要么自发删除输出文件 [英] Makefile pattern rule either ignores phony rule or spontaneously deletes output file

查看:145
本文介绍了Makefile模式规则要么忽略虚假规则,要么自发删除输出文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to write a makefile to produce several output files for each of several sources, using pattern rules.

我有以下Makefile(GNU Make 3.8.1):

I have the following 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不代表真实的输出文件,因此我尝试将其标记为

Since *.all do not represent real output files, I tried marking them as .PHONY. However, running make then doesn't work:

$ 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规则,但跳过了正文.

which seems to be pretending to run the %.all rules, but skipping the bodies.

但是在注释掉.PHONY行的情况下,Make运行目标,但随后自发决定删除输出文件:

But with the .PHONY line commented out, Make runs the targets, but then spontaneously decides to delete the output files:

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

最小示例

给出异常行为的最小示例:

Minimal example

A minimal example giving anomalous behavior:

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

%.out:
    touch $@

我希望运行make somefile.all使其创建文件somefile.out,但它会被删除:

I expect running make somefile.all to cause it to create the file somefile.out, but it gets deleted:

$ make somefile.all
touch somefile.out
Made somefile
rm somefile.out

推荐答案

保持删除中间文件的作用

我建议不要使用.PRECIOUS(有关原因,请参见下文).使用.SECONDARY将保留.out文件:

Keeping make from deleting intermediary files

I recommend against using .PRECIOUS (see below as to why). Using .SECONDARY would preserve the .out files:

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

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

%.out:
    touch $@

.SECONDARY: $(TARGETS:=.out)

$(TARGETS:=.all)只是将.all附加到TARGETS中的所有名称. $(TARGETS:=.out)附加.out.我们显然不能将%.out用作.SECONDARY的目标.这些只是省去了重新列出所有目标的麻烦.

$(TARGETS:=.all) just appends .all to all names in TARGETS. $(TARGETS:=.out) appends .out. We apparently cannot use %.out as a target of .SECONDARY. These just save having to relist all targets individually.

我宁愿不使用.PRECIOUS,因为 the文档说

如果make在执行其食谱期间被杀死或中断,则不会删除目标.

if make is killed or interrupted during the execution of their recipes, the target is not deleted.

这可能会将损坏的文件保留在文件系统中.这是一个例子.

This can leave corrupted files in the file system. Here's an example.

all: foo.all bar.all

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

%.out:
    sh -e -c 'echo "{1, 2, 3" > $@; FAIL!; echo "}" >> $@'

.PRECIOUS: %.out

失败!命令模拟一个在工作中崩溃的工具.这是与上面的Makefile一起使用的Shell会话:

The FAIL! command simulates a tool that crashes in the middle of its work. Here's a shell session working with the Makefile above:

$ 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文件不完整.让我们再次尝试:

Yikes... my foo.out file is incomplete. Let's try making again:

$ 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时,它将以损坏的价格获取损坏的文件. foo.out未被重制(尽管出现了"Made foo"消息),因为它已经存在并且Makefile直接尝试创建bar.

Make is none the wiser about files left around by earlier runs so when you run make again, it will take the corrupted files at face value. foo.out was not remade (despite the "Made foo" message) because it already exists and the Makefile went straight to trying to make bar.

.SECONDARY做到了:

.SECONDARY所依赖的目标被视为中间文件,但它们从未被自动删除.

The targets which .SECONDARY depends on are treated as intermediate files, except that they are never automatically deleted.

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

This means they are never automatically deleted just because they are intermediate files. The default make behavior of deleting targets that were being rebuilt if the tool rebuilding them crashed is not affected.

尽管.PHONY似乎仅适用于显式目标,而不是推断目标.我没有找到证实这一点的文档.但是,这可行:

It seems though that .PHONY works only for targets that are explicit, not inferred. I've not found documentation confirming this. However, this works:

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.allbar.all成为显式目标.没有这些,它们将被推断为目标.

In this rule $(TARGETS_all): %.all: %.out $(TARGETS_all): gives the list of targets to which the pattern can be applied. It makes foo.all and bar.all explicit targets. Without this, they would be inferred targets.

您可以通过在目录中创建名为foo.all的文件并反复运行make来测试其是否有效. foo.all文件对make没有影响.

You can test that it works by creating file called foo.all in your directory and run make over and over. The foo.all file has no effect on make.

这篇关于Makefile模式规则要么忽略虚假规则,要么自发删除输出文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆