pTeX 系(pTeX / upTeX / e-pTeX)

TeX Live 2024 の bin には ptexuptexeptexeuptexplatexuplatex という 6 つのコマンドが並んでいます。ところが ls -l で覗くと、6 つとも euptex というたった一つの実行ファイル への symlink です。日本語のために作られた一連の LaTeX エンジン——pTeX、upTeX、e-pTeX、e-upTeX——は、四半世紀かけて一本の実装に合流しました。このページはその合流を、実際のバナー・ログ・実測値を読みながら追います。縦組みの作法や禁則の細部は別ページに譲り、ここが引き受けるのは エンジンそのもの です。

6 つのコマンド、1 つの実行ファイル

platex という名前の実行ファイルは存在しません。 TeX Live 2024 で platexeuptex への symlink であり、ptexuptexeptexuplatex も同じ euptex を指しています。では何が違うのか——読み込むフォーマットが違う のです。TeX 系のプログラムは、起動時に自分の名前を見て同名のフォーマットファイル(.fmt)を読み込みます。この対応表が fmtutil.cnf で、そこには platex euptex language.dat *platex.iniuplatex euptex language.dat *uplatex.ini の 2 行が並んでいます。第 2 列がエンジン、第 4 列が「そのフォーマットを焼くための ini ファイル」。つまり pLaTeX も upLaTeX も、e-upTeX という同じエンジンの上に載った別のフォーマット です。

terminal
$ ls -l /usr/local/texlive/2024/bin/universal-darwin/ | grep -E "ptex|platex"
lrwxr-xr-x  platex   -> euptex
lrwxr-xr-x  ptex     -> euptex
lrwxr-xr-x  uplatex  -> euptex
lrwxr-xr-x  uptex    -> euptex
lrwxr-xr-x  eptex    -> euptex
-rwxr-xr-x  euptex          # the only real binary

$ grep -E "^(platex|uplatex|ptex|uptex|eptex) " texmf-dist/web2c/fmtutil.cnf
platex  euptex language.dat *platex.ini
eptex   euptex language.def *eptex.ini
ptex    euptex -            ptex.ini
uplatex euptex language.dat *uplatex.ini
uptex   euptex -            uptex.ini

実際に 6 つとも走らせて 1 行目だけ取ると、この構造がそのまま見えます。バナーの本体は全部同じ This is e-upTeX, Version 3.141592653-p4.1.1-u1.30-230214-2.6 (TeX Live 2024) で、違うのは括弧の中だけ——platex 系は (utf8.euc)uplatex 系は (utf8.uptex) と出ます。この括弧が 内部の和文コード を示していて、pTeX の系譜と upTeX の系譜を分ける唯一の外見上の手がかりです。「platex を実行したのに e-upTeX と出るのはおかしいのでは」という質問はよく出ますが、異常ではなく、それが正しい姿 です。

terminal
$ for c in ptex uptex eptex euptex platex uplatex; do
>   printf "%s: " $c; echo "\\end" | $c | head -1
> done
ptex:    This is e-upTeX, Version 3.141592653-p4.1.1-u1.30-230214-2.6 (utf8.euc)   (TeX Live 2024) (preloaded format=ptex)
uptex:   This is e-upTeX, Version 3.141592653-p4.1.1-u1.30-230214-2.6 (utf8.uptex) (TeX Live 2024) (preloaded format=uptex)
eptex:   This is e-upTeX, Version 3.141592653-p4.1.1-u1.30-230214-2.6 (utf8.euc)   (TeX Live 2024) (preloaded format=eptex)
platex:  This is e-upTeX, Version 3.141592653-p4.1.1-u1.30-230214-2.6 (utf8.euc)   (TeX Live 2024) (preloaded format=platex)
uplatex: This is e-upTeX, Version 3.141592653-p4.1.1-u1.30-230214-2.6 (utf8.uptex) (TeX Live 2024) (preloaded format=uplatex)

あの長い数字の列は 1 つのバージョン番号ではなく、4 つの別々の系譜のバージョンを繋げたもの です。頭の 3.141592653 が素の TeX、p4.1.1 が pTeX、u1.30 が upTeX、230214 が e-pTeX(日付形式)、末尾の 2.6 が e-TeX。推測ではありません——エンジンはそれぞれをプリミティブとして持っているので、文書の中から \the\ptexversion などで直接読み出せます。この 1 行が読めるようになると、e-pTeX とは何か という問いに具体的に答えられます。それは「pTeX に e-TeX を併合したもの」であり、いま動いている e-upTeX はさらに upTeX を重ねた 4 層構造だ、ということです。

