[Linux][C/C++] Waf ビルドシステムについてのメモ

# 注意
本ドキュメントは `waf-1.9.3` で確認しています。
変更がある可能性がありますので、[本家ドキュメント](https://waf.io/book/)とクロスチェックしてください。

# 概要
python製のビルドツールであるWafについてのまとめ

Wafでは `wscript` というファイルを定義してビルドを行います。

日本語資料がしっかりしているので、基本的には以下のページを参照すると良いと思います。
（有志の方の訳のため、最新ではない？※要確認）
[The Waf Book](http://matsu911.github.io/waf_book_ja/)

本家英語資料は以下になります。
[The Waf Book](https://waf.io/book/)

# メリット・デメリット
メリット

+ pythonで書ける？ 

デメリット

+ CMakeよりは遅い？(前身のSConsの話？) ※要確認
+ Pythonの知識が少し要りそう(CMakeも独自言語なのでどっちもどっち？)

# 準備
## Waf のダウンロード
[公式サイト](https://waf.io/)、もしくは[Github](https://github.com/waf-project/waf)からソースをダウンロードする。

```console:実行バイナリを直接ダウンロード
$ wget --no-check-certificate https://waf.io/waf-1.9.3 -O waf
```

```console:ソースからビルド
$ git clone https://github.com/waf-project/waf.git
$ cd waf
$ ./waf-light configure build
$ ls
build  build_system_kit  ChangeLog  configure  demos  DEVEL  docs  playground  README.md  tests  TODO  utils  waf  waflib  waf-light  wscript  zip
```

## とりあえずのサンプルの確認

ソースからビルドした場合は、リポジトリ内にデモが用意されています。
いろいろな言語のサンプルがあるため、参考にできると思います。

```console:C言語のサンプルのビルドテスト
$ cd demos
$ ls
asm  bisonflex  c  c++  csharp  d  dbus  fortran  glib2  intltool  java  jni  lua  mac_app  perl  precious  python  qt5  ruby  subst  tex  unit_test  vala  variants  wscript
$ cd c
$ ../../waf configure build
Setting top to                           : /home/user/work/waf/demos/c
Setting out to                           : /home/user/work/waf/demos/c/build
Checking for 'gcc' (C compiler)          : /usr/bin/gcc
Checking for code snippet                : yes
Checking for code snippet                : yes
Checking for code snippet                : yes
Checking for libraries                   : yes
Checking for library m                   : yes
Checking for large file support          : yes
Checking for inline                      : inline
Checking for endianness                  : little
Checking for headers in parallel         : started
... testing an arbitrary build function  : ok
... stdio                                : yes
... unistd                               : yes
... optional xyztabcd.h                  : no
... stdlib                               : aye
... malloc                               : yes
-> processing test results               : 1 test failed
Checking for header stdio.h              : yes
Checking for code snippet                : yes
'configure' finished successfully (1.405s)
Waf: Entering directory `/home/user/work/waf/demos/c/build'
[ 1/16] Creating build/program/b.h
[ 2/16] Creating build/abc.h
[ 3/16] Creating build/stlib/foo.h
[ 4/16] Processing wscript
[ 5/16] Trying again wscript
-Lm -Lncurses -L../wscript ayedoh -Laaa -L/home/user/work/waf/demos/c/wscript

-Lm -Lncurses -L../wscript ayedoh -Laaa -L/home/user/work/waf/demos/c/wscript

[ 6/16] Compiling stlib/main.c
[ 7/16] Compiling program/main.c
[ 8/16] Compiling shlib/test_shlib.c
[ 9/16] Compiling shlib/main.c
[10/16] Compiling stlib/test_staticlib.c
[11/16] Linking build/program/myprogram
[12/16] Linking build/shlib/libmy_shared_lib.so
[13/16] Linking build/stlib/libmy_static_lib.a
[14/16] Linking build/shlib/test_shared_link
[15/16] Linking build/stlib/test_static_link
[16/16] Symlinking build/shlib/libmy_shared_lib.so
Waf: Leaving directory `/home/user/work/waf/demos/c/build'
'build' finished successfully (1.162s)
```

# `wscript` 実装手順
## wscriptの基本

`waf` は `wscript` 内の関数を、 *wafコマンド* として定義します。
例として、wafコマンド `hello` を以下に定義します。

```py:サンプル
#! /usr/bin/env python
# encoding: utf-8

def hello(ctx):
    print('hello world')
```

```console:wafコマンドhelloを実行
$ ./waf hello
hello world
'hello' finished successfully (0.001s)
```

`waf` の実行コマンドとして `hello` を指定することにより、コマンドが実行されていることがわかります。

## C++プロジェクトのビルド

本家ドキュメントの以下を参照
[The Waf Book](https://waf.io/book/#_common_declaration_for_c_c_fortran_and_d_applications)

```cpp:main.cpp
#include <iostream>

int main(int argc, char const* argv[])
{
    std::cout << "hoge" << std::endl;
    return 0;
}
```

```py:C++プロジェクトのビルド
#! /usr/bin/env python
# encoding: utf-8

def options(opt):
    opt.load('compiler_cxx')

def configure(conf):
    conf.load('compiler_cxx')

def build(bld):
    bld.program(source='main.cpp', target='app')
```

```console:ビルドと実行結果
$ ./waf configure build
Setting top to                           : /home/user/work/test
Setting out to                           : /home/user/work/test/build
Checking for 'g++' (C++ compiler)        : /usr/bin/g++
'configure' finished successfully (0.051s)
Waf: Entering directory `/home/user/work/test/build'
Waf: Leaving directory `/home/user/work/test/build'
'build' finished successfully (0.003s)
$ ./build/app
hoge
```

その他詳細(インクルードや、共有ライブラリのビルド等)は本家ドキュメントを参照して下さい
[The Waf Book](https://waf.io/book/#_common_declaration_for_c_c_fortran_and_d_applications)

TODO: 時間があれば追記する

## クロスビルド環境対応

環境変数を変更すればクロスビルドにも対応可能なようです

[The Waf Book](https://waf.io/book/#_extensions)
[Re: [waf-users 4515] Cross-compiling QNX using qcc - Google グループ](https://groups.google.com/forum/#!topic/waf-users/sKGTmoaoF4c)

# 参考
[Waf: the meta build system](https://waf.io/)
[waf の導入 - Mackey's Lab](http://mackey-lab.hatenablog.com/entry/2015/03/19/052015)

以下は日本語資料ですが、内容が古くなっているので注意(2010年&2011年の記事)
[The Waf Book](http://matsu911.github.io/waf_book_ja/)
[waf チュートリアル - 純粋関数型雑記帳](http://d.hatena.ne.jp/tanakh/20100212)