TeX 実行の自動化ツールを作った (ClutTeX)


TeX の実行を自動化するスクリプトというのは latexmk を始めとしてすでに色々世の中に存在するが、新しく作った。

作った物体:minoki/cluttex: Process TeX files without cluttering your working directory

目的

以前の記事に書いた内容とかぶる)

今回作ったツールの最大の特徴は、「作業ディレクトリを汚さない」ことである。

近年は、 Dropbox に代表されるような同期型のオンラインストレージサービスが普及している。このようなサービスに TeX 文書を保存する人も多いだろう。

しかし、同期型のオンラインストレージサービスでは、 TeX 文書の処理時に作られる補助ファイル等 (*.log, *.aux, …) も全て同期対象となってしまう。TeX の実行を補助するスクリプトの中には、このような余計なファイルを削除してくれるものもあるが、ストレージサービスの履歴に残ることには変わりない。できれば、処理の際に作られる補助ファイル等は、どこか別のディレクトリに作って欲しい。

以前書いたように、このような特徴を備えた TeX 実行自動化スクリプトは少ない。なので、自分で作ることにした。

この手の自動化スクリプトは、基本的に、複数を組み合わせて実行するようにはできていない。したがって、新しく作るツールは機能面で既存の TeX 実行自動化ツールの上位互換となっていなければならない:

  • エラー時にユーザーへの入力を求めず、即時に実行を終了するようにする(以前に書いた記事も参照)
  • pTeX 系でもコマンド一発で PDF を生成できる(つまり、自動で dvipdfmx を実行してくれる)
  • 適宜、必要な回数の処理を行い、相互参照等を適切に解決する
  • ファイルを監視して、入力ファイルが変化したら自動で再処理する(現在の cluttex では、外部プログラムを要する)
  • BibTeX や Makeindex のような周辺ツールを適宜実行する【未実装】

想定質問

Q. latexmk に -outdir を指定するのと何が違うの?latexmk を -outdir 付きで実行するラッパースクリプトじゃダメなの?

A. 前の記事に書いたように、本気で出力ファイル等を隔離しようとした時に、 LaTeX-output-directory はあまりにも貧弱である。よって、(筆者の把握している限り)それをそのまま使うだけの latexmk の -outdir も貧弱であると思われる。

一方、 ClutTeX は最初から出力ファイルを隔離しようとするすることを念頭に作られているため、 LaTeX-output-directory の貧弱さをある程度カバーできる。例えば、文書中で \include{path/to/file} としていても問題なく処理を行える。

Q. 新しく作るのではなく、 latexmk を改造するという手は?

A. お前は latexmk がどのスクリプト言語で書かれているか知ってて言っているのか?

Q. ClutTeX の正式な表記は?ClutTeX と書くべき?

A. 未定

インストール

ターミナルで

$ git clone https://github.com/minoki/cluttex.git
$ cd cluttex
$ make

を実行すると bin/ 以下に cluttex コマンドができる。

一応、 Windows 向けの cluttex.bat も作るようになっている。しかし、作者としては Windows 対応は優先度が低い。(特に、Windows で性質の悪いマルチバイト文字エンコーディングが使われていることに起因する問題への対処は絶対に行わない)

以降、 cluttex コマンドにパスが通った状態を仮定する。

使い方

基本

sugoi-document.tex という名前のファイルを pLaTeX で処理したければ、

$ cluttex -e platex sugoi-document.tex

を実行する。platex のところを pdflatex や lualatex に変えれば、それぞれ pdfLaTeX や LuaLaTeX で処理される。

実行がうまくいけば、sugoi-document.pdf というファイルが同じディレクトリにできるはずである。一方で、 sugoi-document.logsugoi-document.aux といった余計なファイルは見当たらないはずだ。

オプション

--help オプションをつけて実行すると、コマンドラインオプションの一覧を表示する。

複数の文字からなる「長い」オプションには2つのハイフンを要する。

複数回の実行

LaTeX で相互参照を正しく表示するには、2回以上処理を行う必要がある。ClutTeX は、そういう「複数回の処理」を自動化する。

処理の回数の上限は、 --max-iterations オプションで指定できる。最初の1回は問答無用で実行され、それ以降の処理の回数が --max-iterations オプションによる制限の対象となる。--max-iterations=0 を指定すれば、LaTeX を1回だけ処理するのとほぼ同じ挙動となる。(この辺の仕様は既存の類似コマンドとは若干異なる。今後変更するかもしれない)

処理回数の上限に達してもなお再処理が必要な場合(補助ファイルが変化した場合)は、 cluttex がメッセージを出力する。

ファイルの監視

入力ファイルを監視して、更新が行われると自動的に再処理を行なってくれると便利である。現在の cluttex では、 fswatch という外部コマンドがインストールされている場合のみファイル監視が可能である。

cluttex をファイル監視モードで実行するには、 --watch オプションを指定する。

$ cluttex --watch -e platex sugoi-document.tex

将来のバージョンでは、 fswatch がなくても最低限の監視はできるようにするかもしれない。

