自動ビルド

「Rerun to get cross-references right」——LaTeX は、一度走らせただけでは正解にならない、数少ない組版システムです。相互参照も目次も引用も一度目の実行では ファイルに書き出されるだけ なので、latexmk のような 自動ビルド ツールが、出力が落ち着くまでの往復を代わりに回してくれます。このページでは、そもそもなぜ複数回のコンパイルが要るのかという仕組みから始めて、latexmk -pdf、保存のたびに組み直す -pvc、掃除の -c-C、設定ファイル latexmkrc、そして ararallmkmake という選択肢までを一本の筋で追います。

なぜ LaTeX は何度もコンパイルが必要なのか

答えは単純で、LaTeX は文書を前から後ろへ一度だけ読む からです。1 ページ目に目次を組む時点では、第 7 節が何ページに落ちるかまだ決まっていません。そこで LaTeX は、走りながら分かったこと——各ラベルの節番号とページ番号、目次の行、引用キー——を .aux.toc.lof.lot といった補助ファイルに書き出し、次の実行の冒頭でそれを読み返します。つまり出力は、いつも 前回 の実行が突き止めた値を材料に組まれています。一度目の PDF に目次が無く、参照の位置が ?? になるのはそのためです。

ここに気の利いた仕掛けがあります。LaTeX は「あと何回まわせばいいか」を数えていません。\end{document} の時点で、今回計算した各ラベルの値を 前回の .aux から読み込んだ値と一つずつ突き合わせ、一つでも食い違えば LaTeX Warning: Label(s) may have changed. Rerun to get cross-references right. と警告します。逆に言えば、この警告が消えたときが「.aux がもう変わらない」状態、つまり 不動点 に達したときです。文書が仕上がったかどうかの判定は、ページの見た目ではなく、補助ファイルの一致で決まっているわけです。

text
% doc.aux -- what one run leaves behind for the next one to read
\@writefile{toc}{\contentsline {section}{\numberline {1}One}{1}{}}
\newlabel{sec:one}{{1}{1}{}{}{}}

