Make and Makefiles

by Mark Hays


Table of Contents


Introduction

This document covers the basics of using the make utility (available on all departmental LINUX systems).

Make is a tool that is designed to help you manage software projects; here, project means a set of files that depend on one another in some way. The canonical example of a project is a set of C (or FORTRAN or whatever) source files and associated header files. The .c files depend on the .h files, .o files depend on .c files, and the final executable depends on the .o files.

In this document, we'll consider a slightly different example: a LaTeX project. For concreteness, suppose we have four files:

diss.tex
LaTeX source for a dissertation
ch1.tex
LaTeX source for chapter 1
fig.ps
a PostScript figure generated by gnuplot
fig.dat
the data file from which fig.ps was generated
There are three major things we might want to do with these files:
  1. Build a .dvi file from the .tex files
  2. Build the .ps figure from the raw data
  3. Build a .ps file from the .dvi file and the PostScript figure
To accomplish number 1, you'd type
latex diss.tex
To build the figure, we start up gnuplot and issue the following commands:
gnuplot> set term post portrait monochrome "Times-Roman" 18
gnuplot> set size .5,.5
gnuplot> set output "fig.ps"
gnuplot> plot "fig.dat" with linespoints
gnuplot> quit
The figure looks like this:
dumb figure
To convert the .dvi file and the figure you just generated to a .ps file named diss.ps, type
dvips -o diss.ps diss.dvi

Make is designed to automatically run commands like these for you whenever necessary. What does "necessary" mean? For example, if you want the most up to date diss.dvi, you will need to run LaTeX on diss.tex if you have modified diss.tex since the last time you LaTeX'ed it. If you need diss.ps, it may be necessary to run LaTeX on diss.tex, run gnuplot to rebuild fig.ps, and finally run dvips to get the latest diss.ps. For nontrivial projects it is annoying (if not impossible) to keep track of these details in your head; just imagine having to keep track of 10 TeX files, 20 data files, and 10 figures! If you rerun your Matlab code and update three of the data files, which of the 10 figures needs to be rebuilt?

Make decides which commands to run based on the modification times of the files involved and a project description file (provided by you) that describes the dependency relationships among your files. When you run make, it reads this input file (named "Makefile" or "makefile", usually) and checks the timestamps on the files required to build your project. It then executes the minimum number of commands necessary to bring everything up to date.

For projects consisting of more than a couple of files, it can be more efficient to spend thirty minutes writing a makefile than to type the same commands over and over again, all the while trying to remember if figure 7 uses data3.out in any way. Your investment in make pays off when you type

make diss.ps
and see dozens of commands flying by as your dissertation gets built.

In the rest of this document, we'll look at various ways to automate and simplify the build process with make.


The Basics of Make

Below is a simple Makefile to manage the project we described earlier:
     1: ########################################
     2: # Makefile -- version 0
     3: 
     4: # diss.dvi depends on diss.tex
     5: diss.dvi:       diss.tex
     6:         make fig.ps
     7:         latex diss.tex
     8: 
     9: # fig.ps depends on fig.dat and fig.gnu
    10: fig.ps: fig.dat fig.gnu
    11:         gnuplot < fig.gnu
    12: 
    13: # diss.ps depends on diss.dvi and fig.ps
    14: diss.ps:        diss.dvi fig.ps
    15:         dvips -o diss.ps diss.dvi

First, a "#" denotes a comment; anything from a "#" to the end of the current line is ignored by make.

This Makefile defines three explicit rules (there are also implicit rules). Line 5 says that the file diss.dvi depends on diss.tex (the colon can be read "depends on"). Lines 6 and 7 tell make what commands to run if diss.dvi is older than diss.tex. In this case, we rebuild the figure and run LaTeX on diss.tex. In make's terminology, the target diss.dvi has the prerequisite or dependent diss.tex. This rule is called explicit because all of the filenames are spelled out in full.

Why do we need to rebuild the figure? Diss.tex includes the figure as follows:

\includegraphics[width=5in]{fig.ps}
The \includegraphics command demands that the file being included already exist; otherwise, you get a LaTeX error. If we start with only diss.tex, fig.dat, and fig.gnu, we need to build the figure before running LaTeX to avoid this problem.

