LoginSignup
10
9

More than 3 years have passed since last update.

makefile と build.ninja の比較。 make から ninja への移行検討メモ

Last updated at Posted at 2019-10-16

これは何

GNU make から ninja に移行を検討中のメモです。

想定読者

makefile を自分でかける人
.PHONY: clean を毎回書くのに飽き飽きした人
素の make の動作が遅いなぁと思う人
ninja 向けのメタビルドツールを作りたい人

ninja って何?

https://mattn.kaoriya.net/software/ninja/20140121141906.htm こことか読んでください。

hello.c のビルドを比較

hello world を出力する hellohello.c でビルドする例を makefilebuild.ninja で示します。
これを試すだけで ninja がいいなぁと思えてきました。

makefile for gcc の場合

makefile の例を示します。デフォルトルールを全力で利用した場合、下記のようになると思います。
ninja との比較がしやすいように、暗黙的に定義されている変数だけを使用しています。

makefile
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 は、暗黙のルールや変数を持ちません。
そのため、すべて明示的に定義しています。

build.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 文によって生成されるファイル(ここでは hellohello.o) が削除されます。make に比べて非常に気が利いていると感じます。

ninja.build for msvc

Microsoft Visual Studio での例を示します。makefile の方は省略します。というか、調べる気が無くなったので。。。

ninja.build
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 を作るのも楽そうではある。

参考リンク

The Ninja build system

10
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
9