This entry was originally submitted to Debian Package of the day, but rejected because make is well known.
![A directed Graph: In connects to InterM that connects to Out](/uploads/2009/02/figure1.png)
Figure 1:The file
In
is used to produce InterM
that is itselfused to produce
Out
. Therefore Out
depends directly on InterM
and indirectly on In
.I agree that most programmers and administrators know GNU make. Sadly, it is ignored by most others. GNU make
solves a very common problem that everyone faces when processing more than one file with more than one programm. It keeps track which file has been changed and which files have to be regenerated.
Consider the abstract example of some output file Out
that is produced out of an intermediate file InterM
that itself is generated from some input file In
(see Figure 1). If In
is changed make
will reproduce InterM
and finally Out
. But if you only tweak InterM
you don’t want it to be overidden by the output of In
. Make
will not do that unless In
is newer than InterM
(i.e. was changed after you tweaked with InterM
).
We will take a short look at an example from the real-world of LaTeX. LaTeX is a typesetting system that produces nicely typeset postscript-files or PDF-files out of files containing the text in a special markup language. Assume that your LaTeX file sample.tex
includes two postscript (ps) figures like Figure 1 and 2 (get the tarball of the example here). These postscript files are generated from two description files by a software called graphviz.
To compile sample.tex
you typically type
dot -Tps -o figure1.ps figure1.dot # to produce Figure 1 dot -Tps -o figure2.ps figure2.dot # to produce Figure 2 latex sample.tex # to compile using latex dvips -o sample.ps sample.dvi # to generate a postscript-file
While editing your document, you have to type the above over and over again. This is tedious and error-prone. You may easily forget to run dot
after changing the figures or even forget what commands to use if you do not edit the text for a while. You may put the above in a shellscript, but then you have to add every figure to your shellscript and if you process a lot of figures it might take much longer than needed to compile your file, since all the figures are generated everytime you run your
shellscript.
Make solves both of these problems. Figure 2 illustrates the dependencies of the files. The information which file depends on which and how to produce one from the other is stored in a so called Makefile
. For our case it might look like this:
FIGURES=figure1.ps figure2.ps all: sample.ps # first rule sample.dvi: sample.tex $(FIGURES) # second rulelatex sample.tex %.ps:%.dot # third rule
dot -Grankdir=LR -Tps -o $@ $< %.ps:%.dvi # fourth rule
dvips -o $@ $<
![The dependencies of sample.tex.](/uploads/2009/02/figure2.png)
Figure 2:If
make
detects a change of a file (here the green figure1.dot
) it rebuilds all parents that depend on it (here all red nodes).So what does this mean?
- The first line defines a variable
FIGURES
. If you want to include another figure in your build-process all you have to do is add it here. - The second paragraph is called a rule (we will refer to it as first rule). It requests
make
to produce the left output (here:all) out of the right input (here: sample.ps). For reasons that will become clear later, we do not tellmake
how to produce “all”. Everything behind a hash#
is a comment. - In the second rule the output depends on
sample.tex
and the figures. Note that the variableFIGURES
has to be preceeded by a dollar sing and embraced by brackets. To fullfill this rulemake
has to runlatex
. We tell it to do so by a line starting with a tab (here marked as ““; it is a very common beginners error to use spaces instead of tabs!). So whenever the dependencies are fullfilled but sample.dvi is not up to date,
make
will runlatex sample.tex
. - The third and fourth rule tell
make
how to produce a ps-file out of a dot-file or a dvi-file. The percentage sign%
is a wildcard character (similar to*
in the shell). The special variable$@
contains the target of the rule (the filename, which matches the left side) while$<
contains the source or dependency of the rule (the right side).
If you type make
, the Makefile
in the current directory will be scanned. Without any further arguments make
will try to build the target of the first rule in the Makefile
that is -in our case- all
. The target all
depends on sample.ps
that itself can be build from
sample.dvi
by the last rule (%.ps:%.dvi
).
To build sample.dvi
, make
needs to invoke the second rule, but first it must meet its dependencys: the figures. The third rule tells make
how to produce the figures and the dependacy is met since the dot-files exist. Once the ps-files are produced, the dependencys of the second rule are fullfilled and make
invokes latex
to produce sample.dvi
that is then converted by the fourth rule to produce sample.ps
. Now make
stops, since there is nothing to do for all
(this is called a phony target).
If you run make
again it will not do much but just say:
make: Nothing to be done for `all'.
Now change something in figure1.dot
and run make
another time. This time make
will rebuild figure1.ps
, sample.dvi
and sample.ps
to incorporate your changes (see Figure 2).
Target Users:
Everyone who uses the command line to mangle several input files into some output files.
Further reading:
- The GNU Make Manual.
- There are plenty of make-tutorials on the internet although very few focus on non-programmers.
- An example of a sophisticated Makefile for LaTeX.
- TeXFAQ about make
Other packages doing similar things:
-
mktex is a special tool that might be a handy replacement of
make
if you’re only focused on LaTeX. - There exist many other buildtools avoiding some of make’s flaws.
You can find the most recent version of GNU make at ftp://ftp.gnu.org/gnu/make/.
Make is available for Debian and Ubuntu (and any other Linux-distribution).