Latexmk/aux_dir と imakeidx の独自スタイルを同時に使いたい

# あらまし
筆者は LaTeX での文書執筆をこよなく愛しているわけですが，慣れているつもりでも頻度よく沼にハマります．今回は先週出会った Latexmk と imakeidx に関する沼を紹介します．

# 結論だけ先出し
まず，うまくいく `latexmkrc` を示しておきます．

```bash:latexmkrc
$pdf_mode = 1; # .tex -> .pdf
$pdflatex = "pdflatex -halt-on-error %O %S";
$aux_dir = "aux";
$makeindex = "makeindex -s ../index.ist %O -o %D %S";
```

あるいは以下も大丈夫です．

```bash:latexmkrc
$pdf_mode = 1; # .tex -> .pdf
$pdflatex = "pdflatex -halt-on-error %O %S";
$aux_dir = "aux";
$makeindex = "makeindex -s index.ist %O -o %D %S";
$makeindex_fudge = 0;
```

検証の結果得られた注意事項は以下の通りです．

- 上記 `$aux_dir` を設定した場合，組版エンジンの `-output-directory` として `$aux_dir` が設定されることになりますが，imakeidx はこのオプションをサポートしていません．つまり，組版エンジンの処理中に実行される `makeindex` は期待通りには動きません．
- 上記 `$makeindex_fudge` の初期値はおそらく `1` になっています．（Texdoc には `0` が既定値とされているにもかかわらず，指定なしと `$makeindex_fudge=0` とでは動作が異なる．）

# 知らない人のために概要紹介
## Latexmk
LaTeX ソースの組版をコマンドラインから実行していると `platex` して `platex` して `dvipdfmx` して...のように何度もコマンドを叩かねばならず，苦労します．人によっては Makefile を作るなどの解法で乗り切ったりもしていますが，TeX Live がインストールされているのであれば，**Latexmk** を利用するのが便利です．

例えば，従来であれば

```bash
pdflatex paper.tex
bibtex paper
pdflatex paper.tex
pdflatex paper.tex
```

と実行する必要があったとしても，`latexmk` であれば

```bash
latexmk paper
```

と実行するだけで，必要なコマンドを内部で順序よくこなしてくれます．

また，`latexmkrc` を用意すれば，細かな設定を事前に決められます．
例えば，`pdflatex` の代わりに `platex` と `dvipdfmx` を使いたい場合，

```bash:latexmkrc
$pdf_mode = 3; # .tex -> .dvi -> .pdf の順で生成するモード
$latex = "platex -halt-on-error %O %S";
$dvipdf = "dvipdfmx %O -o %D %S";
```

のように記述して作業ディレクトリに配置しておけば，うまく機能します．なお，これらの値は基本，`latexmk` コマンドの引数としても指定できます．（面倒なので筆者はやったことありません．）

:::note information
`latexmkrc` で利用できる変数については Texdoc を参照ください．TeX Live が入っているならコマンドラインから以下を実行すると良いでしょう．
```bash
texdoc latexmk
```
:::

`latexmkrc` で設定できる項目の中でもひときわ便利なのは，`$aux_dir` でしょう．LaTeX では参照などの関係で大量の中間ファイル（auxiliary file）が生成されるため，ディレクトリが荒れます．`$aux_dir$` を指定すれば，中間ファイルのみを指定したディレクトリに配置してくれます．

例えば，次のように書いてみるとしましょう．

```bash:latexmkrc
$aux_dir = "aux";
```

すると，組版の結果として生じた中間ファイル（`paper.aux` や `paper.log`も含む）を作業ディレクトリ下の `aux` ディレクトリに配置し，出力ファイルである `paper.pdf` は作業ディレクトリに配置してくれるわけです．

## imakeidx
文量の大きい書類の場合，索引を付けたくなることがあります．
LaTeX では makeidx パッケージと `makeindex` コマンドを利用して索引を作成できます．
さらに，

- 複数の索引を作りたい場合
- 組版エンジン内で索引生成コマンドを自動実行させたい場合
（何度もコマンドを打ちたくない場合）

などでは **imakeidx** を利用できます．

例えば，次のような TeX ソースファイルを準備してみましょう．

```tex:paper.tex
\documentclass{article}
\usepackage{imakeidx}
\usepackage[colorlinks=true,linkcolor=red]{hyperref}
\makeindex

\title{My Paper}
\author{My Name}

\begin{document}
\maketitle

\section{Introduction}
This is a sample\index{sample} paper
to check the index generation.

\printindex
\end{document}
```

sample という単語に索引をつけてみました．

`latexmkrc` には以下の通り記述しておきましょう．

