【问题标题】:Makefile: target with intermediate prerequisites gets rebuilt every timeMakefile:每次都重建具有中间先决条件的目标
【发布时间】:2020-07-04 11:49:15
【问题描述】:

我正在使用 Pandoc 从多个 Mardown 源文件 file1.md file2.md ... 中输出一个 Word 文档 out.docx。但是,这些 Markdown 文件需要经过预处理才能连接并转换为 Word。我为此使用 GNU make

SRC = $(wildcard *.md)
TMP := $(patsubst %.md,%.tmp, $(SRC))

.INTERMEDIATE : $(TMP)

out.docx : $(TMP)
        pandoc -o $@ file1.tmp file2.tmp ... -f markdown

%.tmp : %.md
        pandoc -o $@ $< --filter=...

现在,我只希望在源文件 $(SRC) 更改时重建 out.docx。但是,由于中间文件$(TMP) 在每次构建结束时都会被删除,make 认为 out.docx 每次都需要重新构建。在out.docx的先决条件中使用$(SRC)而不是$(TMP)当然是行不通的,因为根据the docs

make 不会考虑非终端匹配任何规则(即'%:') 在搜索规则以构建隐式规则的先决条件时。

那么我怎样才能优化这个构建并且在不需要的时候不让它运行呢?

【问题讨论】:

  • $(TMP)中的文件不是中间文件,make不会自动删除。您可以看到它们不是中间的,因为您将它们明确列为out.docx 目标的先决条件。该明确的列表足以防止它们被认为是中间的。如果它们被删除,那么您的实际 makefile 与您在此处向我们展示的内容有所不同,而这正是导致您的问题的原因。使用上面的 makefile,.tmp 文件不会被视为中间文件或已删除。
  • 对不起,我忘了说我明确声明了.INTERMEDIATE : $(TMP)
  • 问题是,我不需要 $(TMP) 文件来做其他任何事情,所以我宁愿删除它们,但是我希望目标是仅在 $(SRC) 文件更改时构建。

标签: makefile


【解决方案1】:

请确保您提供的示例确实显示了问题。您的实际情况一定与您在此处显示的有所不同,因为您在此处显示的 makefile 将按您的预期工作。我没有安装pandoc,所以我替换了touch,它工作正常:

SRC = $(wildcard *.md)
TMP := $(patsubst %.md,%.tmp,$(SRC))

.INTERMEDIATE: $(TMP)

out.docx: $(TMP)
        touch $@

%.tmp: %.md
        touch $@

现在:

$ touch foo.md bar.md biz.md

$ make
touch bar.tmp
touch biz.tmp
touch foo.tmp
touch out.docx
rm foo.tmp bar.tmp biz.tmp

$ make
make: 'out.docx' is up to date.

$ touch biz.md

$ make
touch bar.tmp
touch biz.tmp
touch foo.tmp
touch out.docx
rm foo.tmp bar.tmp biz.tmp

您可以运行 make -d(重定向输出以供以后调查)查看为什么 make 认为 out.docx 已过期。

【讨论】:

  • 谢谢。我在我使用的仅订单先决条件之一中打错了字,这导致make 每次都认为所有内容都已过时。
猜你喜欢
  • 2020-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-05
相关资源
最近更新 更多