Building LaTeX papers with Tup

Building complex LaTeX documents can be quite painful. Thankfully, a little program called Tup can automate the build process for you.

When writing a research paper, there are often two options for manuscript creation: Microsoft Word and LaTeX.

In general I prefer to use LaTeX, because the idea of writing what you mean and allowing a powerful typesetting engine produce a beautiful document appeals to me. Furthermore, it is really useful being able to keep track of the manuscript with version control. However, being over 30 years old at this point, LaTeX is not without its warts.

One of the nastiest aspects of LaTeX is the build process. In Microsoft Word, there really isn’t a build step at all—what you see is really what you get. If you need to submit the document somewhere, you can do so and be reasonably confident that the recipient will see the same thing that you do.

LaTeX, in my experience, is a bit more complicated. Which LaTeX compiler command should be used? Which figures need to be built before compiling the main document? What are the dependencies between parts of the document?

In this post we will look at setting up automated builds for LaTeX documents.

Automatic LaTeX builds with Tup

Let’s say that you have a project directory called my_paper/ with a simple LaTeX document called main.tex inside:

My document is so awesome!

We can compile this document into a PDF by running the following command:

$ latexmk -pdf main.tex

Introducing Tup

Tup is a build system that fills a similar role to GNU Make, but has some nifty additional features.

To get started with Tup, create an empty file called Tupfile.ini file beside main.tex so that Tup knows where the root of the project is, then run tup init.

$ touch Tupfile.ini
$ tup init

Tup build rules are defined in Tupfiles. Make a build/ directory, and create a file called Tupfile within it.

: ../main.tex |> latexmk -pdf %f |> %B.pdf

This Tupfile has a single rule which says “take main.tex, run latexmk on it, and we will get main.pdf”. We can trigger the build by running Tup without any arguments.

$ tup

In this case Tup produces the PDF, but does so begrudgingly—look at those angry errors!

tup error: File XXX was written to, but is not in .tup/db. You probably should
specify it as an output

This is because latexmk writes to files other than main.pdf, and Tup needs to know about all outputs produced by a command. No problem, let’s add them in.

: main.tex |> latexmk -pdf %f |> %B.pdf %B.fls %B.log %B.aux %B.fdb_latexmk

Run tup again, and this time the errors should be gone.

Typing tup every time we edit a file is kind of annoying, but fortunately we don’t have to. Tup can monitor relevant files for us, and rerun the appropriate rules when files change.

$ tup monitor -f -a

Integration with Git version control

Let’s add version control to our little project with Git.

$ git init

When we were using Tup earlier, it created a .tup folder to keep track of file states. We should tell Git to ignore this folder.

$ echo ".tup/" >> .gitignore

Furthermore, we don’t want to commit our generated PDFs, logs, and whatever else to version control. Luckily, Tup makes it really easy to exclude generated outputs from Git. Simply add the .gitignore directive to Tupfile like so:

: ../main.tex |> latexmk -pdf %f |> %B.pdf %B.fls %B.log %B.aux %B.fdb_latexmk

Now when we go to stage everything…

$ git add .

…we can see that the generated files in build/ are ignored by Git.

$ git status
Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

  new file:   .gitignore
  new file:   Tupfile.ini
  new file:   build/Tupfile
  new file:   main.tex

Adding a Gnuplot figure

We can add as many rules as we like to our Tupfile. For example, say we want to add a plot of a sine wave. Create a directory called figures/ with a file called sine.gnuplot inside.

set terminal cairolatex input pdf size 8cm,6cm
set output 'sine.tex'
plot sin(x)

Add a new rule to build/Tupfile for compiling the Gnuplot figure. We will make the rule general, so that Tup can compile any .gnuplot file added to the figures/ directory. We will also group the outputs into a group called <figs>. We then add the <figs> group as an order-only input for the main.tex rule, so that Tup knows that the plots should be built before the main document.

: foreach ../figures/*.gnuplot |> gnuplot %f |> %B.tex %B.pdf <figs>
: ../main.tex | <figs> |> latexmk -pdf %f |> %B.pdf %B.fls %B.log %B.aux %B.fdb_latexmk

Finally, we need to actually embed the plot in the main document, main.tex. Note that we refer to the sine.tex as if it is in the current directory, since all building occurs in build/.

My document is so awesome!


Now if you edit either main.tex or sine.gnuplot, the PDF will be automatically rebuilt. Coupled with a nice PDF reader like Evince that refreshes when the document changes, you have the output displayed instantly as you work.

Adding a bibliography

Adding a bibliography works pretty much how you would expect.


  author = {Doe, John},
  title = {How awesome things come to exist},


My document is so awesome \cite{awesome}!




: foreach ../figures/*.gnuplot |> gnuplot %f |> %B.tex %B.pdf <figs>
: ../main.tex | <figs> |> latexmk -bibtex -pdf %f \
|> %B.pdf %B.fls %B.log %B.aux %B.fdb_latexmk %B.blg %B.bbl


There you have it, a nice way of setting up automatic LaTeX builds. Building the document from a fresh clone of the Git repository is as easy as running tup init && tup!