Makefile中的复杂模式规则
我使用以下makefile从一些模板生成文件,生成的文件有两个可能的扩展名:Makefile中的复杂模式规则,makefile,Makefile,我使用以下makefile从一些模板生成文件,生成的文件有两个可能的扩展名: %.tex: %.tex*_tpl ./generate $@_tpl -o $@ %.xml: %.xml*_tpl ./generate $@_tpl -o $@ 这里的依赖项列表将匹配像a.tex\u tpl,a.tex-subpart1\u tpl,a.tex-subpart2\u tpl 虽然这样做有效,但有没有办法避免重复?例如,通过在规则名称中匹配*。{tex,xml},并在依赖项列表
%.tex: %.tex*_tpl
./generate $@_tpl -o $@
%.xml: %.xml*_tpl
./generate $@_tpl -o $@
这里的依赖项列表将匹配像a.tex\u tpl
,a.tex-subpart1\u tpl
,a.tex-subpart2\u tpl
虽然这样做有效,但有没有办法避免重复?例如,通过在规则名称中匹配*。{tex,xml}
,并在依赖项列表中使用整个匹配的名称?看起来像这样的东西:
%.{tex,xml}: $@_tpl
./generate $< -o $@
%.{tex,xml}:$@
/生成$<-o$@
(虽然我知道%.{tex,xml}
不是有效的规则名称,并且您不能在依赖项列表中使用$@
)
或者任何其他(更清洁的?)方式。在我看来,这正是您想要的:
#
# 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 $@
关键是允许在第二个扩展阶段评估$$(通配符%*\u tpl)
。顺便说一句,double$
不是打字错误;它保护表达式在第一次展开时不被计算
如果我用以下文件填充目录:
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
为什么要进行第二次扩张?
如果没有第二次扩展,您必须在依赖项中包含$(通配符%*\u tpl)
,因为使用$$
通配符函数将永远不会执行。相反,make将把$$(通配符..)
字面上看作依赖项,这显然是错误的
好的,所以在第一次运行该行时(这是“第一次扩展”)将对$(通配符%*\u tpl)
进行评估。那时,%
还没有值,所以通配符
大概是在命令行上执行类似于ls%*\u tpl
的操作
出于速度的原因,默认情况下,“make”不会在第一次扩展之后为您提供执行任何评估的机会。如果希望以后有机会,则必须指定.SECONDEXPANSION
,这将打开第二次扩展处理。Make仍然像往常一样执行firts扩展。这就是为什么您需要有$$(通配符)
:在第一次扩展期间,它被转换为$(通配符)
。在第二次扩展时,请查看$(通配符%*\tpl)
,将%
替换为实际的词干,然后使用实际的词干而不是文本%
执行通配符
函数
为什么模式规则中的$(目标)
?
模式规则可以写为:
%: $$(wildcard %*_tpl)
./generate $^ -o $@
没有$(目标)
。但是,这个规则不会起任何作用,因为它是一个。基本上,如果make按照表面上的价值使用了这样一个规则,那么计算成本将是巨大的,而且很可能Makefile
的作者并不是真的想将这个规则应用于任何文件。因此,这样一个规则带有限制,这在这里的Makefile使它变得无用
将
$(目标)
添加到一个,这不是一个匹配任何东西的规则。在目标模式前面添加$(目标)
告诉make,该规则仅适用于这些目标,而不适用于其他任何目标。我想不出任何东西可以使它更干净,尽管这取决于您所说的“干净”是什么意思。您可以将配方放入一个变量中:GENERATE=./GENERATE$@\u tpl-o$@
然后在每个命令中使用$(GENERATE)
变量;这将减少更新配方所需的位置数。这确实更好,谢谢!我真的不知道该称之为“cleaner”,我只能想到一些模糊的描述,如“short and not hacky”。这可能符合“hacky”:D,但听起来很棒!我今天没有更多的时间来测试它,但我会尽快给你回复,谢谢!编辑:并且您的makefile开头的注释是正确的,如果我不清楚,很抱歉。唯一不同的是,生成
脚本只需要一个文件($@_tpl
)作为输入,此文件有说明(jinja的包括
)包括其他(子部分_tpl)但这不应该是一个问题。除了GNU Make guru之外,这并不干净。我实际上非常喜欢它,尤其是它通过查看\u tpl
文件中的内容来生成可用目标的列表。顺便说一下,我不需要将这些目标限制为xml和tex文件,这样我甚至可以将其缩短为目标:=$(patsubst%\u tpl,%,$(wildcard*\u tpl))
。我有两个问题:1)是什么使得.SECONDEXPANSION
成为强制性的?是不是在%
扩展之后必须扩展的通配符
函数?2)我在$(目标)
规则中找不到关于额外:%:
的文档,是什么?(我想它是从一个目标列表中创建了一个模式规则?。@Dettoler如果没有第二次扩展,你会把$(通配符%*\u tpl)
放进去,因为使用$
通配符函数将永远不会执行。现在$(通配符%*\u tpl)
将在make第一次运行该行时进行计算。那时%
还没有值,因此通配符
将大致执行类似于命令行中的ls%*\u tpl
的操作。在第二次扩展时,%
将替换为实际的干,然后通配符
已执行。@Louis谢谢,这是我(模糊地)的想法。'$(目标):'之后的额外“%:”是什么?在哪里记录了它?(或者概念的名称是什么?)