Building Latex Documents with Waf

Every since I started using Dropbox to store my academic research and projects, I've been looking for a solution that allows me to build LaTeX documents without dirtying up the document's directory. Normally I would just ignore the files, but under Dropbox, each time I build the document the files are synchronized to the server. Since there is no way for you to ignore files in Dropbox (please, please, if you're reading, give us a .dropboxignore file) I had to come up with another solution.

The Dark Ages: Makefile

Initially, I used a Makefile littered with chained shell commands that made a copy of the project directory and then forced a change to that temp directory before running any other commands.

PROJECTNAME := thesisIntro
TMPDIR := /tmp/latexBuild.$(PROJECTNAME)/

view: pdf
    -cd $(TMPDIR) && open -a Preview introduction.pdf

pdf: setup
    -cd $(TMPDIR) && pdflatex introduction

    -rm -fr $(TMPDIR)
    -mkdir $(TMPDIR)
    -cp -R * $(TMPDIR)

    -rm -fr $(TMPDIR)
Although it worked, it doesn't really handle anything non-trivial. I could instead move to using one of the large LaTeX Makefiles designed to handle more complicated tasks, like automatically detecting dependencies, etc. But combining the temporary build directory with a non-trivial makefile would be very difficult. ## A new alternative: Waf A few months ago, I saw a [blog post]( by Alan LaMielle talking about using the [`waf`]( build system. `waf` is written in Python with the premise that build systems require real scripting languages as well as powerful tools, and in my opinion it completely delivers. Distributed as a single python script, when first invoked it will unpack the `waf` libraries to a hidden directory and begin working. It comes with build tools for a slew of languages including Go, Python, LaTeX and even good old C programs. Configuring `waf` is a matter of writing a python script called `wscript` in your project directory, containing the project's details. For the LaTeX document I'm currently building, I use the following `wscript`:
#! /usr/bin/env python

top = '.'
out = '/tmp/wafbuild-dphilconf'

def configure(conf):
    conf.find_program('dot', var="DOT")
    if not conf.env.PDFLATEX:
        conf.fatal('could not find the program pdflatex')

def view_pdf(bld):
    bld.exec_command("open -a Preview \"{0}/dphilconf2010.pdf\"".format(out))

def build(bld):
    # Set up rules to build any of the .dot files to png versions
    for x in bld.path.ant_glob('*.dot'):
        tg = bld(rule='${DOT} -Tpdf -o${TGT[0].get_bld().abspath()} ${SRC[0].abspath()}', source=x, target=x.change_ext('.pdf'))


    obj = bld(
            features = 'tex',
            type = 'pdflatex',
            source = 'dphilconf2010.tex',

    if Options.options.view:

def options(opt):

    # custom command-line options
    opt.add_option('--view', action='store_true', default=False, help='View the document')

Breakdown: waf configure

Before I build the document for the first time, I run python waf configure to set up the build directory. Then each time I want to build the document I run python waf build or just python waf. If I want to see the resulting PDF, I just add the --view option.

A normal wscript file will have a configure function, which is called when the user invokes waf configure. In our case, we invoke the tex tool's configuration function by invoking conf.check_tool('tex') and then ensure pdflatex was detected, and add an additional check for the dot command-line program. Here's the output from waf configure:

Setting top to                           : /Users/jnwhiteh/Dropbox/Academic/DPhilConf2010 
Setting out to                           : /tmp/wafbuild-dphilconf 
Checking for program tex                 : /usr/texbin/tex 
Checking for program latex               : /usr/texbin/latex 
Checking for program pdflatex            : /usr/texbin/pdflatex 
Checking for program bibtex              : /usr/texbin/bibtex 
Checking for program dvips               : /usr/texbin/dvips 
Checking for program dvipdf              : not found 
Checking for program ps2pdf              : not found 
Checking for program makeindex           : /usr/texbin/makeindex 
Checking for program pdf2ps              : not found 
Checking for program dot                 : /usr/local/bin/dot 
'configure' finished successfully (0.088s)

As you can see the configure script has detected all of the required programs and set up the build system.

Breakdown: waf build

The actual build function is somewhat straightforward, first it iterates over all of the .dot files in the directory, adding build rules for each of them. This maps every .dot file to a .pdf file, and anywhere that these .pdf files are included in the original LaTeX document, the build system sets up dependencies. This makes it so that if you change the source .dot file, both the .pdf for that image and the main document will all be rebuilt.

The call to bld_add_group() indicates that documents in the first group may be required by documents in the second group. The second group consists of build rule, using the LaTeX package, called tex. We specify that pdflatex should be used, and the source document.

The last bit of the build function checks for the view option, and if it finds it, it adds view_pdf as a function to be run after the build is complete. That function just runs a command on the system to open the PDF.

The view option is defined in the options function, with the command-line argument of --view.

Putting it all together

For you to use this wscript, you will need to alter it (at the very least) to use your LaTeX document as the source document. You'll want to run `waf configurefirst, and can follow that withwaf build` to build your document. Your LaTex document could obviously be simpler, and you can see an example LaTeX wscript in the waf source repository.

The advantage of building documents like this is dependencies are automatically tracked by scanning the original document, and any changes to dependent documents (including graphics files) will trigger a rebuild of the final pdf.





James N. Whitehead II is an author, computer scientist who is currently studying for his DPhil/PhD at the Oxford University Computing Laboratory. This blog is a collection of his thoughts, projects, snippets, photos and any other bits that come along.