大規模文書の扱い

300 ページの学位論文を 1 つの .tex ファイルで書く人はいません。大規模な文書に対する LaTeX の答えは \input\include\includeonly の 3 つで、章ごとにファイルを分けたうえで、いま書いている章だけを組み直せるようにするものです。おもしろいのはその下の仕組みで、LaTeX は \include した章を組み終えるたびに、ページ番号を含む全カウンタの値を チェックポイント としてその章の .aux に書き出しています。飛ばした章が後続の番号を狂わせないのは、これがあるからです。このページはディレクトリ構成から始めて、ほぼ全員が一度は踏む相対パスの罠を通り、通しビルドでしか出てこない故障で終わります。

大きな文書のフォルダ構成——本体ファイルは薄く保つ

出発点は「本体ファイルに本文を一行も書かない」という一点です。main.tex に置くのは文書クラス、プリアンブル、そして \include の並びだけ。章は chapters/、図は figures/、文献データベースは bib/ に分けます。こうすると main.tex 自体が目次のように読め、章の順序を入れ替える作業が行の並べ替えで済みます。共著のときに効くのも同じ性質で、触るファイルが人ごとに分かれるので衝突が減り、Git の差分は「その章のファイルだけ」に収まります。プリアンブルが育ってきたら preamble.tex に切り出し、\input{preamble} で読み込みます——プリアンブルは \include してはいけません。理由は次の節でわかります。

text
thesis/
  main.tex
  preamble.tex          % packages and settings
  chapters/01-intro.tex  02-method.tex  03-results.tex
  figures/              % all images, next to main.tex
  bib/refs.bib
latex
% main.tex -- no prose here, just structure
\documentclass[11pt,a4paper]{report}
\input{preamble}

\begin{document}
\tableofcontents

\include{chapters/01-intro}
\include{chapters/02-method}
\include{chapters/03-results}

\bibliographystyle{plain}
\bibliography{bib/refs}
\end{document}

ファイル名に 01-02- のような連番を付けておくと、エディタのファイル一覧が読む順に並びます。もう一行効くのが、章ファイルの先頭に置く % !TEX root = ../main.tex です。TeXShop・TeXstudio・VS Code など多くのエディタはこの行を読み、章ファイルを開いたままビルドしても main.tex のほうを組んでくれます。これがないと、いつか章ファイルを単体でコンパイルして ! LaTeX Error: Missing \begin{document}. に出くわします。\documentclass を持たないファイルなので当然の結果ですが、気づくまでに数分は溶けます。

\input\include の違い

\input{f}f.tex の中身をその場に貼り付けるだけ、\include{f} は章単位の取り込みで、前後で \clearpage し、しかも その章専用の f.aux を開いて補助情報をそちらに書き出します。この「章ごとの .aux」こそが \include の存在理由です。ページ番号・相互参照・目次の行が章ごとに分かれて保存されるので、あとで章を飛ばしても、飛ばした章の情報だけを前回の値から読み戻せます。逆に \input はファイル境界の痕跡を何も残しません。だからプリアンブルの読み込み、共通マクロ、表の中身、繰り返し使う定型文といった「章より小さい部品」は \input の仕事です。

命令はたらき改ページ入れ子
\inputその位置に .tex の中身を展開するなし
\include章単位で取り込み、専用の .aux を持つ前後に \clearpage不可
\includeonlyプリアンブル専用。処理する \include を絞る
\subfilesubfiles の命令。その章だけでも組めるなし
\subimportimport の命令。中の相対パスがその階層基準になるなし

表の右端の「入れ子」の欄が、この節でいちばん実害の大きい違いです。\include した章のなかでさらに \include を書くと ! LaTeX Error: \include cannot be nested. で止まります。意地悪な制限に見えますが、実装を見れば必然です。LaTeX が章用の .aux に書き出すための出力ストリームはカーネル内にただ一本しかなく、内側の \include には自分の .aux を書く先が残っていないのです。だから節を細かく分けたいときは、章ファイルの中から \input{chapters/02-method/setup} のように \input で呼びます。ついでにもう一つ、\include はプリアンブルでは使えません(\include should only be used after \begin{document} という警告が出ます)。プリアンブルを \input で読む理由はこれです。

もう一つ、知らないと静かに損をする非対称があります。存在しないファイルを \input{chapters/ch9} で読むと ! LaTeX Error: File ... not found. で止まりますが、同じ状況で \include{chapters/ch9} はログに No file chapters/ch9.tex. と書くだけで、何事もなかったように組み上がります。つまり \include のファイル名を打ち間違えると、エラーではなく 章がまるごと消えた PDF が出てきます。章の名前を変えたあとは、ログを No file で検索するのを習慣にしてください。