```bash:latexmkrc
$pdf_mode = 1; # .tex -> .pdf
$pdflatex = "pdflatex -halt-on-error %O %S";
```

:::note warn
あえて今は `$aux_dir` を指定していません．つまり，この場合には普通にコマンドラインで `pdflatex` とすれば全く問題ないのですが，後々のために Latexmk を利用しています．
:::

なお，欧文で準備したので `platex` -> `dvipdfmx` と処理する必要はありません．（和文で `platex` -> `dvipdfmx` と処理するようにしても本記事と同じ現象を確認できます．）

さて，準備が整ったので組版してみましょう．上記 2 つのファイルを作業ディレクトリに置き，下記コマンドを実行します．

```bash
latexmk paper
```

すると，作業ディレクトリ内に中間ファイル群と `paper.pdf` が生成されます．

![Screenshot 2025-04-01 at 11.03.33 AM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/467925/76a9592a-b3df-4b9d-965c-06831aee0b5c.png)
![Screenshot 2025-04-01 at 11.03.42 AM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/467925/117d95c5-cc95-4495-9926-ec0aafc1fcda.png)

`paper.pdf` の中を見てみると，索引が正しく設定されていることがわかります．

索引に見出しなどつけたり，フォーマットを変更したい場合には，[スタイルファイル](https://www.overleaf.com/learn/latex/Indices#Using_style_files)を利用できます．
例えば次のように指定して，作業ディレクトリに配置します．

```bash:index.ist
headings_flag 1

heading_prefix "\n\\large\\noindent\\hspace{20mm}\\textbf{"
heading_suffix "}\\smallbreak\\par\\nopagebreak\\small\n"

delim_0 ": "
```

次にソースファイル内でスタイルファイルを指定します．プリアンブルの `\makeindex` に引数として与えられます．

```diff_te_x:paper.tex
\documentclass{article}
\usepackage{imakeidx}
\usepackage[colorlinks=true,linkcolor=red]{hyperref}
- \makeindex
+ \makeindex[options=-s index.ist]

\title{My Paper}
\author{My Name}

\begin{document}
\maketitle

\section{Introduction}
This is a sample\index{sample} paper
- to check the index generation.
+ to check the index generation\index{generation}
+ using \texttt{index.ist} style\index{style} file.

\printindex
\end{document}
```

せっかく見出しがつくのでいくつか索引も追加しました．

以上を設定の上で組版すると，以下の通り見出しを表示したり，区切り文字を「:」に変更したりできます．

![Screenshot 2025-04-01 at 0.21.45 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/467925/1cf7802b-5701-467e-a18d-e16c0ce7bec9.png)

後の参考のために，ここまでの組版におけるログを表示しておきます．

```plaintext:paper.log（331 行目）
runsystem(makeindex -s index.ist paper.idx)...executed safely (allowed).
```

これは `imakeidx` の仕様で，組版エンジン内で `makeindex` コマンドを実行してくれています．

```plaintext:paper.fdb_latexmk
# Fdb version 4
["makeindex paper.idx"] 1743478765.35031 "paper.idx" "paper.ind" "paper" 1743478766.5314 0
  "paper.idx" 1743478766.39095 102 07868f2c00e9ad40d68d2f5a40e40800 "pdflatex"
  (generated)
  "paper.ilg"
  "paper.ind"
  (rewritten before read)
["pdflatex"] 1743478765.98105 "paper.tex" "paper.pdf" "paper" 1743478766.53151 0
  "/usr/local/texlive/2025/texmf-dist/fonts/map/fontname/texfonts.map" 1577235249 3524 cb3e574dea2d1052e39280babc910dc8 ""

  ...

  "paper.aux" 1743478766.4899 271 f3786a5f805f672544cd5829d7d27549 "pdflatex"
  "paper.ind" 1743478766.48718 289 37fd1595018a2f2dff03423f39afcbe1 "makeindex paper.idx"
  "paper.out" 1743478766.49019 103 9814c2d956916adb9290eca4e25c967a "pdflatex"
  "paper.tex" 1743477689.48545 382 bc6f1c50d51ecb75db516f2d422c7c03 ""
  (generated)
  "paper.aux"
  "paper.idx"
  "paper.log"
  "paper.out"
  "paper.pdf"
  (rewritten before read)
```

`latexmk` のログ？ではスタイルファイルの指定を確認できません．

```plaintext:paper.lig
This is makeindex, version 2.17 [TeX Live 2025] (kpathsea + Thai support).
Scanning style file ./index.ist....done (4 attributes redefined, 0 ignored).
Scanning input file paper.idx....done (3 entries accepted, 0 rejected).
Sorting entries....done (4 comparisons).
Generating output file paper.ind....done (14 lines written, 0 warnings).
Output written in paper.ind.
Transcript written in paper.ilg.
```

一方，`makeindex` のログではスタイルファイルが正しく読み込まれていることを確認できます．

さて，ここまで書いてようやく気づいたのが，`paper.log` や `paper.lig` はコマンドが実行される度に上書きされていて，最新のコマンド履歴しか終えていないということです．そこで，実験的に `latexmk` の出力を適当なファイルにリダイレクトしてみました．

```bash
$ latexmk > stdout.log
This is makeindex, version 2.17 [TeX Live 2025] (kpathsea + Thai support).
Scanning style file ./index.ist....done (4 attributes redefined, 0 ignored).
Scanning input file paper.idx....done (3 entries accepted, 0 rejected).
Sorting entries....done (4 comparisons).
Generating output file paper.ind....done (14 lines written, 0 warnings).
Output written in paper.ind.
Transcript written in paper.ilg.

This is makeindex, version 2.17 [TeX Live 2025] (kpathsea + Thai support).
Scanning input file paper.idx....done (3 entries accepted, 0 rejected).
Sorting entries....done (4 comparisons).
Generating output file paper.ind....done (10 lines written, 0 warnings).
Output written in paper.ind.
Transcript written in paper.ilg.

This is makeindex, version 2.17 [TeX Live 2025] (kpathsea + Thai support).
Scanning style file ./index.ist....done (4 attributes redefined, 0 ignored).
Scanning input file paper.idx....done (3 entries accepted, 0 rejected).
Sorting entries....done (4 comparisons).
Generating output file paper.ind....done (14 lines written, 0 warnings).
Output written in paper.ind.
Transcript written in paper.ilg.

This is makeindex, version 2.17 [TeX Live 2025] (kpathsea + Thai support).
Scanning style file ./index.ist....done (4 attributes redefined, 0 ignored).
Scanning input file paper.idx....done (3 entries accepted, 0 rejected).
Sorting entries....done (4 comparisons).
Generating output file paper.ind....done (14 lines written, 0 warnings).
Output written in paper.ind.
Transcript written in paper.ilg.
```

すると，標準出力は `stdout.log` に流れて，端末には残りの標準エラーが表示されました．（見やすさのために改行を入れています．）
1, 3, 4 回目の `makeindex` ではスタイルファイルを正しく見つけられています．これは `pdflatex` コマンドが内部で処理した `makeindex` が正しく機能していることを表しています．一方で，2 回目の `makeindex` はスタイルファイルを見つけられていません．これは `latexmk` コマンドが用意した `makeindex` コマンドが期待通りには機能していないことを表しています．

すでに問題が浮き彫りになりつつありますが，話を次に進めるとしましょう．

# 出くわす沼
さて，索引を作成すると中間ファイルは 3 つも増えるので，やはり `$aux_dir` を使いたいと思うでしょう．

以下のように `latexmkrc` を変更してみます．

```diff_shell:latexmkrc
$pdf_mode = 1; # .tex -> .pdf
$pdflatex = "pdflatex -halt-on-error %O %S";
+ $aux_dir = "aux";
```

一見問題ないように思えるので，組版してみます．

![Screenshot 2025-04-01 at 0.25.04 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/467925/b2cad890-0dc8-49bc-a029-d649321f5390.png)

おや？スタイルファイルが効いていませんね．
ログを見てみましょう．

```plaintext:paper.log（332 行目）
runsystem(makeindex -s index.ist paper.idx)...executed safely (allowed).
```

executed safely とあるのでエラーはなしのはず．しかし気になるのは `index.ist` と `paper.idx` は別の階層にあるはずなので，このコマンド自体正しくないように思います．

次に latexmk の ログを見てましょう．

```plaintext:paper.fdb_latexmk
# Fdb version 4
["makeindex aux/paper.idx"] 1743477898.16698 "aux/paper.idx" "aux/paper.ind" "aux/paper" 1743477899.36171 0
  "aux/paper.idx" 1743477899.22567 102 07868f2c00e9ad40d68d2f5a40e40800 "pdflatex"
  (generated)
  "aux/paper.ilg"
  "aux/paper.ind"
  (rewritten before read)
["pdflatex"] 1743477898.81907 "paper.tex" "paper.pdf" "paper" 1743477899.36181 0
  "/usr/local/texlive/2025/texmf-dist/fonts/map/fontname/texfonts.map" 1577235249 3524 cb3e574dea2d1052e39280babc910dc8 ""

  ...

  "aux/paper.aux" 1743477899.32109 271 f3786a5f805f672544cd5829d7d27549 "pdflatex"
  "aux/paper.ind" 1743477898.28272 143 f7adbbb4c47f3c04360e74a23f06200e "makeindex aux/paper.idx"
  "aux/paper.out" 1743477899.3214 103 9814c2d956916adb9290eca4e25c967a "pdflatex"
  "paper.tex" 1743477689.48545 382 bc6f1c50d51ecb75db516f2d422c7c03 ""
  (generated)
  "aux/paper.aux"
  "aux/paper.idx"
  "aux/paper.log"
  "aux/paper.out"
  "paper.pdf"
  (rewritten before read)

```

こちらでは `paper.idx` のパスは問題なさそうですが，依然としてスタイルファイルが指定されていません．

実際，`makeindex` のログも覗いてみると，スタイルファイルを読み込んだ形跡がありません．

```plaintext: paper.lig
This is makeindex, version 2.17 [TeX Live 2025] (kpathsea + Thai support).
Scanning input file paper.idx....done (3 entries accepted, 0 rejected).
Sorting entries....done (4 comparisons).
Generating output file paper.ind....done (10 lines written, 0 warnings).
Output written in paper.ind.
Transcript written in paper.ilg.
```

そこで再び，標準出力を省いた `latexmk` の出力を見てみましょう．

```bash
Input index file paper.idx not found.
Usage: makeindex [-ilqrcgLT] [-s sty] [-o ind] [-t log] [-p num] [idx0 idx1 ...]
system returned with code 256
Latexmk: Missing input file 'paper.ind' (or dependence on it) from following:
  No file paper.ind.

This is makeindex, version 2.17 [TeX Live 2025] (kpathsea + Thai support).
Scanning input file paper.idx....done (3 entries accepted, 0 rejected).
Sorting entries....done (4 comparisons).
Generating output file paper.ind....done (10 lines written, 0 warnings).
Output written in paper.ind.
Transcript written in paper.ilg.

Input index file paper.idx not found.
Usage: makeindex [-ilqrcgLT] [-s sty] [-o ind] [-t log] [-p num] [idx0 idx1 ...]
system returned with code 256

Input index file paper.idx not found.
Usage: makeindex [-ilqrcgLT] [-s sty] [-o ind] [-t log] [-p num] [idx0 idx1 ...]
system returned with code 256
```

「**いや，めっちゃエラー出とるやないかい！**」と叫びたくなりますね．
`paper.log` にあった `executed safely` って何なんですかね...

この場合，唯一成功している `latexmk` コマンドが用意した `makeindex` コマンドの出力である，`paper.ind` が利用できるので，組版自体は成功として処理されているのだと思いますが，この `makeindex` はスタイルファイルを読み込んでいないので，もちろん意図しない表示になります．

# `pdflatex` の内部処理は手を付けられない
では，どうするのか，ですが，`makeindex` のログ

```bash
Input index file paper.idx not found.
Usage: makeindex [-ilqrcgLT] [-s sty] [-o ind] [-t log] [-p num] [idx0 idx1 ...]
system returned with code 256
```

を見ればわかるように，`index.ist` ではなく，`paper.ind` に対してパスが通っていません．同ファイルは `$aux_dir` の指定によって `aux` ディレクトリに配置されているので，これが原因と考えて間違いないでしょう．`$aux_dir` の指定は `pdflatex` コマンドでいうところの `-output-directory` オプションの指定と同義ですので，こちらとの対応を調査してみました．

するとやはり，`imakeidx` は `-output-directory` オプションをサポートしていないという[やり取り](https://tex.stackexchange.com/a/548392)が見つかりました．

サポートされていない以上，ハックは難しいでしょう．手のつけようがありません．

# まず思いつく解決策（うまくいかない例）
そこでまず思いつく解決策は `latexmk` 側が用意する `makeindex` をカスタマイズする方法です．

`latexmk` が実行する `makeindex` コマンドは，その他のコマンドと同様に引数等をカスタマイズできます．なので，以下の通りスタイルファイルをベタ打ちで指定すれば，動くはず！

```bash
$pdf_mode = 1; # .tex -> .pdf
$pdflatex = "pdflatex -halt-on-error %O %S";
$aux_dir = "aux";
$makeindex = "makeindex -s index.ist %O -o %D %S";
```

ということで，いざ組版してみると，残念ながらスタイルが適用されません．再び標準エラーを見てみましょう．

```bash
Input index file paper.idx not found.
Usage: makeindex [-ilqrcgLT] [-s sty] [-o ind] [-t log] [-p num] [idx0 idx1 ...]
system returned with code 256
Latexmk: Missing input file 'paper.ind' (or dependence on it) from following:
  No file paper.ind.

This is makeindex, version 2.17 [TeX Live 2025] (kpathsea + Thai support).
Scanning input file paper.idx....done (3 entries accepted, 0 rejected).
Sorting entries....done (4 comparisons).
Generating output file paper.ind....done (10 lines written, 0 warnings).
Output written in paper.ind.
Transcript written in paper.ilg.

Input index file paper.idx not found.
Usage: makeindex [-ilqrcgLT] [-s sty] [-o ind] [-t log] [-p num] [idx0 idx1 ...]
system returned with code 256

Input index file paper.idx not found.
Usage: makeindex [-ilqrcgLT] [-s sty] [-o ind] [-t log] [-p num] [idx0 idx1 ...]
system returned with code 256
```

1, 3, 4 番目のログは前章で見限ったコマンドのログなのでスルーして OK です．2 番目のログをみてみｒおや，やはりスタイルファイルが読めていませんね．

標準出力の方も覗いてみましょう．

![Screenshot 2025-04-01 at 3.31.06 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/467925/66ce1cb7-8e1b-481d-8277-8cba2b631c15.png)

103 行目にヒントがありました．
どうやら `makeindex` を実行するにあたり，作業ディレクトリを `aux` に変更しているようです．

# ようやくたどり着いた解決策
以上により，`aux` ディレクトリから見た相対パスを指定すればいいことがわかりますので，以下が一つの解決策になります．

```bash
$pdf_mode = 1; # .tex -> .pdf
$pdflatex = "pdflatex -halt-on-error %O %S";
$aux_dir = "aux";
$makeindex = "makeindex -s ../index.ist %O -o %D %S";
```

# その他の解決策
## `index.ist` の配置を変える（非推奨）
パスさえ通ればいいので，例えば，`index.ist` を `aux` ディレクトリ下に配置しても OK です．

```bash:tree .
.
├── aux
│   └── index.ist
├── latexmkrc
└── paper.tex
```

ただし，`index.ist` は中間ファイルではなく設定ファイルですので，`aux` ディレクトリに含めるのはあまり得策ではないように思えます．

## `$makeindex_fudge` を設定する
Latexmk では `$makeindex_fudge` という値を設定できます．

Texdoc の説明を見てみましょう．

![Screenshot 2025-04-01 at 3.42.21 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/467925/544e9140-4e14-445f-8d6e-6dd0687c61fa.png)

GPT に和訳させてみましょう．

![Screenshot 2025-04-01 at 3.45.49 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/467925/f40da498-7237-4678-a5e7-4a862473759c.png)

なお，`[0]` は初期値が `0` で指定されていることを示しています．
つまり，`makeindex` に際して，デフォルトでは作業ディレクトリを変更させないということのようです．

そうです．
**これは先程調査した標準出力の情報と矛盾しています．**
どうやら，この初期値は `1` に設定されているようです．

参考までに，`$bibtex_fudge` の初期値を見てみましたが，こちらは `1` になっていました．

![Screenshot 2025-04-01 at 3.54.05 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/467925/942f1d9f-7954-46a6-b280-7c1075e47080.png)

これを鑑みるに，Texdoc に見られる `$makeindex_fudge` の初期値は誤植なのでは，と考えられます．

というわけで，以下でも正しく動作します．

```bash
$pdf_mode = 1; # .tex -> .pdf
$pdflatex = "pdflatex -halt-on-error %O %S";
$aux_dir = "aux";
$makeindex = "makeindex -s index.ist %O -o %D %S";
$makeindex_fudge = 0;
```

# Tips
いずれの解決策も `latexmk` 側の `makeindex` を利用していますので，組版エンジン内部で稼働している `makeindex` は全く機能していません．
リソースの無駄遣いですので，`imakeidx` のオプションに `noautomatic` を指定しておきましょう．

![Screenshot 2025-04-01 at 3.58.35 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/467925/87b20621-f27b-4c93-8765-05d967f92985.png)

ただし，warning が出ます...

```bash
Package imakeidx Warning: Remember to run (pdf)latex again after calling
(imakeidx)                `makeindex paper.idx'.
```

# まとめ
ログが上書きされてしまっているおかげで必要以上に沼ってしまいました．また，imakeidx が組版エンジンの内部でコマンドを実行していることを正しく認識できておらず，全体の概要を理解するのに時間がかかりました．

整理してみると納得のいく話でしたので，やはりプログラムは書いた通りに動くものだと思い知らされますね．

この記事が迷えるどなたかの救いになれば幸いです