始终处理最外部的文件扩展名(以及扩展名)

时间:2019-04-07 21:24:08

标签: makefile gnu-make

我的静态HTML博客中有一堆不同的源文件。最外层的扩展说明了接下来要处理的格式。

示例:源文件article.html.md.gz(目标为article.html)应先由gunzip处理,然后由我的降价处理器处理。

更多详细信息:

  • 扩展名的顺序可能会变化
  • 有时不使用扩展名(article.html.gz
  • 我知道如何处理所有不同的扩展名
  • 我知道最终格式始终为article.html

理想情况下,我希望只编写如下规则:

...

all-articles: $(ALL_HTML_FILES)

%: %.gz
    gunzip ...

%: %.md
    markdown ...

%: %.zip
    unzip ...

然后让make根据扩展顺序找出要采用的路径。

但是,从文档中,我了解到“全部匹配”规则存在一些限制,而上述情况是不可能的。

最好的前进方向是什么? make可以完全解决这种情况吗?

扩展是示例。我实际的源文件更有意义:-)

1 个答案:

答案 0 :(得分:2)

我在度假,所以我要咬。

我不是模式规则的忠实拥护者,它们对我的口味来说过于严格,但同时又过于随意。您可以通过纯粹的方式很好地实现您想要的东西:

.DELETE_ON_ERROR:

all: # Default target

files := a.html.md.gz b.html.gz

cmds<.gz> = gzip -d <$< >$@
cmds<.md> = mdtool $< -o $@

define rule-text # 1:suffix 2:basename
  $(if $(filter undefined,$(flavor cmds<$1>)),$(error Cannot handle $1 files: [$2$1]))
  $2: $2$1 ; $(value cmds<$1>)
  all: $2
endef

emit-rule = $(eval $(call rule-text,$1,$2))# 1:suffix 2:basename
emit-hierachy = $(if $(suffix $2),$(call emit-rule,$1,$2)$(call emit-hierachy,$(suffix $2),$(basename $2)))# 1:suffix 2:basename
emit-rules = $(foreach _,$1,$(call emit-hierachy,$(suffix $_),$(basename $_)))# 1:list of source files

$(call emit-rules,${files})

.PHONY: all
all: ; : $@ Success

此处的关键是将$files设置为文件列表。 然后,此列表将传递到 emit-rules emit-rules 一次将每个文件传递给 emit-hierachy

emit-hierachy 依次剥离每个扩展名, 生成适当的 make 语法,并将其传递给$(eval …) emit-hierachy 一直进行到文件只剩下一个扩展名为止。

因此a.html.md.gz成为以下 make 语法:

a.html.md: a.html.md.gz ; gunzip <$< >$@
a.html: a.html.md ; mdtool $< -o $@
all: a.html

类似地,b.html.gz变为:

b.html: b.html.gz ; gunzip <$< >$@
all: b.html

尼托,还是什么?

如果您给 emit-rules 文件添加了无法识别的扩展名(例如c.html.pp), 您会收到编译时错误:

1:20: *** Cannot handle .pp files: [c.html.pp].  Stop.

编译时?是的,在运行任何shell命令之前。

您可以通过定义.pp来告诉 make 如何处理cmds<.pp>文件:-)

对于加分点,它也是并行安全的。因此,您可以在8 CPU笔记本电脑上使用-j9,在32 CPU工作站上使用-j33。现代生活是吗?