In a typical coding project, some files will be processed to produce other files as output. For example, programs written in C are compiled into
We call the output files target files, and the input files are called source files. The source-target relationships of a project are a crucial component of the structure of the project, because the processing steps are required to reproduce the analysis or update the target files to reflect changes in the source. However, this important structure is not usually apparent from the source and target files themselves.
There are at least two ways to address this problem: (1) document the processing steps in a README file, or (2) write a Makefile, which can be processed by a command-line utility called make to actually carry out the processing steps. The second approach documents the source-target relationships and makes them executable.
Suppose, for example, that we have a file called
raw-data.csv which contains some data we are meant to analyze. We write some code in a file called
clean-data.py to process that data and write a file called
clean-data.csv. Then we run
model.py to do some analysis and come up with a model that we save in a file called
model.pkl. Our Makefile would look something like this:
all : model.pkl
model.pkl : model.py clean-data.csv
clean-data.csv : clean-data.py raw-data.csv
The basic formula for a Makefile entry is
target : dependencies
The command-line function
make looks at whether the dependencies have changed since the target was last built, if they have then it runs the commands in the corresponding recipe.
target can either be an actual target file or a phony target, which is a name used to refer to a given processing step. The phony targets should be declared in a line that begins
.PHONY and lists the phony targets. It's conventional to include the phony targets
clean. These correspond to the operations "build everything" and "remove the target files".
Specific targets can be invoked at the command line by running
make targetname. For example,
make all builds everything and
make clean removes the target files. The target may be omitted, in which case it defaults to the first target in the file.
Write a Makefile which runs
pdflatex my-document.tex to produce
my-document.tex changes. Include the phony targets
clean. Assume that
pdflatex will produce auxiliary files
Solution. We remove the auxiliary files with
clean and make
all include just the target
all : my-document.pdf
my-document.pdf : my-document.tex
.PHONY all clean