コンパイルコマンド

TeX Live 2024 のインストール先で ls -l を打つと、最初の驚きがすぐ来ます。LaTeX のコンパイルコマンドである latex は、プログラムですらありません。pdftex への symbolic link で、しかも同じ一つのファイルを pdflatexetexxmltexamstex など 19 の名前が指しています。どのコマンドを打つかは決定的に重要ですが、その理由は多くの人が思っているのとは違います。名前が選ぶのは別のプログラムではなく 別のフォーマットファイル で、二つのコマンドの違いが整数ひとつに還元されることさえあるのです。このページが扱うのは、実際に手で打つコマンド——pdflatexxelatexlualatexlatexdvipdfmx、そして CJK の platexuplatex——と、覚える価値のある少数のオプション、そして失敗したときのコンソールの読み方です。

.tex をコンパイルするコマンドと、残っていくファイル

一行で済みます。pdflatex document.tex と打てば document.pdf ができます。拡張子 .tex は省略でき、オプションは必ずファイル名の に並べます。ただし PDF だけが残るわけではありません。同じディレクトリに document.aux(相互参照と目次の情報を貯める帳簿)と document.log(画面に流れたものを全部含む完全な記録)が現れます。この二つは消えてもかまわない中間生成物ですが、次に何が起きるかを決めているのは前者です。

terminal
pdflatex document.tex          # -> document.pdf, document.aux, document.log
lualatex document              # the .tex extension is optional
xelatex -synctex=1 document.tex  # options come before the file name

その .aux があるせいで、コンパイルコマンドは ふつう二回打つ必要があります。LaTeX は文書を前から後ろへ一度しか読まないので、1 ページ目に目次を組む時点では第 7 節が何ページに落ちるかをまだ知りません。1 回目の実行は判明した番号を .aux に書き出し、2 回目がそれを読み戻して本文に埋めます。参考文献や索引が絡むとさらに回数が増えます。この繰り返しをいつ止めてよいかを LaTeX がどう判断しているか、そしてそれを自動化する latexmk の仕組みは「自動ビルド」のページが引き受けます。ここで扱うのは、その内側で実際に呼ばれるコマンドそのものです。

latexpdflatex の違いは、整数ひとつ

latex.dvi を、pdflatex.pdf を出力しますが、走っているバイナリは 同一 です。TeX Live 2024 でどちらのリンクをたどっても pdftex に行き着きますし、latex --version は堂々と pdfTeX 3.141592653-2.6-1.40.26 (TeX Live 2024) と名乗ります。違いはプログラムではなく、名前ごとに読み込まれる フォーマットファイル の側にあります。pdflatex.inipdftexconfig.tex を読み込み、そこで \pdfoutput = 1 が設定されます。latex.ini はまったく同じファイルを読み込んだうえで、直後に \pdfoutput=0 で上書きします。二つのコマンドを分けているのは、突き詰めればこの整数ひとつだけです。

terminal
# TeX Live 2024: four commands, three binaries
readlink $(which latex) $(which pdflatex) $(which xelatex) $(which lualatex)
# pdftex
# pdftex
# xetex
# luahbtex

latex --version
# pdfTeX 3.141592653-2.6-1.40.26 (TeX Live 2024)

では一つのバイナリはどのフォーマットを読めばよいと知るのでしょうか。自分が何という名前で呼ばれたか を見ています。pdftex --help はそれを平たく書いていて、起動時の名前を NAME として NAME.fmt を探す、と説明します。リンクの名前を変えれば違う LaTeX が起動するわけです。この推測を上書きしたいときは -fmt=NAME-progname=NAME を渡すか、ファイルの一行目に %&format 行を置きます。同じ仕掛けのおかげで、pdftex という一つの実行ファイルに 20 個の名前がぶら下がっていられます。

\pdfoutput はフォーマット作成時だけの設定ではなく、走行中も生きている pdfTeX のプリミティブです。\documentclass より前、ファイルの一行目に \pdfoutput=0 と書けば、pdflatex で走らせても出てくるのは .dvi です。もっとも実務では -output-format=dvi あるいは -output-format=pdf をコマンドラインで渡すほうが素直で、これは pdfTeX と LuaTeX の両方が受け付けます(XeTeX だけは持っておらず、代わりに -no-pdf を使います)。さらに LaTeX 自身がこの値を見て図版の扱いを切り替えます。DVI モードのときは l3backend-dvips.def を、PDF モードのときは l3backend-pdftex.def を読み込む——.eps が通るか .pdf.png が通るかが分かれるのは、このためです。

pdflatex / xelatex / lualatex の違い — フォントと Unicode で選ぶ

