1 行しかない LaTeX 文書——\documentclass{article}\begin{document}Hi\end{document}——を pdflatex に通すと 11,529 バイト の PDF が出ます。まったく同じソースを latex に通すと、出てくる DVI ファイルは 248 バイト。46 倍の差です。どちらも同じ 1 ページ、同じ「Hi」の 1 語を記述しているのに、これだけ違うのはなぜか。その答えが、TeX の処理の流れ全体を説明します。このページでは、ソースからエンジンを経て出力に至る道筋、.dvi の中に本当は何が入っているのか、そして DVI を経由する古い経路がいまも消えない理由を、実測値とともに追います。
なぜ WYSIWYG ではないのか — 一括処理という選択
TeX が画面を逐次更新しないのは、行分割を段落単位で最適化している からです。TeX は 1 行ずつ順に詰めていくのではなく、段落全体について「行末をどこに置く組み合わせがもっとも見苦しくないか」を評価し、総費用が最小になる解を選びます。その結果、段落の末尾に 1 文字足しただけで その段落の最初の行の折り返し位置まで変わる ことがあります。キーを 1 つ打つたびに全段落を計算し直すのは割に合いません。
そこで TeX は バッチ処理 を選びました。原稿を最後まで読み、全体を一度に組む方式です。失うのは打ちながら結果を見る快適さ、得るのは全体最適な組版、文書全体で崩れない体裁、そしてプレーンテキストゆえの自動化——スクリプトから生成し、Git で差分を取り、サーバー上で無人ビルドできることです。作業のリズムは「書く → コンパイル → PDF を見る」の反復になります。この往復を速くすることが、以下の話のほぼすべてです。
ソースから出力までの 2 つの経路 — 直接 PDF と DVI 経由
エンジンは PDF を直接書き出すか、DVI という中間ファイルを書き出すかのどちらかです。 直接 PDF を出すのは pdflatex・xelatex・lualatex(順に pdfTeX・XeTeX・LuaTeX エンジン)。DVI を出すのは latex と、日本語の platex・uplatex です。DVI を出す場合はそこで終わりではなく、dvi ドライバ と呼ばれる別のプログラムに渡して目的の形式へ変換します——dvipdfmx なら PDF、dvips なら PostScript、dvisvgm なら SVG。画面に描くドライバは dvi ビューア と呼ばれます。
# Direct to PDF, one step
lualatex document.tex # -> document.pdf
pdflatex document.tex # -> document.pdf
# Via DVI, two steps (the Japanese route)
uplatex document.tex # -> document.dvi
dvipdfmx document.dvi # -> document.pdf
# Other dvi drivers, same input
dvips document.dvi # -> document.ps
dvisvgm document.dvi # -> document.svgここで混同しがちなのは、「DVI を経由するか」と「Unicode や OS のフォントが使えるか」は別の軸 だということです。pdflatex は DVI を経由せず PDF を直接出しますが、入力の扱いは古く、OS にインストールされた OpenType フォントをそのまま指定することはできません。逆に xelatex と lualatex は Unicode をそのまま読み、fontspec でフォントを名前で指定できます。二つの軸を分けて考えると、名前の多さが一気に整理されます。
| コマンド | 出力 | 入力とフォント | 扱える画像 |
|---|---|---|---|
latex | DVI(dvi ドライバが必要) | ASCII 中心。TeX 独自のフォント形式 | EPS・PS |
pdflatex | PDF(直接) | Unicode は限定的。OS フォントは使えない | PNG・JPEG・PDF(EPS は自動変換) |
uplatex | DVI(dvipdfmx に渡す) | Unicode 対応の日本語エンジン。和文フォントは埋め込み設定次第 | EPS・PDF・PNG・JPEG |
xelatex | PDF(内部で .xdv を経由) | Unicode。OS の OpenType を fontspec で指定 | PNG・JPEG・PDF・EPS |
lualatex | PDF(直接) | Unicode。OS フォント。内部を Lua で拡張可能 | PNG・JPEG・PDF・EPS |
.dvi の中身は何なのか — 248 バイトを開いてみる
DVI は device independent(装置非依存)の略で、中身は 「どの文字を、どの位置に置くか」だけを並べた命令列 です。TeX Live に付属する dvitype を使うと人間が読める形に展開できます。冒頭の 1 行文書から作った 248 バイトの DVI を開くと、実際に入っていたのは次のものでした。
$ dvitype -output-level=4 one.dvi
numerator/denominator=25400000/473628672
magnification=1000
' TeX output 2026.08.13:1233'
maxv=41484288, maxh=26673152, maxstackdepth=3, totalpages=1
Font 27: cmr10---loaded at size 655360 DVI units
42: beginning of page 1
117: down4 41484288 v:=0+41484288=41484288
140: right3 5046272 h:=0+5046272=5046272
144: fntdef1 27: cmr10
165: fntnum27 current font is cmr10
166: setchar72 h:=5046272+491521=5537793
167: setchar105 h:=5537793+182045=5719838
[Hi]
181: setchar49 h:=15204352+327681=15532033
[ 1]
185: eopこれが全部です。setchar72 は「文字コード 72(H)をここに置け」、setchar105 は「105(i)を置け」。setchar49 は最下部に印字されるページ番号の 1 です。right3 と down4 は現在位置の移動で、単位の DVI unit は 1 sp = 1/65536 pt——だから cmr10 の「655360 DVI units」はちょうど 10 pt です。そして決定的なのは fntdef1 27: cmr10 の行で、DVI はフォントを名前で呼んでいるだけ です。cmr10 がどんな形をしているかは、DVI の中のどこにも書かれていません。
PDF はこの点が正反対です。pdflatex の出した 11,529 バイトの PDF を覗くと、UNYBJV+CMR10 という名前でフォントが 埋め込まれて います。頭の 6 文字はサブセット化の目印で、実際に使った字形だけを抜き出した証拠です。そしてそのフォントを収めたオブジェクトは /Length1 1394 /Length2 8300 /Length3 0 /Length 9259 ——圧縮後で 9,259 バイト、PDF 全体 11,529 バイトの 8 割を占めます。46 倍の差の正体は、ほぼこれです。 DVI は「cmr10 の H」と書けば済むところを、PDF は H の輪郭そのものを持ち歩かなければなりません。どこに持って行っても同じに見える、という PDF の約束の代金です。
ただし、ここで一つ注意があります。「DVI が小さいのはフォントを持たないから」は正しいのですが、「PDF が 11,529 バイトなのはフォントを持つから」だけでは説明が足りません。 同じ 248 バイトの DVI を dvipdfmx に通すと、出てくる PDF は 1,950 バイト です。こちらもフォントを埋め込んでいますが、/Subtype/Type1C という圧縮率の高い形式に変換していて、フォント本体は 546 バイト しかありません。つまり同じ 1 語のページが、記述の仕方だけで 248 → 1,950 → 11,529 バイトと変わるわけです。ファイルサイズを気にする場面では、経路の違いが実際に効いてきます。
DVI 経路がいまも生きている理由 — 日本語と .xdv
DVI が残っている最大の実務的理由は、日本語組版の標準経路がそこにあるからです。 platex と uplatex は DVI を出し、最後に dvipdfmx で PDF にします。この dvipdfmx は Mark A. Wicks の dvipdfm を出発点として日本語の要求に合わせて拡張されたもので、TeX Live 2024 に入っているのは 2024 年 3 月版です。仕事は「DVI の座標命令を PDF の描画命令に翻訳し、参照されているフォントを探して埋め込む」こと。実際に upLaTeX で「こんにちは」と 1 行書いた文書を通すと、396 バイトの DVI が 5,998 バイトの PDF になり、中には和文フォント HaranoAjiMincho が CID フォントとして埋め込まれていました。
そして、この仕組みは思っているより現役です。TeX Live 2024 で dvipdfmx の実体を確かめると、xdvipdfmx への symlink になっています。xdvipdfmx は XeTeX が出す .xdv を読むためのプログラム——つまり XeTeX の中身は「DVI を少し拡張した形式を出し、それをドライバで PDF に変換する」という、まさに DVI 経路そのもの です。実際 xelatex -no-pdf を使うと変換を止めて .xdv を取り出せます。1 行文書なら .xdv は 436 バイト。それを xdvipdfmx に渡すと 2,329 バイトの PDF になり、これは同じソースに xelatex をそのまま実行したときの出力と 同じ大きさ です。手で 2 段に分けて実行したことが、xelatex が内部でやっていることそのものだったわけです。
$ readlink $(which dvipdfmx)
xdvipdfmx
$ xelatex -no-pdf one.tex # stop before the driver stage
$ ls -l one.xdv
-rw-r--r-- 1 user staff 436 one.xdv
$ xdvipdfmx one.xdv # run the driver by hand
$ ls -l one.pdf
-rw-r--r-- 1 user staff 2329 one.pdf実務上の使い分けは単純です。新規に英文・欧文で書くなら直接 PDF の経路(pdflatex か lualatex)を選べば、工程が 1 段減ってトラブルの種も減ります。日本語で既存の資産や研究室の慣行がある場合は DVI 経路(uplatex + dvipdfmx)が依然として堅実で、縦組みや和文の禁則処理の実績があります。判断の詳細は「エンジンの選び方」に譲りますが、少なくとも DVI を「古いから避けるべきもの」と考える必要はありません。
補助ファイルと処理の回数 — BibTeX・makeindex を含む全体像
「エンジンを 1 回走らせて終わり」なのは、参照も目次も文献も索引もない文書だけです。 エンジンは 1 回の実行のあいだに .aux(番号とページの記録)や .toc(目次)を書き出し、次の実行がそれを読み返します。この往復が収束するまで繰り返すのが基本形で、\ref による参照が一つでも出てきた時点で最低 2 回になります。文献や索引が入ると、そこにエンジン以外のプログラムが挟まります——.aux を読んで .bbl を作る BibTeX(あるいは .bcf を読む biber)、.idx を読んで .ind を作る makeindex。それぞれの出力をエンジンが読み込むので、実行順序は下のようになります。
# A document with cross-references, a bibliography and an index
pdflatex thesis # writes .aux, .idx; references still print as ??
bibtex thesis # reads .aux -> writes .bbl
makeindex thesis # reads .idx -> writes .ind
pdflatex thesis # pulls .bbl and .ind in; numbering shifts again
pdflatex thesis # everything settles
# Or simply
latexmk -pdf thesis # figures out the order and the count on its own回数を数えるのをやめる — latexmk・エディタ・SyncTeX
latexmk は、補助ファイルの変化を見て必要な回数だけ自動で再実行するツールです。 .aux などの内容が前回と同じになった時点で「収束した」と判断して止まり、途中で BibTeX/biber や makeindex が必要なら呼びます。既定では最大 5 回まで繰り返し($max_repeat = 5)、それでも落ち着かなければ無限ループとみなして中断します。実務でこの上限に当たることはまずありません。DVI 経路を使いたい場合も、latexmk の設定ファイルに経路を書いておけば同じ 1 コマンドで済みます。
latexmk -pdf document.tex # pdfLaTeX, as many passes as needed
latexmk -lualatex document.tex # LuaLaTeX
latexmk -pv document.tex # build, then open the viewer
latexmk -c # remove .aux, .log, .toc and friends
latexmk -C # the same, and remove the PDF tooVS Code の LaTeX Workshop、TeXShop、TeXstudio、Overleaf といった環境は、たいてい裏で latexmk を呼んでいます。だから「コンパイル」ボタンを押すだけで回数の問題は解決しています。もう一つ組み合わせて効くのが SyncTeX で、これは PDF の各位置がソースの何行目から来たかを .synctex.gz に記録する仕組みです。有効にしておくと、PDF の一点をクリックしてソースの該当行へ飛び、逆にソースから PDF の該当箇所へも飛べます。長い文書ほど効きます。
止まったとき、処理のどの段階を疑うか
エラーメッセージがどの段階から来たかで、探す場所が決まります。 .log にエンジンからのエラーが出ているなら原稿の側、dvi ドライバが文句を言っているなら画像かフォントの側、BibTeX/biber の出力なら .bib の側です。とくに紛らわしいのが「画像が出ない」という症状で、これは経路の違いがそのまま出ます——DVI 経路は EPS を、直接 PDF の経路は PDF・PNG・JPEG を素直に扱うので、latex の文書に PNG を貼ろうとして失敗するのはよくある入り口です。ログの読み方そのものは「エラーの追い方」のページが詳しく扱います。
- 相互参照だけがおかしいとき は補助ファイルを消す前に、まず
latexmkに必要回数を任せて走らせ直す。 - 画像だけが出ないとき は、いま走らせている経路が直接 PDF か DVI かを確かめ、その経路が扱える形式に変換する。
- 原因不明の症状が続くとき に限って
.aux・.toc・.outを消して作り直す(latexmk -c)。古い補助ファイルが原因なら、これで直ります。 - 日本語の PDF でフォントが変わるとき は、
dvipdfmxの埋め込み設定を疑う。エンジンではなくドライバ側の話です。