latex
% read the version primitives back out of the running engine
\typeout{PTEX=\the\ptexversion.\the\ptexminorversion\ptexrevision}
\typeout{UPTEX=\the\uptexversion\uptexrevision}
\typeout{EPTEX=\the\epTeXversion}
\typeout{ETEX=\the\eTeXversion\eTeXrevision}
%  PTEX=4.1.1   UPTEX=1.30   EPTEX=230214   ETEX=2.6
バナーの断片由来TeX Live 2024 で読み出す方法
3.141592653クヌースの素の TeX\the\fmtversion ではなくバナーそのもの
p4.1.1pTeX(アスキー由来の和文拡張)\ptexversion \ptexminorversion \ptexrevision
u1.30upTeX(Unicode 化)\uptexversion \uptexrevision
230214e-pTeX(日付形式のバージョン)\epTeXversion
2.6e-TeX 拡張\eTeXversion \eTeXrevision

pTeX がエンジンに埋め込んだもの——組方向と JFM

pTeX がマクロではなく エンジンの改造 でなければならなかった理由は二つあります。組方向\tate\yoko)と、JFM(和文フォントメトリック) です。開発したのは アスキー——ゲーム雑誌やパソコン誌で知られたあの出版社で、名前の p は publishing、つまり商業出版に耐える日本語 TeX を作るという目標そのものでした。組方向は「文字の並ぶ向き」を変えるだけの話に見えますが、TeX の内部では ボックスの寸法の意味が入れ替わる 事件です。実際に測ってみると、それがそのまま数字に出ます。

同じ「あいう」を \hbox に入れて、横組みと縦組みで寸法を比べてみます。横組みでは高さ 8.46753pt・深さ 1.15465pt——欧文と同じく ベースラインの上に載っている 形です。ところが縦組みでは高さも深さも 4.8111pt、つまり全角幅 9.6222pt の ちょうど半分ずつ になります。縦組みでは文字がベースラインに載るのではなく、行の中心線をまたいで置かれる からです。この寸法の解釈をエンジンの内側で切り替えられることが pTeX の核心で、マクロでは真似できない部分でした。

latex
\documentclass{utarticle}   % ut... = upLaTeX, vertical writing
\begin{document}
\setbox0=\hbox{あいう}
\typeout{TATE w=\the\wd0\space h=\the\ht0\space d=\the\dp0}
\yoko
\setbox0=\hbox{あいう}
\typeout{YOKO w=\the\wd0\space h=\the\ht0\space d=\the\dp0}
\end{document}
% TATE w=28.86658pt h=4.8111pt  d=4.8111pt
% YOKO w=28.86658pt h=8.46753pt d=1.15465pt

\kanjiskip\xkanjiskip——アキはグルーとして入る

和文の字間は文字の幅ではなく グルー(伸縮する空き) として入ります。pTeX 系はこれを 2 種類のレジスタで持っていて、和文どうしのあいだが \kanjiskip、和文と欧文のあいだが \xkanjiskip です。ujarticle(本文 10pt)で実測すると \kanjiskip0.0pt plus 0.4pt minus 0.5pt——自然幅はゼロだが伸び縮みする という設計で、行を整えるときの逃げ道になります。一方 \xkanjiskip2.40555pt plus 1.0pt minus 1.0pt。この 2.40555 という半端な数の正体は、全角幅 9.6222pt をちょうど 4 で割った値、つまり 四分アキ です。「日本語と英単語のあいだに四分の空きを入れる」という組版の慣習が、レジスタの初期値として直に置かれているわけです。

latex
\documentclass{ujarticle}
\begin{document}
\typeout{KANJISKIP=\the\kanjiskip}
\typeout{XKANJISKIP=\the\xkanjiskip}
\setbox0=\hbox{}\typeout{EM=\the\wd0}
\setbox0=\hbox{あAい}\typeout{WITH=\the\wd0}
{\xkanjiskip=0pt \setbox0=\hbox{あAい}\typeout{WITHOUT=\the\wd0}}
\end{document}
% KANJISKIP=0.0pt plus 0.4pt minus 0.5pt
% XKANJISKIP=2.40555pt plus 1.0pt minus 1.0pt
% EM=9.6222pt   WITH=31.5555pt   WITHOUT=26.7444pt
% 31.5555 - 26.7444 = 4.8111 = 2 x 2.40555
レジスタTeX Live 2024 の実測値何を決めるか
\kanjiskip0.0pt plus 0.4pt minus 0.5pt和文どうしのアキ。自然幅ゼロで伸縮のみ
\xkanjiskip2.40555pt plus 1.0pt minus 1.0pt和欧文間のアキ。全角 9.6222pt のちょうど 1/4
\prebreakpenalty に対して 10000行頭に来てはいけない文字。10000 は「絶対に折らない」
\postbreakpenalty開き鉤括弧に対して 10000行末に来てはいけない文字。禁則はペナルティで表現される
\jcharwidowpenalty500段落の最終行に和文 1 文字だけ残るのを抑える

