処理方式と処理の流れ(DVI/PDF)

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 を出すのは pdflatexxelatexlualatex(順に pdfTeX・XeTeX・LuaTeX エンジン)。DVI を出すのは latex と、日本語の platexuplatex です。DVI を出す場合はそこで終わりではなく、dvi ドライバ と呼ばれる別のプログラムに渡して目的の形式へ変換します——dvipdfmx なら PDF、dvips なら PostScript、dvisvgm なら SVG。画面に描くドライバは dvi ビューア と呼ばれます。

terminal
# 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 フォントをそのまま指定することはできません。逆に xelatexlualatex は Unicode をそのまま読み、fontspec でフォントを名前で指定できます。二つの軸を分けて考えると、名前の多さが一気に整理されます。

コマンド出力入力とフォント扱える画像
latexDVI(dvi ドライバが必要)ASCII 中心。TeX 独自のフォント形式EPS・PS
pdflatexPDF(直接)Unicode は限定的。OS フォントは使えないPNG・JPEG・PDF(EPS は自動変換)
uplatexDVI(dvipdfmx に渡す)Unicode 対応の日本語エンジン。和文フォントは埋め込み設定次第EPS・PDF・PNG・JPEG
xelatexPDF(内部で .xdv を経由)Unicode。OS の OpenType を fontspec で指定PNG・JPEG・PDF・EPS
lualatexPDF(直接)Unicode。OS フォント。内部を Lua で拡張可能PNG・JPEG・PDF・EPS

.dvi の中身は何なのか — 248 バイトを開いてみる

DVI は device independent(装置非依存)の略で、中身は 「どの文字を、どの位置に置くか」だけを並べた命令列 です。TeX Live に付属する dvitype を使うと人間が読める形に展開できます。冒頭の 1 行文書から作った 248 バイトの DVI を開くと、実際に入っていたのは次のものでした。

terminal
$ 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 です。right3down4 は現在位置の移動で、単位の 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 が残っている最大の実務的理由は、日本語組版の標準経路がそこにあるからです。 platexuplatex は 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 が内部でやっていることそのものだったわけです。

terminal
$ 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 の経路pdflatexlualatex)を選べば、工程が 1 段減ってトラブルの種も減ります。日本語で既存の資産や研究室の慣行がある場合は DVI 経路uplatex + dvipdfmx)が依然として堅実で、縦組みや和文の禁則処理の実績があります。判断の詳細は「エンジンの選び方」に譲りますが、少なくとも DVI を「古いから避けるべきもの」と考える必要はありません。

補助ファイルと処理の回数 — BibTeX・makeindex を含む全体像

「エンジンを 1 回走らせて終わり」なのは、参照も目次も文献も索引もない文書だけです。 エンジンは 1 回の実行のあいだに .aux(番号とページの記録)や .toc(目次)を書き出し、次の実行がそれを読み返します。この往復が収束するまで繰り返すのが基本形で、\ref による参照が一つでも出てきた時点で最低 2 回になります。文献や索引が入ると、そこにエンジン以外のプログラムが挟まります——.aux を読んで .bbl を作る BibTeX(あるいは .bcf を読む biber)、.idx を読んで .ind を作る makeindex。それぞれの出力をエンジンが読み込むので、実行順序は下のようになります。

terminal
# 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 コマンドで済みます。

terminal
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 too

VS 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 の埋め込み設定を疑う。エンジンではなくドライバ側の話です。