\includeonly で編集中の章だけ組む——ページ番号が狂わない理由

プリアンブルに \includeonly{chapters/02-method} と書くと、\include のうちその章だけが処理され、残りは読み飛ばされます。数分かかっていた通しビルドが数秒で終わり、しかも 飛ばした章のページ番号も相互参照も正しいまま です。仕掛けは二段構えになっています。第一に、LaTeX は章を飛ばすときでも main.aux\@input{chapters/01-intro.aux} の行を必ず書きます——つまり前回の .aux を必ず読み戻すので、そこに記録された \newlabel が生きていて \ref が解決します。第二に、章を組み終えるたびに、LaTeX はその章の .aux の末尾へ全カウンタの現在値を書き出します。カーネルのソースはこれを文字どおり チェックポイント と呼んでいて、章を飛ばすときはこの一行を再生するだけで、ページ・章・図表の番号が「その章が終わった時点」まで一気に進みます。

latex
% in the preamble of main.tex
\includeonly{chapters/02-method}
% several at once, comma separated, no spaces needed around the commas
% \includeonly{chapters/02-method,chapters/03-results}
text
% chapters/01-intro.aux, written by the last full build (trimmed)
\newlabel{ch:intro}{{1}{2}{}{}{}}
\@setckpt{chapters/01-intro}{
\setcounter{page}{5}
\setcounter{chapter}{1}
\setcounter{figure}{0}
}

この二段構えのおかげで、部分ビルドの PDF は思ったより本物に近くなります。目次すら壊れません——.toc は実行の最後に .aux から書き出されるので、飛ばした章も前回のページ番号のまま目次に並びます。それでも守るべき前提が一つあります。最初に一度は全章を通して組む こと。.aux がまだ無い章を飛ばすと、参照は ?? のまま、ログには LaTeX Warning: There were undefined references. が残ります。細かい話をもう二つ。\includeonly\include も末尾の .tex を落として比較するので、\includeonly{chapters/02-method.tex} と書いても一致します。そして \includeonly はプリアンブル専用で、\begin{document} のあとに書くと ! LaTeX Error: Can be used only in preamble. になります。提出前には必ずこの行を消して、全章で組み直してください。部分ビルドの PDF は作業用の近似であって、最終版そのものではありません。

相対パスは章ファイルではなく本体ファイルから解決される

\input\include も、カレントディレクトリを変えません。TeX はすべての相対パスを 実行時の作業ディレクトリ——ふつうは main.tex が置かれた場所——から解決します。だから chapters/02-method.tex の中に書く画像パスも main.tex から見た形にします。\includegraphics{figures/plot} は通り、章ファイルの位置から見れば正しいはずの \includegraphics{../figures/plot}! LaTeX Error: File ... not found. で落ちます。ここで多くの人が「章を移動したら図が見つからなくなった」と悩みますが、動いたのはファイルであって、基準点はずっと main.tex のままなのです。

手当ては二通りです。ふつうは graphicx\graphicspath をプリアンブルに置き、探しにいくフォルダを登録します。書式が独特で、フォルダごとに波括弧で包み、末尾のスラッシュを必ず付ける のが要点です(\graphicspath{{figures/}{chapters/figures/}})。これで章のどこからでも \includegraphics{plot} と拡張子もフォルダも省いて書けます。パスの区切りは Windows でもスラッシュを使ってください。もう一通りは、章ごとに自分の図フォルダを持たせたい場合で、import パッケージの \subimport{chapters/}{02-method} を使うと、その章の中の相対パスが chapters/ 基準で解決されるようになります。章を丸ごと別プロジェクトへ持ち出す予定があるなら、こちらのほうが移植性が高くなります。

latex
% option A -- one shared figure folder, registered once in the preamble
\usepackage{graphicx}
\graphicspath{{figures/}{chapters/figures/}}   % braces per folder, trailing slash
% then, anywhere in any chapter:
%   \includegraphics[width=0.8\linewidth]{plot}

% option B -- each chapter carries its own figures
\usepackage{import}
% in main.tex, instead of \include{chapters/02-method}:
\subimport{chapters/}{02-method}   % paths inside resolve from chapters/

章を単体でも組めるようにする——subfilesstandalone

\includeonly は「全体のなかの一章」を速く組む道具で、章を独立した PDF にするわけではありません。章そのものを一本の文書として扱いたいときは subfiles パッケージを使います。章ファイルの先頭に \documentclass[../main]{subfiles} と書いておくと、その章は本体のプリアンブルを借りて単体でコンパイルでき、同時に本体側の \subfile{chapters/02-method} でいつもどおり本文に流し込めます。図の側にも同じ発想があり、standalone クラスで書いた TikZ の絵は 1 枚の PDF として単独で組めて、本体では \usepackage{standalone} を入れて \input するだけで貼り込めます。