ここで大事なのは、禁則処理が「規則」ではなくペナルティの数値として表現されている ことです。TeX の行分割は候補ごとの費用を足し合わせて最小を選ぶ仕組みなので、句読点に 10000 という上限値を与えるだけで「絶対に行頭に置かない」が実現できます。逆に言えば、値を下げれば禁則をゆるめられます。JFM のほうは、和文文字の幅・高さ・深さに加えて どの文字とどの文字のあいだにどれだけ空きを入れるか を型として持つメトリックで、句読点や括弧まわりの詰めはここから来ます。個々の約物の詰め方や \inhibitglue の使い所は日本語組版のページの担当です。

pTeX と upTeX の違い—— が通るかどうか

違いは 内部で使う文字コード の一点に尽きます。pTeX の内部コードは EUC-JP または Shift_JIS で、扱える漢字は事実上 JIS の範囲に縛られます。upTeX は内部が Unicode なので、その枠がありません。抽象論では伝わりにくいので、1 文字で試すのがいちばん早い——いわゆる「はしごだか」(U+9AD9)です。platex に食わせると ! LaTeX Error: Unicode character ^^e9^^ab^^99 (U+9AD9) not set up for use with LaTeX. で止まります。同じ文字を uplatex\documentclass[uplatex]{jsarticle})に渡すと、何ごともなく Output written on ... .dvi まで走ります。人名や地名を扱う文書で platex が突然エラーを吐く原因は、たいていこれです。

terminal
$ platex kanji.tex          # \documentclass{jsarticle} + 髙
! LaTeX Error: Unicode character ^^e9^^ab^^99 (U+9AD9)
               not set up for use with LaTeX.

$ uplatex kanji2.tex        # \documentclass[uplatex]{jsarticle} + 髙
Output written on kanji2.dvi (1 page, 304 bytes).

upTeX を 2007 年から開発しているのは 田中琢爾(Takuji Tanaka) です。TeX Live に同梱される uplcore.ltx の冒頭には Copyright (c) 2016 Takuji Tanaka の 1 行がそのまま残っていて、この系譜の出所を今も証言しています。upTeX の設計でとくに効いているのは \kcatcode という仕組みで、文字の範囲ごとに「これは和文として扱う/欧文として扱う」を切り替えられます。だから upTeX は日本語だけでなく 簡体字・繁体字の中国語、韓国語(ハングル)を同じ文書の中で同時に組める——TeX Live の tlmgr info uptex の説明文にも、4 つのスクリプトを同時に処理できると明記されています。pTeX 時代には手の届かなかった領域です。

e-pTeX はどこから来たか——大学の実習レポートから

e-pTeX の出発点は、北川弘典 が大学の実習科目「計算数学 II」に提出した作業記録でした。信じがたい話に聞こえますが、その文書は現在も TeX Live に eptex_resume.pdf として同梱されています——表紙には「計算数学 II 作業記録」、班名は epsilon。同じ文書は、角藤亮が 2007 年 12 月 30 日に pTeX と e-TeX を合わせる実験を行い、それを peTeX と呼んでいたことも記録しています(p と e が逆なのが面白い、と本人が書き添えています)。TeX Live の ptex-manual バンドルは、この種の古い資料を「歴史的な理由でのみ」収録している、と README で断っています。いま何千という日本語文書のコンパイルを支えているエンジンの初期資料が、学生の提出物として残っているわけです。

では e-TeX 拡張は何を足したのか。\numexpr などの整数演算、マクロを展開から守る \protected、レジスタの本数の大幅な増加、双方向組版のための基盤——地味ですが、いまの LaTeX パッケージの多くはこれらを 前提として書かれています。だから日本語の環境でも e-TeX 抜きでは動かないものが増え、結果として e-pTeX / e-upTeX が既定になりました。\protected が無ければ \section の中に置いた命令が目次に展開されて壊れる、というような話が、実務では毎日起きています。この合流の到達点が、冒頭で見た「6 つのコマンドが 1 つの euptex」という景色です。

いま誰が保守しているのか

日本語 TeX 開発コミュニティ(Japanese TeX Development Community、通称 texjporg) です。企業から community へ引き継がれた瞬間は、ファイルの著作権表示にそのまま刻まれています。TeX Live 2024 に入っている plcore.ltx(pLaTeX の中核)の冒頭 2 行は Copyright (c) 2010 ASCII MEDIA WORKSCopyright (c) 2016-2020 Japanese TeX Development Community で、その下に This file is part of the pLaTeX2e system (community edition). と続きます。upLaTeX 側の uplcore.ltx は同じ場所に ASCII MEDIA WORKS・Takuji Tanaka・Japanese TeX Development Community の 3 者を並べています。日本語 TeX の系譜が、出版社から個人へ、そして共同体へ渡ってきた 30 年が、コメント行 3 本に畳まれているわけです。

