Oregon State University
2025-02-26
Tools like “Make” were developed to help compile complex software, but can also be used to automate any workflow.
Makefile
.Makefile
#
indicates a commenttarget : prerequisite
\
) splits lineRun using command make
results/moby_dick.csv
doesn’t exist, Make runs recipe to create itdata/moby_dick.txt
is newer than results/moby_dick.csv
, Make runs recipe to update itresults/moby_dick.csv
is newer than its prerequisite, nothing happensMakefile
By default, Make only attempts to update the first target (default target)
Could specify target directly: make results/jane_eyre.csv
Better, create “phony target” and place at top: all
Then type make all
clean
By convention a clean target provides rules to remove results/generated outputs
Then type make clean
. Safer than manually typing!
The results also depend on the programs used to generate them, so add to prerequisites:
# regenerate results for "Moby Dick"
results/moby_dick.csv : data/moby_dick.txt src/countwords.py
python src/countwords.py data/moby_dick.txt > results/moby_dick.csv
# regenerate results for "Jane Eyre"
results/jane_eyre.csv : data/jane_eyre.txt src/countwords.py
python src/countwords.py data/jane_eyre.txt > results/jane_eyre.csv
Makefile
.PHONY : all clean
COUNT=src/countwords.py
RUN_COUNT=python $(COUNT)
# regenerate all results
all : results/moby_dick.csv results/jane_eyre.csv
# regenerate results for "Moby Dick"
results/moby_dick.csv : data/moby_dick.txt $(COUNT)
$(RUN_COUNT) data/moby_dick.txt > results/moby_dick.csv
# regenerate results for "Jane Eyre"
results/jane_eyre.csv : data/jane_eyre.txt $(COUNT)
$(RUN_COUNT) data/jane_eyre.txt > results/jane_eyre.csv
# remove all generated files
clean :
rm -f results/*.csv
Automatic variable for target of the rule: $@
# regenerate results for "Moby Dick"
results/moby_dick.csv : data/moby_dick.txt $(COUNT)
$(RUN_COUNT) data/moby_dick.txt > $@
The first prerequisite of the rule: $<
# regenerate results for "Moby Dick"
results/moby_dick.csv : data/moby_dick.txt $(COUNT)
$(RUN_COUNT) $< > $@
Also: all prerequisites of the rule: $^
Create pattern rule using wildcard: %
So full Makefile is:
Makefile
.PHONY : all clean
COUNT=src/countwords.py
RUN_COUNT=python $(COUNT)
# regenerate all results
all : results/moby_dick.csv results/jane_eyre.csv \
results/time_machine.csv
# regenerate results for any book
results/%.csv : data/%.txt $(COUNT)
$(RUN_COUNT) $< > $@
# remove all generated files
clean :
rm -f results/*.csv
Use variable to list all results files present:
But, only works if results already exist. Instead, use list of files data/
directory.
Use pattern substitution to create corresponding output files:
settings
targetUse settings
target to print variables, using @
to avoid repeating command in output:
Remove RUN_COUNT
variable:
Since all depends on $(RESULTS)
we can regenerate in one step:
Create a phony target help
to print commands:
.PHONY: all clean help settings
# ... other definitions ...
# show help
help :
@echo "all : regenerate all results."
@echo "results/*.csv : regenerate result for any book."
@echo "clean : remove all generated files."
@echo "settings : show variables' values."
@echo "help : show this message."
Problem with this? It requires manual updates.
Use ##
to mark lines to display and grep
to pull lines:
Makefile
.PHONY: all clean help settings
COUNT=src/countwords.py
DATA=$(wildcard data/*.txt)
RESULTS=$(patsubst data/%.txt,results/%.csv,$(DATA))
## all : regenerate all results.
all : $(RESULTS)
## results/%.csv : regenerate result for any book.
results/%.csv : data/%.txt $(COUNT)
python $(COUNT) $< > $@
## clean : remove all generated files.
clean :
rm -f $(RESULTS)
## settings : show variables' names
settings :
@echo COUNT: $(COUNT)
@echo DATA: $(DATA)
@echo RESULTS: $(RESULTS)
## help : show this message
help :
@grep '^##' ./Makefile
Makefile
.PHONY: all paper clean help settings
COUNT=src/countwords.py
DATA=$(wildcard data/*.txt)
RESULTS=$(patsubst data/%.txt,results/%.csv,$(DATA))
## all : regenerate paper and all results.
all : paper.pdf $(RESULTS)
## results/%.csv : regenerate result for any book.
results/%.csv : data/%.txt $(COUNT)
python $(COUNT) $< > $@
## paper.pdf : regenerate paper.
paper.pdf : paper.tex paper.bib $(RESULTS)
latexmk -pdf $<
## clean : remove all generated files.
clean :
rm -f $(RESULTS)
latexmk -c
## settings : show variables' names
settings :
@echo COUNT: $(COUNT)
@echo DATA: $(DATA)
@echo RESULTS: $(RESULTS)
## help : show this message
help :
@grep '^##' ./Makefile