はじめに
LaTeXによってある程度長い文書を作成したことがある方なら,ビルドにかかかる時間が長いために作業効率が悪くなってしまった,という経験を持っていると思います.数十ページ規模の文書であれば必然的にコンパイルが遅くなりますし,そうでなくてもたとえば実験レポートであれば大量に画像を貼り付けるために重くなってしまいます.1そこでこの記事ではLaTeXのファイル分割の方法を紹介したいと思います.
とはいってもLaTeXのファイル分割方法にはいくらかありますが,ここではsubfilesパッケージを用いた方法を紹介したいと思います.
\input,\includeを用いた方法が紹介されることも多いと思いますし,実際Qiita上にはそのような解説がいくらかあります.subfilesパッケージによるファイル分割方法には利点があり,具体的には
- 単独でコンパイル可能
- プリアンブルを引き継ぐことができる
という利点があります.これらの利点は\input,\includeを用いた方法では実現されません.2
前提
前提としては
- ローカルな環境でTeX文書を編集していること
- subfilesパッケージがインストールされていること
の2点を挙げておきます.後者に関して,最近のTeXLiveでTeXをインストールしているのなら大丈夫だと思います.また,前者についても,試してはいませんがoverleafなどでも問題なくできそうな気がします.
この方法は,WindowsでもMacでもLinuxでも変わらずできるはずです.
subfilesパッケージは以下で配布されています.
https://www.ctan.org/pkg/subfiles
ファイル分割のやり方
subfilesパッケージを用いてファイル分割を行うには,要点だけ言うと,
- 親ファイルを用意してsubfileパッケージを読み込み,親ファイルで(document環境内で)\subfile{subfile_name}とする.
- 子ファイルを用意して文書クラスを\documentclass[mainfile_name]{subfiles}とする.
です.これだけ言っても意味がないので,詳しいやり方は次で説明します.
構成
ある程度実際的な状況として,メインのファイルが一つあり,子ファイル2つに分割されていて,内容として,数式や画像挿入を行うという状況を考えることにします.
reportというフォルダを作って,その中を次のような構造にして作業することにします.
.
├── main
│ └── main.tex
├── sub
│ ├── sub1
│ │ └── sub1.tex
│ └── sub2
│ └── sub2.tex
└── images
├── sub1
│ └── sub1_1.png
└── sub2
└── sub2_1.png
.texや.pngといった拡張子がついてないものはフォルダを指します.省略していますが,sub1.texをコンパイルした際にはもちろん,sub1にsub1.pdfやsub1.logといったファイルが生成されます.main.texやsub2.texに関してももちろん同じです.
また,sub1,sub2としか書いていませんが,実際にはintroduction,body1,body2,conclusionなどと分けると良いでしょう.
ファイル分割が済んだら,
- sub1.texやsub2.texを編集
- コンパイルして出来栄えを確認
- 完成すればmain.texを実行することで全部あわせたpdfを作成
という流れで編集を行えます.各子ファイル(sub1.tex,sub2.tex)は単独でコンパイルをすることができます.
各ファイルの中身
main.tex
大本であるmain.texの中身は次のようになっています.
\documentclass[uplatex,dvipdfmx]{jsarticle}
% platexを使っている場合は\documentclass[platex,dvipdfmx]{jsarticle}など
\usepackage{subfiles}% 必須
\usepackage{amsmath}
\usepackage{comment}
\usepackage[dvipdfmx]{graphicx}
\graphicspath{{../images/}}
% 画像フォルダ(images)へのパス.{}が余計に必要なことに注意
\numberwithin{equation}{section}
% section単位で数式に付番
\newcommand{\hoge}{hoge}
% LaTeXマクロのサンプル
\title{subfileによるファイル分割}
\author{kemukowa}
\date{\today}
\begin{document}
\maketitle
\begin{comment}
\clearpage
\subfile{../sub/sub1/sub1.tex}
\clearpage
\subfile{../sub/sub2/sub2.tex}
\end{comment}
% 完成させるときにはcomment環境から外に出す
\end{document}
これをコンパイルするとタイトルだけが書き込まれたpdfが生成されます.
comment環境に書いた内容は全てコメントアウトされます.\subfile{../sub/sub1/sub1.tex}
をcomment環境の外に出してmain.texのコンパイルを行うと,sub1.texのdocument環境内の文字列が展開されて,コンパイルが行われます.
\input
や\include
による方法では,texファイル内の文章が全て展開されてしまうので,これはsubfileによる方法の利点の一つです.3
comment環境に入れているのは,main.texに\subfile{../sub/sub1/sub1.tex}
とあると,sub1.texをコンパイルした際にmain.texがコンパイルされてしまうためです.これはおそらくsubfileパッケージの仕様です.4
\graphicspath{}は画像フォルダへのパスを表します.内側にもう一つ{}を書いてくくらなければならないので,注意しましょう.複数のパスを通す際には
\graphicspath{{dir1}{dir2}}
のように書きます.
もちろん
\graphicspath{{dir1}}
\graphicspath{{dir2}}
と分けて書いてもよいです.
\subfile{../sub/sub1/sub1.tex}
と書いていますが,もちろん../sub/sub1/sub1.tex
という名前のファイルが存在するわけではなく,実際に存在するのはsub1.tex
という名前のファイルで,../sub/sub1/
はmain.texからみたそのファイルの場所を指します.謎の../
は"ひとつ上"のディレクトリを指します.
つまり,../sub/sub1/sub1.tex
は「ひとつ上(reportフォルダ)にあるsubというフォルダにあるsub1というフォルダにあるsub1.texという名前のファイル」を意味するわけですね.
sub1.tex
分割先のファイルであるsub1.texの中身は次のようになっています.
\documentclass[../../main/main.tex]{subfiles}
% 文書クラスが特殊であることに注意.
% オプション引数に親ファイルへのパスを指定し,クラスをsubfilesとする.
\graphicspath{{../../images/}}
% sub1.texからみた画像フォルダへのパス
\setcounter{section}{0}
% セクション番号を1から付番(0からではないです)
\begin{document}
\section{サブ1}
これはsub1.texです.
コンパイル時に親ファイルのプリアンブルが引き継がれるので親ファイルで設定したマクロも使えます:\hoge
もちろん親ファイルで読み込んだパッケージも使えます.
\begin{comment}
コメント環境
\end{comment}
画像フォルダにパスを通しているので,
\begin{figure}[h]
\centering
\includegraphics{sub1/sub1_1.png}
\caption{hoge}
\end{figure}
のようにして画像を挿入することができます.
一応数式を書いてみます.
\begin{align}
y=f(x)
\end{align}
コメントアウトでも指摘していますが,特殊な文書クラスになっていることに注意してください.
親ファイルのプリアンブルは引き継がれる5ので親ファイルで定義したマクロやプリアンブルはそのまま使えます.プリアンブルを更新したい場合,親ファイルのプリアンブルを更新するだけで済む(いちいち子ファイルにも書く必要がない)ことはsubfileによる分割法の利点の一つです.
また,子ファイルにプリアンブルを書くこともできるので柔軟に書くことができます.子ファイルに書いたプリアンブルは親ファイルのコンパイル時には読み込まれません.
例えば子ファイルだけに書いたマクロを使用して文書を作成した場合,main.tex
をコンパイルした際にはエラーが起きます.この点には注意してください.
画像フォルダへのパスを子ファイルからも通しておくことで,sub1.texをコンパイルしたときとmain.texをコンパイルしたときの両方で上手くいきます.
もしよければ,main.texの\numberwithin{equation}{section}
や,sub1.texの\setcounter{section}{0}
の意味について考えてみてください.もちろんsubfileによるファイル分割において必須なことではないのですが,ちょっとしたノウハウ的なやつです()
sub2.tex
sub2.texの中身については,sub1.texとほとんど同じなので折りたたんでおきます.
sub2.texの中身
\documentclass[../../main/main.tex]{subfiles}
% 文書クラスが特殊であることに注意.
% オプション引数に親ファイルへのパスを指定し,クラスをsubfilesとする.
\graphicspath{{../../images/}}
% sub1.texからみた画像フォルダへのパス
\setcounter{section}{1}
% セクション番号を2から付番(1からではないです)
\begin{document}
\section{サブ2}
これはsub2.texです.
コンパイル時に親ファイルのプリアンブルが引き継がれるので親ファイルで設定したマクロも使えます:\hoge
もちろん親ファイルで読み込んだパッケージも使えます.
\begin{comment}
コメント環境
\end{comment}
画像フォルダにパスを通しているので,
\begin{figure}[h]
\centering
\includegraphics{sub2/sub2_1.png}
\caption{huga}
\end{figure}
のようにして画像を挿入することができます.
一応数式を書いてみます.
\begin{align}
y=f(x)+g(x)
\end{align}
subfilesによる分割法のメリット,デメリット
メリットとデメリットについてまとめてみます.
まずメリットとしては,本文中でも何回か述べたように,
- 子ファイル単体でコンパイルできる
- 親ファイルのプリアンブルを変えれば,子ファイルのプリアンブルをいちいち変えたりしなくて済む
ということが挙げられます.
デメリットとして,
- ファイルにパスを通すのがちょっと複雑
ということは挙げられるかもしれません.また,
- 相互参照が上手くいかない
という明確なデメリットがあります.このデメリットというのは,subfilesの特性と言うよりも,ファイルを分割したことによる弊害ということです.
たとえば,上記のディレクトリ構成で,sub1.texの数式に\label{eq:sub1_1}
とあったとして,sub2.texで\ref{eq:sub1_1}
としてコンパイルすると,(??)という出力になります.これは別のファイルにある\label{}
の内容をコンパイラが認識できないからなのですが,この問題はファイルを分割していなければ起きない問題ですよね.
コンパイルエラーが起きるのではなく(??)と出力されるのでその意味で致命的な問題ではないですし,main.texでまとめてコンパイルしたときにはファイルを分割していないときと同じ表示になるので,私は気にしていません.(別の章,節の数式や図を参照することがそもそも少ないということもあります)
この問題の解決法をご存じの方がおられましたら教えてください.
subfilesをもう少し活用してみる
\subfileinclude
親ファイルで\subfile{}
とすることで子ファイルを読み込みますが,このとき\subfile{}
が子ファイルのdocument環境内のコードに置き換えられます.
これは実は\input{}
と同様の挙動です.TeXに組み込みのファイル分割方法としては,
\include{}
もあります.両者は同じような挙動をしますが,\include{}
は引数として受け取ったtexファイル内のコードに置き換えた後に前後に\clearpage
を挿入します.
\input{}
は単に置き換えるだけなので,プリアンブルでも用いることができますが,
\include{}
は使用できません.\clearpage
はプリアンブルでは使用できないためです.6
\subfile{}
を\input{}
ではなく\include{}
に似た挙動をさせる方法として,
\subfileinclude{}
が提供されています.
利用方法としては,たとえば,main.texで
\clearpage
\subfile{../sub/sub1/sub1.tex}
\clearpage
\subfile{../sub/sub2/sub2.tex}
としている所を
\subfileinclude{../sub/sub1/sub1.tex}
\subfileinclude{../sub/sub2/sub2.tex}
とすることが考えられます.
子ファイルのコンパイルかどうかで条件分岐したい
今まで述べたように,子ファイルは単独でコンパイル可能で,親ファイルで\subfile{}
とすることで子ファイルを引っ張ってくることが可能ですが,
場合によっては,特定のコードを子ファイルのコンパイル時にだけ実行されて親ファイルをコンパイルする時には実行されないようにしたいということがあり得ます.
専門的な文章を書いていて,引用文献の引用を何回も行っているという場合を考えてみましょう.
~.bib
というファイルに所定の形式で文献を記しておき,各文献のラベルを,たとえばラベルがreference_keyだとして,本文中で\cite{reference_key}
と書くことでその文献を引用することができます.7
ここで問題となるのはBibTeXの仕様です.\bibliography{~.bib}
とすることで引用した文献の一覧を表示できるのですが,BibTeXはこの引数として指定されたbibファイルを文献のリストとして使用します.そのために\bibliography{}
は文書中に1個は必ずないといけないが,2個以上あってはならない. という制約があります.
この制約のために,subfilesで分割した先の子ファイルには\bibliography{}
を書かなければコンパイルは通らないが,各子ファイルにそれを書いてしまうと今度は親ファイルのコンパイルが通らないというジレンマが生じます.
これを解決するために,子ファイルに書いた\bibliography{}
が子ファイルのコンパイル時にだけ実行されて,親ファイルのコンパイル時には実行されないようにしましょう.そのようなコマンドがsubfilesパッケージによって提供されています.あとは親ファイルにも\bibliography{}
を記述しておくことでコンパイルが通ります.
そこで登場するのが,\ifSubfilesClassLoaded{}{}
です.子ファイルのコンパイル時には1つめの引数の内容が実行され,親ファイルのコンパイル時には2つめの引数の内容が実行されます.
例を次に示します.
ディレクトリ構成
.
├── main.tex
├── sub.tex
└── ref.bib
main.texの中身
\documentclass[uplatex,dvipdfmx]{jsarticle}
\usepackage{subfiles}
\begin{document}
% contents…
\subfile{sub.tex}
\bibliographystyle{junsrt}
\bibliography{ref.bib}
\end{document}
sub.texの中身
\documentclass[main.tex]{subfiles}
\begin{document}
引用してみる.\cite{reference_key}
\ifSubfilesClassLoaded{
\bibliographystyle{junsrt}
\bibliography{ref.bib}
}{}
\end{document}
ref.bibの中身(例)
@Book{reference_key,
author = "Milton Abramowitz and Irene A. Stegun",
title = "Handbook of Mathematical Functions with
Formulas, Graphs, and Mathematical Tables",
publisher = "Dover",
year = 1964,
address = "New York",
edition = "ninth Dover printing, tenth GPO printing"
}
ただしこの内容はhttps://ja.wikipedia.org/wiki/BibTeX に記載のあるものをラベルだけ変更して転載しました.
さいごに
今回はsubfilesパッケージによるファイル分割について説明してみました.もし何かあれば,この記事のコメントか,筆者のツイッターアカウントDMまでお知らせください.
参考文献
なお,以下の記事を参考にしました.
-
グラフをvector画像として生成することである程度軽量化することができます.私自身の別の記事にそのような方法について記述しておいたのでもし良ければ参考にしてください.
https://qiita.com/kemukowa/items/4b6578e798d91417a901 ↩ -
\input,\includeは雑に言うとTeXコードを物理的に分割します. ↩
-
プリアンブルごと展開されてしまうのでコンパイル時にエラーを起こさないためにはサブファイルの方にdocument環境内のコードのみを書くしかなく,それではサブファイルが単体ではコンパイルできないという問題がsubfilesパッケージによる方法では解決されているということです. ↩
-
まぁ「おそらく」とか言ってる暇があったらちゃんと確かめるべきなんですが… ↩
-
子ファイルの\documentclass[]{}の部分が親ファイルのプリアンブル(\documentclass{}も含めて)が置き換えられます.にもかかわらず,親ファイルと子ファイルでLaTeXマクロの定義が衝突した場合に親ファイルの定義の方が優先されるという現象を観測しています(未検証)が原因を知っている方がおられましたら教えてください. ↩
-
\clearpage
が使えないtabular環境,figure環境などでは\include{}
は使用できません. ↩ -
ただしBibTeXが実行できる環境が必要です.VScode上で作業を行っている方が多いと思いますが,latexmkにbib関連の記述があるか確認してみてください. ↩