判断基準は一つで足ります。文書がラテン文字中心で、速度とパッケージ互換性を最優先するなら pdflatex。OS にインストール済みのフォントを名前で指定したい、あるいはラテン文字の外の文字を扱う——その瞬間に xelatexlualatex へ移ります。三つとも PDF を出力し、同じ .tex を受け取りますが、フォントの入り口だけがまるで違います。

なぜコマンドがこれほど増えたのかは、歴史を見ると一本の線で説明できます。Knuth の TeX は 1978 年から書かれ、出力形式は DVI(device-independent)でした——PDF は 1993 年に Adobe が発表するもので、当時は存在すらしていなかったからです。pdfTeX はその隔たりを埋めた拡張です。作者の Hàn Thế Thành が博士研究で取り組んだのは マイクロタイポグラフィ、つまり行末で文字をわずかに版面の外へ突き出させ、字幅を目に見えない程度に伸縮させて灰色度を均す技術でした。その研究の副産物として、DVI を経由せず PDF を直接書き出す TeX が生まれます。今日 pdflatex がもっとも速く、もっとも多くのパッケージが前提にしているのは、単純にいちばん長く使われてきたからです。

xelatex は Jonathan Kew が 2004 年前後に開発した XeTeX を動かします。fontspec パッケージを使えば、OS にある OpenType フォントを名前で指定できます。ただし XeTeX は PDF を直接は書きません。DVI を拡張した .xdv を作り、それを xdvipdfmx に渡して PDF にします。-no-pdf を付ければ .xdv の段階で止まりますし、-output-driver=CMD で変換プログラム自体を差し替えることもできます。三つのうち XeTeX だけが -output-format を持たないのは、この構造の帰結です。

lualatex には仕掛けがあります。TeX Live 2024 でこのリンクをたどると、着く先は luatex ではなく luahbtex です。LuaHBTeX は LuaTeX に文字整形ライブラリ HarfBuzz を組み込んだ版で、アラビア文字やインド系文字のような複雑な整形規則を持つ文字体系を正しく組めるのはこの部分の働きです。素の luatex も残っていて、後述の dvilualatex はそちらを指しています。LuaTeX の看板は名前どおり Lua の埋め込みで、行分割やフォント読み込みといった組版の内部処理に文書の側から手を入れられます。ここで版番号を並べてみると面白いことに気づきます。tex --versionTeX 3.141592653 と表示します——Knuth は TeX の版番号を更新のたびに円周率の桁を一つずつ伸ばす形で付けており、pdfTeX も XeTeX もその接頭辞をそのまま受け継いでいます。LuaTeX だけがこの伝統から降り、Version 1.18.0 と名乗ります。

コマンド実体(TeX Live 2024)出力フォントと文字
pdflatexpdftexPDFTeX 内蔵フォント。最速・最も広い互換性
xelatexxetexPDF(内部で .xdv 経由)OS の OpenType フォントを fontspec で
lualatexluahbtexPDFOS フォント+HarfBuzz 整形+Lua スクリプト
latexpdftexDVITeX 内蔵フォント。EPS 図版と PSTricks 向け
dvilualatexluatexDVILuaTeX の機能を DVI 出力で使いたいとき
platexeuptexDVI日本語。内部コードは EUC で JIS X 0208 の範囲
uplatexeuptexDVI日本語。内部コードが Unicode で外字も通る

latex から dvipdfmx へ — いまも DVI 経由を選ぶ理由

理由は今も二つあります。ひとつは DVI しか話せない仕組みが残っていること——PSTricks のように PostScript を前提に描画するパッケージ群は、latex から dvips を通す経路でこそ本領を発揮します。もうひとつは、次節で扱う日本語組版が伝統的にこの経路を通ってきたことです。latex document.texdocument.dvi を作り、dvipdfmx document.dvi がそれを PDF にします。PostScript が要るなら dvips です。LuaTeX の機能を使いながら DVI が欲しいという珍しい要求には dvilualatex があり、こちらは HarfBuzz なしの素の luatex を指しています。

terminal
latex document.tex        # -> document.dvi
dvipdfmx document.dvi     # -> document.pdf
dvips document.dvi        # -> document.ps (for PSTricks and friends)

日本語・中国語・韓国語のコマンド — platex / uplatex とその代替

日本語に専用のコマンドがあるのは、日本語の組版に専用の規則があるからです。縦組み、行頭行末に置いてよい文字を縛る禁則処理、和文と欧文のあいだに入るべき固定の空き——これらをマクロではなくエンジン自体に埋め込んだのが pTeX で、その上で動く LaTeX が pLaTeX、すなわち platex です。フォーマットファイル platex.ini の一行目にはいまも「for pLaTeX (ASCII Nihongo LaTeX)」と書かれており、アスキー由来であることが読み取れます。upTeX は田中琢爾氏による pTeX の拡張で、内部の文字コードを完全な Unicode にしたもの。その上の LaTeX が upLaTeX、すなわち uplatex です。どちらも出力は必ず DVI で、PDF を直接は書きません。

