【问题标题】:Can I simplify this Makefile involving files in subfolders?我可以简化这个涉及子文件夹中文件的 Makefile 吗?
【发布时间】:2020-04-05 16:27:34
【问题描述】:

例如,我有以下 Makefile 可以从子目录中的 Markdown 文件生成 PDF 文件:

FOLDERS = f1 f2 f3
.PHONY: $(FOLDERS)

f1: f1/f1.md
    cd $@ && pandoc $(notdir $^) -o $(patsubst %.md,%.pdf,$(notdir $^))

f2: f2/f2.md
    cd $@ && pandoc $(notdir $^) -o $(patsubst %.md,%.pdf,$(notdir $^))

f3: f3/f3.md
    cd $@ && pandoc $(notdir $^) -o $(patsubst %.md,%.pdf,$(notdir $^))

预期结果是make f1 需要f1/f1.md 的存在,并将生成的PDF 生成为f1/f1.pdff2f3 也是如此。这可行,但声明似乎不必要地重复。

有没有办法将这三个规则合并为一个通用规则?也就是说,不需要显式写出 PDF 文件或 Markdown 文件的所有路径,因为我可能会动态添加子文件夹,而且我更愿意在第一行更改 FOLDERS 的定义。我已经四处搜索并尝试了一些东西,但我觉得要么我找不到正确的咒语来使用,要么我错过了有关 Makefile 如何工作的知识。有人可以指出我正确的方向吗?

【问题讨论】:

  • 请注意,您可能希望使用$< 而不是$^。另请注意,您可以将$(notdir $<) 替换为$(<F)。这是某种程度的简化。
  • 关于第一个建议,当只有一个先决条件时,$<$^ 之间是否存在功能差异?谢谢你的第二个!
  • 功能上没有区别。但是,如果您只想要第一个先决条件,$^ 是错误的。

标签: makefile


【解决方案1】:

首先,请注意这里没有充分的理由使用 PHONY 目标,因为这些规则似乎在构建名称事先已知的文件。像f1/f1.pdf 这样的目标会更好。

不幸的是,当词干(例如f1)在先决条件中重复时,我们不能使用模式规则。但是"canned recipe" 可以解决问题:

define pdf_template
$(1): $(1)/$(1).md
    cd $$@ && pandoc $$(notdir $$^) -o $$(patsubst %.md,%.pdf,$$(notdir $$^))
endef

$(eval $(call pdf_template,f1))
$(eval $(call pdf_template,f2))
$(eval $(call pdf_template,f3))

(请注意您必须如何转义模板中的 $ 符号。)

如果那些$(eval...) 行看起来过于重复,您可以用循环替换它们:

$(foreach folder,$(FOLDERS),$(eval $(call pdf_template,$(folder))))

编辑:想一想,还有另一种方法。您不能构造多次使用词干的模式规则:

$(FOLDERS): %: %/%.md
    cd $@ && ... this won't work

并且您不能在先决条件列表中使用automatic variables,因为它们尚未在需要时定义:

$(FOLDERS): $@/$@.md
    cd $@ && ... this won't work either

但是如果你使用Secondary Expansion,你可以在那里使用它们,这会导致 Make 再次扩展 prereq 列表:

.SECONDEXPANSION:

$(FOLDERS): $$@/$$@.md
    cd $@ && ... this works

再次注意转义的$ 符号。

【讨论】:

  • 如果您将目录作为目标,您确实需要.PHONY。如果您按照您的建议进行操作并将目标更改为$(1)/$(1).pdf,那么您不需要(或不想要).PHONY。您可能还想添加$(1): $(1)/$(1).pdf,这样您仍然可以运行make f1 等。如果您这样做,您仍然需要.PHONY。所以,你可能想保留.PHONY :)
  • 谢谢,这对我有用。 TIL 关于罐头食谱,很好的解决方案。我给了你一个赞成票,但显然我的代表太低了,无法显示公开分数。我决定保留这些虚假信息,因为我很懒,而且输入整个路径的工作量太大;)
  • @MadScientist:嘿,我没说不要保留.PHONY,我说不要保留PHONY 目标。我的意思是,我知道没有“PHONY”就不能有假目标,而且你不应该有不是PHONY目标而是目标的“假”目标i> 那个,那个我,那个你,我的意思是他——哦,我的脑袋……
猜你喜欢
  • 1970-01-01
  • 2018-01-03
  • 1970-01-01
  • 2011-01-25
  • 1970-01-01
  • 2012-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多