pTeX 계열

TeX Live 2024의 bin 디렉터리에는 ptex, uptex, eptex, euptex, platex, uplatex이라는 여섯 개의 명령이 나란히 놓여 있습니다. 그런데 ls -l로 들여다보면 여섯 개 모두 euptex이라는 단 하나의 실행 파일을 가리키는 심볼릭 링크입니다. 일본어를 위해 만들어진 일련의 LaTeX 엔진——pTeX, upTeX, e-pTeX, e-upTeX——은 사반세기에 걸쳐 하나의 구현으로 합류했습니다. 이 페이지는 그 합류를 실제 배너와 로그, 실측값을 읽으며 따라갑니다. 세로쓰기의 작법이나 금칙의 세부는 다른 페이지에 맡기고, 여기서 다루는 것은 엔진 그 자체입니다.

여섯 개의 명령, 하나의 실행 파일

platex이라는 이름의 실행 파일은 존재하지 않습니다. TeX Live 2024에서 platexeuptex을 가리키는 심볼릭 링크이고, ptex, uptex, eptex, uplatex도 마찬가지입니다. 그렇다면 무엇이 다른가——읽어 들이는 포맷이 다릅니다. TeX 계열 프로그램은 실행될 때 자기 이름을 보고 같은 이름의 포맷 파일(.fmt)을 읽습니다. 그 대응표가 fmtutil.cnf이며, 거기에는 platex euptex language.dat *platex.iniuplatex euptex language.dat *uplatex.ini 두 줄이 나란히 있습니다. 두 번째 열이 엔진, 네 번째 열이 그 포맷을 굽는 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

여섯 개를 모두 실행해 첫 줄만 남기면 이 구조가 그대로 보입니다. 배너의 본문은 매번 같습니다——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)

그 긴 숫자열은 하나의 버전 번호가 아니라 서로 다른 네 계보의 버전을 이어 붙인 것입니다. 맨 앞의 3.141592653은 순수 TeX, p4.1.1은 pTeX, u1.30은 upTeX, 230214는 e-pTeX(날짜 형식), 끝의 2.6은 e-TeX입니다. 추측이 아닙니다. 엔진이 각각을 프리미티브로 가지고 있어서 문서 안에서 \the\ptexversion 등으로 직접 읽어 낼 수 있습니다. 이 한 줄을 읽을 수 있게 되면 e-pTeX이 무엇인가라는 물음에 구체적으로 답할 수 있습니다. pTeX에 e-TeX 확장을 병합한 것이고, 지금 돌아가는 e-upTeX은 거기에 upTeX을 한 겹 더 얹은 네 층 구조라는 것입니다.

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
배너 조각출처읽어 내는 방법
3.141592653커누스의 순수 TeX프리미티브가 아니라 배너에만 나옵니다
p4.1.1pTeX — ASCII에서 온 일본어 확장\ptexversion, \ptexminorversion, \ptexrevision
u1.30upTeX — 유니코드화\uptexversion, \uptexrevision
230214e-pTeX — 날짜를 버전으로 씁니다\epTeXversion
2.6e-TeX 확장\eTeXversion, \eTeXrevision

pTeX이 엔진에 심은 것——조판 방향과 JFM

pTeX이 매크로가 아니라 엔진의 개조여야 했던 이유는 둘입니다. 조판 방향(\tate\yoko), 그리고 JFM(일본어 폰트 메트릭)입니다. 개발한 곳은 아스키(ASCII Corporation)——컴퓨터·게임 잡지로 알려진 그 출판사이고, 이름의 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 계열은 이를 두 개의 레지스터로 가지고 있어, 일본어끼리는 \kanjiskip, 일본어와 로마자 사이는 \xkanjiskip입니다. ujarticle(본문 10pt)에서 실측하면 \kanjiskip0.0pt plus 0.4pt minus 0.5pt——자연 폭은 0이지만 신축한다는 설계로, 행을 고를 때의 여유분이 됩니다. 한편 \xkanjiskip2.40555pt plus 1.0pt minus 1.0pt. 이 어중간해 보이는 2.40555의 정체는 전각 폭 9.6222pt를 정확히 4로 나눈 값, 곧 4분의 1 전각입니다. “일본어와 로마자 낱말 사이에 4분의 1만큼 띄운다”는 조판 관례가 레지스터 기본값으로 그대로 놓여 있는 것입니다.

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일본어 글자 사이의 공백. 자연 폭 0에 신축만
\xkanjiskip2.40555pt plus 1.0pt minus 1.0pt일본어와 로마자 사이의 공백. 전각 9.6222pt의 정확히 1/4
\prebreakpenalty일본어 쉼표에 대해 10000행 첫머리에 오면 안 되는 문자. 10000은 “절대 끊지 않음”
\postbreakpenalty여는 낫표에 대해 10000행 끝에 오면 안 되는 문자. 금칙은 페널티로 표현됩니다
\jcharwidowpenalty500문단 마지막 줄에 일본어 한 글자만 남는 것을 억제합니다

