2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

LaTeXのドライバオプションの扱いがカンタンになった話、もっとカンタンにする話

Posted at

これは「TeX & LaTeX Advent Caleandar 2025」の25日目の記事です。
(24日目→ golden_lucky さん

​「(La)TeXをカンタンにする方法」​を重点テーマとする「TeX & LaTeX Advent Calendar 2025」もいよいよクリスマス:christmas_tree:の日を迎えることになりました。最終日となる今日は、現状のLaTeXにおける一つの“難所”について、それをカンタン:blush:にする方策について考えてみます。それは​「ドライバオプションの指定」​です。

ドライバオプションの扱いがカンタンになった話

ドライバオプションを語ってみる

現状のLaTeXの世界では複数のワークフロー(LaTeXエンジンとDVIドライバ1の組み合わせ)が併用されています。日本語文書で利用される主なものに限っても以下のワークフローがあります。

  • pLaTeX+dvips
  • pLaTeX+dvipdfmx
  • upLaTeX+dvipdfmx
  • LuaLaTeX(PDF出力)

通常、LaTeXパッケージはワークフローによる(TeX言語レベルの)実装の差異を吸収して共通のインタフェースで使える2ように設計されています。しかし「DVIドライバの種類に応じて内部動作を変える」必要がある(この性質を​「ドライバ依存」​と呼びます)ようなパッケージについては、「自分がどのDVIドライバを使っているか」の情報をドライバオプションという形でユーザ(文書作成者)が教える必要があります。

LaTeXエンジンは「自分がどのLaTeXエンジンであるか」は知っていますが「自分が出力したDVIファイルがこの後どのDVIドライバに入力されるか」を知る術は当然ありません。従ってドライバ依存をもつ場合は「ユーザに正しいDVIドライバの種類を教えてもらう」のが最善の方法となるわけです。

  • DVIドライバとしてdvipsを使う場合にはdvipsを指定する
  • DVIドライバとしてdvipdfmxを使う場合にはdvipdfmxを指定する
  • DVIドライバを使わない(PDF出力のエンジンの)場合には指定しない

最近(大体2015年以降)の標準的な方式としてはドライバオプションは文書クラスのオプション(つまり\documentclass命令のオプション)として指定します。これによりドライバ依存をもつ全てのクラスとパッケージに正しいドライバオプションが適用されます。このようなオプションの指定方法を​「グローバルオプション」​と呼びます。

% dvipsを使う場合
\documentclass[dvips]{‹文書クラス›}
% dvipdfmxを使う場合
\documentclass[dvipdfmx]{‹文書クラス›}
% PDF出力の場合
\documentclass{‹文書クラス›}

昔はドライバ依存をもつパッケージのオプションとしてドライバオプションを指定する方式が用いられていました。

% dvipdfmxを使う場合
\usepackage[dvipdfmx]{graphicx}

しかしこの昔の方式には多くのデメリットがあります。

  • 大量のオプション指定が要るので単純に面倒で、指定漏れが発生しやすい。
  • ユーザが「どのパッケージがドライバ依存をもつか」という情報を把握する必要がある。
  • 最近ではグローバルオプションの方式のみをサポートするようなパッケージ(TikZがその筆頭)があるので、結局グローバルオプションが必要になりえる。

このため最近はグローバルオプションの方式が推奨されています。(この点で既に昔よりカンタン:blush:になっているわけです。)

まとめると、2015年頃の状況としては「ドライバ依存のパッケージを使う場合には正しいドライバオプションをグローバルオプションとして指定する必要がある」となっていました。

ドライバオプションは厄介だった

「正しいドライバオプションが必要」という要請はユーザに多少の面倒をもたらすもの(それでも昔に比べるとかなりマシになった)なのは確かですが、実はこれによりもっと大きな問題が発生しています。それは「ドライバ依存のパッケージの解説文書を書くのが難しい」という問題です。

例えばTikZパッケージの入門記事(つまり初めて使う人を対象とした解説記事)を書きたいとします。すると当然、その中で「tikzパッケージの読込」の方法を説明しないといけません。どう書けばいいでしょうか。

tikzを読み込むにはグローバルのドライバオプションの指定が必要で、読者はそれをまだ知らない可能性があります。となると、フツーに考えると先述のような「使用中のDVIドライバに応じて正しいオプションを指定する」という指示になるはずです。

% dvipsを使う場合
\documentclass[dvips]{‹文書クラス›}
% dvipdfmxを使う場合
\documentclass[dvipdfmx]{‹文書クラス›}
% PDF出力の場合
\documentclass{‹文書クラス›}

% その上でパッケージを読み込む
\usepackage{tikz}

ところが、記事の筆者の中には「初心者が使用中のDVIドライバの種類を把握していることは期待できないので、この指示では解説記事として機能しないのでは:cold_sweat:」と思って“正しい指示”を書くことを躊躇する人もいます。もちろん、読者が使用中のDVIドライバを筆者が代わりに把握することはできません。このどうしようもない状況で記事を書こうとして結果的に「DVIドライバの把握が不要になるように大ウソの説明を書く」強硬手段に訴える人もいます。

  • 「無条件にdvipdfmxオプションを指定しましょう:sunglasses:
  • 「日本語文書の場合はdvipdfmxオプションを指定しましょう:sunglasses:
  • (LaTeXエンジンの種類は把握していると想定した上で)「(u)pLaTeXの場合はdvipdfmxオプションを指定しましょう:sunglasses:

しかし現実として「LuaLaTeXを選択するLaTeX入門者」や「今でもdvipsを使っている人」は確実に存在します。そういう人が“ウソを見抜けるほど詳しい”とは限らないため、大ウソの説明に実際に騙される可能性が否定できません。結果的に折角書いた解説記事の価値を大きく損なうことになってしまいます。

ドライバオプションが必須になった

ところが2020年の2月にこの状況が一変する出来事が起こりました。LaTeXカーネルにexpl3の機能が統合された3のです。この改修はドライバオプションの指定の在り方にも大きな影響を与えました。

expl3の機能には「文字の色を指定する(\color_select:nn)」や「出力PDFのバージョンを指定する(\pdf_version_gset:n)」等のドライバ依存をもつものが存在します。そのようなexpl3がカーネルに統合されたということは、結局LaTeXのカーネル自体がドライバ依存をもつようになったことを意味します。

ユーザの視点で見ると、これまでは「ドライバ依存のパッケージを使う場合にはドライバオプションを指定すべき」だったのが「常にドライバオプションを指定すべき」に変わったことになります。

ドライバオプションはやっぱり必須

先に「ドライバオプションが常時必須になった」と述べましたが読者の中にはこれに懐疑的で「やっぱりドライバオプションの状態には“無指定”もありえてその場合はexpl3の一部の機能が使えなくなるだけでは?:thinking:」と思った人もいるでしょう。ここでは「ドライバオプションの“無指定”という状態は存在しない」ことを確認します。

パッケージを何も使っていない超単純な欧文LaTeXの文書を用意します。

test.tex
% for latex
% No driver option!
\documentclass[a4paper]{article}
\begin{document}
Hello!
\end{document}

ここで\documentclassにドライバオプションを指定していないことに注意してください。このtest.texをlatexでタイプセットみます。

latex test.tex

ログファイルを見ると以下のような記述があります。

test.log(抜粋)
File: l3backend-dvips.def 2025-10-09 L3 backend support: dvips

つまり、dvips用のexpl3の補助ファイルが読み込まれています。さらにいうと、ここで出力されたtest.dviには次のようなspecial命令が含まれています。(dv2dtによるダンプ形式で示します。)

test.dvi(ダンプ;抜粋)
special1 26 'header=l3backend-dvips.pro'

ここに記されているl3backend-dvips.proというはPostScript言語で書かれたdvips用の補助プログラムです。つまりこのDVIファイルはdvips用の出力であることは明確です。

以上のことから、ドライバオプションを指定しない場合の既定値は“無指定”などではなくdvipsであることが判りました。実際にはさっきのtest.dviをdvipdfmxで変換しても希望通りのPDFファイルが得られるのですが、それはマチガッテル使い方(バッドノウハウ)と考えるべきでしょう。

ドライバオプションはカンタンになった

ドライバオプション指定が常時必須になったことの影響をまとめましょう。

まずユーザ(文書作成者)から見ると、ドライバオプションに関する判断が(さらに)カンタン:blush:になりました。これまでは「ドライバ依存のパッケージを使っているかを自分で判断してドライバオプションの有無を使い分ける」必要があったのですが、これからは使い分ける必要がなくなりました。

単発のパッケージの解説記事の筆者から見ると、「ドライバオプションに関する指示を書く」という難行から解放されてカンタン:blush:になりました。ドライバオプションの指定が必須であるということは、LaTeXの最低限の文書ソースが書ける入門者はもうその段階で正しいドライバオプションの書き方も把握しているはずです。従って、TikZの解説記事を書く人がドライバオプションの話をする必要はもうありません。tikzパッケージの読込方法の説明は\usepackage{tikz}だけで済んでしまいます。

TikZの解説でドライバオプションを扱う必要がなくなったということは、ドライバオプションに関する解説の責任はLaTeX自体の入門記事に任されたことになります。そういう入門文献の筆者から見るとどうでしょうか。イマドキのLaTeXの使用ではたとえ入門段階であってもドライバ依存のパッケージ(例えばgraphicx等)は避けられません。従って、マトモな入門文献であれば当然既に、パッケージオプションはどこかの時点で扱っていたはずで、負担が増えることにはならない4でしょう。むしろ、環境構築の話の直後に(採用したワークフローに応じた)ドライバオプションの指定の指示が書けるので、説明がスムーズに行えてカンタン:blush:になったといえます。

以上をまとめると、2020年に行われた「expl3のマージ」というカーネル改修はドライバオプションの扱いをカンタン:blush:にしたと結論できます。

ドライバオプションの扱いをもっとカンタンにしたい話

昔と比べて随分とカンタン:blush:になったドライバオプションの扱いですが、現時点ではまだムズカシイ:weary:点が残っています。それは「指定がマチガッテル場合に適切なエラーが出ない」ということです。

例えばupLaTeX+dvipdfmxのワークフローで次のような文書をビルドしようとします。dvipdfmxを使うのでドライバオプションが必要ですが指定を忘れています

% upLaTeX文書
% dvipdfmxオプションがない!!
\documentclass[uplatex,a4paper]{jsarticle}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\draw (0,0)--(1,1)--(2,0)--cycle;
\end{tikzpicture}
\end{document}

この文書をビルドすると、uplatexの実行では何もエラーは起きず、dvipdfmxにおいて次のようなわけのわからない警告が出て、出力は異常(TikZの図が欠落する)になります。

dvipdfmx:warning: Unknown token "pgfo"
dvipdfmx:warning: Interpreting PS code failed!!! Output might be broken!!!
dvipdfmx:warning: Interpreting special command ps: (ps:) failed.
dvipdfmx:warning: >> at page="1" position="(81.3485, 701.052)" (in PDF)
dvipdfmx:warning: >> xxx "ps:: pgfo"
dvipdfmx:warning: Unknown token "save"
dvipdfmx:warning: Interpreting PS code failed!!! Output might be broken!!!
dvipdfmx:warning: Interpreting special command ps: (ps:) failed.
dvipdfmx:warning: >> at page="1" position="(81.3485, 701.052)" (in PDF)
……(略)……

dvipdfmxオプションがないのはマチガイなので、本来ならばLaTeX(uplatex)を実行する段階でエラーになってほしいところです。しかし前述の通り、LaTeXエンジンは「ユーザがどのDVIドライバを使おうとしているか」を判断できないのでそれは原理的に無理です。

しかし「dvipdfmxを使う場合にdvipdfmxオプションが必須になった」ということ利用すると、ここで適切なエラーが出す方法を思いつきます。それは「ビルドフローの中にチェックを組み込む」という方法です。「dvipdfmxを使うビルドフローを実行している」前提であればグローバルのdvipdfmxの指定がないのは確実にマチガイなのでそれを判定して適切なエラーを出せるはずです。

ドライバオプションの扱いをもっとカンタンにした話

というわけでつくりました:smiley:

このLuaスクリプトはDVIファイルの中身5を解析してどのDVIドライバのためのものであるかを判定して、それによりドライバオプションが適切であったかを検査します。

chkdvidriverの実行にはLuaTeXのLuaモード(texlua)を利用します。

texlua chkdvidzriver.lua ‹オプション›... ‹引数›...

以下の説明ではchkdvidzriver.luaをchkdvidzriverというコマンド名で実行できることを仮定します。

以下ではビルド方法が何であるかに応じて、ビルドフローへの組み込み方について説明します。実行例として以下の2つのupLaTeX文書から生成されるDVIファイルを使用します。test-dvipdfmx.dviはdvipdfmx用で、test-dvips.dviはdvips用です。

test-dvipdfmx.tex
% upLaTeX文書
% ドライバオプションに'dvipdfmx'
\documentclass[uplatex,dvipdfmx,a4paper]{jsarticle}
\begin{document}
こんにちは、dvipdfmx!
\end{document}
test-dvips.tex
% upLaTeX文書
% ドライバオプションがない! (既定のdvipsになる)
\documentclass[uplatex,a4paper]{jsarticle}
\begin{document}
こんにちは、dvipdfmx!% 違う😥
\end{document}

シェルスクリプト使用の場合

chkdvidriverの最も基本的な使い方では「期待するドライバ(dvipsまたはdvipdfmx6)」と「入力DVIファイル名」を指定します。この場合は「DVIファイルの実際の想定ドライバが期待値と一致するか」を検査してその結果を終了ステータスに返します。

chkdvidriver ‹期待するドライバ› ‹入力DVIファイル›

一致する場合は終了ステータスとして0(真)を返します。

> chkdvidriver dvipdfmx test-dvipdfmx.dvi
#(終了ステータスは0)

一致しない場合は簡単な警告メッセージを表示した上で終了ステータスとして2(偽)を返します7

> chkdvidriver dvipdfmx test-dvips.dvi
chkdvidriver: FAIL: actual dvi file setting is: dvips
#(終了ステータスは2)

終了ステータスを利用して「ドライバが期待値と一致しない場合はビルドを中断する」という処理が実現できます。

(bashの場合の一例)
chkdvidriver dvipdfmx $IN.dvi || exit
(コマンドプロンプトの場合の一例)
chkdvidriver dvipdfmx %IN%.dvi || exit /B

オプションに-aを指定すると(‹期待するドライバ›dvipdfmxである場合に限って)不一致時にもう少し派手(かつ説明的)な警告メッセージを表示します。

> chkdvidriver dvipdfmx test-dvips.dvi
chkdvidriver: FAIL: actual dvi file setting is: dvips
|!!!!!!!!!!!!!!!!!!!!!  F A I L U R E  !!!!!!!!!!!!!!!!!!!!!
|   This DVI file is built for dvips, NOT dvipdfmx.
|   You must specify the global option 'dvipdfmx'.
|       \documentclass[dvipdfmx, ...]{...}
|!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#(終了ステータスは2)

なお、-s ‹入力DVIファイル›という書式で実行した場合は、入力DVIファイルの想定のドライバの値を出力します。

> chkdvidriver -s test-dvips.dvi
dvips

Latexmk使用の場合

-lオプションはLatexmkのDVIフィルタとして適した動作を指示します。

chkdvidriver -l ‹期待するドライバ› ‹入力DVIファイル› ‹出力DVIファイル› ‹TeXファイル›

コマンドラインから直接この形式を実行8してもあまり意味はなくて、Latexmkの設定ファイル(.latexmkrc等)で以下のように設定する利用法が想定されています。この設定を加えると、

$dvi_filter = "hkdvidriver -l ‹期待するドライバ› %S %D %T";

upLaTeX+dvipdfmxのビルドの場合の設定の一例です。

.latexmkrc
# この辺りはいつも通りに
$latex = "uplatex -interaction=nonstopmode -file-line-error %O %S";
$dvipdf = "dvipdfmx %O -o %D %S";
$pdf_mode = 3;
# この設定を追加する
$dvi_filter = "chkdvidriver -l dvipdfmx %S %D %T";

この設定でtest-dvips.texのビルドを試みると、chkdvidriverが不一致のため失敗するのでビルドが失敗します。

> latexmk test-dvips.tex
Rc files read:
  /home/zr/.latexmkrc
  .latexmkrc
Latexmk: This is Latexmk, John Collins, 15 June 2025. Version 4.87.
No existing .aux file, so I'll make a simple one, and require run of *latex.
Latexmk: applying rule 'latex'...
……(略)……
------------
Run number 1 of rule 'dvifilter'
------------
Latexmk: Making 'test-dvips.dviF' via temporary '/tmp/test-dvips_tmp1.dviF'...
------------
Running 'chkdvidriver -l dvipdfmx "test-dvips.dvi" "/tmp/test-dvips_tmp1.dviF" "test-dvips.tex"'
------------
chkdvidriver: FAIL: wrong dvi file setting: expected=dvipdfmx: actual=dvips
Latexmk: Errors, so I did not complete making targets
……(略)……

LaTeX Workshopを使う場合

-lオプション付加での実行においてさらに-wオプションを付けると「VSCode+LaTeX WorkshopにおいてLatexmk利用のビルドを行う」場合のDVIフィルタとして適した動作を指示します。

実際には-wは自動的に-lを有効化するので-wだけ指定すれば十分です。

chkdvidriver -w ‹期待するドライバ› ‹入力DVIファイル› ‹出力DVIファイル› ‹TeXファイル›

このモードの場合、chkdvidriverが不一致で失敗した場合は、LaTeX Workshopのエラー報告について、あたかも「LaTeXソースファイルの\documentclassのある行」でエラーが発生したかのような挙動になります。

以下で実行例を示します。test-dvips.texのあるディレクトリをVSCodeで開きます。さらに、前節のupLaTeX+dvipdfmxビルド用の.latexmkrc-l-wに変えたものを同じディレクトリに配置します。

.latexmkrc
# この辺りはいつも通りに
$latex = "uplatex -interaction=nonstopmode -file-line-error %O %S";
$dvipdf = "dvipdfmx %O -o %D %S";
$pdf_mode = 3;
# この設定を追加する
$dvi_filter = "chkdvidriver -w dvipdfmx %S %D %T";

その上で、LaTeX Workshopの既定設定の「latexmk (latexmkrc)」レシピでtest-dvips.texのビルドを開始します。

「latexmk (latexmkrc)」レシピの設定内容
// latex-workshop.latex.recipes
{
	"name": "latexmk (latexmkrc)",
	"tools": [
		"latexmk_rconly"
	]
}
// latex-workshop.latex.tools
{
	"name": "latexmk_rconly",
	"command": "latexmk",
	"args": [
		"%DOC%"
	],
	"env": {}
}

すると、chkdvidriverが不一致のため失敗するので以下のようなエラー表示になります。

image-1.png

ユーザの視点では「\documentclassでドライバオプションが抜けている」というエラーに見えるわけです。

まとめ

LuaLaTeX者「LuaLaTeXでは元々何も考える必要がなくて9カンタン:blush:なので、メリークリスマス!:christmas_tree::snowflake::gift::snowman:

  1. pdfLaTeXやLuaLaTeXのようなPDF出力のエンジンの場合はDVIドライバは「無し」となります。

  2. 例えば、「画像ファイルの画像を挿入する」ためのTeX言語のコードはdvips・dvipdfmx・pdfTeX・XeTeX・LuaTeXの各々で全く異なるのですが、LaTeXのgraphicxパッケージではどのワークフローでも\includegraphics{‹ファイル名›}で画像が挿入できます。

  3. それまではexpl3言語を使うためにはexpl3という名前のLaTeXパッケージを読み込む必要がありました。

  4. 同様の理由で、ドライバオプションが必須になることによりユーザの負担が増えることにはならないはずです。

  5. 実はLaTeX文書において「グローバルにドライバオプションを指定する」方法はグローバルオプションの他にもいくつかあるので、LaTeX文書のソースを解析して判定するのは容易ではありません。

  6. DVI出力におけるexpl3の有効なドライバの種類はdvipsdvipdfmxしかありません。

  7. DVIファイルが壊れている等の理由で異常終了した場合は終了ステータスとして1を返します。

  8. 一応説明しておくと、従来の動作に加えて、一致の場合は<入力DVIファイル>の内容を何も改変せずに<出力DVIファイル>に出力します。端末出力メッセージが変わることがあり、その際に<TeXファイル>のパス名や内容が使われることがあります。この場合、ビルドフローの中でLatexmkが自動的にchkdvidriverを実行してドライバを検査して不一致の場合はそこでビルドを失敗させます。

  9. 「dvipdfmx前提のLaTeX文書をLuaLaTeXでビルドしようとしてしまう」事例は実際にあるので、実は考慮すべきことはあります。2020年のカーネルの改修でこのパターンにも適切なエラーが返るようになりました。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?