実装の詳細

これ以降は、 ClutTeX の現時点での実装方法と制限事項について述べる。

カレントディレクトリを散らかさない

大雑把な動作としては、専用の出力ディレクトリを用意して TeX-output-directory として渡している。(cluttex 自身に --output-directory を渡して出力ディレクトリを指定することもできるが、その場合 cluttex の存在意義が激減する)

出力ディレクトリの場所は、テンポラリディレクトリ(環境変数 TMPDIR, TMP, TEMP のうち最初に見つかったもの)に、適当なハッシュ値を含むサブディレクトリを掘って使う。テンポラリディレクトリを表す環境変数が見つからなかった場合は、ホームディレクトリ以下に適当にディレクトリを用意する。ディレクトリ名に使うハッシュ値は、「処理対象の TeX ファイルのフルパス」「エンジン名」「jobname」の3つに依存する。

出力ディレクトリが何処であれ、最終的に出来上がる PDF ファイルは入力ファイルと同じ場所にあって欲しい。そこで、pdfTeX 等の PDF を直接出力するエンジンの場合は、出力ディレクトリからカレントディレクトリに PDF ファイルをコピーする。一方、 DVI を経由する場合は dvipdfmx へ -o オプションを渡して PDF ファイルの場所を指定する。

cluttex を複数回実行する場合、以前の補助ファイルはそのまま残る。補助ファイルを削除して、クリーンな状態で処理を行いたいという場合は、 --fresh オプションを使う。--fresh オプションは出力ディレクトリに対して rm -r 相当の動作を行う。安全のために、ユーザーによって --output-directory が指定された場合は --fresh は使えないようになっている。

前に書いたように、LaTeX-output-directory を使うと種々の問題が発生する。cluttex はこれらの問題に対してある程度対策をしている。

まず、(想定質問のところで既に書いたが、)サブディレクトリの \include に関しては既に対策を実装済みである。

次に、シェルエスケープに関してだが、--change-directory オプションを指定すれば、 TeX コマンドの実行前にカレントディレクトリを出力先の方に移動できる。この場合、外部コマンドが「入力ファイルが見つからない」というエラーを吐く可能性がある。これについては、個別に対策を打っていくつもりである。

現時点では、 epstopdf パッケージについては既に個別の対策を打ってあって、 pdfLaTeX で EPS ファイルを読み込もうとした場合は次のような流れとなる:

  1. とりあえず TeX を実行する。
  2. epstopdf コマンドが入力ファイルを見つけられないので失敗する。
  3. cluttex が代わりに epstopdf コマンドを正しい引数で実行してやる。
  4. もう一度 TeX を実行する。今度は epstopdf パッケージが EPS ファイルに対応する PDF ファイルを見つけてくれるので、正常に処理が完了する。

個別の対策を拡充した暁には、 --change-directory オプション付きをデフォルトの動作にするかもしれない。

複数回の実行

再処理の必要性を正確に判断するためには、 TeX が使ったファイルの一覧を得る必要がある。そのため、 TeX は常に -recorder 付きで実行される。

補助ファイルの中身が変化した場合、補助ファイルが増えた場合、および(補助ファイルでない)入力ファイルのタイムスタンプが変化した場合は、再処理を行う。ただし、増えた .aux ファイルの中身が \relax の一行だった場合は、その .aux ファイルは変更されていないものとみなす。

ファイルの監視

ファイルの監視には fswatch という外部のプログラムを使う。あらかじめパッケージマネージャー等でインストールしておくべし。

現在の実装の制限として、cluttex 起動後に入力ファイルが増えた場合に、増えたファイルに対しては監視が行われない。

実装に使うプログラミング言語

Lua を採用した。

Lua は LuaTeX に採用されており、 TeX Live がインストールされていれば処理系を別途用意する必要がない。(LuaTeX のインタプリターを利用できる)

ハマった点として、 LuaTeX の os.execute の戻り値の仕様が Lua 5.1 の仕様だった。(最新版の LuaTeX でどうなっているかは未確認)

ツールの名前

TeX が使いにくいせいで、この手の自動化ツールはすでに無数にある。従って、他と被らない名前を考案するのが最大の難関だった。

「作業ディレクトリを汚さない」ことが特徴だから、 “TidyTeX” あたりが妥当かとも思ったが、同名のプログラムが既に存在した。

TODO リスト

  • マジックコメントへの対応
  • 処理するファイルの preamble を読んでエンジンの自動検出
  • BibTeX 等の周辺ツールを自動で実行する
  • fswatch なしでの最低限のファイル監視
  • CTAN に登録する
  • jobname.synctex(.gz) を出力ファイルと同じ場所にコピーする
  • シェルエスケープを使うパッケージへの個別の対策(epstopdf は対処済み)

関連記事

TeX の実行あれこれ

LaTeX と -output-directory

関連しそうな Stack なんとか:

TeX 実行の自動化ツールを作った (ClutTeX)」への1件のフィードバック

  1. ピンバック: LuaTeX における外部コマンド実行とログ出力 | 雑記帳

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です