Makefile中的复杂模式规则

时间:2014-10-31 10:13:28

标签: makefile

我有以下用于从某些模板生成文件的makefile,生成的文件有两个可能的扩展名:

%.tex: %.tex*_tpl
    ./generate $@_tpl -o $@

%.xml: %.xml*_tpl
    ./generate $@_tpl -o $@

依赖项列表将匹配a.tex_tpla.tex-subpart1_tpla.tex-subpart2_tpl等内容。

虽然这有效,但有没有办法避免重复?例如,通过匹配规则名称中的*.{tex,xml}并使用依赖项列表中的整个匹配名称?看起来像这样的东西:

%.{tex,xml}: $@_tpl
    ./generate $< -o $@

(虽然我知道%.{tex,xml}不是有效的规则名称,您不能在依赖项列表中使用$@

或任何其他(清洁?)方式。

1 个答案:

答案 0 :(得分:4)

在我看来,这就是你要找的东西:

#
# I've assumed that files of the form:
#
#  a.xml_tpl
#  b.tex_tpl
#
# determine what targets you want to build
#
TARGETS:=$(patsubst %_tpl,%,$(wildcard *.xml_tpl *.tex_tpl))

.PHONY: all
all: $(TARGETS)

.SECONDEXPANSION:
$(TARGETS): %: $$(wildcard %*_tpl)
    ./generate $^ -o $@

关键是使用.SECONDEXPANSION允许在第二个扩展阶段评估$$(wildcard %*_tpl)。顺便说一下,双$不是拼写错误;它保护表达式在第一次扩展时不被评估。

如果我使用这些文件填充目录:

a.tex-subpart1_tpl
a.tex_tpl
a.xml-subpart1_tpl
a.xml-subpart2_tpl
a.xml_tpl

并运行make -n,我在控制台上看到了这个:

./generate a.xml_tpl a.xml-subpart1_tpl a.xml-subpart2_tpl -o a.xml
./generate a.tex_tpl a.tex-subpart1_tpl -o a.tex

为什么第二次扩张?

如果没有第二次扩展,您必须在依赖项中拥有$(wildcard %*_tpl),因为使用$$通配符函数永远不会执行。相反,make会将$$(wildcard..) 字面上视为依赖,这显然是错误的。

好的,所以$(wildcard %*_tpl)会在第一次跨越该行时进行评估(这是&#34;第一次扩展&#34;)。 当时 %没有任何价值,因此wildcard大致会在命令行中执行类似ls %*_tpl的操作。

出于速度原因,默认情况下make不会让您有机会在第一次扩展之后进行任何评估。如果您想要以后的机会,则必须指定.SECONDEXPANSION,这将启用第二次扩展处理。 Make仍像往常一样执行第一次扩展。这就是您需要$$(wildcard的原因:在第一次扩展期间,它会转换为$(wildcard。在第二次展开时,make $(wildcard %*_tpl)用实际的词干替换%,然后用实际的词干执行wildcard函数而不是文字%

为什么$(TARGETS)在模式规则中?

可以写出模式规则:

%: $$(wildcard %*_tpl)
    ./generate $^ -o $@

没有$(TARGETS)。但是,这条规则什么都不做,因为它是"match-anything rule"。基本上,如果make在表面上采用了这样的规则,那么计算成本就会很高,而且很可能不是Makefile 的作者真的意味着应用这个规则任何文件。所以这样的规则带有限制,这在Makefile中使它变得无用。

添加$(TARGETS)会使其成为static pattern rule,这不是匹配任何规则。在目标模式前添加$(TARGETS)会告知该规则仅适用于这些目标,而不适用于其他目标。