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:
- 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\svnInfowhose arguments get updated every time you commit. While you can certainly loadsvninfo.styin the precompiled preamble, you also want the\svnInfoto remain inmain.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. - Extract the static part of the preamble into, say,
preamble.tex. At this point,main.texno longer contains the static part. It should start with the dynamic part, or simply\begin{document}if you have nothing dynamic. - Execute
latex -ini -job-name="main" "&latex preamble.tex\dump". You will notice that a new filemain.fmthas been generated in the same directory, along with other auxiliary files. PDF users can replacelatexwithpdflatexin both occurrences and the same applies to the steps below. Also, in some distributions, the options could be “-jobname”. Make sure you getmain.fmtand notpreamble.fmtin this step. - Edit the first line of
main.texso 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.)
- (Drum beats) Execute
latex main.texas usual. You may get an error about the class file immediately, or you may notice thatlatexfinishes 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! - If you happen to hit an error, you will need to run
latex -parse-first-line main.texinstead. The extra option will forcelatexto parse the first line ofmain.texwhere we have asked formain.fmtto be used instead of the default format. (In Linux, you can try to locatetexmf.cnfand change the optionparse_first_linefromftot.)
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.
3:13 on November 11th, 2007
I was trying to do this for a talk that uses beamer (I’m not sure if all of this works with pdflatex).
In any case, first of all, the file that gets created for me is preamble.fmt, not main.fmt. So I renamed it.
But then, when I tried to latex main.tex, (or pdflatex it), I got all kinds of errors that didn’t appear in the original latex workflow
11:43 on November 11th, 2007
The principle applies to pdflatex and I’ve just tried it successfully using conference-ornate-20min.en.tex from beamer and pdflatex. I am guessing it has something to do with your distribution.
My main concern is that you do not get main.fmt at all. There was indeed an earlier revision of this article that gives you preamble.fmt. But since you know you should be getting main.fmt instead, I suppose you are already following the updated instructions.
I have uploaded a zip file that records all my steps and all the files I get in my experiment using MiKTeX 2.6. See the updated post. The commands I have executed are in go.bat and you can look at transcript.txt for the output. The tex files are there so that you can run the experiment on your machine to find the discrepancy.
Let me also take this chance to note the running time I observed. It takes about 7 seconds to get the preamble precompiled. Then each run takes 3 to 4 seconds. But without the precompiled preamble, each run takes 9 to 11 seconds. The time saving is very real.
Finally, feel free to send me your directory including the log and aux files. I am sure you know my email address.
11:01 on December 20th, 2007
It works great - as long as I compile from the command prompt… Simply typing xelatex main.tex does the job.
But when I run LaTeX (XeLaTeX) from GNU Emacs (w/ AUCTeX), then it doesn’t work and preamble.tex is used… The log file says: Running `LaTeX’ on `main’ with “xelatex -interaction=nonstopmode “\input” “main.tex””
Does that have something to do with nonstopmode or input? How can I change that in Emacs?
Thanks a lot for any hints!
9:44 on December 21st, 2007
You want to change your TeX-command-list variable. Here is one way you can do it:
M-x customize-variable ENTER TeX-command-list ENTER
In the customization screen, find the LaTeX entry. The command you would see is probably:
%l -interaction=nonstopmode \input %t
(This is my guess based on your log file quote.)
You want to change the command to
%l -interaction=nonstopmode %t
(Basically, take out the \input.)
Select “Save for Future Sessions” and restart Emacs.
15:16 on December 29th, 2007
Sorry for my late reply this time - the holidays were just a busy time…
So, I got to the customization page but I haven’t been able to find the “interaction” command. The LaTeX command is the following:
%`%l%(mode)%’
Does this tell you anything? Changing the command to just %t doesn’t work…
Thanks again for the help!
Kind regards,
Jan-Henrik
14:36 on January 2nd, 2008
It’s still the \input problem, and it’s hardcoded in the expansion of the
%'. Assuming that you don’t have spaces in your file name (and path name), try this:%l%(mode) %t12:44 on January 14th, 2008
That actually works…
Thank you! 
6:23 on May 8th, 2008
I don’t think the “-job-name=”main” ” in the command below is necessary
latex -ini -job-name=”main” “&latex preamble.tex\dump”
Exec-ing, instead
latex -ini “&latex preamble \dump”
generates preamble.fmt. Also note that i’ve left out the file extension in preamble.tex. (La)TeX knows what file types to look for.
I tried both variants, with identical results. The latter makes more sense to me however; since we’re (pre-)loading the contents of preamble into main.
Thanks for your post, which inspired me to start my own blog today