ここでも同じ驚きが繰り返されます。TeX Live 2024 では platexuplatex はどちらも euptex という一つのバイナリへのリンクで、ptexeptexuptex もそこに合流します。区別しているのは内部の漢字コードです。platex --versione-upTeX 3.141592653-p4.1.1-u1.30-230214-2.6 (utf8.euc) と表示し、uplatex --version は末尾が (utf8.uptex) になります。つまり同じ実行ファイルが、名前に応じて -kanji-internal を切り替えているだけです。pLaTeX は内部 EUC の古典 pTeX として振る舞うので扱える漢字はおおむね JIS X 0208 の範囲に収まり、upLaTeX は内部が Unicode なので人名の外字や CJK 統合漢字をそのまま通せます。新規の日本語文書で uplatex が既定の選択になっているのは、この一点の差によります。なお、この一本化は比較的最近の変更です。TeX Live に同梱される pTeX の公式ガイドによれば、platex は TeX Live 2012 から 2022 までは e-pTeX の上で動いており、2023-06-01 に e-upTeX の legacy-encoding-compatibility mode へ移りました。upTeX の追加プリミティブが pLaTeX でも使えるようになる一方、日本語文字の内部コードは後方互換のために非 Unicode のまま残されています。

内部コードと入力ファイルの文字コードは別物です。入力側は -kanji=STRING で指定し、eucjissjisutf8uptex を取ります。近年の TeX Live は UTF-8 を既定にしているので省けることも多いのですが、明示しておけば環境が変わっても崩れません。BOM のない UTF-8 を確実に通したいときは -no-guess-input-enc を併用して、文字コードの推測そのものを止めます。出力は DVI なので、仕上げは dvipdfmx です。

terminal
# Japanese, the traditional route: typeset -> DVI -> PDF
uplatex -kanji=utf8 -no-guess-input-enc document.tex   # -> document.dvi
dvipdfmx document.dvi                                 # -> document.pdf

中国語と韓国語はこの経路を使いません。どちらも Unicode ネイティブなエンジンに任せるのが定石で、中国語なら xelatexlualatexctex バンドル(内部で xeCJK などを呼びます)、韓国語なら同じエンジンに kotex を組み合わせます。日本語でも、DVI を経由したくなければ lualatexluatexja を読ませれば PDF が直接出ます。この道を選ぶと -kanji は不要になります——エンジンが最初から Unicode で動いているので、切り替えるべき内部コードがそもそも存在しないからです。

よく使うオプション — -interaction=nonstopmode / -halt-on-error / -output-directory

オプションは必ずファイル名より前に置き、以下は pdfTeX・XeTeX・LuaTeX のどのコマンドでも通ります。日常的に効くのは実質 4 つで、エディタ連携に -synctex=1、止まらせないために -interaction=nonstopmode、逆に最初の一件で見切るために -halt-on-error、そして機械が読める形式にするために -file-line-error です。

