В makefile, как мне обработать несколько целей за один вызов? - PullRequest
0 голосов
/ 22 января 2020

Я использую приватный скрипт, который обычно конвертирует несколько (~ 100) текстовых файлов в HTML. Я написал make-файл для преобразования только текстовых файлов с изменениями:

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 запускать скрипт так, как это?

Ответы [ 2 ]

2 голосов
/ 22 января 2020

Если вы не возражаете против создания файла, который содержит время последней сборки (т. Е. last-run.txt здесь), вы можете сделать это. Здесь я использую $?, чтобы получить все текстовые файлы, которые новее, чем last-run.txt. ср GNU Make Automati c Переменные .

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 > $@ выполняет свою работу.

1 голос
/ 22 января 2020

Вы можете использовать переменные для хранения файлов, которые должны быть изменены, вместо фактического запуска команды непосредственно в ${OUTPUT_DIR}/%.html target.

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 $< $@)
...