GNU Makefile:单个规则的多个输出防止中间文件被删除

发布于 2024-09-06 09:39:09 字数 1606 浏览 5 评论 0 原文

这是问题的延续 这里。问题在于,有一个规则从单个输入生成多个输出,并且该命令非常耗时,因此我们希望避免重新计算。现在还有一个额外的问题,我们希望防止文件作为中间文件被删除,并且规则涉及允许参数的通配符。


建议的解决方案是我们设置以下规则:

file-a.out: program file.in
    ./program file.in file-a.out file-b.out file-c.out

file-b.out: file-a.out
    @

file-c.out: file-b.out
    @

然后,调用 make file-c.out 创建两者,并且我们可以避免与 并行运行 make 的问题-j 开关。到目前为止一切都很好。


问题如下。由于上述方案在DAG中设置了一条链,所以make对其的考虑有所不同;文件 file-a.outfile-b.out 被视为中间文件,默认情况下,一旦 file-c 出现,它们就会因为不必要而被删除.out 已准备就绪。

这里提到了一种避免这种情况的方法,包括添加 file-a.outfile-b.out 作为目标 .SECONDARY< 的依赖项/code>,这可以防止它们被删除。不幸的是,这并不能解决我的问题,因为我的规则使用通配符模式;具体来说,我的规则看起来更像是这样:

file-a-%.out: program file.in
    ./program $* file.in file-a-$*.out file-b-$*.out file-c-$*.out

file-b-%.out: file-a-%.out
    @

file-c-%.out: file-b-%.out
    @

这样就可以传递一个包含在文件名中的参数,例如通过运行

make file-c-12.out

make 文档建议的解决方案是将这些作为隐式规则添加到.PRECIOUS 的依赖项列表,从而防止这些文件被删除。


使用 .PRECIOUS 的解决方案有效,但它也可以防止在规则失败且文件不完整时删除这些文件。还有其他方法可以使这项工作有效吗?

解决这个问题的一个技巧是定义一个没有先决条件的目标 .SECONDARY ,即

.SECONDARY:

通知 make 所有文件都应该被视为辅助文件,因此不会被删除,除非make 被中断或规则失败。不幸的是,这不允许选择带有通配符的规则子集以这种方式工作,所以我认为这只是一个黑客(即使它很有用)。

This is sort of a continuation of question from here. The problem is that there is a rule generating multiple outputs from a single input, and the command is time-consuming so we would prefer to avoid recomputation. Now there is an additional twist, that we want to keep files from being deleted as intermediate files, and rules involve wildcards to allow for parameters.


The solution suggested was that we set up the following rule:

file-a.out: program file.in
    ./program file.in file-a.out file-b.out file-c.out

file-b.out: file-a.out
    @

file-c.out: file-b.out
    @

Then, calling make file-c.out creates both and we avoid issues with running make in parallel with -j switch. All fine so far.


The problem is the following. Because the above solution sets up a chain in the DAG, make considers it differently; the files file-a.out and file-b.out are treated as intermediate files, and they by default get deleted as unnecessary as soon as file-c.out is ready.

A way of avoiding that was mentioned somewhere here, and consists of adding file-a.out and file-b.out as dependencies of a target .SECONDARY, which keeps them from being deleted. Unfortunately, this does not solve my case because my rules use wildcard patters; specifically, my rules look more like this:

file-a-%.out: program file.in
    ./program $* file.in file-a-$*.out file-b-$*.out file-c-$*.out

file-b-%.out: file-a-%.out
    @

file-c-%.out: file-b-%.out
    @

so that one can pass a parameter that gets included in the file name, for example by running

make file-c-12.out

The solution that make documentation suggests is to add these as implicit rules to the list of dependencies of .PRECIOUS, thus keeping these files from being deleted.


The solution with .PRECIOUS works, but it also prevents these files from being deleted when a rule fails and files are incomplete. Is there any other way to make this work?

A hack to solve this is to define a target .SECONDARY with no prerequisites, i.e.,

.SECONDARY:

which informs make that all files should be treated as secondary and thus not removed, unless when make gets interrupted or a rule fails. Unfortunately, this does not allow for selecting a subset of rules with wildcards to work this way, so I consider this only a hack (even though it's useful).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

青朷 2024-09-13 09:39:09

最简单的事情

file-a-%.out file-b-%.out file-c-%.out: program file.in
    ./program $* file.in file-a-$*.out file-b-$*.out file-c-$*.out

将完全满足您的要求。

(具有多个目标的模式规则与您询问的具有多个目标的正常规则不同 此处。请参阅 制作手册。)

The Simplest Thing

file-a-%.out file-b-%.out file-c-%.out: program file.in
    ./program $* file.in file-a-$*.out file-b-$*.out file-c-$*.out

will do exactly what you want.

(Pattern rules with multiple targets are different than the normal rule with multiple targets that you were asking about here. See the bison example in the make manual.)

む无字情书 2024-09-13 09:39:09

如果您的输出不是从单个 file.in 生成的,而是从包含词干的先决条件文件生成的,即

file-a.out: program file-%.in
    ./program file-$*.in file-a-$*.out file-b-$*.out file-c-$*.out

您可以构建所有可能的目标匹配的列表:

inputs = $(wildcard file-*.in)
secondaries = $(patsubst file-%.in,file-a-%.out,$(inputs)) \
    $(patsubst file-%.in,file-b-%.out,$(inputs))

同样,如果词干来自有限集:

batchnos = 17 18 19 20 
batchnos = $(shell seq 17 20)
secondaries = $(patsubst %,file-a-%.out,$(batchnos)) $(patsubst %,file-b-%.out,$(batchnos))

那么只需添加这些作为 .SECONDARY 目标的先决条件

.SECONDARY: $(secondaries)

If, instead of a single file.in, your outputs were generated from a prerequisite file that included the stem, i.e.

file-a.out: program file-%.in
    ./program file-$*.in file-a-$*.out file-b-$*.out file-c-$*.out

you can then build a list of all possible target matches:

inputs = $(wildcard file-*.in)
secondaries = $(patsubst file-%.in,file-a-%.out,$(inputs)) \
    $(patsubst file-%.in,file-b-%.out,$(inputs))

Similarly if the stem comes from a finite set:

batchnos = 17 18 19 20 
batchnos = $(shell seq 17 20)
secondaries = $(patsubst %,file-a-%.out,$(batchnos)) $(patsubst %,file-b-%.out,$(batchnos))

Then just add these as prereqs to the .SECONDARY target

.SECONDARY: $(secondaries)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文