1. typstがいまアツイ
みなさんtypst使っていますか?かく言う私は初めて本格的に組版するためにtypstを使おうとしています。なんかLaTeXより早くてかきやすいらしいですシランケド。個人的にはコマンドがかなりわかりやすくてCMakeラッパーを簡単に作りやすい点が気に入っています。
2. だからこそビルドツールが大事と言う話
さてそんなtypstですが使う方法がいくつかあります。
- VSCode拡張機能のtypst-lspによる自動ビルド
- typst公式サイトのウェブアプリ
- rust製のtypstコンパイラ
- cmakeラッパー(NEW!!!)
プログラマの皆さんならわかってもらえるかなと思うのですがファイルを分けて書きたい(もちろん1ファイルでもいいと思いますがセクションごと作りたいとかフォルダごと分類しておきたい)という需要があると思います。そこで大事になってくるのがビルドツールです。極端な話優秀なビルドツールがあるかないかだけで100倍快適さが違うと思います。
3. CMakeというビルドツールの可能性
CMakeというビルドツールは以下の点において他のビルドツールを遥かに凌ぎます
- 変数やターゲットの宣言及び操作は全て関数呼び出し形式のためビルド一貫性がかなりつよいです
- ユーティリティ関数が適切に柔軟なので割と雑に書けます
- ジェネレーター式というビルドスクリプト生成直前に評価される式によりビルドが適切に柔軟性を得ます
- 複数ディレクトリ前提で、独立したディレクトリを組み合わせることもできます
個人的にはビルド一貫性が保てて簡単に書ければビルドツールはほぼ何でもいいのでCMakeでtypstをコンパイルしない選択肢はありませんでした。
4. CMakeラッパーがないので作ったよ
本題です。CMakeでtypstをコンパイルできないのでコンパイルするためのUseTYPST.cmake(UseLATEX.cmakeみたいなやつ)というtypstをコンパイルするためのユーティリティ関数を提供してくれるやつを作りました。
ダウンロードはこちら
5. 使い方
サンプルプロジェクト
cmake_minimum_required(VERSION 3.20)
project(UseTYPST)
include(UseTYPST.cmake)
add_typst_document(example example.typ)
add_subdirectory(subdir)
まずプロジェクトでUseTYPST.cmakeをインクルードします。
cmake_minimum_required(VERSION 3.20)
project(UseTYPST)
include(UseTYPST.cmake)
そしてadd_typst_document(${書類の名前} ${ルートtypstファイル})を呼び出します。(例では書類の名前をexample、ルートtypstファイルをexample.typにしています)
add_typst_document(example example.typ)
これだけで普段と同じようにtypstを書いてビルドするだけでコンパイル可能です(typstがPATHの中に見つかる必要があります。)
もしファイルを分割したいのなら次のようにします
typst_document_sources(example subdir_example.typ)
この例ではsubdir_example.typをexample書類のもう一つのファイルとして追加しています。もちろんsubdir_example.typを編集したらexample書類は再コンパイルされます!やった!!!
typst_document_sourcesは追加したtypファイルの変更を追跡し、変更されたら再コンパイルする設定しか行いません。pdfに表示するためにはルートtypファイルでincludeやinputを行う必要があります。
例)
#include "subdir/subdir_example.typ"
余談(CMakeの挙動)
このUseTYPST.cmakeを作る上で重要なCMakeの挙動について触れようと思います。それがadd_custom_command, add_custom_targetとGenerator Expressionです。
add_custom_commandとadd_custom_targetの使い方はこの記事が詳しいと思います。簡単に言うとadd_custom_commandで作成したビルドスキームをadd_custom_targetで発火できると言う仕組みです。もちろんadd_custom_commandで生成するファイルを他のターゲットが依存するようにもできるし、他のターゲットがadd_custom_targetによって作成されたターゲットに依存し、そのターゲットがadd_custom_commandで出力されたファイルに依存することでadd_custom_commandの出力ファイルが最新の状態(最新なら再ビルドしないで)他のターゲットのビルドを走らせるなんてこともできます。
このようにします
add_custom_target(${DOCUMENT_NAME} SOURCE ${DOCUMENT_NAME}.pdf)
set_property(TARGET ${DOCUMENT_NAME} PROPERTY USETYPST_DEPENDS ${DEPEND_FILES})
add_custom_command(OUTPUT ${DOCUMENT_NAME}.pdf COMMAND ${BUILD_COMMAND} args... DEPENDS $<TARGET_PROPERTY:${DOCUMENT_NAME},USETYPST_DEPENDS>)
ここで重要なのが、add_custom_commandの呼び出し制限を回避するためにadd_custom_commandのDEPENDSにジェネレータ式($)を指定することです。基本的にadd_custom_commandは一度だけしか呼び出せないと思ってください。そこでジェネレート直前に評価されるジェネレータ式の出番です。つまりジェネレータ式に渡せる変数(ここではターゲットプロパティを使用しています。ターゲットプロパティは自由な変数名を指定できるのでなるべく被らない変数名を使用しています。)を使うことでadd_custom_commandを一度だけで依存ファイルの追加を後からすることができます。typst_document_sourcesの実装を見てみましょう。
get_property(current_depends TARGET ${DOCUMENT_NAME} PROPERTY USETYPST_DEPENDS)
set(next_depends ${current_depends} ${CMAKE_CURRENT_SOURCE_DIR}/${iterator})
set_property(TARGET ${DOCUMENT_NAME} PROPERTY USETYPST_DEPENDS ${next_depends})
DOCUMENT_NAMEに保存されているターゲット名のUSETYPST_DEPENDSプロパティに依存ファイルを追加しています。こうすることによって依存ファイルをユーザーが後から自由に追加できるようになっています。やったぁ!!!
みなさんもLaTeXとかその他諸々のcmakeビルドラッパーを作るときに参考にしてみてください!
以上!
ありがとうございました。