8.1. Make Files

The make utility has been available from a very long time. Almost since 1976. The original purpose of make was to switch away from regular shell scripts and automate things based on their dependencies.

1theFinalDocument.pdf : theFinalDocument.tex
2
3   latexrun theFinalDocument.tex

The above line means, theFinalDocument.pdf is dependent on (timestamp of) theFinalDocument.tex. Whenever the user want to create theFinalDocument.pdf, if theFinalDocument.pdf is newer than theFinalDocument.tex, nothing needs to be done. But if, theFinalDocument.tex was modified and it is newer than theFinalDocument.pdf; theFinalDocument.pdf needs to be re-generated. And the way to do is to call latexrun theFinalDocument.tex. Of course, the above code expects all necessary tools are installed in the system, and theFinalDocument.tex is a valid Latex file.

So, when the user runs make theFinalDocument.pdf, if theFinalDocument.tex was not modified, theFinalDocument.pdf is created, else nothing needs to be done.

Let’s extend the same file to do a better Makefile

 1# Makefile to create theFinalDocument.pdf
 2
 3all: doc
 4
 5doc: theFinalDocument.pdf
 6
 7theFinalDocument.pdf : theFinalDocument.tex
 8
 9   latexrun theFinalDocument.tex
10
11.PHONY: all doc
Line 1:

Comments start with a #

Line 3:

The default target. If the user invokes make, the first target is used by default. This also means make, make all are the same thing. And the target all depends on doc

Line 5:

Giving a meaningful name to the target, doc, because we are actually creating a document. doc depends on theFinalDocument.pdf

Line 7:

Same as the previous code snippet. theFinalDocument.pdf depends on theFinalDocument.tex

Line 9:

The actual command. It is very important that this line is prefixed with a TAB

Line 11:

When we declare dependency between theFinalDocument.pdf and theFinalDocument.tex, we are actually comparing the timestamps of these files. But the targets all and doc would not have any timestamps.

.PHONY is used to denote this fact that these targets don’t have any timestamps and for calculation of dependencies, their targets’ timestamps would be used.

Finally, let’s extend the same file with a target to clean temporary/generated files.

 1# Makefile to create theFinalDocument.pdf
 2
 3all: doc
 4
 5doc: theFinalDocument.pdf
 6
 7theFinalDocument.pdf : theFinalDocument.tex
 8
 9    latexrun theFinalDocument.tex
10
11clean:
12
13    -rm -f *.dvi *.log *.ind *.aux *.toc *.syn
14    -rm -f *.idx *.out *.ilg *.pla *.mtc* *.maf
15
16.PHONY: all doc clean

The - in front of rm denotes that even if rm fails, the make utility should not bother itself with that failure.

Warning

Makefiles become way more complicated and difficult to maintain when a complex steps and conditions are required in the code base.

Also, see https://books.purnank.in/c-cpp-sw-build-systems/. It shows how to use/write Make Files for C/C++ Code in a step-by-step manner for a small set of use case.