C++ Boostライブラリ（filesystem etc.）をWindows用（MinGW用、Visual Studio用）にビルドする

# Boostとは
　BoostとはC++のライブラリです。
　C++の次の標準機能を実装検討の実験場になっていて、Boostで検討された機能がC++の標準機能に取り込まれます。沢山の機能がC++11, C++14に取り入れられ、現在は、C++17の機能の実装検討をしています。
　また、複数のプラットフォーム、複数のコンパイラで動作するようになっているため、Boostのライブラリを使うことで、複数のプラットフォームで動作するプログラムを作ることができます。
　Boostのライブラリを利用したプログラムは、以下のメリットがあります。  

+ C++で標準化されていないライブラリを使うことができる。
+ プログラムを次世代のC++標準に移植するのが容易。
+ プログラムを異なるプラットフォームに移植するのが容易。
+ プラットフォーム依存を処理する`#ifdef`が減りテストが容易。

　大部分は、ヘッダーオンリーで利用することができますが、一部分はビルドが必要です。
　Boost ver.1.61.0では以下のようになっています。

+ ライブラリ全体：１０８
    - ヘッダオンリーなライブラリ：８３
    - ビルドするライブラリ：２５

**ビルドするライブラリ一覧**

|ライブラリ名|C++11|備考|
|:-----|:-----:|:-----|
|atomic|○||
|chrono|○|`BOOST_CHRONO_HEADER_ONLY`をdefineすればヘッダオンリーで使用可能|
|container|△||
|context|||
|coroutine|||
|date_time||posix timeのみを使用する場合は、`BOOST_DATE_TIME_NO_LIB`をdefineすればヘッダオンリーで使用可能|
|exception|△||
|filesystem||時刻処理が入らなければ、Chronoは不要。|
|graph||GraphMLを使用しなければヘッダオンリー|
|iostreams|||
|locale|||
|log|||
|math|△||
|program_options|||
|python|||
|random|○|`random_device`を使用しない場合、ヘッダオンリーで使用可能。|
|regex|○||
|serialization|||
|signals|||
|system|||
|test|||
|thread|○||
|timer|||
|type_erasure|||
|wave|||

Boostライブラリのいくつかは、C++11, C++14に取り込まれています。C++11, C++14をサポートしたコンパイラを使っている場合は、C++標準の利用を選択してください。

Boost → C++11 の対応をまとめたサイト
http://boostjp.github.io/tips/cxx11-boost-mapping.html

# C++17 filesystem
+ 標準化
    C++17では、ファイル／ディレクトリ操作に関する標準化作業を進めています。
    https://isocpp.org/files/papers/P0218r1.html
    
+ 機能
    主要な機能は以下のようになっています。
    - ファイルのコピー
    - ファイルの削除
    - ファイルの移動／ファイル名の変更
    - ファイルが存在するかを調べる
    - ファイルサイズを取得する
    - ファイルの最終更新日時を取得する
    - パスのファイル名を取得する
    - パスの拡張子を取得する
    - パスの拡張子を変更する
    - ディレクトリを作成する
    - ディレクトリ内のファイルを列挙する
    - ディレクトリ内のすべてのファイルを再帰的に列挙する
    - エラーハンドリング
    
+ 利用方法
    C++17でfilesystemが標準化されると次のように使えるようになります。
    
    ```
    #include <filesystem>
    namespace fs = std::filesystem;
    ```
    
+ 実装状況
    実装状況は以下のようになっています。
    - Boost
        Boost Filesystem Libraryが2003年～提供されています。
        ライブラリのビルドが必要です。
        プログラムで使用する際は、以下のようにします。
        
        ```
        #include <boost/filesystem.hpp>
        namespace fs = boost::filesystem;
        ```
        歴史が長く、先行検討されていた一部のAPIには廃止になったものがあります。
        過去のプログラムのコンパイルが通らない場合は、こちらが参考になります。
        http://www.boost.org/doc/libs/1_61_0/libs/filesystem/doc/deprecated.html
        
    - Microsoft
        Visual C++ 2015から正式提供されています。
        プログラムで使用する際は、以下のようにします。
        
        ```
        #include <filesystem>
        namespace fs = std::experimental::filesystem::v1;
        ```
        Windowsのルートパス、文字列、ディレクトリ属性は、Posix標準とは異なります。
        相違点は、こちらで解説されています。
        https://msdn.microsoft.com/ja-jp/library/hh874694.aspx
    - libstdc++
        gcc-5.3から提供されています。
        `libstdc++fs.a`に含まれているため、`-lstdc++fs`オプションを指定してg++でビルドします。
        libstdc++はPOSIXベースの機能のみサポートしているため、Windowsファイルシステムでは基本的な部分のみ動作します。

        プログラムで使用する際は、以下のようにします。
        
        ```
        #include <experimental/filesystem>
        namespace fs = std::experimental::filesystem::v1
        ```
        リファレンスマニュアルは以下で公開されています。
        - gcc-5.4.0 API  
            https://gcc.gnu.org/onlinedocs/gcc-5.4.0/libstdc++/api/a01795.html
        - gcc-6.2.0 API  
            https://gcc.gnu.org/onlinedocs/gcc-6.2.0/libstdc++/api/a01834.html

