これは何
GNU make から ninja に移行を検討中のメモです。
想定読者
makefile
を自分でかける人
.PHONY: clean
を毎回書くのに飽き飽きした人
素の make の動作が遅いなぁと思う人
ninja 向けのメタビルドツールを作りたい人
ninja って何?
https://mattn.kaoriya.net/software/ninja/20140121141906.htm こことか読んでください。
hello.c のビルドを比較
hello world を出力する hello
を hello.c
でビルドする例を makefile
と build.ninja
で示します。
これを試すだけで ninja がいいなぁと思えてきました。
makefile for gcc の場合
makefile
の例を示します。デフォルトルールを全力で利用した場合、下記のようになると思います。
ninja との比較がしやすいように、暗黙的に定義されている変数だけを使用しています。
CFLAGS = -Wall -Os -MMD -MP
CPPFLAGS = -DNDEBUG
.PHONY:clean
hello:hello.o
clean:
$(RM) hello hello.o hello.d
-include hello.d
記述量は非常に少なく、簡潔です。
makefile の暗黙ルールに精通した人なら、こんなもんだなぁ程度に感じます。
makefile に精通していない人は、 hello.o:hello.c
のような記述不要な依存関係とか書いたりして、余計な記述が増えがちです。
ビルド実施後、 hello
, hello.o
, hello.d
の 3ファイルが生成されます。
clean
ルールを書くのが面倒くさいです。
ninja.build for gcc の場合
上記 makefile と同等の build.ninja を示します。 ninja は、暗黙のルールや変数を持ちません。
そのため、すべて明示的に定義しています。
cc = cc
cflags = -Wall -Os
cppflags = -DNDEBUG
rule compile
deps = gcc
depfile = $out.d
command = $cc -MMD -MP -MF $out.d $cflags $cppflags $target_arch -c -o $out $in
rule link
command = $cc $ldflags $target_arch $in $loadlibes $ldlibs -o $out
build hello: link hello.o
build hello.o: compile hello.c
makefile に比べて記述量が増えていますが、何をやるのかがすべて記述されるのでわかりやすいです。
makefile の場合、暗黙ルールや変数を理解しないと何をやるのかが全くわからないものでしたが、ninja の場合は違います。
ビルド実施後、 hello
, hello.o
, .ninja_deps
, .ninja_log
の 4ファイルが作成されます。 .d
ファイルは消え去ります。この、.d
が残らないところがポイントです。 複数の .d
ファイルを元に一つの .ninja_deps
を作成し、依存情報を集約してくれています。ビルドを行う際、依存関係を捜査してどのファイルがリビルド必要かを調べますが、細かいファイルをたくさん開くよりも、一つの大きなファイルを開く方が実行時間が短くてすみます。これがいいところです。
ninja は、組み込みオプションで clean 操作ができます。 ninja -t clean
です。 build 文によって生成されるファイル(ここでは hello
と hello.o
) が削除されます。make に比べて非常に気が利いていると感じます。
ninja.build for msvc
Microsoft Visual Studio での例を示します。makefile の方は省略します。というか、調べる気が無くなったので。。。
msvc_deps_prefix = メモ: インクルード ファイル:
cflags = /Wall /Os
cppflags = /DNDEBUG
rule compile
deps = msvc
command = cl /nologo /showIncludes $cflags $cppflags /c /Fo$out $in
rule link
command = link /NOLOGO $ldflags $target_arch $loadlibes $ldlibs /OUT:$out $in
build hello.exe: link hello.obj
build hello.obj: compile hello.c
msvc_deps_prefix は、実行環境の codpage で変わります。この例は、932 です。
windows 環境に make をインストールしようとすると cygwin にするか msys にするか SFU にするかで迷いますが、 ninja だったら公式に choco install ninja
で良いと示しているので迷うことがなくて気持ちがいいです。
感想
make は普段使用しない言語に対する暗黙ルールがたくさんあって、 make -p
したときの変数リストを調べるのが面倒くさいと感じていました。ninja くらい割り切ってくれた方が、小さいプロジェクトだと書きやすくて良いと思った。
また、make の暗黙ルールじゃカバーできないようなビルドを実行したいとき、( .md から .pdf をビルドするような場合 ) ルールをすべて記述しなくちゃいけなくなるので、 build.ninja にすべてを記述することに違和感は特にない。
vpath や、 変数の置換展開とかといった便利な機能が ninja にはないので、 何かしらのスクリプトで build.ninja を生成する必要はある。もともとメタビルドツールの下回りを想定して設計しているので、当然といえば当然です。かなり仕様がシンプルなので、自前のスクリプトで build.ninja を作るのも楽そうではある。