これは「SATySFi Advent Caleandar 2022」の4日目の記事です。
(3日目は zr_tex8r さん、5日目は yozu さんです。)
SATySFiの環境を整備するのは、ちょっと厄介です。例えば
- インストールしないといけないものが多い。例えば、opam, ocaml, satysfi, satyrographos, 各種パッケージ, ...
- インストール手順が煩雑。例えばopamリポジトリの設定、satyrographosの実行、...
- 各ドキュメント毎にパッケージを管理したい(仮想環境)のに、通常のパッケージ管理ではユーザー全体のパッケージデータベースに影響を与えてしまう
- satysfiやsatyrographos、各種パッケージのバージョンをドキュメント毎に変えるのが大変
- SATySFiパッケージとOCamlのパッケージが混ざるので管理しづらい
このような点を解決するMakefileを作成しました。
$ wget https://gist.githubusercontent.com/yasuo-ozu/ef3134dbc80f657a9f476de4c80df113/raw/00f972c64113c7b94dbb6af14649e8398a230dab/Makefile
使い方
- まずシステムに
opam
をインストールします。 - ドキュメント用のディレクトリを作成し、そこに移動します。
- Makefileをダウンロードして配置します。
-
make
を実行します。Satyristes
ファイルが無い状態で実行するとサンプルの*.saty
ファイルを作成しpdfを生成します。
例えば、 satysfi_doc
という空ディレクトリの中で上の手順を行うと、以下のようなファイルが生成されます。
$ ls
.gitignore Makefile Satyristes _build _opam satysfi-satysfi_doc.opam satysfi_doc.pdf satysfi_doc.saty satysfi_doc.satysfi-aux
ファイルの説明
Satyristes
satyrographos
が読み込むファイルで、*.saty
ファイルのコンパイルに必要なSATySFiパッケージをリストアップします。同じフォルダに複数の *.saty
ファイルが存在する場合、 Satyristes
にも対応する doc
エントリが存在する必要があります。
このファイルが存在しない場合、 make
実行時にサンプルのファイル構成が生成されます。
サンプル
(lang 0.0.3)
(doc
(name "satysfi_doc")
(workingDirectory "./")
(build (
(make-with-env-var "satysfi_doc.pdf")
))
(dependencies (dist))
(autogen ($today))
)
satysfi-ドキュメント名.opam
opamが読み込むファイルで、ドキュメント名.saty
で使われるパッケージとそのバージョンをリストアップします。 Satyristes
ファイルで指定されたパッケージはすべてこのファイルにも含まれる必要があります。
SATySFiのパッケージ管理では、パッケージをインストールするのはsatyrographosですが、ダウンロードやバージョンの解決のためにopamが使われるため、Satyrographos
と*.opam
の両方が必要になっています。
サンプル
opam-version: "2.0"
depends: ["satysfi" { >= "0.0.5" & < "0.0.7" } "satysfi-dist" "satyrographos"]
ドキュメント名.saty
メインのファイルです。
サンプル
@require: stdjabook
@require: $today
let-inline ctx \today = Today.datetime |> embed-string |> read-inline ctx
in
document (|
title = {\SATySFi;};
author = {};
show-title = true;
show-toc = false;
|) '<
+p { Today is \today; }
>
ドキュメント名.d
Makeが読み込むファイルで、ドキュメント名.saty
内に画像ファイルが使われていた場合、make
実行時にそのパスがドキュメント名.d
ファイル内にリストアップされます。
そのため、実際にその画像が存在しない場合でも、*.pdf
を生成する前に make 画像ファイル名
が実行されるため、予め Makefile
内に適切なルールを書いておくことで*.saty
ファイル内で使用している画像を別のソフトウェアで生成することができます。(make cleanで削除される)
_build
satyrographosが作成する仮想環境用のディレクトリです。(make cleanで削除される)
_opam
satysfi
, satyrographos
等のバイナリや satysfi-dist
等のパッケージのファイルがインストールされる仮想環境です。(make cleanで削除される)
*.satysfi-aux
SATySFi が生成する一時ファイルです。(make clean で削除される)
解説
仮想環境について
このMakefileでは、ユーザーの環境に対して影響を与えないため、ドキュメントのディレクトリに閉じた仮想環境を作成します。
ここでいう仮想環境には、以下の2つが存在します。
- opamの仮想環境 ...
opam switch
コマンドによって_opam
以下に作成される。 - satyrographosの仮想環境 ...
satyrographos build
コマンドによって_build
以下に作成される。
パッケージをインストールするのになぜ2つも仮想環境が必要になるのが疑問に思うでしょうが、それはSATySFiのパッケージをインストールする際に以下のような2段階の処理が行われるからです。
-
opam install パッケージ名
コマンドでSATySFiのパッケージ(にsatysfi-
というプレフィクスをつけたもの)をsatyrographos-repo
というopamリポジトリからダウンロードしてインストールする。インストールされたファイルはopamレポジトリ(仮想環境の場合は_opam
)で管理される。 -
satyrographos install
コマンドを実行すると opam リポジトリを探索してsatysfiパッケージを探し出し、必要なファイルをdist
ディレクトリにインストールする。 -
satysfi
コマンドはコンパイル中@require:
を処理する際、dist
ディレクトリを参照する
そのため本Makefile では opam switch
及び satyrographos build
を活用することで2つの仮想環境を管理しています。
make build
コマンドの動作
make
(もしくは make build
) を実行すると以下の処理が行われます。
- 存在しない場合、opamの仮想環境
_opam
を作成する。 -
Satyristes
が存在しない場合、サンプルファイルを生成する。 - 仮想環境
_opam
内にsatysfi
,satyrographos
をインストールする。(この際、*.opam
内に書かれたバージョン制約を反映) -
satyrographos build
コマンドを用いて、Satyristes
内に記述されたドキュメントを全てコンパイルする
satyrographos build
コマンドが参照するSatyristes
は例えば次のようになっています。
(lang 0.0.3)
(doc
(name "satysfi_doc")
(workingDirectory "./")
(build (
(make-with-env-var "satysfi_doc.pdf")
))
(dependencies (dist))
(autogen ($today))
)
ここでは make-with-env-var
が使われており、これはsatysfi_doc.pdf
生成時にmake
コマンドを使用することを意味します。この場合 satyrographos build
コマンドは以下のことをします。
- ドキュメント毎に仮想環境を作る。(
_build
) -
Satyristes
内に指示された依存パッケージを_opam
から探し出し、仮想環境にインストールする。 -
make satysfi_doc.pdf
を実行する。
ここでmake satysfi_doc.pdf
が実行された時に呼ばれる部分は以下のようになっています。
%.pdf: %.saty $(SATYSFI_BIN) Makefile
@if [ -n "$$SATYSFI_RUNTIME" ]; then \
eval $$(opam env) && satysfi -C "$$SATYSFI_RUNTIME" --no-default-config "$<" -o "$@" ; \
fi
$SATYSFI_RUNTIME
には satyrographos build
が作成した仮想環境のディレクトリが与えられます。これを -C
オプションを界してsatysfiに与えています。
ここでpdfを作成するためにわざわざMakefileを呼び出している理由なのですが、それは*.saty
が依存しているファイルをMakefile内で同時に生成することを想定しているからです。例えば、satysfi_doc.saty
ファイルの中でexample.pdf
ファイルを使用している場合、最初のmake build
実行時に以下のファイルが自動的に生成されます。
satysfi_doc.pdf: example.pdf
このファイルはsatysfi_doc.pdf
を生成するためにはexample.pdf
が必要であるという事実を述べており、make satysfi_doc.pdf
を実行したときに読み込まれます。
example.pdf
が存在しない場合、自動的にmake example.pdf
が実行され、Makefile が画像ファイルを生成しようとします。
例えば、example.svg
から自動的にexample.pdf
を生成したい時は、Makefile
に以下の内容を追記(もしくはinclude.am
というファイルを作成)すればよいです。
(なお、この場合example.pdf
はmake clean
で自動的に削除されないので注意してください。このような中間ファイルは一時ディレクトリを作成し、その中に生成させるのがおすすめです。)
%.jpg: %.svg
inkscape "--export-filename=$@" "$<"