Exercises - Make#

Our Makefile currently reads as follows:

.PHONY: all clean help settings

COUNT=bin/countwords.py
COLLATE=bin/collate.py
PLOT=bin/plotcounts.py
DATA=$(wildcard data/*.txt)
RESULTS=$(patsubst data/%.txt,results/%.csv,$(DATA))

## all : regenerate all results.
all : results/collated.png

## results/collated.png: plot the collated results.
results/collated.png : results/collated.csv
	python $(PLOT) $< --outfile $@

## results/collated.csv : collate all results.
results/collated.csv : $(RESULTS) $(COLLATE)
	@mkdir -p results
	python $(COLLATE) $(RESULTS) > $@

## results/%.csv : regenerate result for any book.
results/%.csv : data/%.txt $(COUNT)
	python $(COUNT) $< > $@

## clean : remove all generated files.
clean :
	rm $(RESULTS) results/collated.csv results/collated.png

## settings : show variables' values.
settings :
	@echo COUNT: $(COUNT)
	@echo DATA: $(DATA)
	@echo RESULTS: $(RESULTS)
	@echo COLLATE: $(COLLATE)
	@echo PLOT: $(PLOT)

## help : show this message.
help :
	@grep '^##' ./Makefile

A number of the exercises below ask you to make further edits to Makefile.

1) Report results that would change#

How can you get make to show the commands it would run without actually running them? (Hint: look at the manual page.)

2) Useful options#

  1. What does Make’s -B option do and when is it useful?

  2. What about the -C option?

  3. What about the -f option?

3) Make sure the output directory exists#

One of our build recipes includes mkdir -p. What does this do and why is it useful?

5) Create all results#

The default target of our final Makefile re-creates results/collated.csv. Add a target to Makefile so that make results creates or updates any result files that are missing or out of date, but does not regenerate results/collated.csv.

6) The perils of shell wildcards#

What is wrong with writing the rule for results/collated.csv like this:

results/collated.csv : results/*.csv
	python $(COLLATE) $^ > $@

(The fact that the result no longer depends on the program used to create it isn’t the biggest problem.)

7) Making documentation more readable#

We can format the documentation in our Makefile more readably using this command:

## help : show all commands.
help :
	@grep -h -E '^##' ${MAKEFILE_LIST} | sed -e 's/## //g' \
	| column -t -s ':'

Using man and online search, explain what every part of this recipe does.

8) Configuration#

A next step in automating this analysis might include moving the definitions of the COUNT, COLLATE, and PLOT variables into a separate file called config.mk:

COUNT=bin/countwords.py
COLLATE=bin/collate.py
PLOT=bin/plotcounts.py

and using the include command to access those definitions in the existing Makefile:

.PHONY: results all clean help settings

include config.mk

# ... the rest of the Makefile ...

Under what circumstances would this strategy be useful?