% doc.log -- the first run, before the .aux settles
LaTeX Warning: Reference `sec:two' on page 1 undefined on input line 5.
LaTeX Warning: There were undefined references.
LaTeX Warning: Label(s) may have changed. Rerun to get cross-references right.

文献を付けると、この往復はさらに長くなります。\cite が要求した鍵は一度目の .aux に記録され、それを読んだ bibtex あるいは biber.bbl を作り、二度目の実行が .bbl を取り込み、番号がずれた参照を直すために三度目が要る——有名な latex → bibtex → latex → latex という呪文の正体はこれです。索引があれば同じ鎖に makeindex が挟まります。手で回している限り、毎回「どこまで戻ればよいか」を判断し続けることになります。

latexmk の基本的な使い方——1 コマンドで往復を回す

打つのは latexmk -pdf document.tex の一行だけです。あとは latexmk が .aux の変化を見ながら pdflatex を必要な回数だけ走らせ、途中で bibtexbibermakeindex を適切な順序で呼び、警告が消えたところで止まります。この道具の来歴は少し変わっていて、もとは David J. Musliner が書いた go という小さなスクリプトでした。それを Evan McLean が改造して latexmk と名付け、いまはペンシルベニア州立大学の物理学者 John Collins が Perl で保守しています——手元の TeX Live 2024 では latexmk -v が「Latexmk, John Collins, 31 Jan. 2024. Version 4.83.」と答えます。TeX Live にも MiKTeX にも同梱されているので、追加インストールは基本的に不要です。

terminal
$ latexmk -pdf doc.tex
Latexmk: applying rule 'pdflatex'...
Run number 1 of rule 'pdflatex'
Running 'pdflatex  -recorder  "doc.tex"'
Latexmk: References changed.
Latexmk: applying rule 'pdflatex'...
Run number 2 of rule 'pdflatex'
Running 'pdflatex  -recorder  "doc.tex"'
Latexmk: All targets (doc.pdf) are up-to-date

出力に現れる -recorder は latexmk が自分で足したものです。このオプションが付くと TeX エンジンは、その回に読んだファイルと書いたファイルの一覧を .fls に吐き出します。latexmk はそれをログと突き合わせて依存関係を割り出し、各ファイルの状態を .fdb_latexmk というデータベースに残します。肝心なのは判定の基準で、latexmk は更新時刻ではなく 中身のチェックサム を比べます。マニュアルはその理由をはっきり書いています。LaTeX の実行中に書き出されたファイルは、実行前に読み込まれたファイルよりも必ず新しくなるため、時刻だけを見ていると永久に「古いまま」に見えてしまう——この循環依存は LaTeX に固有の問題で、latexmk はそれを乗り越えるために作られた、というのです。暴走に備えた保険もあり、$max_repeat(既定は 5 回)を超えても収束しなければ、無限ループとみなして打ち切ります。

-pdf-lualatex-xelatex の違い——エンジンを選ぶ

-pdfpdflatex-lualatexlualatex-xelatexxelatex を使うという指定です。何も付けないと latexmk は昔ながらに .dvi を作るので、PDF が欲しければどれかを必ず添えます。ここに一つ、知っておくと得な仕掛けがあります。-xelatex を指定しても latexmk は xelatex に直接 PDF を書かせません。まず中間形式の .xdv を作り、往復をすべてその上で終わらせてから、最後に一度だけ xdvipdfmx を呼びます。大きな .png を貼った文書では PDF 生成に時間がかかるので、往復のたびに画像を埋め込み直さずに済ませるための工夫です。-lualatex-pdflua -dvi- -ps- の、-xelatex-pdfxe -dvi- -ps- の短縮形にあたります。日本語の upLaTeX+dvipdfmx のように DVI を経由する経路なら -pdfdvi を選びます。

オプション何をするか使いどころ
-pdfpdflatex で PDF を作る欧文中心の標準的な文書
-lualatexlualatex で PDF を作る(-pdflua -dvi- -ps- と同じ)OpenType フォントや Lua による拡張
-xelatexxelatex.xdv を作り、最後に xdvipdfmx を呼ぶシステムフォントを直接使いたいとき
-pdfdvi.dvi を作ってから PDF に変換するupLaTeX+dvipdfmx など DVI 経由の経路
-pvcソースを監視し、変わるたびに組み直す執筆中。保存するたびに結果を見たいとき
-pvctimeout変化の無い時間が続いたら -pvc を終了させる(既定 30 分)無人で走らせっぱなしにしたくないとき
-c再生成できる中間ファイルを消す(PDF は残す)作業ディレクトリを片づけたいとき
-C-c に加えて .dvi.ps.pdf も消すクリーンビルドの確認、配布物の準備
-gg-C 相当の掃除をしてから通常のビルドを行うゼロからの組み直しを一発で
-fエラーが出ても処理を続行するログをまとめて確認したいとき
-silentエンジンの出力を抑える(-quiet と同じ)CI のログを読みやすくしたいとき
-r指定した設定ファイルを追加で読み込む一時的に別の経路で組みたいとき

保存するたびに組み直す——latexmk -pvc

-pvc は preview continuously の略で、ビューアを開いたまま latexmk が常駐し、ソースのどれかが変わるたびに往復をまるごと回し直します。監視対象は本体の .tex だけではありません。.fls から組み立てた依存関係がそのまま監視リストになるので、\input\include で取り込む章ファイルも、貼り込んだ画像も、.bib も含まれます。文書版の開発サーバのような使い心地です。仕様上の癖もいくつかあります。-pvc一つのファイルにしか使えず-p-pv とは併用できません。またこのモードでは強制実行 -f が自動的に切られるので、どうしても両方欲しいときは -pvc -f の順で書きます。既定では放置しても自分から終了することはありません。無人で走らせたくないときは -pvctimeout を添えると、変化の無い時間が続いたところで終了します——その待ち時間は既定で 30 分 で、-pvctimeoutmins= で変更でき、-pvctimeout- で無効に戻せます。ビューア選びにも注意が要り、マニュアルは Windows の acroread が PDF をロックして新しい版を書けなくするため、連続プレビューには向かないと明記しています。

terminal
latexmk -pdf -pvc doc.tex                 # watch the sources, rebuild on every save
latexmk -pdf -pvc -pvctimeout doc.tex     # same, but give up after 30 idle minutes
latexmk -lualatex -pvc doc.tex            # the same loop, driven by lualatex

エディタ側の「保存時にビルド」も、中身はたいてい latexmk です。VS Code の LaTeX Workshop、TeXstudio、TeXShop、Emacs の AUCTeX、Overleaf——名前は違っても、走っているのは同じコマンドか、同じ考え方の内蔵実装です。だから -pvc をターミナルで覚えておくと退避先ができます。エディタが不調なときに素のコマンドへ落とせば、悪いのが文書なのか設定なのかを切り分けられるからです。エディタのビルドだけが失敗して latexmk が通るなら、疑うべきは文書ではなくエディタの設定です。

latexmk -c-C の違い——生成ファイルを掃除する

違いは一点、PDF を残すか消すか です。-c は再生成できるファイル——.aux.log.toc.fls.fdb_latexmk など——を消しますが、.dvi.ps.pdf は残します。-C はそこに出力そのものも加えて全部消します。掃除してから組み直すところまで一度にやりたいときは -gg です。なぜこれが実務で効くかというと、古い .aux が事故を隠すからです。節を並べ替えたり \label を消したりしても、前回の値が手元に残っているせいで PDF はそれらしく出てしまい、リポジトリを clone したばかりの共著者や CI では壊れる——という食い違いが起こります。提出前に latexmk -C してから latexmk -pdf が通ること、これが「ソースだけから組める」ことの証明になります。

terminal
latexmk -c                  # remove aux, log, toc, fls, fdb_latexmk ... keep the PDF
latexmk -C                  # remove all of that plus the dvi / ps / pdf output
latexmk -gg -pdf doc.tex    # clean first, then build again from scratch

設定を latexmkrc に書いてプロジェクトごと固定する

文書の隣に latexmkrc あるいは .latexmkrc という名前のファイルを置くと、そのディレクトリで latexmk と打つだけで全員が同じ経路を通ります。latexmk は起動時に、システム全体の設定 → ユーザの $HOME/.latexmkrc(または $XDG_CONFIG_HOME/latexmk/latexmkrc)→ カレントディレクトリの latexmkrc.latexmkrc-r で指定したファイル、の順に読みます。後から読んだものが勝つので、プロジェクトの設定は各自の好みを上書きします。中身は Perl のコードで、# から行末がコメント。多くの場合は変数への代入を数行並べれば足ります。共同執筆では、このファイルをリポジトリに入れて「この文書はこれで組む」という取り決めにしてしまうのがいちばん揉めません。

perl
# latexmkrc -- lives next to the document and is committed with it

$pdf_mode = 4;           # 4 = build the PDF with lualatex
$max_repeat = 7;         # allow a couple of extra passes on a long document

# Alternative route: upLaTeX -> DVI -> dvipdfmx
# $latex    = 'uplatex -interaction=nonstopmode -halt-on-error %O %S';
# $dvipdf   = 'dvipdfmx %O -o %D %S';
# $pdf_mode = 3;         # 3 = make the PDF from the DVI file

# Extra extensions that -c and -C should remove as well.
$clean_ext = 'synctex.gz run.xml bcf';

latexmk 以外の選択肢——ararallmkmake

分かれ目は「誰が手順を決めるか」の一点です。latexmk はログと依存関係から手順を 推論 します。対する arara は推論しません。文書に書いたディレクティブ——% arara: pdflatex のような一行のコメント——を読み、書いてあるとおりに、書いてある順で実行します。CTAN の記述が明言するとおり、ログ解析のような間接的な手がかりではなくソース中のメタデータから動作を決める設計で、Paulo Roberto Massa Cereda を中心に Island of TeX が開発しています(実行には Java が要ります)。llmk(TeX Live でのパッケージ名は light-latex-make、作者は Takuto Asakura)はもう一段宣言的で、手順を llmk.toml かソース中の TOML フィールドに書き、texlua だけで動きます。どの環境でもまったく同じ結果になることを最優先した設計です。

latex
% arara directives: the document itself states the workflow
% arara: pdflatex
% arara: biber
% arara: pdflatex
% arara: pdflatex
\documentclass{article}
toml
# llmk.toml -- next to the document; "source" is required in this file
source = "doc.tex"
latex = "lualatex"
bibtex = "biber"
sequence = ["latex", "bibtex", "latex", "latex"]

では素の make はどうでしょうか。Makefile を書けば LaTeX も回せますが、make の判断基準は 更新時刻 です。.aux は毎回の実行で書き直されるので、時刻だけを見ていると、読み込まれた側より常に新しい——つまり永久に古いまま、という循環に落ちます。latexmk のマニュアルが自ら「この循環依存は LaTeX に固有のもので、latexmk はそれを乗り越えるために作られた」と書いているのは、まさにこの点についてです。それでも make を使うなら、.aux の写しを取って差分を見るか、Makefile のターゲットから latexmk を呼ぶのが現実的です。実際、多くのプロジェクトの Makefile は latexmk -pdf $< の一行に落ち着いています。

ツール手順の決め方設定の置き場所必要なもの
latexmkログ・.fls・中身のチェックサムから推論するlatexmkrc / .latexmkrc(Perl)Perl。TeX Live・MiKTeX に同梱
arara文書に書いたディレクティブのとおりに実行する文書冒頭の % arara: コメントJava
llmkTOML に宣言した sequence のとおりに実行するllmk.toml またはソース中の TOML フィールドtexlua のみ
make更新時刻の新旧で判断する(.aux の循環に弱い)Makefilemake。多くの環境に既存

執筆中・共同執筆・提出前でどう使い分けるか

使い分けは三つに整理できます。書いている最中は -pvc で保存のたびに見る、人に渡す前は素の latexmk を一度通す、提出の直前には latexmk -C で全部消してから組み直す——この三段です。とくに最後の一段を習慣にすると、締切前に「自分の環境でしか通らない文書」に気づけないという事故が減ります。設定を latexmkrc に固定してリポジトリに入れておけば、CI サーバも共著者も同じ経路をたどるので、「私の環境では通る」という言い合いそのものが起きにくくなります。

  • 執筆中latexmk -pdf -pvc doc.tex:保存するたびに自動で組み直す。放置したくなければ -pvctimeout を添える。
  • エンジンを固定latexmkrc$pdf_mode などを書き、リポジトリに入れて全員で共有する。
  • 共著者に渡す前 → 素の latexmk -pdf を一度通し、LaTeX Warning: Label(s) may have changed. が残っていないか確認する。
  • 提出・配布の直前latexmk -C で全消去してからクリーンビルド。一発で済ませるなら latexmk -gg -pdf doc.tex
  • サーバや CI で組む なら CI のページへ。-silent を添えるとログが読みやすくなる。