Precompiled Preamble for LaTeX

If you can save six seconds every time you run LaTeX, would you do it?

Indeed, I have been pondering on this issue for quite some time now. Every time I compile “a large document that shall not be named”, I notice that the first six seconds are used to process the code before \begin{document}. But this code—known as the preamble—hardly sees any changes between runs. The preamble for this particular document may be a bit longer than usual, but considering that I am usually working on a chapter at a time using the \includeonly facility (see a tutorial here), these six seconds actually represent over 50% of the running time. Computationally and environmentally, this is horribly inefficient.

But a few days ago, I have finally stumbled upon a solution—it’s called “custom format file”. However, let me call it precompiled preamble, borrowing the concept from C compilers that support precompiled headers. Assuming your source file is main.tex, here is how you may use this method:

  1. Rearrange your preamble so that its static part precedes any dynamic part. What in the preamble can be “dynamic”? For example, if you use \includeonly, you probably want to change its argument rather frequently and so it is not static. Another example is the svninfo package, which introduces a command \svnInfo whose arguments get updated every time you commit. While you can certainly load svninfo.sty in the precompiled preamble, you also want the \svnInfo to remain in main.tex. Finally, some packages read and write auxiliary files when you issue a command that you should put in the preamble (eg, nomencl uses \makenomenclature). Clearly, you have to run these commands in every run.
  2. Extract the static part of the preamble into, say, preamble.tex. At this point, main.tex no longer contains the static part. It should start with the dynamic part, or simply \begin{document} if you have nothing dynamic.
  3. Execute latex -ini -job-name="main" "&latex preamble.tex\dump". You will notice that a new file main.fmt has been generated in the same directory, along with other auxiliary files. PDF users can replace latex with pdflatex in both occurrences and the same applies to the steps below. Also, in some distributions, the options could be “-jobname”. Make sure you get main.fmt and not preamble.fmt in this step.
  4. Edit the first line of main.tex so that it starts with %&main. There can be other stuff on that line too, for example

    %&main -*- mode: latex; TeX-master: "main.tex"; -*-

    works for me. (See this post if you are not familiar with Emacs local variables.)

  5. (Drum beats) Execute latex main.tex as usual. You may get an error about the class file immediately, or you may notice that latex finishes as usual. But if you have paid attention to the output, or if you inspect the the log file, then you will see that the preamble gets processed in “no time” at all. At this point, cheers!
  6. If you happen to hit an error, you will need to run latex -parse-first-line main.tex instead. The extra option will force latex to parse the first line of main.tex where we have asked for main.fmt to be used instead of the default format. (In Linux, you can try to locate texmf.cnf and change the option parse_first_line from f to t.)

To make things slightly fancier, here is an modification of my own. First, add this to the end of preamble.tex:

\def\preambleloaded{Precompiled preamble loaded.}

Then, before the dynamic preamble (or \begin{document} if there is none) of main.tex, add:

\def\ifundefined#1{\expandafter\ifx\csname#1\endcsname\relax}
\ifundefined{preambleloaded}\input{preamble}\else\typeout{\preambleloaded}\fi

The idea is to define a macro in the precompiled preamble and use it to detect if the precompiled preamble has been loaded or not. If not, \input{preamble} will be used to pull the static preamble back in and you will not see any error at all.

Of course, the actual amount of time saved will depend on your computer and your preamble. But in my case of long preamble and short document, the saving has been truly tremendous. (Hence I took some time to write this post in the hope that it would help someone down the road.)

Updated 2007/11/04: Changed the format file name to main.fmt and expanded on the dynamic preamble note.

File 2007/11/11: Attached beamer preamble test files in a zip, as referred to in my comment.

Updated 2007/11/11: Added comments for Linux users, after resolving the issue raised by Suresh’s comment.

Leave a comment ?

13 Comments.

  1. Great article and thanks Jan-Henrik – I would never have worked out that XeLaTeX needs the preamble (main) saved as ANSI !!

    A variant with relevance to XeLaTeX

    Do not include \begin{document} in the preamble (main) but place it in the “cut down” second file.

    This allows additional packages to be loaded before \begin{document} that cannot be supported otherwise – for me these are
    \usepackage{fontspec,xltxtra}%

    These give native font support which with Unicode is why I am using XeLatex

  2. Hi
    This was just what I was looking for but alas I couldn’t get it working yet.
    For me the problem is very similar to Suresh’s.
    I use beamer on Ubuntu. Somehow I keep getting
    the error
    ” pdfTeX error (ext1): cannot find referenced object.”
    Any clues?
    Regards
    Benny

  3. Hi,

    I am trying to fix a problem relating to LATEX. I prepared a document which I converted to pdf and my margin and everything is set in preamble, but then also in the resulting pdf file, I could see few lines are out of right margin. While compiling the document, I noticed some errors relating to spacing, but since my compiler just made the pdf, so I don’t understand what the problem was ? I am newbie with LATEX and usingWinEDT for writing. I would appreciate any help to resolve this issue.

    –SS

Leave a Comment


NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>