Makefiles for LaTeX

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
Figure 1:The file In is used to produce InterM that is itself
used 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 rule
<TAB> latex sample.tex

%.ps:%.dot                          # third rule
<TAB> dot -Grankdir=LR -Tps -o $@ $<

%.ps:%.dvi                          # fourth rule
<TAB> dvips -o $@ $<
The dependencies of sample.tex.
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 tell make 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 variable FIGURES has to be preceeded by a dollar sing and embraced by brackets. To fullfill this rule make has to run latex. We tell it to do so by a line starting with a tab (here marked as “<TAB>“; 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 run latex 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:

Other packages doing similar things:

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).