0
votes

I'm using a private script that routinely converts multiple (~100) text files to HTML. I wrote a makefile to only convert text files with changes:

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

When I run make, it calls the script once per each changed file:

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

This is quite slow, because the script takes a bit of time on initial load as it reads config and does setup. Processing all files in a single run is much faster:

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

How do I make GNU Make run the script like this?

2

2 Answers

2
votes

If you don't mind creating a file that holds the last build time (i.e. last-run.txt here), you can do this. Here I'm using $? to get all the text files that are newer than last-run.txt. cf. 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 > $@

The contents of last-run.txt doesn't matter as long as the file's modified time gets updated; so touch $@ instead of date > $@ does the job.

1
votes

You can use variables to store the files that has to be changed, instead of actually running the command directly in ${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 $< $@)