Makefiles for LaTeX

To edit LaTeX documents, I use three programs for compiling, editing and viewing, glued together by awesome and run via a Makefile. These three usual suspects are:

We will now see how to write some Makefiles to automatically recompile LaTeX documents upon changes to the source TeX or figure files (PDF, SVG, etc.).

Minimal Makefile

Here is a minimal Makefile to recompile the document upon saving the TeX file. It relies on inotifywait to recompile the document upon changes to the TeX source. On Debian/Ubuntu, you will find this tool in the inotify-tools package (sudo apt-get install inotify-tools).

# LaTeX Makefile v0.33 -- LaTeX only

PAPER=paper.tex  # set the path to your TeX file here
SHELL=/bin/zsh   # for the while loop below

all:  ## Compile paper
    rubber --pdf $(PAPER)

clean:  ## Clean output files
    rubber --clean $(PAPER)

watch:  ## Recompile on updates to the source file
    @while [ 1 ]; do; inotifywait $(PAPER); sleep 0.01; make all; done
    # for Bash users, replace the while loop with the following
    # @while true; do; inotifywait $(PAPER); sleep 0.01; make all; done

After setting PAPER to your TeX file’s name, run make watch and the document will be automatically recompiled any time you save it in your text editor. Your PDF viewer should also reload the file automatically upon updates (Zathura does it).

Addendum

An astute reader pointed out on Reddit that the latexmk tool does exactly the job of make watch when using the -pvc (PreView Continuously) option:

latexmk -pdf -pvc paper.tex

However, in my experience LaTeX errors sometimes put this tool in an inconsistent state, requiring a Ctrl-C and restart to update the PDF correctly. At any rate, we will see below how we can extend our make watch rule to recompile SVG figures as well upon updates, which latexmk doesn’t do.

Adding figures

Maybe you have SVG figures in your document, which you manually export to PDF and include in your document via \includegraphics. This process can be automated in the Makefile by calling Inkscape from the command-line. Here is an extended Makefile that will automatically recompile PDF figures from their SVG sources upon saving:

# LaTeX Makefile v0.66 -- LaTeX + PDF figures

ALL=$(wildcard *.sty *.tex figures/*.svg)
PAPER=paper.tex
SHELL=/bin/zsh

FIGURES_SVG=$(wildcard figures/*.svg)
FIGURES_PDF=$(FIGURES_SVG:.svg=.pdf)

all: $(FIGURES_PDF)  ## Build full thesis (LaTeX + figures)
    rubber --pdf $(PAPER)

clean:  ## Clean LaTeX and output figure files
    rubber --clean $(PAPER)
    rm -f $(FIGURES_PDF)

figures/%.pdf: figures/%.svg  ## Figures for the manuscript
    inkscape -C -z --file=$< --export-pdf=$@

watch:  ## Recompile on any update of LaTeX or SVG sources
    @while [ 1 ]; do; inotifywait $(ALL); sleep 0.01; make all; done

Makefile of my PhD thesis

Rubber automates the compilation of LaTeX documents, and using inotifywait and inkscape automates the process further. As an example, below is the full Makefile I used to compile my PhD thesis, as well as associated resources such as the (HTML 5) slides of my defense. The directory structure was:

$ tree -L 2 ~/Documents/Thesis
/home/scaron/Documents/Thesis
├── cleanthesis.sty
├── content
├── defense
   ├── images
   ├── index.html
   └── static
├── figures
   ├── pdf
   ├── static
   └── svg
├── Makefile
├── refs.bib
└── thesis.tex

And the corresponding Makefile:

# LaTeX Makefile v1.0 -- LaTeX + PDF figures + PNG figures

ALL=$(wildcard *.tex content/*.tex defense/index.html figures/svg/*.svg)
MAIN=thesis.tex
LATEX=rubber --pdf
SHELL=/bin/zsh

FIGURES_SVG=$(wildcard figures/svg/*.svg)
FIGURES_PDF=$(subst svg/,pdf/,$(FIGURES_SVG:.svg=.pdf))
FIGURES_PNG=$(subst figures/svg/,defense/images/,$(FIGURES_SVG:.svg=.png))

all: $(FIGURES_PDF) $(FIGURES_PNG)  ## Build full thesis (LaTeX + figures)
    $(LATEX) $(MAIN)                # main run
    bibtex $(MAIN:.tex=)            # bibliography
    makeglossaries $(MAIN:.tex=)    # list of abbreviations, nomenclature
    $(LATEX) $(MAIN)                # incremental run

clean:  ## Clean LaTeX and output figure files
    rubber --clean $(MAIN)
    rm -f $(FIGURES_PDF) $(FIGURES_PNG)

figures/pdf/%.pdf: figures/svg/%.svg  ## Figures for the manuscript
    inkscape -C -z --file=$< --export-pdf=$@

defense/images/%.png: figures/svg/%.svg  ## Figures for my defense slides
    inkscape -C -z --file=$< --export-png=$@

watch:  ## Recompile on any update of LaTeX or SVG sources
    @while [ 1 ]; do;          \
        inotifywait $(ALL);    \
        sleep 0.01;            \
        make all;              \
        echo "\n----------\n"; \
        done

help:  # http://marmelab.com/blog/2016/02/29/auto-documented-makefile.html
    @grep -P '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
.DEFAULT_GOAL := help
.PHONY: help

It includes two minor changes compared to the previous Makefile: the compilation of both PDF and PNG figures (rewrite rules get a bit more complex) and the nice help snippet from the marmelab blog.

Integrating Inkscape and LaTeX

There is room for improvement in the integration between Inkscape and LaTeX. So far, I have been using the textext extension to embed LaTeX equations into SVG files. However, with this approach one needs to coordinate by hand the font size between the SVG and LaTeX documents. For instance, when you scale the figure in \includegraphics, its text gets scaled as well.

Looking at the LaTeX page of the Inkscape wiki and the related svg-inkscape LaTeX package, it seems one can alternatively process SVG figures directly from LaTeX. This has the benefit not only of using the same text scaling between figure and document, but also enables you to use other contextual macros such as \ref and \cite. One should definitely try it out 😉

Discussion

Feel free to post a comment by e-mail using the form below. Your e-mail address will not be disclosed.

📝 You can use Markdown with $\LaTeX$ formulas in your comment.

By clicking the button below, you agree to the publication of your comment on this page.

Opens your e-mail client.