TeX Live 入りコンテナと Makefile で LaTeX 文書をコンパイルする
はじめに
LaTeX 文書のコンパイルには TeX Live などのディストリビューションが必要ですが、ローカルに数 GB のフルインストールを行うと、マシンごとにバージョンが揺れたり、数年後に再ビルドできなくなったりします。TeX Live 入りの Docker コンテナを用意しておけば、環境はイメージの中に固定され、どのマシンでも、CI 上でも同じ PDF が得られます。
とはいえ docker run に長いオプションを毎回打つのは現実的ではありません。そこで Makefile にコンテナの起動と latexmk の呼び出しをまとめ、make だけでコンパイルできるようにします。この記事ではその最小構成を示します。
全体像
プロジェクト/
├── Dockerfile … TeX Live 入りイメージの定義(任意。公式イメージ直利用も可)
├── Makefile … コンテナ起動と latexmk 呼び出しをまとめる
├── .latexmkrc … 組版エンジンとビルド経路の指定
└── main.tex … 原稿
make を実行すると、Makefile がコンテナを起動し、その中で latexmk main.tex が走り、ホスト側に main.pdf が出力されます。
コンテナを用意する
公式イメージをそのまま使う
もっとも手軽なのは Docker Hub の texlive/texlive です。latexmk や和文パッケージ(collection-langjapanese)を含むフル構成で、latest のほか TL2024 のような年号入りタグがあります。年号タグを指定すると、その年の TeX Live に固定でき再現性が上がります。
docker pull texlive/texlive:TL2024
Dockerfile で薄く作る
イメージサイズを抑えたい、あるいは特定のパッケージやフォントを足したいときは、公式イメージをベースに Dockerfile を書きます。
# TeX Live を年号で固定。必要なものだけ追加する
FROM texlive/texlive:TL2024
# 例:latexmk・和文一式・推奨フォントを明示的に導入
RUN tlmgr install \
latexmk \
collection-langjapanese \
collection-fontsrecommended \
&& tlmgr path add
WORKDIR /work
docker build -t mytex:latest .
いずれの場合も、コンテナはコンパイルのたびに使い捨て(--rm)にし、原稿ディレクトリだけをボリュームでマウントする方針にします。
docker run を手で叩くと
Makefile にまとめる前に、素の起動コマンドを確認しておきます。
docker run --rm \
-v "$PWD":/work -w /work \
-u "$(id -u):$(id -g)" -e HOME=/tmp \
mytex:latest \
latexmk main.tex
ポイントは 3 つです。
-v "$PWD":/work -w /work… カレントディレクトリをコンテナ内/workにマウントし、そこを作業ディレクトリにする。生成された PDF はホスト側にそのまま残る。-u "$(id -u):$(id -g)"… コンテナ内のプロセスをホストと同じ UID/GID で動かし、出力ファイルがroot所有になるのを防ぐ。-e HOME=/tmp… 上記で HOME が無いユーザーになるため、latexmk や tlmgr が書き込み先に困らないよう書き込み可能な HOME を与える。
Makefile にまとめる
この起動処理を変数 RUN に押し込み、各ターゲットから使い回します。
# ==== 設定(コマンドラインから上書き可)====
IMAGE ?= mytex:latest # 使うイメージ
DOC ?= main # 対象は $(DOC).tex
DOCKER ?= docker
# コンテナ内でコマンドを1回実行するための共通部分
RUN = $(DOCKER) run --rm \
-v "$(CURDIR)":/work -w /work \
-u "$(shell id -u):$(shell id -g)" -e HOME=/tmp \
$(IMAGE)
.PHONY: all image build watch shell clean distclean help
all: build
## image : Dockerfile からイメージをビルド(初回・Dockerfile 変更時のみ)
image:
$(DOCKER) build -t $(IMAGE) .
## build : コンテナ内で latexmk を1回まわして PDF を生成
build:
$(RUN) latexmk $(DOC).tex
## watch : 保存のたびに自動で再コンパイル(Ctrl-C で終了)
watch:
$(RUN) latexmk -pvc -view=none $(DOC).tex
## shell : コンテナの中に入って手作業する
shell:
$(DOCKER) run --rm -it -v "$(CURDIR)":/work -w /work $(IMAGE) bash
## clean : 中間ファイルを削除(PDF は残す)
clean:
$(RUN) latexmk -c $(DOC).tex
## distclean: PDF も含めて生成物を全部削除
distclean:
$(RUN) latexmk -C $(DOC).tex
## help : ターゲット一覧を表示
help:
@grep -E '^## ' $(MAKEFILE_LIST) | sed 's/^## //'
Makefile のレシピ行は、行頭がスペースではなくタブでなければなりません。コピー時に崩れたら
makeがmissing separatorを出します。
使い方は次のとおりです。
make image # 最初に一度(公式イメージを直接使うなら不要)
make # main.pdf を生成
make watch # 執筆中は監視モード
make clean # 中間ファイルの掃除
DOC や IMAGE はコマンドラインで上書きできます。
make build DOC=chapter1
make build IMAGE=texlive/texlive:TL2024
.latexmkrc(和文文書の場合)
和文は upLaTeX で DVI を作り dvipdfmx で PDF 化する経路が一般的です。コンテナ内にはビューアがないので、プレビュー系は無効にしておきます。
$latex = 'uplatex %O -synctex=1 -halt-on-error -interaction=nonstopmode %S';
$bibtex = 'upbibtex %O %B';
$biber = 'biber %O --bblencoding=utf8 -u -U --output_safechars %B';
$makeindex = 'upmendex %O -o %D %S';
$dvipdf = 'dvipdfmx %O -o %D %S';
$pdf_mode = 3; # DVI -> PDF
$max_repeat = 5;
$view = 'none';
このファイルをリポジトリに含めておけば、make する人・CI のどちらも同じ設定で組版できます。詳しくは latexmk の記事を参照してください。
CI へそのまま持ち込む
ローカルで使っているイメージを CI でも指定すれば、手元と同じ環境でビルドできます。GitLab CI の例:
compile:
image: texlive/texlive:TL2024
script:
- latexmk main.tex
artifacts:
paths:
- main.pdf
GitHub Actions なら container: に同じイメージを指定します。CI 側では Docker を介さず直接 latexmk を呼べるので、Makefile の build ターゲットの中身(latexmk $(DOC).tex)だけをそのまま流用できます。「ローカルは make、CI はイメージ直実行、コマンドは同一」という形に落ち着きます(詳しくは GitHub Actions で自動化する)。
関連記事
- latexmk — コンテナ内で呼ぶ組版コマンドと
.latexmkrc - Docker の基本 —
docker runのオプションとイメージのしくみ - LaTeX コンパイルを GitHub Actions で自動化する — 同じイメージを CI で使う
- Hugo と GitLab で静的 Web サイトを作る — CI と同じイメージでのローカル開発
まとめ
- TeX Live 入りコンテナを使うと、組版環境をイメージに固定でき、マシン差や経年劣化に強くなる。年号タグでの固定が要点。
docker runの定型オプション(マウント、UID 合わせ、HOME)を Makefile の共通変数にまとめると、makeだけでコンパイルできる。.latexmkrcと同じイメージを CI にも渡せば、ローカルと CI で同一の PDF が得られる。
原稿と一緒に Dockerfile / Makefile / .latexmkrc を配布する運用にしておくと、受け渡し先でも「make するだけ」で再現できます。