こんにちは。
最近はC言語で書かれたAndroid/iOS SDKのプロジェクトにjoinしまして、ビルドや単体テストの自動化について色々試行錯誤しております。
最初はMakefileで色々頑張っていたのですが、前から試してみたかったninja-buildというビルドツールを使ってみて、意外と便利だったため共有します。
apple/swift のビルドにも使われていたので、CやC++の皆さんの間では有名なのかもしれませんね。オープンソースで、C++で実装されているようです。
https://ninja-build.org
https://github.com/ninja-build/ninja
*Windowsでも使えるようですが、この記事ではMacで動作確認しております。
homebrewでインストールできました。
$ brew install ninja
$ ninja --version
1.7.1
例えばMakefileで下記のように書いていたビルドスクリプト。
obj=clang -c -g
app=clang
add:
$(obj) add.c
addapp: add
$(obj) addapp.c -o addapp.o
main: addapp add
$(app) addapp.o add.o -o main
add.cを書き換えても、mainのジョブは差分を検知してくれません。
(*追記:これはMakefileの書き方が間違っているだけでした。Makefileでも差分ビルドはできます!)
c $ make main
clang -c -g add.c -o add.o
clang -c -g addapp.c -o addapp.o
clang addapp.o add.o -o main
c $ make main
make: `main' is up to date.
c $ echo "// hello" >> add.c
c $ make main
make: `main' is up to date.
ninja-buildで依存関係を記述しておけば、簡単に差分ビルドの問題を解決できます。
rule obj
command=clang -c -g $in -o $out
rule app
command=clang $in -o $out
build addapp.o: obj addapp.c
build add.o: obj add.c
build main: app addapp.o add.o
default main
c $ ninja -v
[1/3] clang -c -g add.c -o add.o
[2/3] clang -c -g addapp.c -o addapp.o
[3/3] clang addapp.o add.o -o main
c $ ninja -v
ninja: no work to do.
c $ echo "// hello" >> add.c
c $ ninja -v
[1/2] clang -c -g add.c -o add.o
[2/2] clang addapp.o add.o -o main
add.cしか書き換えてないので、addapp.o はそのまま置いておいてくれました。
構文もシンプルで、出力もわかりやすい気がします。
書き方についてはドキュメントや参考サイトを参考にして欲しいのですが、差分検知の対象($in)に指定するのはディレクトリでも良いため、大きなプロジェクトにも対応できると思います。
環境変数を読み込むような難しいことはできないため、実際の運用ではbuild.ninjaファイルを出力してninjaコマンドを実行するスクリプトを別途書くことになると思います。
ninja = ninja -v
build-hoge:
./createbuildninja.sh hoge
$(ninja)
build-fuga:
./createbuildninja.sh fuga
$(ninja)
余談になりますが、Xcode8でLLVMの大幅なパフォーマンス改善がされ、複雑な差分ビルドにも対応したとのことでした。
今後も色々検証してみたいと思います。
参考:
http://bigoyayubi.hatenablog.com/entry/2015/08/02/222909
http://mattn.kaoriya.net/software/ninja/20140121141906.htm