首页 > 解决方案 > 使 .SECONDEXPANSION 配方执行两次

问题描述

使用 GNU make,我试图解决一个类似于make recipe 执行两次的问题——也就是说,让 Makefile 配方运行两次。然而,在我的例子中,配方是在.SECONDEXPANSION目标下运行的,两个不同的运行将使用不同的参数调用,以从同一个输入文件生成不同版本的输出文件。也就是说,使用输入文件foo,这个示例 Makefile 应该可以通过调用make foo.pdfmake foo.expanded.pdf构建一个 .pdf 文件,或make all构建两个 .pdf 文件:

.PHONY: all

all: foo.pdf foo.expanded.pdf

.SECONDEXPANSION:
%.expanded.pdf %.pdf: %
    @echo building $(basename $@)

在该答案中给出的两个解决方案中,第一个是不合适的,因为它总是运行规则两次;我希望它在用户要求时运行两次。

在那里发布的第二个解决方案概念上是我正在寻找并在上面的示例 Makefile 中实现的,只有一个小问题是它不起作用:虽然all目标将两个 .pdf 文件都列为依赖项,但只有一个是在什么时候构建make all的跑。

有没有办法告诉 GNU make 在 a 下使用相同的规则构建两个不同的文件.SECONDEXPANSION

编辑:在问题描述中澄清了相同的输入文件用于构建输出文件的两个版本,并修改了示例 Makefile 以包含此依赖项。

编辑:我想要一个尽可能可扩展的解决方案;也就是说,如果输入文件名包含点,它应该可以工作,指定额外的输出文件foo.reduced.pdf应该只需要根据需要调整目标和配方等。这限制了执行依赖于在这个狭窄示例中给出的文件名的字符串手术(例如,%.pdf: $$(firstword $$(subst ., ,$$*))如果输入文件可以是foofoo.bar) ,则将规则更改为失败。

标签: makefilegnu-make

解决方案


你的问题与.SECONDEXPANSION. 您可以放弃它,问题将是相同的。

您的问题是您正在使用具有多个目标模式的模式规则,并期望它与具有多个目标的显式规则类似。但事实并非如此(事实上,您不能同时拥有包含模式和显式目标的规则)。

对于具有多个目标模式的模式规则,Make 将相同的模式匹配到所有的%,包括目标中的多次,然后假设它只需使用该模式执行一次配方,它将生成所有匹配的目标。

在您的情况下,最好的方法是使用多个规则(我更改了您的食谱,因为echo用作 Make 食谱是一个坏主意):

.PHONY: all
all: foo.expanded.pdf foo.pdf 

RECIPE = touch $@

%.expanded.pdf:
    $(RECIPE)

%.pdf:
    $(RECIPE)

推荐阅读