yumetodoの旅とプログラミングとかの記録

旅や登山の記録やプログラミング関連の話とかフリーソフト紹介とか

Boost1.59.0をなんとなく導入する

皆様、ナマステ。
いやね、私は確かにmsxmlのラッパーを書いていたはずなんですよ。
そしたらいつの間にかBoostを導入していました。使う予定も無いのに。
きっとmsxmlのラッパーが何故にや知らんcmp命令で落ちるので
xmlの読み込み途中で落ちる · Issue #2 · yumetodo/xml_test_cooking_quiz
やけになったんでしょう、きっと。
あと、Sprout C++ Librariesを面白半分で落として、さらに無意味にcmakeしようとしたらboost必要、みたいなエラーが出たせいでもあります。

といっても導入方法は
近代汎用術式Boost C++ 1.57.0をVisual Studio 2013で使う ~導入と使い方~ - Gobble up pudding
と一切変わりません。boostとVisual Studioのバージョンが違うくらいです。

導入手順(超省略版)

  1. まずはBoostを公式サイトから落とす
    http://www.boost.org/
    ここね。入れたのはバージョン1.59.0。
    落とすときにいくつかの形式を選べるけど7zで落とした。
  2. 解凍(展開)する。私はCubeICEを使うぜ。
    そういえば解凍中に幾つかエラー出てたんだようなぁ、何だったんだろう。
  3. Visual Studio 2015の開発者コマンドプロンプトを立ち上げる。
  4. pushd C:\lib\boost_1_59_0
    bootstrap.bat && b2.exe -j 4
  5. 気長に待つ。え、カップ麺でも食べたかって?
    これみてたに決まってますよね。
  6. 環境変数を設定する。某友人(同じサークルの人)はphp開発環境導入の時に忘れて痛い目を見たらしいので、侮る事なかれ。

導入確認テスト

参考サイトではboost.regex使ったサンプルをビルドしているようですが、regexならC++11にありますしちっともありがたくないです。
というわけでC++17に入る・・・かどうかは知らないけど私の中ではBoostと言ったら
BoostAsioで可読性を求めるのは間違っているだろうか
from Yuki Miyatake

Boost.asioなんですよね~。
なんでboost.asioなのかというと、このうえのスライド、ドワンゴの「歌舞伎座.tech #8 「C++初心者会」」で発表されたもので、これの司会は日本一C++規格に詳しい江添亮さん。
全国のC++erのみなさん、この生放送のTS録画は義務ですよ(もうTS期限切れてるけど)
で、使いたい、と思ったら、
./boost_1_59_0/libs/asio/example/cpp11/buffers
というサンプルが元からついてきている。
しかもそれの解説サイトもある
C++ - 【boost::asio buffers】 boost::asioでセッション管理にはshared_ptrが便利だ - Qiita
じゃあこれで試すか。

ご丁寧にCMakeLists.txtを配布してくれてるのでそれをいじってビルドすることにする

  1. CMakeLists.txtを上のコードの「view raw」を右クリックから落として、reference_counted.cppと同じパスに置く
  2. フツーにCMake。悪いけどVisual StudioでかつWindows7以上前提で書いたからそれ以外の人は適宜直してくれ
  3. ソリューション(.sln)を開いたら、 ./boost_1_59_0/boost/asio/detail/config.hpp
    を開く。
    #if !defined(BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT)
    # if (BOOST_VERSION >= 105300)
    #  define BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT BOOST_NOEXCEPT
    # elif defined(__clang__)
    #  if __has_feature(__cxx_noexcept__)
    #   define BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true)
    #  endif // __has_feature(__cxx_noexcept__)
    # elif defined(__GNUC__)
    #  if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
    #   if defined(__GXX_EXPERIMENTAL_CXX0X__)
    #     define BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true)
    #   endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
    #  endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
    # endif // defined(__GNUC__)
    # if defined(BOOST_ASIO_MSVC)
    #  if (_MSC_VER >= 1900)
    #   define BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true)
    #  endif // (_MSC_VER >= 1900)
    # endif // defined(BOOST_ASIO_MSVC)
    # if !defined(BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT)
    #  define BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT
    # endif // !defined(BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT)
    #endif // !defined(BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT)
    これだと二重定義になるので
    #if !defined(BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT)
    # if (BOOST_VERSION >= 105300)
    #  define BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT BOOST_NOEXCEPT
    # elif defined(__clang__)
    #  if __has_feature(__cxx_noexcept__)
    #   define BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true)
    #  endif // __has_feature(__cxx_noexcept__)
    # elif defined(__GNUC__)
    #  if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
    #   if defined(__GXX_EXPERIMENTAL_CXX0X__)
    #     define BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true)
    #   endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
    #  endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
    # elif defined(BOOST_ASIO_MSVC)
    #  if (_MSC_VER >= 1900)
    #   define BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true)
    #  endif // (_MSC_VER >= 1900)
    # endif // defined(BOOST_ASIO_MSVC)
    # if !defined(BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT)
    #  define BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT
    # endif // !defined(BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT)
    #endif // !defined(BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT)
    に書き換える。Visual Studio 2015はnoexceptに対応してるからね。これで213行目の定義だけになるはず。
  4. もう一箇所。ctime関数はstatic領域へのポインタを返すから危険というわけで_s付き関数使えというエラー対策。おのれPOSIX
      void do_write()
      {
        std::time_t now = std::time(0);
        shared_const_buffer buffer(std::ctime(&now));
    
        auto self(shared_from_this());
        boost::asio::async_write(socket_, buffer,
            [this, self](boost::system::error_code /*ec*/, std::size_t /*length*/)
            {
            });
      }
    
      void do_write()
      {
        const auto now = std::time(0);
    #ifdef _MSC_VER
    	char buf[128];
    	ctime_s(buf, _countof(buf), &now);
    	shared_const_buffer buffer(buf);
    #else
        shared_const_buffer buffer(std::ctime(&now));
    #endif
    
        auto self(shared_from_this());
        boost::asio::async_write(socket_, buffer,
            [this, self](boost::system::error_code /*ec*/, std::size_t /*length*/)
            {
            });
      }

実行ファイルは、reference_counted.cppと同じパスにできるbinフォルダ内にあるのでそれをコマンドプロンプトでそのパスに移ってから

reference_counted.exe 8000

のように実行すると簡易サーバーが立ち上がる。ブラウザから、
http://localhost:8000
にアクセスして見ると現在時刻が表示されると思う。初めてHello World!をCで書いたとき並に私は感動したよ。
あ、ちなみ、Windows7標準機能のlocalhostと喧嘩したのか、ブラウザでlocalhostをしょっちゅう見失ってたことを付け加えておきます。というかFirefoxと相性悪い・・・?

msys2でもboostしたい

導入は至って簡単です。すでにgcc/clangは入っているものとします。

pacman -S mingw-w64-i686-boost mingw-w64-x86_64-boost

これで導入完了。exampleは別途落とさないといけないので上記参考に落としてきます。とくにファイルに修正はいりません。cmakeも不要。適当なディレクトリにreference_counted.cppをコピーしてcdしてそこに移りましょう。

g++ -std=c++14 reference_counted.cpp -lboost_system-mt -lboost_thread-mt -lboost_serialization-mt -lws2_32 -lwsock32 -o reference_counted.exe

これだけ。あとは

./reference_counted.exe 8000

として実行してみてください。あとは同じ。