Lines 10 and 11 are similar: they tell make how to build the figure fig.ps from fig.dat and fig.gnu (fig.gnu contains the commands we entered at the gnuplot prompt eariler). To regenerate the figure, we run gnuplot and tell it to read commands from fig.gnu. Fig.gnu in turn tells gnuplot to send PostScript output to the file fig.ps. Note that make will rebuild the figure for two reasons: because fig.dat has changed or because fig.gnu has changed. If we rerun the code that produced fig.dat, make will automatically rebuild fig.ps. If, on the other hand, we modify fig.gnu, make will also rebuild fig.ps. In other words, having fig.ps depend on both files causes the figure to be rebuilt when

This can be Very Handy.

Finally, lines 13 and 14 tell make that diss.ps depends on both diss.dvi and fig.ps. To build diss.ps, we run dvips with the -o <output_file> option; otherwise, the PostScript output gets sent to the printer, which is not (necessarily) what we want.

So how does all this work? Well, let's suppose you start with only diss.tex, fig.dat, and fig.gnu. If you type

make diss.ps
make will execute the following:
                gnuplot < fig.gnu
                latex diss.tex
                dvips -o diss.ps diss.dvi
Make looks at the diss.ps rule and sees that it needs to build diss.dvi first. The rule for diss.dvi causes make to run another copy of make to build fig.ps. Since fig.ps doesn't exist, the second copy of make runs gnuplot and exits. Back in the diss.dvi rule, the original make runs LaTeX to produce diss.dvi. Having done all this, make continues scanning the diss.ps rule. The next prerequisite is fig.ps. Make looks at the timestamps on fig.dat, fig.gnu, and fig.ps, and decides that fig.ps is up to date (we just built it), so there's nothing to do. Now that all of the prerequisites of diss.ps are in place, make runs dvips to produce diss.ps.

What happens if you type "make diss.ps" again? Make issues the message

