Boost.Build の簡単な使い方 (TDDしてみる)

  • 22
    Like
  • 0
    Comment
More than 1 year has passed since last update.

はじめに

あんまりまとまった日本語のドキュメントが見つけられなかったので、自分用のメモも兼ねて書いてみます。

公式リファレンスがいまいち探しにくいので、リンクもできるだけ貼るようにします。

何をするツールなのか

C++用のコマンドラインビルドツールです。

Makeみたいなものです。

MakeよりもC++のソースファイルのビルドに特化しているので記述量が少なく簡単に書けます。

何が便利なのか

ちょこっとプログラムを書いて、ちょこっとテストしてみるのが、すっごい便利です。

つまり、テストを書きながら開発していく(TDD)ときにとても便利です。

例えれば、PHPやRubyくらいお手軽です。

xcodeやVisual Studioでプロジェクト作ってごにょごにょするよりずっと簡単!
(Gitやコマンドラインに慣れていれば)

準備する

Boost C++ Library ( http://www.boost.org/ )のソースをダウンロードしてきて展開するか、GitHubからクローンしてくると使えるようになります。

./bootstrap.sh みたいなシェルを実行すると、bjamとb2が生成され準備完了です。
ライブラリは必要に応じて勝手にビルドされるので、あらかじめビルドしておく必要はありません。

環境変数BOOST_ROOTにBoost C++ Libraryを展開したディレクトリーを設定しておくと何かと便利です。

環境変数PATHにbjamとb2が実行でいるようにディレクトリーを追加しておきましょう。

使ってみる

Hello world をビルドしてみる

適当なプログラムを作り、プロジェクトファイルとしてJamroot.jamを作ります。
(Jamroot.jamはいくつか名前があり、例えば拡張子がないJamrootでも大丈夫です)

hello_world.cpp
#include <iostream>

using namespace std;

int main()
{
    cout << "Hello world" << endl;
    return 0;
}
Jamroot.jam
exe hello_world : hello_world.cpp ;

コマンドラインから

./b2

と実行すれば、ビルドが完了しbin/以下に実行ファイルができます。

注意点として、セミコロンやコロンのまわりにはスペースや改行が必要です。
これは他のプログラミング言語とは異なりますので注意してください。

このあたりに書いてあります。
http://www.boost.org/boost-build2/doc/html/bbv2/tasks.html#bbv2.tasks.programs

Hello worldをTDDしてみる

ビルドしてみるだけだと、Makeでも簡単だし何も面白くありません。

ビルドと同じくらい簡単にテストが実行ができるのがいいところです。

Jamroot.jamを書き直してみます。

Jamroot.jam
import testing ;
unit-test hello_world : hello_world.cpp ;

これで

./b2

と実行すると、ビルドとテスト実行が同時にできています。

ここでいうテストとは、プロセスの終了コードが0(正常終了)か0以外(異常終了)かを見ています。

以下のように書くと、さらに記述量を減らせて便利です。普段はこっちを使います。

Jamroot.jam
import testing ;
run hello_world.cpp ;

リファレンスではここを参照です。
http://www.boost.org/boost-build2/doc/html/bbv2/builtins/testing.html

複数のテストを実行したいとき

いくつか方法はありますが、単純に並べて書くこともできます。

Jamroot.jam
import testing ;
run test1.cpp ;
run test2.cpp ;
run test3.cpp ;
run test4.cpp ;

フォルダー内のファイルを自動的にビルドしてテスト実行するなんてこともできます。

Jamroot.jam
import testing ;

for f in [ glob *.cpp ]
{
    run $(f) ;
}

このあたりは普通のスクリプト言語のように自由にできます。

forやifなど言語構造に関することはこちらに書いてあります。

http://www.boost.org/boost-build2/doc/html/bbv2/overview/jam_language.html

ソースファイルが複数あるとき

ファイルを並べればOKです。

Jamroot.jam
import testing ;
run main.cpp
    source1.cpp
    source2.cpp
    ;

もしやりたければ、 glob などでファイルのリストを作って渡すこともできます。

インクルードパスを指定するには

例えば、ソースはsrc/フォルダーに、インクルードファイルはinclude/以下にあるというプロジェクトもあると思います。そんな場合はインクルードパスを指定すればOKです。

Jamroot.jam
import testing ;
run src/main.cpp
    src/source1.cpp
    src/source2.cpp
    :
    :
    :
    <include>include
    ;

環境変数からインクルードパスを取得するには

os.environで環境変数にアクセスできます。

Jamroot.jam
import testing ;
import os ;

local BOOST_ROOT = [ os.environ BOOST_ROOT ] ;

run src/main.cpp
    src/source1.cpp
    src/source2.cpp
    :
    :
    :
    <include>$(BOOST_ROOT)
    ;

リファレンスだとここに書いてあります。
http://www.boost.org/boost-build2/doc/html/bbv2/faq/envar.html

Boostライブラリーとリンクするには

Boostのように、Boost.Buildで管理されているプロジェクトであればとても簡単です。

以下の例を見てください。

Jamroot.jam
import testing ;
import os ;

use-project /boost : [ os.environ BOOST_ROOT ] ;

run hello_world.cpp /boost/system ;

ここで私が最初わからなかったのは、use-projectに何を指定すればよいのかと、/boost/systemとは何か、なぜ/boostではないのかです。

一応この辺を何回も読めばさらっと書いてあるような気もしますが
http://www.boost.org/boost-build2/doc/html/bbv2/tutorial/hierarchy.html
結構大事なことなのにわかりにくいです。

まず、use-projectでJamroot(またはJamfile)のあるフォルダーへのエイリアスを作り、そこからたどっていきます。

この例だと /boost にはJamrootがあります。
そのなかでいくつかサブプロジェクトが定義されており、/boost/systemはサブプロジェクトの名前になります。

プロジェクトを指定するだけではなく、さらにプロジェクトの中のライブラリ名まで明示したいような場合は、//で区切って名前を書きます。

例えば以下のような感じです。

Jamroot.jam
import testing ;
import os ;

use-project /boost : [ os.environ BOOST_ROOT ] ;

run hello_world.cpp /boost/system//boost_system ;

逆に、他の人が書いたプロジェクトファイルを調べたいときは、
まず、use-projectされている先にJamrootかJamfileがあるのでそこを見ます。

次に、もし/boost/systemのようにサブプロジェクトが使われている場合は、Jamrootの中のサブプロジェクトの定義(エイリアス)を探すか、あるいはフォルダ階層を探します。

//が指定されている場合は、さらにライブラリーなどのターゲットが明示的に指定されています。

外部ライブラリーとリンクするには

例として、Google Testを利用してみます。

まずはGoogle Testのソースコードを vendor/gtest/google-test/ の中に展開します。

Google TestをビルドするためのJamfileを作ります。

vendor/gtest/Jamfile.jam
lib gtest
    :
    googletest/src/gtest-all.cc
    :
    <include>googletest/include
    <include>googletest
    <link>static
    :
    :
    <include>googletest/include
    ;

それをJamrootからuse-projectして利用します。

Jamroot.jam
import testing ;
import os ;

use-project /boost : [ os.environ BOOST_ROOT ] ;
use-project /gtest : vendor/gtest ;

run hello_world.cpp /boost/system /gtest ;

工夫としては、外部のライブラリーの中にプロジェクトファイルを置くのは嫌だったので、ひとつフォルダーを入れてそこにプロジェクトファイルを置いたことですね。

まとめると

Boost.Buildはとても短い記述でビルドからテスト実行まで面倒をみてくれるのでとても便利です。
コマンドラインツールだから小回りもきくし、Jenkinsとの相性も良いです。

みなさん、もっとbjam使いましょう! ← 言いたかったこと

もっと詳しく知るには

以下に参考になるサイトを書いておきます。