<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<!--
  BBv2 Tutorial Source

  Copyright Takeshi Mouri 2008.
  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE_1_0.txt or copy at
  http://www.boost.org/LICENSE_1_0.txt)
-->
<article lang="ja">
  <artheader>
    <title>Boost.Build バージョン2 チュートリアル</title>
    <author lang="en">
      <firstname>Takeshi</firstname>
      <surname>Mouri</surname>
    </author>
    <copyright lang="en">
      <year>2008</year>
      <holder>Takeshi Mouri</holder>
    </copyright>
  </artheader>
  <section id="introduction">
    <title>はじめに</title>
    <para><application class="software" lang="en">Boost.Build</application> バージョン2 (<abbrev lang="en">BBv2</abbrev>)は「<ulink href="http://www.boost.org/" lang="en">Boost C++ Libraries</ulink>」で利用されているビルドシステムで、<application class="software" lang="en">Boost.Jam</application>(<abbrev lang="en">bjam</abbrev>)ツールとそのモジュール群から成ります。</para>
    <para><abbrev lang="en">BBv2</abbrev>には次のような特徴があります。</para>
    <itemizedlist>
      <listitem><simpara>マルチコンパイラ/マルチプラットフォーム</simpara></listitem>
      <listitem><simpara>表現力の高いJam言語によるスクリプティング</simpara></listitem>
      <listitem><simpara>モジュールによる機能拡張</simpara></listitem>
    </itemizedlist>
    <para>文法やモジュールに関しては、<ulink url="http://hamigaki.sourceforge.jp/" lang="en">Hamigaki C++ Libraries</ulink>の付録A「<ulink url="http://hamigaki.sourceforge.jp/doc/html/bbv2.html">Boost.Buildについて</ulink>」も参考にしてください。</para>
  </section>
  <section id="jam-language">
    <title>Jam言語</title>
    <para><application class="software" lang="en">Boost.Jam</application>はJam言語に基づくインタプリタです。次のコードはJam言語におけるHelloWorldプログラムです。</para>
    <programlisting>EXIT Hello, world! ;</programlisting>
    <para>Jam言語にはC/C++のような区切り文字の概念はないので、セミコロンの前の空白は必須です。このプログラムを実行するには、プログラムを<filename>hello.jam</filename>という名前で保存して、コマンドラインから次のコマンドを入力します。</para>
    <programlisting><command>bjam</command> <option>-f</option> <filename>hello.jam</filename></programlisting>
    <para>結果は次のように出力されます。</para>
    <screen>Hello, world!</screen>
    <para>メッセージを出力するのに<computeroutput>EXIT</computeroutput>というコマンド(Jam言語ではルールと呼びます)を用いているのが奇妙に思えるかもしれません。実は、<computeroutput>EXIT</computeroutput>はメッセージを出力してスクリプトの実行を終了するルールで、単にメッセージを表示する<computeroutput>ECHO</computeroutput>というルールもあるのですが、これを用いると次のようなエラーメッセージが表示されることになります。</para>
    <screen><![CDATA[Hello, world!
don't know how to make all
...found 1 target...
...can't find 1 target...]]></screen>
    <para>これは<application class="software" lang="en">Boost.Jam</application>がビルドツールであるためで、Jamスクリプトが正常に終了するとビルド処理に移るのですが、既定のビルドターゲット<computeroutput>all</computeroutput>のビルド方法を指定していないため、ビルドに失敗しているのです。</para>
    <para>先ほどの例では、<computeroutput>EXIT</computeroutput>ルールによってスクリプトの実行が中断され、ビルド処理が実行されなかったのでした。</para>
  </section>
  <section id="variables">
    <title>変数</title>
    <para>続いて変数の使い方を示します。</para>
    <programlisting><![CDATA[name = Taro ;
EXIT "Hello $(name)." ;
]]></programlisting>
    <para>一行目が変数への代入です。代入された値を参照するには「$(<replaceable>変数名</replaceable>)」とします。実行結果は次のようになります。</para>
    <screen>Hello Taro.</screen>
    <para>Jam言語で使用するデータ型は文字列のリストだけです。よって変数にも複数の文字列を代入できます。</para>
    <programlisting><![CDATA[name = Taro Hanako ;
EXIT "Hello $(name)." ;
]]></programlisting>
    <para>このプログラムの出力は興味深いものです。</para>
    <screen>Hello Taro. Hello Hanako.</screen>
    <para>このように、リストを連結する際は直積になります。</para>
  </section>
  <section id="rules">
    <title>ルール</title>
    <para>ルールは他のプログラミング言語における関数に相当する機能です。</para>
    <programlisting><![CDATA[rule hello
{
    ECHO Hello, world ;
}

hello ;
EXIT ;
]]></programlisting>
    <para>キーワード<computeroutput>rule</computeroutput>がルールを定義することを示します。その後ろにルールの名前、ルール本体と続きます。こうして定義したルールは組み込みのルールと同様に使用することができます。</para>
    <para>次のJamスクリプトは引数を使った例です。</para>
    <programlisting><![CDATA[rule greet
{
    ECHO "Hello, $(1)-$(2)." ;
}

greet Taro : kun ;
greet Hanako : san ;
EXIT ;
]]></programlisting>
    <para>Jam言語ではルール呼び出しの際に引数を「:」で区切ります。ルール側では順に「$(1)、$(2)、…、$(9)」として参照できます。<footnote><simpara>引数の数は9個が最大です。</simpara></footnote></para>
    <para><application class="software" lang="en">Boost.Jam</application>の拡張として、仮引数に名前を付けることもできます。</para>
    <programlisting><![CDATA[rule greet ( name : postfix )
{
    ECHO "Hello, $(name)-$(postfix)." ;
}
]]></programlisting>
    <para>また、仮引数の名前の次に「?」、「*」、「+」を置くことで、リストのサイズを制限することもできます。</para>
    <programlisting><![CDATA[rule example ( targets + : sources * : option ? ) { }

example a ;
example a : b ;
example a : b : c ;
example a : : b ;
example a b c : d e : f ;

EXIT ;
]]></programlisting>
    <para>各シンボルの意味は次のようになります。</para>
    <table frame="all">
      <title>仮引数の制約</title>
      <tgroup cols="2">
        <thead>
          <row>
            <entry>シンボル</entry>
            <entry>リストのサイズ</entry>
          </row>
        </thead>
        <tbody>
          <row>
            <entry>?</entry>
            <entry>0または1</entry>
          </row>
          <row>
            <entry>*</entry>
            <entry>0以上</entry>
          </row>
          <row>
            <entry>+</entry>
            <entry>1以上</entry>
          </row>
          <row>
            <entry>なし</entry>
            <entry>1</entry>
          </row>
        </tbody>
      </tgroup>
    </table>
    <para>戻り値は<computeroutput>return</computeroutput>文で設定します。また、戻り値が必要な箇所ではルールの呼び出しを「[」と「]」で囲みます。</para>
    <programlisting><![CDATA[rule greet-msg ( name : postfix )
{
    return "Hello, $(name)-$(postfix)." ;
}

EXIT [ greet-msg Taro : kun ] ;
]]></programlisting>
    <para>なお、Jam言語の<computeroutput>return</computeroutput>文は戻り値を設定するだけで制御フローに影響しないので、<computeroutput>return</computeroutput>文が実行された後もルールの実行が継続されることに注意してください。<footnote><simpara>Jamのオリジナル実装である<application class="software" lang="en">Perforce Jam</application>のバージョン2.5以降では<computeroutput>return</computeroutput>文がルールの実行を中断するようになりました。しかし、<application class="software" lang="en">Boost.Jam</application>はバージョン2.4を基にしているため、この機能を持っていません。</simpara></footnote></para>
  </section>
  <section id="control-flow">
    <title>制御フロー</title>
    <para>Jam言語には制御構文として、<computeroutput>for</computeroutput>文、<computeroutput>if</computeroutput>文、<computeroutput>return</computeroutput>文、<computeroutput>switch</computeroutput>文、<computeroutput>while</computeroutput>文を持っています。ここでは<computeroutput>for</computeroutput>文と<computeroutput>if</computeroutput>文のみ説明します。</para>
    <para>まず、<computeroutput>for</computeroutput>文の例を示します。</para>
    <programlisting><![CDATA[for x in Taro Hanako Saburo
{
    ECHO Hello, $(x). ;
}

EXIT ;
]]></programlisting>
    <para>実行結果はこうなります。</para>
    <screen><![CDATA[Hello, Taro.
Hello, Hanako.
Hello, Saburo.

]]></screen>
    <para>Jam言語の<computeroutput>for</computeroutput>文は、いわゆる<ulink url="http://ja.wikipedia.org/wiki/Foreach%E6%96%87">foreach文</ulink>で、指定した変数にリストの各要素を代入して順にブロックを評価します。</para>
    <para>続いて、<computeroutput>if</computeroutput>文の例です。</para>
    <programlisting><![CDATA[if $(OS) = NT
{
    EXIT Your system is Windows. ;
}
else
{
    EXIT Your system is not Windows. ;
}
]]></programlisting>
    <para>Windows上で実行した場合の実行結果はこうなります。</para>
    <screen><![CDATA[Your system is Windows.
]]></screen>
    <para>Windows以外ならこうなります。</para>
    <screen><![CDATA[Your system is not Windows.
]]></screen>
    <para>「<computeroutput>$(OS) = NT</computeroutput>」が<computeroutput>if</computeroutput>文の条件で、変数<varname>OS</varname>の値が「NT」なら真となり、条件に続くブロックが評価されます。それ以外の場合は<computeroutput>else</computeroutput>に続くブロックが評価されます。なお、変数<varname>OS</varname>は実行環境のOS名を表す事前定義の変数です。</para>
    <para>条件に使用できる演算子は以下の通りです。</para>
    <table frame="all">
      <title>演算子一覧</title>
      <tgroup cols="2">
        <thead>
          <row>
            <entry>条件式</entry>
            <entry>評価値</entry>
          </row>
        </thead>
        <tbody>
          <row>
            <entry><replaceable>a</replaceable></entry>
            <entry><replaceable>a</replaceable>に空でない文字列が含まれていれば真</entry>
          </row>
          <row>
            <entry><replaceable>a</replaceable> = <replaceable>b</replaceable></entry>
            <entry><replaceable>a</replaceable>と<replaceable>b</replaceable>の要素がすべて同じ場合に真</entry>
          </row>
          <row>
            <entry><replaceable>a</replaceable> != <replaceable>b</replaceable></entry>
            <entry><replaceable>a</replaceable>と<replaceable>b</replaceable>の要素に同じでないものが含まれる場合に真</entry>
          </row>
          <row>
            <entry><replaceable>a</replaceable> &lt; <replaceable>b</replaceable></entry>
            <entry>辞書順で<replaceable>a</replaceable>が<replaceable>b</replaceable>より小さい場合に真</entry>
          </row>
          <row>
            <entry><replaceable>a</replaceable> &lt;= <replaceable>b</replaceable></entry>
            <entry>辞書順で<replaceable>a</replaceable>が<replaceable>b</replaceable>以下の場合に真</entry>
          </row>
          <row>
            <entry><replaceable>a</replaceable> &gt; <replaceable>b</replaceable></entry>
            <entry>辞書順で<replaceable>a</replaceable>が<replaceable>b</replaceable>より大きい場合に真</entry>
          </row>
          <row>
            <entry><replaceable>a</replaceable> &gt;= <replaceable>b</replaceable></entry>
            <entry>辞書順で<replaceable>a</replaceable>が<replaceable>b</replaceable>以上の場合に真</entry>
          </row>
          <row>
            <entry><replaceable>a</replaceable> in <replaceable>b</replaceable></entry>
            <entry><replaceable>a</replaceable>の要素が全て<replaceable>b</replaceable>に含まれる場合に真</entry>
          </row>
          <row>
            <entry>! <replaceable>cond</replaceable></entry>
            <entry><replaceable>cond</replaceable>が偽の場合に真</entry>
          </row>
          <row>
            <entry><replaceable>a</replaceable> &amp;&amp; <replaceable>b</replaceable></entry>
            <entry><replaceable>a</replaceable>が真かつ<replaceable>b</replaceable>が真の場合に真</entry>
          </row>
          <row>
            <entry><replaceable>a</replaceable> || <replaceable>b</replaceable></entry>
            <entry><replaceable>a</replaceable>が真または<replaceable>b</replaceable>が真の場合に真</entry>
          </row>
          <row>
            <entry>( <replaceable>cond</replaceable> )</entry>
            <entry><replaceable>cond</replaceable>が真の場合に真</entry>
          </row>
        </tbody>
      </tgroup>
    </table>
  </section>
  <section id="configuration">
    <title>環境設定</title>
    <para>ここまでは<application class="software" lang="en">Boost.Jam</application>をスクリプトエンジンとして利用しましたが、通常は<option>-f</option>オプションを使用せずに組み込みのスクリプトを利用します。この場合、いくつかの設定をする必要があります。</para>
    <variablelist>
      <varlistentry>
        <term><ulink url="http://www.google.co.jp/search?hl=ja&amp;q=%E7%92%B0%E5%A2%83%E5%A4%89%E6%95%B0">環境変数</ulink><envar>BOOST_BUILD_PATH</envar></term>
        <listitem>
          <para><abbrev lang="en">BBv2</abbrev>のインストール先ディレクトリ(<filename>boost-build.jam</filename>があるディレクトリ)を指定します。指定されていない場合は環境変数<envar>BOOST_ROOT</envar>が使用されます。</para>
          <example>
            <title><filename>boost-build-2.0-m12.zip</filename>を<filename class="directory">C:\tools\boost-build</filename>に展開した場合</title>
            <programlisting>set BOOST_BUILD_PATH=C:\tools\boost-build</programlisting>
          </example>
          <example>
            <title><filename>boost_1_34_1.zip</filename>を<filename class="directory">C:\Boost\boost_1_34_1</filename>に展開した場合</title>
            <programlisting>set BOOST_ROOT=C:\Boost\boost_1_34_1</programlisting>
          </example>
          <example>
            <title><filename>boost_1_34_1.zip</filename>を<filename class="directory">C:\tools\boost_1_34_1</filename>に展開し、<filename class="directory">C:\tools\hamigaki_0_40_1</filename>に展開したHamigakiライブラリ付属モジュールも使用する場合</title>
            <programlisting>set BOOST_BUILD_PATH=C:\tools\boost_1_34_1\tools\build\v2;C:\tools\hamigaki_0_40_1\tools\build</programlisting>
          </example>
        </listitem>
      </varlistentry>
      <varlistentry>
        <term>設定ファイル<filename>user-config.jam</filename></term>
        <listitem>
          <para>使用するツールセットの設定のため、<ulink url="http://boost.org/boost-build2/doc/html/bbv2/reference.html#bbv2.reference.init.config">ホームディレクトリ</ulink>に用意するJamスクリプトファイルです。いくつか例を示します。</para>
          <example>
            <title>Microsoft Visual C++用の設定</title>
            <programlisting>using msvc ;</programlisting>
          </example>
          <example>
            <title>GNU GCC用の設定</title>
            <programlisting>using gcc ;</programlisting>
          </example>
          <example>
            <title>VC8とgcc3.4.5用の設定</title>
            <programlisting>using msvc : 8.0  ;
using gcc : 3.4.5 : C:/MinGW/bin/g++.exe ;</programlisting>
          </example>
          <para>他のツールセットや設定の詳細に関しては、ユーザーマニュアルの「<ulink url="http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html" lang="en">Builtin tools</ulink>」の項を参考にしてください。</para>
        </listitem>
      </varlistentry>
    </variablelist>
  </section>
  <section id="simple-usage">
    <title>簡単な使い方</title>
    <para>次のJamスクリプトは、C++ソースファイル<filename>hello.cpp</filename>から実行ファイル<filename>hello</filename>を作成するものです。</para>
    <programlisting>exe hello : hello.cpp ;</programlisting>
    <para>これを<filename>Jamroot</filename><footnote><simpara><filename>Jamroot</filename>の代わりに<filename>Jamroot.jam</filename>も使用できます。先頭は小文字でも構いません。また、グローバル変数<varname>JAMROOT</varname>でファイル名を指定することもできます。</simpara></footnote>という名前でソースファイルと同じディレクトリに保存します。実際にビルドするには<command>bjam</command>コマンドをオプションを付けずに実行するだけです。<application class="software">Microsoft Visual C++ 2005</application>での実行結果を示します。</para>
    <screen><![CDATA[...found 10 targets...
...updating 6 targets...
MkDir1 bin
MkDir1 bin\msvc-8.0
MkDir1 bin\msvc-8.0\debug
MkDir1 bin\msvc-8.0\debug\threading-multi
compile-c-c++ bin\msvc-8.0\debug\threading-multi\hello.obj
hello.cpp
msvc.link bin\msvc-8.0\debug\threading-multi\hello.exe
...updated 6 targets...]]></screen>
    <para>この例では、<filename>bin\msvc-8.0\debug\threading-multi\hello.exe</filename>が生成された実行ファイルになります。この長いパスはツールセットの種類やコンパイラオプションを元に決定されるもので、異なる設定でビルドしてもファイルが重複しないようになっています。</para>
    <para>ビルドの設定は<command>bjam</command>のオプションで変更できます。</para>
    <example>
      <title>GNU GCCでビルド</title>
      <programlisting><command>bjam</command> toolset=gcc</programlisting>
    </example>
    <example>
      <title>リリースモードでビルド</title>
      <programlisting><command>bjam</command> release</programlisting>
    </example>
    <example>
      <title>VC8とgcc3.4.5でビルド</title>
      <programlisting><command>bjam</command> toolset=msvc-8.0,gcc-3.4.5</programlisting>
    </example>
    <para>また、<option>--clean</option>オプションを指定するれば、ビルドする代わりに削除を行うこともできます。</para>
    <para>より複雑なオプションについては、ユーザーマニュアルの「<ulink url="http://boost.org/boost-build2/doc/html/bbv2/reference.html#bbv2.reference.init.args" lang="en">Command line arguments</ulink>」の項を見てください。</para>
  </section>
  <section id="building-libraries">
    <title>ライブラリのビルド</title>
    <para>今度はライブラリのビルドです。次のJamスクリプトは<filename>hello.cpp</filename>からスタティックリンクライブラリを作成するものです。</para>
    <programlisting><![CDATA[lib hello : hello.cpp : <link>static ;]]></programlisting>
    <para>実行結果は次のようになります。</para>
    <screen><![CDATA[...found 12 targets...
...updating 7 targets...
MkDir1 bin
MkDir1 bin\msvc-8.0
MkDir1 bin\msvc-8.0\debug
MkDir1 bin\msvc-8.0\debug\link-static
MkDir1 bin\msvc-8.0\debug\link-static\threading-multi
compile-c-c++ bin\msvc-8.0\debug\link-static\threading-multi\hello.obj
hello.cpp
msvc.archive bin\msvc-8.0\debug\link-static\threading-multi\libhello.lib
...updated 7 targets...]]></screen>
    <para><computeroutput>lib</computeroutput>ルールがライブラリを作るためのルールで、「<computeroutput><![CDATA[<link>static]]></computeroutput>」という指定がスタティックリンクライブラリを作成することを示しています。この指定を「<computeroutput><![CDATA[<link>shared]]></computeroutput>」にすればダイナミックリンクライブラリを作成できるのですが、この場合はWindowsの関数エクスポートをサポートするためにソースコードに次のような変更を加える必要があります。</para>
    <example>
      <title><filename>hello.hpp</filename></title>
      <programlisting><![CDATA[#ifndef HELLO_HPP
#define HELLO_HPP

#include <boost/config.hpp>

#if defined(BOOST_HAS_DECLSPEC)
    #if defined(BOOST_ALL_DYN_LINK) || defined(HELLO_DYN_LINK)
        #ifdef HELLO_SOURCE
            #define HELLO_DECL __declspec(dllexport)
        #else
            #define HELLO_DECL __declspec(dllimport)
        #endif
    #endif
#endif

#if !defined(HELLO_DECL)
    #define HELLO_DECL
#endif

HELLO_DECL void hello();

#endif // #ifndef HELLO_HPP
]]></programlisting>
    </example>
    <example>
      <title><filename>hello.cpp</filename></title>
      <programlisting><![CDATA[#define HELLO_SOURCE
#include "hello.hpp"
#include <iostream>

HELLO_DECL void hello()
{
    std::cout << "Hello, world!" << std::endl;
}
]]></programlisting>
    </example>
    <para><filename>hello.hpp</filename>でマクロ<varname>HELLO_DYN_LINK</varname>をダイナミックリンクするかどうかの判定に使用しているので、<filename>Jamroot</filename>でこれを定義します。また、Boostのヘッダファイルを使用しているので、インクルードディレクトリの設定も必要です。</para>
    <programlisting><![CDATA[import os ;

BOOST_INCLUDE = [ os.environ BOOST_INCLUDE ] ;

lib hello
    :
    hello.cpp
    :
    <include>$(BOOST_INCLUDE)
    <link>shared:<define>HELLO_DYN_LINK
    ;
]]></programlisting>
    <para>ここではインクルードディレクトリを環境変数<envar>BOOST_INCLUDE</envar>で指定することにしています。環境変数を調べるには、<computeroutput>os.environ</computeroutput>ルールを使用します。<computeroutput>os.environ</computeroutput>ルールを呼び出す前に<computeroutput><![CDATA[import os ;]]></computeroutput>が必要なことに注意してください。<computeroutput>import</computeroutput>ルールはモジュールを読み込むためのルールです。<computeroutput>os.environ</computeroutput>ルールは<computeroutput>os</computeroutput>モジュールで定義されているので、この読み込みが必要となります。</para>
    <para>「<computeroutput><![CDATA[<include>$(BOOST_INCLUDE)]]></computeroutput>」がインクルードディレクトリの指定、「<computeroutput><![CDATA[<link>shared:<define>HELLO_DYN_LINK]]></computeroutput>」がダイナミックリンクの場合のみマクロ<varname>HELLO_DYN_LINK</varname>を定義するという意味です。</para>
    <para>今度はスタティックリンク/ダイナミックリンク両対応なので、<command>bjam</command>のオプションで<computeroutput>link=static</computeroutput>を指定するとスタティックリンクに、<computeroutput>link=shared</computeroutput>を指定するとダイナミックリンクになります。どちらも指定しなければ、通常はダイナミックリンクになります。</para>
    <para>Boostのガイドライン「<ulink url="http://www.boost.org/more/separate_compilation.html" lang="en">Guidelines for Authors of Boost Libraries Containing Separate Source</ulink>」も見てください。</para>
  </section>
  <section id="linking-libraries">
    <title>ライブラリのリンク</title>
    <para>前の節で作成したライブラリhelloを利用するプログラムを考えます。</para>
    <example>
      <title><filename>main.cpp</filename></title>
      <programlisting><![CDATA[#include "hello.hpp"

int main()
{
    hello();
}
]]></programlisting>
    </example>
    <para>これをビルドするには、次のようなJamスクリプトを<filename>Jamroot</filename>に追加します。</para>
    <programlisting><![CDATA[import os ;

BOOST_INCLUDE = [ os.environ BOOST_INCLUDE ] ;

exe main
    :
    main.cpp
    hello
    :
    <include>$(BOOST_INCLUDE)
    <link>shared:<define>HELLO_DYN_LINK
    ;
]]></programlisting>
    <para>ソースファイルにライブラリhelloを追加することで、このライブラリをリンクすることができます。</para>
    <para>また、<filename>main.cpp</filename>が<filename>main.hpp</filename>をインクルードしているので、ライブラリhelloと同じインクルードディレクトリとマクロ定義が必要になります。このような設定をライブラリ利用者側で行うのは面倒です。この問題を解決するには、<computeroutput>lib</computeroutput>ルールの呼び出しにusage-requirementsと呼ばれる引数を追加します。</para>
    <programlisting><![CDATA[import os ;

BOOST_INCLUDE = [ os.environ BOOST_INCLUDE ] ;

lib hello
    :
    hello.cpp
    :
    <include>$(BOOST_INCLUDE)
    <link>shared:<define>HELLO_DYN_LINK
    :
    :
    <include>$(BOOST_INCLUDE)
    <link>shared:<define>HELLO_DYN_LINK
    ;

exe main : main.cpp hello ;
]]></programlisting>
    <para>同じ設定が並んでいるので分かりにくいですが、下に追加した引数がusage-requirementsで、このライブラリを利用するターゲットのビルド設定に自動的に追加されます。</para>
  </section>
  <section id="sub-projects">
    <title>サブプロジェクト</title>
    <para>前の節ではライブラリと実行ファイルのビルドを一つの<filename>Jamroot</filename>で行っていました。今度はこの二つを分離してみます。ディレクトリ階層は次のように変更します。</para>
    <screen><![CDATA[top/
  |
  +-- Jamroot
  |
  +-- exe/
  |    |
  |    +-- Jamfile
  |    +-- main.cpp
  |
  +-- lib/
       |
       +-- Jamfile
       +-- hello.cpp
       +-- hello.hpp
]]></screen>
    <para>これまで使ってきた<filename>Jamroot</filename>はプロジェクトに一つだけ存在し、名前の示す通りプロジェクトのルートディレクトリに配置します。個々のディレクトリ(サブプロジェクト)では代わりに<filename>Jamfile</filename><footnote><simpara><filename>Jamfile</filename>の代わりに<filename>Build.jam</filename>、<filename>Jamfile.v2</filename>、<filename>Jamfile.jam</filename>も使用できます。先頭は小文字でも構いません。また、グローバル変数<varname>JAMFILE</varname>でファイル名を指定することもできます。</simpara></footnote>という名前のファイルを使用します。</para>
    <example>
      <title><filename>exe/Jamfile</filename></title>
      <programlisting>exe main : main.cpp ../lib//hello ;</programlisting>
    </example>
    <para>実行ファイルのビルドではライブラリの指定方法が変わっています。他のプロジェクトのターゲットを参照するには、「<replaceable>プロジェクトのパス</replaceable>//<replaceable>ターゲット名</replaceable>」という形式を使用します。</para>
    <example>
      <title><filename>lib/Jamfile</filename></title>
      <programlisting><![CDATA[import os ;

BOOST_INCLUDE = [ os.environ BOOST_INCLUDE ] ;

lib hello
    :
    hello.cpp
    :
    <include>$(BOOST_INCLUDE)
    <link>shared:<define>HELLO_DYN_LINK
    :
    :
    <include>.
    <include>$(BOOST_INCLUDE)
    <link>shared:<define>HELLO_DYN_LINK
    ;
]]></programlisting>
    </example>
    <para><filename>hello.hpp</filename>のパスが変更されたため、ライブラリのビルドではusage-requirementsに<computeroutput><![CDATA[<include>.]]></computeroutput>が追加されています。ここでディレクトリ「<filename class="directory">.</filename>」は、<filename class="directory">exe</filename>ではなく<filename class="directory">lib</filename>を意味します。</para>
    <para>また、<filename>Jamroot</filename>は空ファイルで構いませんが、プロジェクトのルートディレクトリを示すために必要です。</para>
    <para>なお、ビルドの際は依存するターゲットも自動的にビルドされます。<filename class="directory">exe</filename>でビルドした場合の出力例を示します。</para>
    <screen><![CDATA[...found 54 targets...
...updating 13 targets...
MkDir1 bin
MkDir1 bin\msvc-8.0
MkDir1 bin\msvc-8.0\debug
MkDir1 bin\msvc-8.0\debug\threading-multi
compile-c-c++ bin\msvc-8.0\debug\threading-multi\main.obj
main.cpp
MkDir1 ..\lib\bin
MkDir1 ..\lib\bin\msvc-8.0
MkDir1 ..\lib\bin\msvc-8.0\debug
MkDir1 ..\lib\bin\msvc-8.0\debug\threading-multi
compile-c-c++ ..\lib\bin\msvc-8.0\debug\threading-multi\hello.obj
hello.cpp
msvc.link.dll ..\lib\bin\msvc-8.0\debug\threading-multi\hello.dll
   ライブラリ ..\lib\bin\msvc-8.0\debug\threading-multi\hello.lib とオブジェクト
 ..\lib\bin\msvc-8.0\debug\threading-multi\hello.exp を作成中
msvc.link bin\msvc-8.0\debug\threading-multi\main.exe
...updated 13 targets...
]]></screen>
  </section>
  <section id="project-settings">
    <title>プロジェクト設定</title>
    <para>前の節でプロジェクトを分割したため、ビルドディレクトリが２つに分離してしまいました。これを一箇所にまとめるには<filename>Jamroot</filename>に以下のJamスクリプトを追加します。</para>
    <programlisting><![CDATA[project : build-dir bin ;
]]></programlisting>
    <para>これでビルドディレクトリはプロジェクトのルートディレクトリ配下の<filename class="directory">bin</filename>ディレクトリが利用されるようになります。</para>
    <para><computeroutput>project</computeroutput>ルールで設定できるのはビルドディレクトリだけではありません。次のJamスクリプトはBoostのヘッダファイルをプロジェクト全体で利用できるようにします。</para>
    <programlisting><![CDATA[import os ;

BOOST_INCLUDE = [ os.environ BOOST_INCLUDE ] ;

project
    : build-dir bin
    : requirements <include>$(BOOST_INCLUDE)
    ;
]]></programlisting>
    <para><computeroutput>project</computeroutput>ルールで設定できるオプションには次のようなものがあります。</para>
    <table frame="all">
      <title><computeroutput>project</computeroutput>ルールのオプション</title>
      <tgroup cols="2">
        <thead>
          <row>
            <entry>オプション名</entry>
            <entry>意味</entry>
          </row>
        </thead>
        <tbody>
          <row>
            <entry>source-location</entry>
            <entry>ソースファイルのディレクトリ位置</entry>
          </row>
          <row>
            <entry>requirements</entry>
            <entry>ビルドに必要な設定</entry>
          </row>
          <row>
            <entry>default-build</entry>
            <entry>既定のビルド設定</entry>
          </row>
          <row>
            <entry>build-dir</entry>
            <entry>ビルドファイルの出力先ディレクトリ</entry>
          </row>
        </tbody>
      </tgroup>
    </table>
    <para>オプションの指定順に決まりはありませんが、オプションの名前と値を対にして設定する必要があります。</para>
    <para>また、これらの設定はサブプロジェクトでも行えます。</para>
  </section>
  <section id="installing-targets">
    <title>ターゲットのインストール</title>
    <para>ここまでは実行ファイルとライブラリのビルドのみを行ってきました。BBv2でビルドしたプログラムを実行するにはどうすればよいでしょうか？</para>
    <para>スタティックリンクの場合は簡単です。ビルドディレクトリに生成された実行ファイルを起動するだけです。</para>
    <para>一方、ダイナミックリンクの場合は環境変数の変更が必要です。例えば、次のようになるでしょう。</para>
    <screen><![CDATA[cd exe
bjam
setlocal
set Path=..\bin\lib\msvc-8.0\debug\threading-multi;%Path%
..\bin\exe\msvc-8.0\debug\threading-multi\main.exe
endlocal
]]></screen>
    <para>この方法では非常に不便です。このような場合は<computeroutput>install</computeroutput>ルールを使って、実行ファイルとダイナミックリンクライブラリを同じディレクトリにコピーすると便利です。<filename>Jamfile</filename>に次のJamスクリプトを追加します。</para>
    <programlisting><![CDATA[install dist
    :
    main
    :
    <install-dependencies>on
    <install-type>EXE
    <install-type>LIB
    <location>../dist
    ;
]]></programlisting>
    <para>これで<filename class="directory">dist</filename>ディレクトリに<filename>hello.exe</filename>と<filename>hello.dll</filename>、<filename>hello.lib</filename>がコピーされます。Windowsでは実行ファイルと同じディレクトリのDLLは環境変数<envar>PATH</envar>に関係なく参照できるので、そのまま実行できるようになります。</para>
    <para>なお、UNIX系のOSではBBv2が既定で共有ライブラリのパスを実行ファイルに埋め込むので、そのまま実行できます。逆に<computeroutput>install</computeroutput>ルールでコピーする際は共有ライブラリのパスを埋め込まない形で再リンクされるため、別途環境変数(<envar>LD_LIBRARY_PATH</envar>等)を設定する必要があります。</para>
    <para>常にインストールされるのが不便であれば、次のJamスクリプトを追加してください。</para>
    <programlisting>explicit dist ;</programlisting>
    <para><computeroutput>explicit</computeroutput>ルールはターゲットが暗黙的にビルドされないようにします。よって、インストールしたい場合は明示的に行う必要があります。</para>
    <programlisting><command>bjam</command> dist</programlisting>
  </section>
  <section id="unit-testing">
    <title>単体テスト</title>
    <para>BBv2でプログラムを直接実行することもできます。この場合、<computeroutput>exe</computeroutput>ルールの代わりに<computeroutput>unit-test</computeroutput>ルールを使用します。</para>
    <programlisting><![CDATA[import testing ;
unit-test main : main.cpp ../lib//hello ;
]]></programlisting>
    <para><computeroutput>unit-test</computeroutput>ルールは<computeroutput>testing</computeroutput>モジュールで定義されているので、インポートが必要です。</para>
    <para>ビルド結果の例を示します。</para>
    <screen><![CDATA[...found 55 targets...
...updating 15 targets...
MkDir1 ..\bin
MkDir1 ..\bin\exe
MkDir1 ..\bin\exe\msvc-8.0
MkDir1 ..\bin\exe\msvc-8.0\debug
MkDir1 ..\bin\exe\msvc-8.0\debug\threading-multi
compile-c-c++ ..\bin\exe\msvc-8.0\debug\threading-multi\main.obj
main.cpp
MkDir1 ..\bin\lib
MkDir1 ..\bin\lib\msvc-8.0
MkDir1 ..\bin\lib\msvc-8.0\debug
MkDir1 ..\bin\lib\msvc-8.0\debug\threading-multi
compile-c-c++ ..\bin\lib\msvc-8.0\debug\threading-multi\hello.obj
hello.cpp
msvc.link.dll ..\bin\lib\msvc-8.0\debug\threading-multi\hello.dll
   ライブラリ ..\bin\lib\msvc-8.0\debug\threading-multi\hello.lib とオブジェクト
 ..\bin\lib\msvc-8.0\debug\threading-multi\hello.exp を作成中
msvc.link ..\bin\exe\msvc-8.0\debug\threading-multi\main.exe
testing.unit-test ..\bin\exe\msvc-8.0\debug\threading-multi\main.passed
Hello, world!
...updated 15 targets...
]]></screen>
    <para>そのほか、<computeroutput>testing</computeroutput>モジュールには次のようなルールが含まれています。</para>
    <table frame="all">
      <title><computeroutput>testing</computeroutput>モジュールのルール</title>
      <tgroup cols="2">
        <thead>
          <row>
            <entry>ルール</entry>
            <entry>意味</entry>
          </row>
        </thead>
        <tbody>
          <row>
            <entry>rule compile ( sources + : requirements * : target-name ? )</entry>
            <entry>コンパイルに成功することを確認する</entry>
          </row>
          <row>
            <entry>rule compile-fail ( sources + : requirements * : target-name ? )</entry>
            <entry>コンパイルに失敗することを確認する</entry>
          </row>
          <row>
            <entry>rule link ( sources + : requirements * : target-name ? )</entry>
            <entry>コンパイル、リンクに成功することを確認する</entry>
          </row>
          <row>
            <entry>rule link-fail ( sources + : requirements * : target-name ? )</entry>
            <entry>コンパイルに成功し、リンクに失敗することを確認する</entry>
          </row>
          <row>
            <entry>rule run ( sources + : args * : input-files * : requirements * : target-name ? : default-build * )</entry>
            <entry>コンパイル、リンク、実行に成功することを確認する</entry>
          </row>
          <row>
            <entry>rule run-fail ( sources + : args * : input-files * : requirements * : target-name ? : default-build * )</entry>
            <entry>コンパイル、リンクに成功し、実行に失敗することを確認する</entry>
          </row>
        </tbody>
      </tgroup>
    </table>
    <para>先ほどの例を<computeroutput>run</computeroutput>を使って書き直すとこうなります。</para>
    <programlisting><![CDATA[import testing ;
run main.cpp ../lib//hello ;
]]></programlisting>
    <para>なお、<computeroutput>run</computeroutput>/<computeroutput>run-fail</computeroutput>ルールはテストに成功した場合、プログラムの出力が見れません。成否を問わず結果を見たい場合は<command>bjam</command>に<option>--verbose-test</option>オプションを渡します。</para>
  </section>
  <section id="using-project">
    <title>プロジェクトの利用</title>
    <para>次のC++コードはBoost.Testライブラリの単体テストフレームワークを利用した簡単なプログラムです。</para>
    <programlisting><![CDATA[#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_CASE(test)
{
    BOOST_CHECK(1 + 1 == 2);
}
]]></programlisting>
    <para>これをビルドするには次のようなJamスクリプトを使用します。</para>
    <programlisting><![CDATA[import os ;
import testing ;

BOOST_ROOT = [ os.environ BOOST_ROOT ] ;

use-project /boost : $(BOOST_ROOT) ;

run test.cpp
    :
    :
    :
    <define>BOOST_ALL_NO_LIB=1
    <library>/boost/test//boost_unit_test_framework
    ;
]]></programlisting>
    <para><computeroutput>use-project</computeroutput>ルールは現在のプロジェクト階層とは別のプロジェクトを参照するためのルールです。ここでは、環境変数<envar>BOOST_ROOT</envar>で指定したディレクトリにあるプロジェクトを<computeroutput>/boost</computeroutput>という名前で参照できるようにしています。</para>
    <para><computeroutput><![CDATA[<library>/boost/test//boost_unit_test_framework]]></computeroutput>は単体テストフレームワークのライブラリをリンクすることを意味しています。マクロ<varname>BOOST_ALL_NO_LIB</varname>はWindows用コンパイラで利用されるオートリンク機能を無効にするためのもので、BBv2は必要に応じてライブラリをビルド/リンクするので、通常は<varname>BOOST_ALL_NO_LIB</varname>を1に定義します。</para>
    <para>参考までにBoost 1.34.1におけるライブラリターゲットの一覧を載せておきます。</para>
    <table frame="all">
      <title>Boostのライブラリターゲット</title>
      <tgroup cols="2">
        <thead>
          <row>
            <entry>ターゲット</entry>
            <entry>意味</entry>
          </row>
        </thead>
        <tbody>
          <row>
            <entry>/boost//headers</entry>
            <entry>Boostのヘッダファイルのみ</entry>
          </row>
          <row>
            <entry>/boost/date_time//boost_date_time</entry>
            <entry>Boost.Date_Time</entry>
          </row>
          <row>
            <entry>/boost/filesystem//boost_filesystem</entry>
            <entry>Boost.Filesystem</entry>
          </row>
          <row>
            <entry>/boost/graph//boost_graph</entry>
            <entry>Boost.Graph</entry>
          </row>
          <row>
            <entry>/boost/iostreams//boost_zlib</entry>
            <entry>zlib</entry>
          </row>
          <row>
            <entry>/boost/iostreams//boost_bzip2</entry>
            <entry>bzip2</entry>
          </row>
          <row>
            <entry>/boost/iostreams//boost_iostreams</entry>
            <entry>Boost.Iostreams</entry>
          </row>
          <row>
            <entry>/boost/program_options//boost_program_options</entry>
            <entry>Boost.Program_options</entry>
          </row>
          <row>
            <entry>/boost/python//boost_python</entry>
            <entry>Boost.Python</entry>
          </row>
          <row>
            <entry>/boost/regex//boost_regex</entry>
            <entry>Boost.Regex</entry>
          </row>
          <row>
            <entry>/boost/serialization//boost_serialization </entry>
            <entry>Boost.Serialization(ナロー文字版)</entry>
          </row>
          <row>
            <entry>/boost/serialization//boost_wserialization </entry>
            <entry>Boost.Serialization(ワイド文字版)</entry>
          </row>
          <row>
            <entry>/boost/signals//boost_signals</entry>
            <entry>Boost.Signals</entry>
          </row>
          <row>
            <entry>/boost/test//boost_prg_exec_monitor</entry>
            <entry>Boost.Testのプログラム実行モニタ</entry>
          </row>
          <row>
            <entry>/boost/test//boost_test_exec_monitor</entry>
            <entry>Boost.Testのテスト実行モニタ</entry>
          </row>
          <row>
            <entry>/boost/test//boost_unit_test_framework</entry>
            <entry>Boost.Testの単体テストフレームワーク</entry>
          </row>
          <row>
            <entry>/boost/thread//boost_thread</entry>
            <entry>Boost.Thread</entry>
          </row>
          <row>
            <entry>/boost/wave//boost_wave</entry>
            <entry>Boost.Wave</entry>
          </row>
        </tbody>
      </tgroup>
    </table>
  </section>
  <section id="prebuilt-libraries">
    <title>ビルド済みライブラリ</title>
    <para>BBv2でビルド済みのライブラリを参照するには二つの方法があります。</para>
    <variablelist>
      <varlistentry>
        <term>名前で検索する方法</term>
        <listitem>
          <para>一つ目の方法は、ライブラリの名前を指定してライブラリパスから検索する方法です。</para>
          <programlisting><![CDATA[lib foo : : <name>foo0 <search>C:/tools/lib ;]]></programlisting>
          <para>この例では、<filename class="directory">C:\tools\lib</filename>から<computeroutput>foo0</computeroutput>という名前のライブラリを検索します。</para>
          <para><computeroutput><![CDATA[<name>]]></computeroutput>プロパティが指定されない場合は<computeroutput>lib</computeroutput>ルールのターゲット名が使用されます。また、<computeroutput><![CDATA[<search>]]></computeroutput>プロパティが指定されない場合はプロジェクトの既定ライブラリパスから検索されます。なお、このターゲットを参照したライブラリまで名前で検索する方式になってしまうため、usage-requirementsに<computeroutput><![CDATA[<search>]]></computeroutput>プロパティを含めてはいけません。そのような場合は代わりに<computeroutput><![CDATA[<library-path>]]></computeroutput>プロパティを使用します。</para>
        </listitem>
      </varlistentry>
      <varlistentry>
        <term>ファイル名を指定する方法</term>
        <listitem>
          <para>もう一つの方法は、ライブラリのパスを直接指定する方法です。</para>
          <programlisting><![CDATA[lib bar : : <file>C:/tools/lib/bar.lib ;]]></programlisting>
          <para>これは説明の必要がないでしょう。</para>
        </listitem>
      </varlistentry>
    </variablelist>
    <para>Boostのようにビルドオプションによってライブラリが異なる場合は、条件を追加した上で同名のライブラリターゲットを定義します。</para>
    <programlisting><![CDATA[import os ;
import testing ;

BOOST_INCLUDE = [ os.environ BOOST_INCLUDE ] ;
BOOST_LIBPATH = [ os.environ BOOST_LIBPATH ] ;

project
    : build-dir bin
    : requirements
      <define>BOOST_ALL_NO_LIB=1
      <include>$(BOOST_INCLUDE)
    ;

lib utf : :
    <variant>debug
    <link>shared
    <file>$(BOOST_LIBPATH)/boost_unit_test_framework-vc80-mt-gd.lib
    : :
    <define>BOOST_TEST_DYN_LINK=1
    <dll-path>$(BOOST_LIBPATH)
    ;

lib utf : :
    <variant>release
    <link>shared
    <file>$(BOOST_LIBPATH)/boost_unit_test_framework-vc80-mt.lib
    : :
    <define>BOOST_TEST_DYN_LINK=1
    <dll-path>$(BOOST_LIBPATH)
    ;

lib utf : :
    <variant>debug
    <link>static
    <file>$(BOOST_LIBPATH)/libboost_unit_test_framework-vc80-mt-gd.lib
    ;

lib utf : :
    <variant>release
    <link>static
    <file>$(BOOST_LIBPATH)/libboost_unit_test_framework-vc80-mt.lib
    ;

run test.cpp utf ;
]]></programlisting>
    <para>ダイナミックリンクの場合は、usage-requirementsにマクロ(ここでは<varname>BOOST_TEST_DYN_LINK</varname>)の定義と<computeroutput><![CDATA[<dll-path>]]></computeroutput>プロパティが必要なことに注意してください。<computeroutput><![CDATA[<dll-path>]]></computeroutput>プロパティは実行時に参照されるDLLのパスを設定するオプションです。</para>
  </section>
  <section id="custom-commands">
    <title>カスタムコマンド</title>
    <para>BBv2は多くのツールに対応していますが、未対応のツールを利用できる手段が用意されています。次のJamスクリプトはsortコマンドを用いて<filename>in.txt</filename>をソートした結果を<filename>out.txt</filename>に出力する例です。</para>
    <programlisting><![CDATA[import make ;

actions sort
{
    sort $(2) > $(1)
}

make out.txt : in.txt : @sort ;
]]></programlisting>
    <para><computeroutput>make</computeroutput>ルールの第一引数は出力ファイル名、第二引数は入力ファイル名、第三引数がビルドに使用するアクションです。アクションとはJamスクリプトの実行後、実際のビルドに利用されるコマンドを定義するものです。アクションを定義するには<computeroutput>actions</computeroutput>キーワードに続いて、アクション名と波カッコで囲んだコマンド文字列を記述します。出力ファイル名、入力ファイル名がそれぞれ<computeroutput>$(1)</computeroutput>、<computeroutput>$(2)</computeroutput>で渡されます。</para>
    <para>出力するファイルがない場合は代わりに<computeroutput>notfile</computeroutput>ルールを使用します。次の例は、ソースファイルの名前<filename>in.cpp</filename>を画面に出力します。</para>
    <programlisting><![CDATA[import notfile ;

actions echo
{
    echo $(2)
}

notfile echo-souces : @echo : in.cpp ;
]]></programlisting>
    <para><computeroutput>make</computeroutput>ルールと違い、<computeroutput>notfile</computeroutput>ルールのソースファイルにはBBv2に登録された拡張子のファイルしか使用できないので注意してください。<footnote>
      <simpara>次のように拡張子をBBv2登録することで、独自の拡張子も使用できます。</simpara>
      <programlisting><![CDATA[import type ;
type.register TXT : txt ;
]]></programlisting>
    </footnote></para>
    <para>今度はビルド設定に応じてコマンドに渡すオプションを変えることを考えます。</para>
    <programlisting><![CDATA[import notfile ;

actions echo-link-mode
{
    echo $(MSG)
}

notfile echo-default-link : @echo-link-mode ;
]]></programlisting>
    <para>ここで変数<varname>MSG</varname>をビルド設定がスタティックリンクかダイナミックリンクかで違うものにしたいとします。そこで、</para>
    <programlisting>if <emphasis>スタティックリンクか？</emphasis>
{
    MSG = "static link" ;
}
else
{
    MSG = "dynamic link" ;
}
</programlisting>
    <para>のようなコードを追加したとしても、</para>
    <screen>bjam link=static link=shared</screen>
    <para>のように二つのリンクモードを同時にビルドした際に正しく処理できません。変数<varname>MSG</varname>は実ターゲット毎に設定する必要があるわけです。これを実現するには、次のようなアクションと同名のルールを定義します。</para>
    <programlisting><![CDATA[rule echo-link-mode ( targets * : sources * : properties * )
{
    if <link>static in $(properties)
    {
        MSG on $(targets) = "static link" ;
    }
    else
    {
        MSG on $(targets) = "dynamic link" ;
    }
}
]]></programlisting>
    <para>ここで注目すべき点は、「<computeroutput>MSG on $(targets)</computeroutput>」の部分です。これはターゲット変数と呼ばれるもので、ターゲット毎に異なる値を記録することができます。アクションの定義中ではターゲット変数が参照されるため、ターゲット毎に適切な値に展開されます。</para>
  </section>
</article>