make: `diss.ps' is up to date.

indicating that nothing needs to be done (since all of the prerequisites of diss.ps are older than diss.ps).

Now, suppose that you edit fig.dat and remove an "outlier" data point. If you type

make diss.ps
make executes the following commands:
                gnuplot < fig.gnu
                dvips -o diss.ps diss.dvi

Instead of running "make fig.ps" in line 6, we could have made diss.dvi depend on fig.ps on line 5. If you use LaTeX2e, doing this would ensure that you would always have the most up to date figures in xdvi. However, it would also mean that make would have also run LaTeX above, which, strictly speaking, isn't necessary.

There are a few format restrictions that you should observe in your Makefiles. Lines that state dependencies (like line 5) should not have any whitespace at the beginning of the line. The colon should be followed by a TAB (even when there are no dependents), and the dependents can be separated by arbitrary whitespace. If the list of dependents (or targets) is longer than one line, you can use the line continuation character, "\" to split the list across multiple lines; for example,

                diss.dvi:       diss.tex ch1.tex ch2.tex \
                                ch3.tex ch4.tex ch5.tex ch6.tex
                        latex diss
The "\" must be the last character on the line. Lines that list commands to run (like lines 6 and 7) must begin with a TAB character (this is how make tells where the list begins and ends). There are actually many versions of make; this list of rules takes the low road and will hopefully keep you out of trouble.

Dummy Targets

In the previous example we saw that make will rebuild a target for two reasons: In the above example, the commands specified for each target actually create the target. For example, the rule for diss.dvi runs LaTeX on diss.tex. This creates diss.dvi.

The commands for "dummy targets" do not actually create the target; instead, they perform some other action. Since the target never exists, make always executes these commands. This is best illustrated by example.

     1: ########################################################################
     2: # Makefile -- version 1
     3: 
     4: all:    view
     5: 
     6: diss.dvi:       diss.tex
     7:         make fig.ps
     8:         latex diss.tex
     9: 
    10: fig.ps: fig.dat fig.gnu
    11:         gnuplot < fig.gnu
    12: 
    13: diss.ps:        diss.dvi fig.ps
    14:         dvips -o diss.ps diss.dvi
    15: 
    16: clean:  
    17:         /bin/rm -f diss.dvi diss.aux diss.log diss.ps fig.ps
    18: 
    19: view:   diss.dvi
    20:         xdvi diss.dvi
    21: 
    22: psview: diss.ps
    23:         ghostview diss.ps
    24: 
    25: print:  diss.dvi fig.ps
    26:         dvips diss.dvi

Lines 6-14 are the same as in the previous Makefile.

First, consider the dummy target "view" defined on lines 19 and 20. "View" depends on diss.dvi, and so make rebuilds diss.dvi if necessary. The command that ostensibly builds the file "view" instead runs xdvi on diss.dvi. The file "view" never gets built, so any time you type

make view
make will run xdvi for you (possibly running LaTeX first). What if there is a file named "view"? Then things get goofy because make uses that file's timestamp to decide what to build. Dummy targets (by definition) never exist as files.

Similarly, lines 2-26 define the dummy targets "psview" and "print", which run ghostview on diss.ps (so you can preview the final product) and print out diss.dvi, respectively. The print target also updates fig.ps so that we always the most current set of figures.

Lines 16 and 17 define a target "clean" which removes all of the files generated by LaTeX, dvips, and gnuplot. This is convenient when you want a clean slate or want to recover some disk space. It is of course important that you only remove things that can be rebuilt :-)

Line 4 gives a rule (with no commands) for the dummy target "all". "All", in turn, depends on the dummy target "view" (which runs xdvi). This rule also exists for convenience. If you type "make" (or "make all") instead of "make <target>", make builds the first target it finds in the Makefile. If you are actively editing diss.tex, you can view your progress by simply typing "make".


Macros

Make lets you define and use macros (simple variables) in your Makefiles. In this section, we'll see how to use macros to eliminate some of the repetitiveness in the previous Makefile and construct a simple LaTeX Makefile template.
     1: ########################################################################
     2: # Makefile -- version 2
     3: 
     4: all:    view
     5: 
     6: ########################################
     7: # base filename of the project
     8: base=diss
     9: 
    10: # files included by $(base).tex
    11: texdeps=ch1.tex
    12: 
    13: # list of figures -- THEY ARE ALL REMOVED BY "make clean"!!
    14: #   if you don't have any figures, set it to "nofigures"
    15: figures=fig.ps
    16: 
    17: ########################################
    18: # put rules to build individual figures here
    19: 
    20: fig.ps: fig.dat fig.gnu
    21:         gnuplot < fig.gnu
    22: 
    23: ########################################
    24: # boilerplate follows...
    25: 
    26: texfile=$(base).tex
    27: dvifile=${base}.dvi
    28: psfile =$(base).ps
    29: 
    30: # things removed by "make clean"
    31: junk=$(dvifile) $(base).aux $(base).log $(figures) $(psfile)
    32: 
    33: nofigures:      
    34: 
    35: $(dvifile):     $(texfile) $(texdeps)
    36:         $(MAKE) $(figures)
    37:         latex $(texfile)
    38: 
    39: $(psfile):      $(dvifile) $(figures)
    40:         dvips -o $@ $(dvifile)
    41: 
    42: clean:  
    43:         /bin/rm -f $(junk)
    44: 
    45: view:   $(dvifile) $(figures)
    46:         xdvi $(dvifile)
    47: 
    48: psview: $(psfile)
    49:         ghostview $(psfile)
    50: 
    51: print:  $(dvifile) $(figures)
    52:         dvips $(dvifile)

Line 8 defines a macro called "base" whose value is "diss". This macro is used, for example, on lines 26 and 27. To reference a macro, you refer to it as $(name) or ${name}. These two lines also illustrate that macros can be used to define other macros. Recursive macros (ones that directly or indirectly reference themselves) are not allowed. References to nonexistent macros are replaced with the empty string "". Finally, macros do not have to be defined in any particular order: make processes all macro definitions before doing any expansions. This implies that the last definition of a macro is the one that gets used.

How is this helpful? For simple projects, you only have to edit lines 8, 11, 15, and tell make how to build your figures after line 19. This Makefile assumes that you have one main LaTeX file that \input's all of the other LaTeX files. It also assumes that everything is in the current directory (actually, this is a limitation imposed by make itself).

In line 8, you give the name of your main LaTeX file, without an extension. The Makefile uses this in lines 26-28 to construct the specific names of .tex, .dvi, and .ps files that go with your project. In line 11, you list the files included by the main LaTeX file; these are used in the dependency list to produce the .dvi file. Line 15 is a list of figures to be automatically generated by make, based on the rules you supply after line 19. This list is used in the dependencies for the .ps file and for printing.

Everything in this list is removed by "make clean"
Do not put anything in this list that cannot be generated by make.

There is one other new feature in this Makefile: the "$@" macro used in line 40. $@ always evaluates to the current target.

http://math.arizona.edu/~swig/documentation/makefiles/dissertation/index.php
Last modified: Fri, 14 Dec 2007 15:50:52 -0700
E-mail: swig@math.arizona.edu
Valid XHTML 1.0! Valid CSS!