これは TeX & LaTeX Advent Calendar 2025 の 9 日目の記事です。
アドベントカレンダー 8 日目は zr_tex8r さんの「2025年版 TeX Live で使えるゆきだるま☃のまとめ」でした。
10 日目は津茶利休さんの「 KAGE 形式を METAFONT 処理して TeX で多様な文字をより簡単に印字」です。
LaTeX で使ったことの無いパッケージを初めて使うとき、〈パッケージ名〉.tex のようなファイル名にして試してみることがあるのではないでしょうか。
パッケージのマニュアルや Web ページを見ながら実際に書いてみて、いざタイプセットしてみようとなったときにエラーが出てしまうと、使い方を間違えたかな? などと思ってしまいます。
しかし、実際はそれが原因ではないエラーがあります。タイトルにあるエラーです。
実例を見た方が分かりやすいと思います。次のような chemfig パッケージを使用した場合を考えてみます。
%% chemfig.tex
\documentclass{article}
\usepackage{chemfig}
\begin{document}
Hello, chemfig!
\end{document}
これを以下のように LaTeX でタイプセットします。
$ pdflatex -interaction=nonstopmode chemfig.tex
すると、エラーとなり以下のようなメッセージが生成されます。
Two \documentclass or \documentstyle commands.
このエラーメッセージをそのまま読むと、「\documentclass あるいは \documentstyle 1 が 2 つあるよ」と言っています。
しかし、ファイルを見ても \documentclass は 1 回しか使用していません。内容にもエラーの原因となるようなものも見えません。
どうしてダメになってしまうのでしょうか。
内部で TeX ファイルが呼び出されている?!
意図していないにも拘わらず 2 度も \documentclass が読み込まれている理由、それは「パッケージの内部で 〈パッケージ名〉.tex が呼び出されているから」です。
先と同じように chemfig パッケージを例にとって考えてみます。
まずは chemfig.sty の中身を見てみましょう。例えばシェルで以下のようにすれば chemfig.sty の中身を閲覧できます。
cat "$(kpsewhich chemfig.sty)"
さて、chemfig.sty の中はと言うと、以下のように \input を使って chemfig.tex を読み込む行がありました。
(中略)
\input chemfig.tex
(中略)
本来、この \input で呼び出される chemfig.tex は chemfig.sty のあるディレクトリのファイルです。
しかし、chemfig.tex が LaTeX を実行したカレントディレクトリにある場合、パッケージ内にある \input chemfig.tex によって呼び出されるファイルはカレントディレクトリのファイルになってしまうのです。
そのため、今回の chemfig の例では再帰的に呼び出されている状態です。
したがって、先に示したテストファイルは、LaTeX にとって以下のように見えてしまうことになります。
\documentclass{article}
\documentclass{article}
\usepackage{chemfig}
\begin{document}
Hello, chemfig!
\end{document}
\begin{document}
Hello, chemfig!
\end{document}
……![]()
![]()
まさに、エラーの通り \documentclass が 2 つ現れてしまいました。
以上のことをまとめると、次の条件がすべて揃ったときにこのような問題が生じることが分かります。
- パッケージの内部で
\input 〈パッケージ名〉.texが使用されている - パッケージの内部の
\inputで呼び出された .tex ファイルと同名のファイルが、文書作成用のファイルとしてカレントディレクトリにある
このようなパッケージはどれくらいあるのか
本題です。
具体的に「どのパッケージを利用するときに 〈パッケージ名〉.tex と言う名前を使ってはいけないのか」を知りたいです。
これは重要な情報になりえるでしょう。これを知っていれば、あるいは知らずに使っていたとしても、これがエラー原因になることが分かることは非常に有益です。
そもそも、〈パッケージ名〉.sty ファイルが内部で \input 〈パッケージ名〉.tex する場合をすべて叩き出すことはできるのでしょうか。
—— できます。
以下の 2 ステップを踏むことで当該パッケージを叩き出すことができました。
- texlive.tlpdb から .sty と .tex のファイル名が同じものを抽出する
- 該当した hoge.sty を読んでファイル内に
\input hoge.texが含まれているかを判定する
ステップ ①
texlive.tlpdb から .sty と .tex のファイル名が同じものを抽出する
TeX Live のすべてのパッケージは texlive.tlpdb 2(超巨大!)と言うファイルに書き出されています。ローカルに TeX Live がある場合は $TEXLIVE/20**/tlpkg/ に格納されています。
ここには、すべてのパッケージの情報が書かれており、パッケージに含まれるファイルもすべて書かれています。これを読むことで該当するファイルを探しましょう。
例として、再度 chemfig パッケージを見てみましょう。パッケージの情報を見るには tlmgr info を使って以下のようにすれば良いのでした。
$ tlmgr info chemfig --list
package: chemfig
category: Package
shortdesc: Draw molecules with easy syntax
longdesc: The package provides the command \chemfig{<code>}, which draws molecules using the TikZ package. The <code> argument provides instructions for the drawing operation. While the diagrams produced are essentially 2-dimensional, the package supports many of the conventional notations for illustrating the 3-dimensional layout of a molecule. The package uses TikZ for its actual drawing operations.
installed: Yes
revision: 76701
sizes: doc: 1985k, run: 133k
relocatable: No
cat-version: 1.71
cat-license: lppl1.3c
cat-topics: graphics diagram chemistry pgf-tikz macro-gen etex
collection: collection-pictures
Included files, by type:
run files:
texmf-dist/tex/generic/chemfig/chemfig-lewis.tex
texmf-dist/tex/generic/chemfig/chemfig.sty
texmf-dist/tex/generic/chemfig/chemfig.tex
doc files:
texmf-dist/doc/generic/chemfig/README details="Readme"
texmf-dist/doc/generic/chemfig/changelog.tex
texmf-dist/doc/generic/chemfig/chemfig-en.pdf language="en" details="Package documentation (English)"
texmf-dist/doc/generic/chemfig/chemfig-en.tex
texmf-dist/doc/generic/chemfig/chemfig-fr.pdf language="fr" details="Package documentation (French)"
texmf-dist/doc/generic/chemfig/chemfig-fr.tex
これを見てみれば、run files: に続く部分で次のように同名の .sty ファイルと .tex ファイルがあります。
texmf-dist/tex/generic/chemfig/chemfig.sty
texmf-dist/tex/generic/chemfig/chemfig.tex
このようなパターンをすべて書き出せば、内部で TeX ファイルを読む可能性のあるパッケージをすべて知ることが出来ます。
“可能性のある” ものにとどまるのは、パッケージ内部で 〈パッケージ名〉.tex が必ず呼び出されるとは限らないためです。
これをステップ ② で解決します。
ステップ ②
該当した hoge.sty を読んでファイル内に
\input hoge.texが含まれているかを判定する
愚直にファイルを見ていく作業です。ファイルのある場所は kpsewhich を使って探します。
ファイルの中身を見て、以下のパターンの行があれば該当ファイルです。
\input 〈パッケージ名〉\input 〈パッケージ名〉.tex\input{〈パッケージ名〉}\input{〈パッケージ名〉.tex}
Lua スクリプトを作ってみた
具体的にやるべきことが分かったので、Lua スクリプトを書いてみました。成果物は以下のリポジトリにあります。
このスクリプトでは内部で kpsewhich を使用しますが、TeX Live をふつうに導入していれば利用可能になっているはずです。また、Lua も texlua の形で利用できるようになっているはずです。そのため、TeX Live 以外の環境構築は必要ありません。
まず、ステップ ① として、find-sty-tex.lua を texlua で実行します。動作はそこそこ早いです。
$ texlua find-sty-tex.lua > duplicate_name.txt
ローカルにある texlive.tlpdb は以下の 2 つあります。
- texlive.tlpdb: ローカルに保存されているパッケージ
- texlive.tlpdb.main.〈long-hash〉: TeX Live 全体のパッケージ
find-sty-tex.lua では基本的に texlive.tlpdb を読みますが、main オプションを課すことで texlive.tlpdb.main.〈long-hash〉 を読むようになります。
私の full scheme ではないローカル環境で実行してみると(main 無し)、以下の 92 のファイルが該当することが分かりました。(main 付では 232 ありました 3)
2up apalike chemfig chickenize clock cloze colorprofiles colortab commutative-diagrams rotate blackdvi colordvi enigma farbe filemod filemod-expmin fp frame gates ibycus4 interpreter knitting fontsmpl leipzig librarian listbib listofitems lparse lt3luabridge lua-widow-control luaaddplot luakeys luakeys-debug luavlna markdown markdownthemewitiko_markdown_defaults memoizable memoize nomemoize minim-mp nodetree pdfextra pnets pndraw pntext pgfbaselayers tikz pgfbasesnakes pgfbaseimage pgfcore pgf pgffor pgfbasematrix pgfbaseplot pgfsys pgfrcs pgfkeys pgfmath pgfcalendar pgfbaseshapes pgfbasepatterns pgfplots pgfplotstable pictex pictexwd poster scontents simplekv skeyval-pstkey standalone tex-locale texdraw thumbpdf pgfcalendar-ext pgffor-ext pgftree pgfsubpic tikz-qtree tokcycle fontsmpl tracklang tracklang-scripts tsvtemplate unibidi-lua witharrows xkeyval pst-xkey xstring xy xypic yax zeckendorf
次に、ステップ ② として、find-sty-input.lua を texlua で実行します。
$ texlua find-sty-input.lua duplicate_name.txt
すると、私のローカル環境では 36 が該当しました。chemfig もちゃんと含まれていますね!
2up, chemfig, chickenize, clock, cloze, colortab, enigma, farbe, frame, gates, interpreter, librarian, listofitems, lparse, luaaddplot, minim-mp, nodetree, pdfextra, pndraw, pictex, pictexwd, poster, simplekv, skeyval-pstkey, tex-locale, texdraw, pgftree, pgfsubpic, tikz-qtree, tokcycle, tracklang, tracklang-scripts, tsvtemplate, xstring, xy, yax
|
私のローカル環境では、これらのパッケージを使うときには「ファイル名をパッケージ名と同じにしてはならない」と言うことが分かりました。
余談
かなりの数がありましたね。新たに使ってみるパッケージでエラーが出てしまうと、使い方に慣れていないことが原因だと思ってしまいますが、これも十分に原因になりうることが分かります。
しかし、そもそも 〈パッケージ名〉-test.tex のように、パッケージ名をそのままファイル名にしなければ絶対にこのようなエラーに見舞われることはないでしょう。そうなるとこの記事の意味はほとんど無くなってしまいますが。
スクリプトには漏れや誤解しているものがあるかも知れません。もしも、「このパッケージもファイル名として使えないよ」や「これはパッケージ名をファイル名として使えるよ」と言うものがあれば教えてください。
さて、TeX & LaTeX アドベントカレンダー 2025 年の重点テーマは「(La)TeXをカンタンにする方法」でした。この記事で何がカンタンだったかと言うと、Lua スクリプトを ChatGPT を利用してカンタンに作成していた(非常に広義の意味でカンタン)と言うことでした ![]()