Building Latex Documents with Waf
Posted
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
setup:
-rm -fr $(TMPDIR)
-mkdir $(TMPDIR)
-cp -R * $(TMPDIR)
clean:
-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](http://alan.lamielle.net/2009/09/29/using-waf-to-build-latex-documents)
by Alan LaMielle talking about using the [`waf`](http://code.google.com/p/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.check_tool('tex')
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'))
bld.add_group()
obj = bld(
features = 'tex',
type = 'pdflatex',
source = 'dphilconf2010.tex',
)
if Options.options.view:
bld.add_post_fun(view_pdf)
def options(opt):
opt.tool_options('tex')
# 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.
Links
- Waf build system - http://code.google.com/p/waf/
- Ultimate LaTeX buildfile - http://www.acoustics.hut.fi/u/mairas/UltimateLatexMakefile/
- LaTeX makefile - http://code.google.com/p/latex-makefile/



















