まえがき
ビルドツールのmakeよりも新しくて、しかも早いという噂のninjaを試してみました。基本的にはmakeとほとんど同じですが、暗黙のルールがなく明示的に記述する必要があるので、見返したときに読みやすいと感じました。
公式サイトにも書いてある通り、build.ninjaは読みやすいが、手書きでは書きにくく、より高度なビルドシステム(makeでいえばAutotools)が生成するものです。今回は自分の理解のためにbuild.ninjaを少し手書きで書いてみました。
より高度なビルドシステムとしては、CMakeやMesonがあげられます。そのうち動かしてみようと思います。
インストール
$ apt install ninja-build
$ ninja --version
1.8.2
テスト用ソースコード
ninjaの実行のためにテスト用のソースコードを3つ用意しました。
// main.cc
# include <iostream>
# include "gcd.hh"
using namespace std;
int main()
{
ll a = 10, b = 15;
cout << gcd(a, b) << endl;
}
// gcd.cc
# include "gcd.hh"
ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; }
// gcd.hh
using ll = long long;
ll gcd(ll x, ll y);
build.ninja
makeで言えばMakefileがninjaではbuild.ninjaです。あまり手書きでbuild.ninjaを作成することは無いらしいのですが、理解のため書いてみました。基本的にはMakefileと変わらないようです。依存関係も解決できるように-MMD -MF
を使っています。
$ cat build.ninja
cc = g++
cxxflags = -Wall
rule obj
depfile = $out.d
command = $cc -MMD -MF $out.d $cxxflags -c $in -o $out
rule app
command = $cc $ldflags $in -o $out
build main.o: obj main.cc
build gcd.o: obj gcd.cc
build main: app main.o gcd.o
ビルド
このようなファイルがある環境です。
$ ls
build.ninja gcd.cc gcd.hh main.cc
実行はninja
でできます。make
コマンド相当ですね。
-v
オプションを付けると、実行したコマンドを表示できます。
$ ninja -v
[1/3] g++ -MMD -MF gcd.o.d -Wall -c gcd.cc -o gcd.o
[2/3] g++ -MMD -MF main.o.d -Wall -c main.cc -o main.o
[3/3] g++ main.o gcd.o -o main
オブジェクトファイル、依存ファイル、実行ファイルが作成されました。
$ ls
build.ninja gcd.cc gcd.hh gcd.o gcd.o.d main main.cc main.o main.o.d
クリーン
-t
オプションでclean
を指定すると生成したファイルを削除します。
$ ninja -t clean
Cleaning... 5 files.
$ ls
build.ninja gcd.cc gcd.hh main.cc
その他コマンド
ターゲットをすべて表示します。
$ ninja -t targets all
main.o: obj
gcd.o: obj
main: app
コマンドをすべて表示します。
$ ninja -t commands
g++ -MMD -MF main.o.d -Wall -c main.cc -o main.o
g++ -MMD -MF gcd.o.d -Wall -c gcd.cc -o gcd.o
g++ main.o gcd.o -o main
他のコマンドはヘルプで確認できます。
$ ninja --help
usage: ninja [options] [targets...]
if targets are unspecified, builds the 'default' target (see manual).
options:
--version print ninja version ("1.8.2")
-C DIR change to DIR before doing anything else
-f FILE specify input build file [default=build.ninja]
-j N run N jobs in parallel [default=8, derived from CPUs available]
-k N keep going until N jobs fail [default=1]
-l N do not start new jobs if the load average is greater than N
-n dry run (don't run commands but act like they succeeded)
-v show all command lines while building
-d MODE enable debugging (use -d list to list modes)
-t TOOL run a subtool (use -t list to list subtools)
terminates toplevel options; further flags are passed to the tool
-w FLAG adjust warnings (use -w list to list warnings)