オプション働き
-synctex=1document.synctex.gz を書き出し、エディタと PDF の相互ジャンプを可能にする
-interaction=nonstopmodeエラーで入力待ちにならず最後まで走る。batchmode は端末出力も抑える
-halt-on-error最初のエラーで打ち切る。PDF は生成されない
-file-line-errorメッセージ冒頭を ./document.tex:3: の形にする。IDE と CI が解析できる
-output-directory=DIR出力と補助ファイルを DIR に書く。DIR は先に存在していなければならない
-jobname=NAME出力ファイルの拡張子より前の部分を NAME にする
-draftmodePDF を書かずに走る(pdfTeX / LuaTeX)。参照を固めるだけの中間実行に
-output-format=FORMATdvipdf を選ぶ(pdfTeX / LuaTeX のみ。XeTeX は -no-pdf
-shell-escape\write18 による外部コマンド実行を無制限に許す(次節の警告を読むこと)
terminal
pdflatex -synctex=1 -interaction=nonstopmode -halt-on-error -file-line-error document.tex

mkdir -p build   # -output-directory will NOT create it for you
pdflatex -output-directory=build document.tex

-output-directory には CI でよく踏む落とし穴があります。指定したディレクトリは先に存在していなければなりません。 pdfTeX のヘルプも「既存の DIR を使う」と書いています。無ければ実行は「Please type another transcript file name」と言い出し、続けて ! Emergency stop と「Fatal error occurred, no output PDF file produced!」で終わります。原因が組版と無関係なので、ログを読み慣れていても一瞬止まります。mkdir -p を一行前に置くだけで済む話です。

-shell-escapeminted に必要な理由と、危険な理由

このオプションは、文書に 任意のシェルコマンドをあなたのマシン上で実行する権利 を与えます。実は既定でも外部コマンドは完全に閉じているわけではありません。TeX Live は 制限付きモード で動いていて、実行時に restricted \write18 enabled. という行が出ます。この状態で \write18 が呼べるのは texmf.cnf の許可リストに載っているものだけで、TeX Live 2024 のそれは短いものです——bibtexbibtex8extractbbgregoriokpsewhichmakeindexmemoize-extract.plmemoize-extract.pyrepstopdfr-mposttexosquery-jre8。参考文献と索引が何のオプションもなしに動くのは、この二つが最初から許されているからです。

そのリストに pygmentize はありません。texmf.cnf はそれを意図的に外していて、フィルタ機能が安全かどうか疑問だ、という趣旨のコメントを添えています。コードを色分けする minted はまさにその pygmentize を呼ぶので、制限付きモードでは動かず、-shell-escape を丸ごと開けるしかありません。そして「丸ごと」は文字どおりです。他人から受け取った .tex は、その一回のコンパイルでファイルを消すことも、手元のデータを外に送ることも、何かを仕込むこともできます。判断は単純にしてよく——自分が書いた文書を、自分が管理するディレクトリで組むときだけ有効にする。 ダウンロードしたテンプレートや、査読で回ってきた投稿原稿には絶対に付けない、で十分です。

terminal
# minted calls pygmentize, which the restricted allow-list does not include
pdflatex -shell-escape document.tex

# turn it off explicitly when compiling a file you did not write
pdflatex -no-shell-escape untrusted.tex

コンパイルが失敗したときのコンソールの読み方

末尾ではなく、! で始まる最初の行から読みます。 LaTeX のエラーは連鎖するので、画面の最後に残っているのはたいてい最初の一件が引き起こした二次被害です。原因は上にあります。エラー報告はいつも同じ形をしていて、! の行が症状、その下の l. で始まる行が場所を示します。

console
! Missing $ inserted.
<inserted text>
                $
l.3 Some text with a bare x^
                            2 here.
?

重要なのは l.3 の行です。ソースの 3 行目という意味ですが、TeX が読み終えた地点でちょうど二つに折られて 表示されています。折れ目の前は消費済み、後ろはまだ読んでいない部分です。この例では折れ目が x^ の直後にあるので、犯人は上付き文字の記号だと一目で分かります。! Undefined control sequence. も同じ形で、折れ目の直前に置かれた綴りの怪しい命令がそのまま答えになります。最後の ? は入力待ちのプロンプトで、既定の errorstopmode で止まっている印です。Enter を押せば続行、x で中断できます。

この対話が邪魔になるのがスクリプトと CI で、そのために対話モードを切り替えます。-interaction=nonstopmode は止まらずに全部吐き、batchmode はさらに端末への出力も抑え、scrollmode はファイルが見つからないときだけ尋ねます。逆に最初の一件だけ見たいなら -halt-on-error で、この場合は ! Emergency stop.Fatal error occurred, no output PDF file produced! で終わります。-file-line-error を足すと見出しが ./document.tex:3: Missing $ inserted. に変わり、エディタや CI がクリック可能なリンクとして解釈できるようになります。そして何を選んでいても、完全な記録は必ず .log に残ります——端末を見逃しても、そちらを開けば同じものが読めます。

結局どのコマンドを打てばよいか

  • ラテン文字中心の文書pdflatex。いちばん速く、いちばん多くのパッケージが前提にしている既定値です。
  • OS のフォントを名前で使いたいxelatexlualatex。どちらも fontspec で指定します。
  • 複雑な整形規則の文字体系や、組版そのものをスクリプトしたいlualatex(実体は HarfBuzz 入りの luahbtex)。
  • 新規の日本語文書uplatex から dvipdfmx、または lualatexluatexja
  • 中国語・韓国語xelatexlualatexctex あるいは kotex。DVI は経由しません。
  • PSTricks など DVI 前提の仕組みlatex から dvips または dvipdfmx

最後に、切り分けの手順を一つ。エディタのビルドボタンが失敗したときは、まず同じコマンドをターミナルで手打ちしてください。それで通るなら問題はエディタの設定側にあります。人に渡す前や CI に載せる前は -halt-on-error -file-line-error -interaction=nonstopmode を付けた一回を通し、最初の本当のエラー位置が読める状態にしておきます。そして日常的には、これらを手で二回打つ人はほとんどいません——必要な回数と dvipdfmx の呼び出しまで面倒を見る latexmk に任せるのが普通で、その仕組みは「自動ビルド」のページが引き受けます。