+ サンプルプログラム
    Boost 1.61.0 と Visual C++ 2015 でディレクトリ内のファイル名を出力してみます。
    
    Boost 1.61.0 のプログラム
    
    ```boost.cpp
    #include <iostream>
    
    #include <boost/filesystem.hpp>
    namespace fs = boost::filesystem;
    
    int main()
    {
        const string directory = "dir";
        
        fs::path p(directory);
        for (fs::directory_iterator next(p), end; next != end; ++next)
        {
            cout << next->path() << endl;
        }
    }
    ```
    
    Visual C++ 2015 のプログラム
    
    ```msvc.cpp
    #include <iostream>
    
    #include <filesystem>
    namespace fs = std::experimental::filesystem::v1;
    
    int main()
    {
        const string directory = "dir";
        
        fs::path p(directory);
        for (fs::directory_iterator next(p), end; next != end; ++next)
        {
            cout << next->path() << endl;
        }
    }
    ```
    
    includeとnamespaceは異なりますが、プログラムは共通です。
    > fs::path p(directory);  
    
    の部分では、pathクラスのインスタンスを`インスタンス名("文字列")`で作成しています。
    directory_iteratorは、次のようになります。
    
    - 引数なしのコンストラクタ  
        イテレータを終端にセットしたインスタンスを生成します。
    - 引数のあるコンストラクタ  
        引数で与えられたディレクトリにイテレータをセットします。
    - 次の要素  
        `++`オペレータで次の要素にイテレータを移動させます。
    
    for文の`++`オペレータでイテレータを順次移動させ、イテレータが終端に達するまで処理を続けます。
    　
    
+ エラー出力の比較
    Boost 1.61.0 と Visual C++ 2015 のfilesystemのエラー出力を比べてみます。
    存在しないファイルのサイズを取得しようとしてみます。
    
    Boost 1.61.0 のプログラム
    
    ```boost.cpp
    #include <iostream>

    #include <boost/filesystem.hpp>
    namespace fs = boost::filesystem;

    int main()
    {
        const fs::path file("abc.txt"); // 存在しないファイル

        try {
            fs::file_size(file);
        }
        catch (fs::filesystem_error& ex) {
            std::cout << ex.what() << std::endl;
            throw;
        }
    }
    ```
    
    Boost 1.61.0 のエラー出力
    
    ```
    boost::filesystem::file_size: 指定されたファイルが見つかりません。: "abc.txt"
    ```

    Visual C++ 2015 のプログラム
    
    ```msvc.cpp
    #include <iostream>

    #include <filesystem>
    namespace fs = std::experimental::filesystem::v1;

    int main()
    {
        const fs::path file("abc.txt"); // 存在しないファイル

        try {
            fs::file_size(file);
        }
        catch (fs::filesystem_error& ex) {
            std::cout << ex.what() << std::endl;
            throw;
        }
    }
    ```
    
    Visual C++ 2015 のエラー出力
    
    ```
    file_size(p): invalid argument: operation not permitted
    ```
    
    歴史の差でしょうか、Boostのほうが分かりやすいエラーメッセージになっていました。
    
# Visual Studio用にビルドしてみる
BoostのfilesystemライブラリをVisual Studio用にビルドしてみます。
Visual Studioをインストールした環境で試したところすんなりといきました。

1. Visual Studio 2015をインストール  
2. Boostをダウンロード＆展開  
3. Boostのディレクトリで以下のコマンドを実行
    32bit版
    
    ```
    $ bootstrap.bat
    $ b2.exe --address-model=32 --with-filesystem
    ```
    64bit版
    
    ```
    $ bootstrap.bat
    $ b2.exe --address-model=64 --with-filesystem
    ```

4. `stage\lib`にライブラリ完成


# MinGWのg++用にビルドしてみる
BoostのfilesystemライブラリをMinGWのg++用にビルドしてみます。
こちらは、Visual Studioのようにすんなりとはいきませんでした。
ネットで検索しましたが、情報が錯綜。以下、こんな感じでうまくいった人がいる、程度の参考にしてください。

+ gcc 5.3.0-2 (MinGW)をインストールする
+ Boost 1.61.0のソースをビルドしてライブラリを作成する

以下のような段階を踏みました。
1. gccをMinGW Installation ManagerでMinGWのBasicSetupとしてインストール。
2. .\bootstrap.batでb2.exe（Boost.Build engine）を作成。
3. b2.exe（Boost.Build engine）でBoostのライブラリをg++でコンパイル＆ビルド。


# Boostのライブラリをg++でビルドする手順
filesystemライブラリをビルドしてみます。

