在 makefile 中,如何在一次调用中处理多个目标?

In makefile, how do I process multiple targets in one call?

我正在使用一个私有脚本,该脚本会定期将多个 (~100) 个文本文件转换为 HTML。我写了一个 makefile 只转换有变化的文本文件:

TEXT_DIR = /path/to/app/data/
OUTPUT_DIR = /path/to/app/reports/

.PHONY : html

html : $(wildcard $(OUTPUT_DIR)/*.html)

$(OUTPUT_DIR)/%.html : $(TEXT_DIR)/%.txt
    generate_html --html $< $@

当我 运行 make 时,它会为每个更改的文件调用一次脚本:

generate_html --html /path/to/app/data/file1.txt /path/to/app/reports/file1.html
generate_html --html /path/to/app/data/file2.txt /path/to/app/reports/file2.html
generate_html --html /path/to/app/data/file3.txt /path/to/app/reports/file3.html

这非常慢,因为脚本在读取配置和设置时在初始加载时需要一些时间。在一个 运行 中处理所有文件要快得多:

generate_html --html /path/to/app/data/file1.txt /path/to/app/reports/file1.html --html /path/to/app/data/file2.txt /path/to/app/reports/file2.html --html /path/to/app/data/file3.txt /path/to/app/reports/file3.html

如何制作 GNU Make 运行 脚本?

如果您不介意创建一个保存上次构建时间的文件(即这里的 last-run.txt),您可以这样做。在这里,我使用 $? 获取所有比 last-run.txt 更新的文本文件。比照。 GNU Make Automatic Variables.

TEXT_DIR = /path/to/app/data
OUTPUT_DIR = /path/to/app/reports

build_html_name = $(OUTPUT_DIR)/$(notdir $(1:.txt=.html))

.PHONY: html
html: last-run.txt

last-run.txt: $(wildcard $(TEXT_DIR)/*.txt)
    ./generate_html $(foreach f,$?,--html $f $(call build_html_name,$f))
    date > $@

只要文件的修改时间得到更新,last-run.txt的内容并不重要;所以 touch $@ 而不是 date > $@ 完成了这项工作。

您可以使用变量来存储必须更改的文件,而不是直接在 ${OUTPUT_DIR}/%.html 目标中直接 运行 命令。

TEXT_DIR = /path/to/app/data/
OUTPUT_DIR = /path/to/app/reports/

.PHONY : html

html : $(wildcard $(OUTPUT_DIR)/*.html)
    generate_html ${TODO}

$(OUTPUT_DIR)/%.html : $(TEXT_DIR)/%.txt
    $(eval TODO=${TODO} --html $< $@)