여기서 중요한 것은 금칙이 “규칙”이 아니라 페널티라는 수치로 표현되어 있다는 점입니다. TeX의 행 분할은 후보마다 비용을 더해 최소를 고르는 방식이므로, 쉼표에 상한값 10000을 주기만 하면 “절대 행 첫머리에 두지 않는다”가 실현됩니다. 뒤집어 말하면 값을 낮추면 금칙이 느슨해집니다. 한편 JFM은 일본어 글자의 폭·높이·깊이뿐 아니라 어떤 문자와 어떤 문자 사이에 얼마나 띄울지를 형태로 가지는 메트릭이며, 구두점과 괄호 주위의 조임이 여기서 나옵니다. 개별 약물의 조정법이나 \inhibitglue를 쓸 자리는 일본어 조판 페이지의 몫입니다.

pTeX과 upTeX의 차이——글자 하나로 갈립니다

차이는 내부에서 쓰는 문자 코드 한 가지로 귀결됩니다. pTeX의 내부 코드는 EUC-JP 또는 Shift_JIS라서 다룰 수 있는 한자가 사실상 JIS 범위에 묶입니다. upTeX은 내부가 유니코드라 그 울타리가 없습니다. 추상적으로 말하면 잘 와닿지 않으니 글자 하나로 시험하는 편이 빠릅니다——이른바 “사다리 다카” (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라는 한 줄이 그대로 남아, 이 계보의 출처를 지금도 증언합니다. upTeX 설계에서 특히 효과를 내는 것은 \kcatcode라는 장치로, 문자 범위별로 “이것은 일본어로 다룬다/로마자로 다룬다”를 전환할 수 있습니다. 그래서 upTeX은 일본어뿐 아니라 간체·번체 중국어와 한국어 한글을 같은 문서 안에서 동시에 조판할 수 있습니다. TeX Live의 tlmgr info uptex 설명에도 네 문자 체계를 동시에 처리한다고 분명히 적혀 있습니다. 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 인수 안에 넣은 명령이 목차로 전개되어 망가집니다. 이론상의 걱정이 아니라 매일 일어나는 일입니다. 이 합류의 도착점이 바로 첫머리에서 본 “여섯 개의 명령, 하나의 euptex”이라는 풍경입니다.

지금은 누가 보수하고 있는가

일본어 TeX 개발 커뮤니티(Japanese TeX Development Community, 흔히 texjporg)입니다. 기업에서 공동체로 넘어간 순간은 파일의 저작권 표시에 그대로 새겨져 있습니다. TeX Live 2024에 들어 있는 plcore.ltx(pLaTeX의 핵심) 첫 두 줄은 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 셋을 나란히 적고 있습니다. 일본어 TeX의 계보가 출판사에서 개인으로, 다시 공동체로 건너온 30년이 주석 세 줄에 접혀 있는 셈입니다.

이 계보 바깥에는 pTeX-ng(명령 이름 ApTeX, Clerk Ma의 재구현)도 있습니다. e-TeX·pTeX·upTeX 프리미티브를 갖춰 e-upTeX 호환을 유지하면서 내부를 유니코드 전역으로 넓히고, 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-TeXTeX Live 2024에서의 실체
pTeXEUC-JP / Shift_JIS없음독립 실행 파일 없음. ptexeuptex으로 가는 심볼릭 링크
upTeXUnicode(UTF-8)없음위와 같음. uptexeuptex으로 가는 심볼릭 링크
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로 변환합니다. PDF를 직접 쓰는 pdfTeX·XeTeX·LuaTeX과의 결정적 차이이며, 이를 모르면 “uplatex을 돌렸는데 PDF가 안 생긴다”에서 멈추게 됩니다. 표준 절차는 uplatex을 두 번(상호 참조와 목차를 안정시키기 위해), 이어서 dvipdfmx를 한 번입니다. 참고로 TeX Live에서는 dvipdfmx 자체도 xdvipdfmx로 가는 심볼릭 링크라 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)입니다.
  • 질문하거나 버그를 보고할 때는 명령 이름(platex인지 uplatex인지), 로그 첫 줄의 배너, 소스의 저장 인코딩 세 가지를 반드시 붙입니다. 배너가 (utf8.euc)인지 (utf8.uptex)인지만으로 이야기의 절반이 정해집니다.
  • 새로 시작한다면 지정이 없는 한 UTF-8 소스에 uplatex, dvipdfmx, 그리고 jlreq 또는 학교 지정 클래스를 씁니다. 기존 템플릿이 platex 전제라면 유행 때문에 고쳐 쓰지 말고 그 템플릿의 빌드 절차를 따릅니다.
  • 글꼴을 자유롭게 고르고 싶다면 pTeX 계열에서 버티지 말고 LuaLaTeX(LuaTeX-ja)나 XeLaTeX(xeCJK)을 검토합니다. 시스템 OpenType 글꼴을 이름으로 지정할 수 있고 PDF도 한 번에 나옵니다.

결국 판단은 이렇게 접힙니다. 실적과 속도로 일본어 논문을 안전하게 조판하려면 e-upTeX(uplatex) → dvipdfmx, OS 글꼴이나 Lua 확장이 필요하면 LuaLaTeX, XeTeX 자산이 있으면 XeLaTeX + xeCJK. 그리고 잊지 말아야 할 것은 pTeX 계열의 “오래됨”이 결점이 아니라는 점입니다. 세로쓰기와 JFM을 엔진 안쪽에 두겠다는 1980년대의 판단이 있었기에 일본어 상업 출판이 TeX으로 성립했습니다. 지금 uplatex이라고 칠 때, 당신이 시동하는 것은 그 판단의 40년째입니다.