始终处理最外层的文件扩展名(并沿途剥离扩展名)

Always process outermost file extension (and strip extensions along the way)

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

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

更多详情:

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

...

all-articles: $(ALL_HTML_FILES)

%: %.gz
    gunzip ...

%: %.md
    markdown ...

%: %.zip
    unzip ...

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

然而,从文档中,我了解到对 match-all 规则有限制,上述情况是不可能的。

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

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

我在放假,所以我会咬人。

我不喜欢模式规则,它们太受限制,但同时又太随意,不符合我的口味。你可以在纯 make 中很好地实现你想要的:

.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<>)),$(error Cannot handle  files: []))
  :  ; $(value cmds<>)
  all: 
endef

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

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

.PHONY: all
all: ; : $@ Success

此处的关键是将 $files 设置为您的文件列表。 然后将此列表传递给 emit-rulesemit-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

Neato,还是什么?

如果你给 emit-rules 一个带有无法识别扩展名的文件(c.html.pp 说), 你得到一个编译时错误:

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

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

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

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