1. MinGWのインストール  
    MinGWでgccをインストールしておき、インストールしたg++にPATHを通しておきます。  
    g++がインストールされるPATHは`[MinGW Innstall Dir]/bin`になります。  
    PATHは今回インストールしたg++がPCにインストールされている他のg++よりも先になるように設定してください。  
    PATHは空白を含まないディレクトリにしてください。  
2. Boost ver.1.61.0をダウンロード  
    http://www.boost.org/users/download/#live  
    から`boost_1_61_0.zip`をダウンロードします。サイズは、約152MBです。  
3. Boostの配置
    ダウンロードした`boost_1_61_0.zip`を展開します。
    サイズは、約563MBです。
    他のディレクトリにインストールする場合は空白を含まないディレクトリにしてください。
    今回は以下に展開しました。
    > C:\dev\boost\boost_1_61_0  
    
4. コマンドプロンプトでBoostのディレクトリに移動します。  
    > $ cd C:\dev\boost\boost_1_61_0
5. b2.exe（Boost.Build engine）の作成  
    > $ .\bootstrap.bat
    > $ .\bootstrap.bat gcc
6. コンパイル＆ビルド
    > $ .\b2.exe toolset=gcc --with-filesystem
    
    コンパイル＆ビルドが実行され、filesystemライブラリが`stage\lib`ディレクトリに生成されます。オプションを指定していないためデフォルト値が適用され設定は下記のようになっています。  
    + gcc-mingw-5.3.0
    + debug, release
    + staticリンク
    + マルチスレッド
    
    ライブラリを`--with`で指定しないと、長時間のビルド、ファイルのコピーが始まり、以下が`stage\lib`ディレクトリに生成されます。
    `atomic, chrono, container, context, coroutine, date_time, exception, filesystem, graph, iostreams, locale, log, math, program_options, python, random, regex, serialization, signals, system, test, thread, timer, type_erasure, wave`

# b2.exe（Boost.Build engine）のビルドオプション
ビルドの組み合わせを指定することができます。

+ --build-type
    - minimal  
        Windowsではデバッグ用とリリース用のstaticリンク用＆マルチスレッド用のライブラリが生成されます。  
        `--build-type`の指定を省略したときのデフォルト値です。
    - complete  
        可能な限りすべての組み合わせのビルドが実行されます。

ビルド対象を個々に指定することができます。

+ --toolset  
    ビルドを実行するツールセットを指定します。  
    例）--toolset=gcc
+ --variant
    - debug  
        デバッグ用のビルドを実行します。
    - release  
        リリース用のビルドを実行します。
+ --link
    - static  
        staticリンク用としてビルドします。
    - shared  
        sharedライブラリ用としてビルドします。
+ --threading
    - single  
        シングルスレッド用としてビルドします
    - multi  
        マルチスレッド用としてビルドします
+ --runtime-link
    - static  
        staticなC/C++のランタイムにリンクします。
    - shared  
        sharedなC/C++のランタイムにリンクします。

# b2.exe（Boost.Build engine）のinstallオプション
+ --prefix=\<PREFIX>  
    アーキテクチャ非依存なファイルをインストールするディレクトリを指定します。  
    Windowsのデフォルト値：C:\Boost  
    Linuxのデフォルト値：/usr/local  
+ --exec-prefix=\<EPREFIX>  
    アーキテクチャ依存のファイルをインストールするディレクトリを指定します。  
    デフォルト値：\<PREFIX>  
+ --libdir=\<DIR>  
    ここのライブラリがインストールされます。  
    デフォルト値：\<EPREFIX>/lib  
+ --includedir=\<HDRDIR>  
    ここのヘッダーがインストールされます。  
    デフォルト値：\<PREFIX>/include  

# b2.exe（Boost.Build engine）のstageオプション
+ --stagedir=\<STAGEDIR>  
    ライブラリをインストールするディレクトリを指定します。  
    デフォルト値：./stage

# b2.exe（Boost.Build engine）の並列実行オプション
+ -j [Num]  
    [Num]に並列実行させる数を指定します。

# b2.exe（Boost.Build engine）の32bit/64bitオプション
+ address-model=[N bit]  
    [N bit]に32または64を指定します。

# b2.exe（Boost.Build engine）のその他オプション
+ --with-\<library>  
    特定のライブラリのみをビルド＆インストールします。  
    複数のライブラリを指定したい場合は、`--with-filesystem --with-system`のように列挙します。  
    このオプションを指定しない場合のデフォルト値は全てのライブラリのビルド＆インストールです。  
+ --without-\<library>  
    特定のライブラリをビルド＆インストール対象からはずします。  
    このオプションを指定しない場合のデフォルト値は全てのライブラリのビルド＆インストールです。  

# 参考情報
+ BoostのConfiguration  
    http://www.boost.org/build/doc/html/bbv2/overview/configuration.html
+ Boostとgccやmsvcの連携  
    http://www.boost.org/build/doc/html/bbv2/reference/tools.html
+ Boost日本語情報サイト  
    http://boostjp.github.io/howtobuild.html