latex
% main.tex
\documentclass{report}
\usepackage{graphicx}
\usepackage{subfiles}
\begin{document}
\subfile{chapters/02-method}
\end{document}

% chapters/02-method.tex -- also compiles on its own
\documentclass[../main]{subfiles}
\begin{document}
\chapter{Method}
This chapter builds alone and inside the book.
\end{document}

代償もはっきりしています。単体で組んだ章は 1 ページ目から始まり、他章で定義された \label は見えないので、\ref?? になり LaTeX Warning: There were undefined references. が出ます。全体の番号を保ったまま速く回したいなら \includeonly、指導教員に「第 3 章だけ」を渡したいなら subfiles——用途で選ぶのが実務的です。最終的に 1 つの PDF として提出する学位論文なら \include\includeonly の組み合わせが素直で、章が論文・講義ノート・配布資料としても独り立ちする文書なら subfiles が向きます。両方を同じプロジェクトで混ぜると、プリアンブルの管理が二重になって割に合いません。

draft オプションで試し組みを速くする

\documentclass[draft]{report} は、大きな文書の試し組みで二つの仕事をします。第一に、行が版面からはみ出した箇所——overfull hbox——を余白の黒い罫線で示すので、崩れを目で拾えます。第二に、画像を実際に描画せず、ファイル名を入れた枠に置き換えます。画像処理が丸ごと省かれるぶんコンパイルが軽くなり、図の多い章ほど効きます。画像だけを軽くしたいなら \usepackage[draft]{graphicx} と範囲を絞れますし、逆に画像は見たまま overfull だけ知りたいなら \overfullrule=5pt を置けば罫線だけが出ます。仕上げのビルドでは draftfinal に戻すのを忘れずに。

latex
\documentclass[draft]{report}   % skip images, show overfull rules
% scope it to images only:
% \usepackage[draft]{graphicx}
% keep images, still flag overfull lines:
% \overfullrule=5pt

章単体では通るのに全体では通らないとき

この症状の原因は、ほぼ四つのどれかです。(1) その章のプリアンブルにしか無いパッケージやマクロを使っている——単体ビルドでは通り、本体では ! Undefined control sequence. になります。(2) 二つの章が同じ \label を定義していて、LaTeX Warning: Label ... multiply defined. が出たまま参照が別の場所を指す。(3) 章のフォルダから見て正しい相対パスを書いている(前節の罠)。(4) .aux が古い。とくに (2) は静かに間違った番号を刷るので危険で、\label{fig:method-setup} のように章の名前を接頭辞にしておくと構造的に避けられます。

.aux の腐りかたも覚えておく価値があります。ビルドを途中で止めたり、章の名前を変えたりすると、書きかけの .aux が残ることがあります。次の実行はそれを読んで、いま編集した箇所とはまるで関係のない行で転びます。「さっきまで通っていたのに、直した覚えのない場所でエラーになる」ときは、まず生成物を消してからやり直してください。手で消すなら .aux .toc .lof .lot .out を——章ごとの .auxchapters/ の中にもある点に注意——、latexmk を使っているなら latexmk -c で中間ファイルだけ、latexmk -C で PDF まで含めて片付きます。消したあとは、参照と目次を落ち着かせるために 2 回通してください。

  • \includeonly で作業を始める前に、必ず一度は全章を通してビルドし、各章の .aux を新しくしておく。
  • 重い TikZ の図は外部化するか、あらかじめ PDF に焼いてから \includegraphics で読む。
  • 章ファイルの先頭に % !TEX root = ../main.tex を置き、どのファイルを開いていても本体が組まれるようにする。
  • import を使わないなら、figures/bib/ は章の隣ではなく main.tex の隣に置く。
  • \label には fig:method-setup のように章を示す接頭辞を付け、multiply defined を構造的に防ぐ。
  • 提出前に \includeonlydraft を外し、生成物を消してクリーンビルドし、ログの WarningNo file を最後まで読む。

最後にリズムの話をひとつ。長い文書がうまく進むのは、「毎回すべてを完全に組む」でも「ずっと部分ビルドだけ」でもなく、その二つを使い分けているときです。ふだんは \includeonly で担当章だけを回し、保存のたびの再ビルドは latexmk に任せます。節目には \includeonlydraft を外して全体を組み、番号・目次・索引・文献が落ち着くのを確かめます。そして提出前には生成物を消してクリーンビルドし、ログを最後まで読みます。分割は速さのためだけの工夫に見えて、じつは「いつでも全体を正しく組み直せる」という安心のための工夫でもあります。