February 22, 2019

Beyond Makefiles: GNU make is For More Than Just Compiling

make and LaTex

  • June 15, 2010
  • By Juliet Kemp

Juliet Kemp

You've probably encountered make as a compile tool, used for turning source code into executables (make; make install). However, make can do a lot more than just that. You can use it to automate pretty much any process which involves running a set of commands on source files. Read on to find out what make actually does, and how you can use it.

How make works

To get its instructions, make looks for a file called makefile or Makefile, which contains definitions for constructing different targets. You specify the target on the command line, and then make carries out the actions for that target (e.g. make install will carry out the commands for the install target). However, the makefile also specifies a set of files on which each target depends, and the commands will be run only if those files have been modified since the last time this target was generated. Otherwise, make will not do anything.

Here's a basic compile example:

.PHONY: all
all: myfile

myfile: myfile.o
	gcc -g -o $@ $<
The target all is the one that is called by default if you just type make from the command line. It's declared as a phony target so that if you end up with a file named all in the working directory, it won't get in the way of this target. Here it would call the myfile target. If the dependency, myfile.o, has been modified more recently than the target myfile, or if myfile doesn't exist, then the command gcc - -o $@ $< will be run. $@ refers to the target name, and $< refers to the dependency. Note that if you don't specify a dependency, that section of the makefile will never run.

make and LaTeX

So, what make really does is to generate a target from any dependency. This means that you can use make not just for compiling programs, but to act when any sort of file is changed. For example, you could use this makefile to automate running LaTeX:

all: myreport

myreport.pdf: myreport.tex
        pdflatex $<
        bibtex myreport
        pdflatex $<
        pdflatex $<
        xpdf $@
(pdflatex must be run several times due to the interaction with bibtex.) Here, if myreport.tex is edited, running make (no argument needed) will regenerate the target file (myreport.pdf) with appropriate reference updates, and then open it with xpdf. You could add the name of the bibliography file as well as the TeX source file so that make would run if either file were altered.

A note: if you haven't edited the file but you want make to run anyway, type touch filename to trick make into thinking an edit has been made. Alternatively, run make myreport and the target will be run whether or not the source files have been changed.

Here's a slightly neater version:

LATEX  = pdflatex
BIBTEX = bibtex
VIEWER = xpdf

all: myreport

myreport: myreport.tex
        $(LATEX) $<
        $(BIBTEX) $@
        $(LATEX) $<
        $(LATEX) $<
        $(VIEWER) $@.pdf
The first advantage of this is that you use variables in your commmands. So if you decide to use latex and xdvi rather than pdflatex and xpdf, it's a two-line edit. The second advantage is that the dependency and target are always referred to with $< and $@.

However, if you do it this way, the commands will always be run, because there is no target file myreport to check the update time of the source file myreport.tex against (there's only myreport.pdf). You could fix this like this:

myreport: myreport.tex
        $(LATEX) $<
        $(BIBTEX) $@
        $(LATEX) $<
        $(LATEX) $<
		mv $@.pdf $@
        $(VIEWER) $@
This way your output file will have the same name as the target, and the update times can be compared.

Most Popular LinuxPlanet Stories