この系譜の外側には pTeX-ng(コマンド名 ApTeX、Clerk Ma による再実装)もあります。e-TeX・pTeX・upTeX のプリミティブをそろえて e-upTeX 互換を保ちつつ内部を Unicode 全域に広げ、dvipdfmx をライブラリ化した libdpx を組み込んで DVI を経由せず直接 PDF を出す のが特徴です。ただし正直に書いておくと、TeX Live 2024 には入っていませんtlmgr info ptex-ngcannot find package ptex-ng を返します(存在の痕跡としては、ctex パッケージが ctex-engine-aptex.def というエンジン定義を同梱しています)。実務の既定は今のところ e-upTeX で、pTeX-ng は別途入れて試す対象です。

エンジン内部の文字コードe-TeX 拡張TeX Live 2024 での実体
pTeXEUC-JP / Shift_JISなし独立した実行ファイルは無い。ptexeuptex への symlink
upTeXUnicode(UTF-8)なし同上。uptexeuptex への symlink
e-pTeXEUC-JP / Shift_JISありeptex フォーマット。バナーは (utf8.euc)
e-upTeXUnicode(UTF-8)あり唯一の実バイナリ。platexuplatex もこれが動く
pTeX-ng / ApTeXUnicode(0x10FFFF まで)あり同梱されていない。tlmgr info ptex-ng は見つからないと答える

実務——uplatex から dvipdfmx を経て PDF まで

pTeX 系は PDF を直接吐きません。出力は必ず DVI で、それを dvipdfmx が PDF に変換します。pdfTeX・XeTeX・LuaTeX が PDF を直接書き出すのと決定的に違う点で、ここを知らないと「uplatex を走らせたのに PDF ができない」で止まります。標準の手順は uplatex を(相互参照と目次のために)2 回、続いて dvipdfmx を 1 回。なお dvipdfmx 自身も TeX Live では xdvipdfmx への symlink なので、ls -l で見ると名前が変わって驚くかもしれませんが、これも正常です。

latex
\documentclass{ujarticle}   % uj... = upLaTeX, horizontal;  ut... = vertical
\begin{document}
こんにちは、\LaTeX。日本語が美しく組めます。
\[ E = mc^2 \]
\end{document}
terminal
$ uplatex document.tex      # pass 1 -> document.dvi + document.aux
$ uplatex document.tex      # pass 2 -> cross-references settle
$ dvipdfmx document.dvi     # -> document.pdf
  • PDF ができない ときは、まず .dvi があるか確認します。あるなら問題は dvipdfmx 側、無いなら uplatex 側です。切り分けはこれで半分終わります。
  • 文字化けするなら、ソースが UTF-8 で保存されているか、クラスが upLaTeX 向けか(ujarticleutarticle、または \documentclass[uplatex]{jsarticle})を順に見ます。エンジン側の指定は -kanji=STRING(入力/出力、euc|jis|sjis|utf8|uptex)と -kanji-internal=STRING(内部コード、euc|sjis|uptex)です。
  • 質問や不具合報告をするときは、コマンド名(platexuplatex か)、ログ 1 行目のバナー、ソースの保存エンコーディングの 3 点を必ず添えます。バナーの (utf8.euc)(utf8.uptex) だけで、話が半分決まります。
  • これから新しく書くなら、指定が無い限り UTF-8 のソース+uplatexdvipdfmxjlreq もしくは大学指定クラス。既存テンプレートが platex 前提なら、流行で書き換えず、そのテンプレートの手順に従います。
  • フォントを自由に選びたいなら、pTeX 系で粘らず LuaLaTeX(LuaTeX-ja)や XeLaTeX(xeCJK)を検討します。OS の OpenType フォントを名前で指定でき、PDF も直接出ます。

結局のところ、判断はこう畳めます。実績と速度で日本語論文を安全に組むなら e-upTeX(uplatex)→ dvipdfmxOS フォントや Lua による拡張が要るなら LuaLaTeXXeTeX の資産があるなら XeLaTeX + xeCJK。そして忘れてはいけないのは、pTeX 系の「古さ」は欠点ではないということです。縦組みと JFM をエンジンの内側に持つという 1980 年代の判断があったからこそ、日本語の商業出版が TeX で成立しました。いま uplatex と打つとき、あなたが起動しているのはその判断の 40 年目です。