はじめに
僕はObjective Cが苦手だ。文法が分からない・・。しかし、現実の要求は、エンジニアに言語を選択する自由を与えてくれない。これは、既存のObjective Cのコードにサーバ機能をつけなくてはいけなくなった奮闘の記録(リマインダ)である。
環境
XCodeのプログラムでboostを使う問題は、Stack Overflowでもいろいろ議論されており、バージョンが違うとインタフェースも変わってしまったり解決方法が適用できなくなったりするので、この記録が役に立つかは分からない。ただ、少なくとも動いた環境は明確にしておく。
- XCode Ver. 5.0.2
- boost_1_55_0
- homebrewによってインストールされている
- 使用したパッケージ
- boost::asio
既存のXCodeのプロジェクトにboost::asioを使ったサーバ機能を付加する目的で行った。また、実際に使ったプロジェクトのビルドに関するすべては膨大になるので、触れない。
前提
とりあえず、C++のソースを絡めてビルドするためのお約束は守る。
- ソースファイルが、<filename>.mだったら、<filename>.mmに変更する
- Project設定のBuild Settingsで、LinkingのOther Linker Flagsに以下のフラグを追加
- -L/usr/local/lib
- -lboost_thread-mt
- -lboost_system-mt
- -lboost_date_time-mt
- -lc++
※なお、必要なboostのライブラリはそれぞれ異なるので、必要に応じて、設定しよう
ここで、注目なのが、-lc++をリンクしているところだ。makeするときのように-lstdc++としたら、コンパイルが失敗した。
トライアル1: そのまま使う
まず第一に思いつくのが、boostのヘッダをObjective-C++のコードに直接インクルードして使う方法。しかし、この試みは水泡に帰した。具体的には、has_binary_operator.hppというソースの以下の部分でビルドエラーが出る。
template < typename Lhs, typename Rhs >
struct operator_exists {
static ::boost::type_traits::yes_type check(has_operator); // this version is preferred when operator exists
static ::boost::type_traits::no_type check(no_operator); // this version is used otherwise
BOOST_STATIC_CONSTANT(bool, value = (sizeof(check(((make<Lhs>() BOOST_TT_TRAIT_OP make<Rhs>()),make<has_operator>())))==sizeof(::boost::type_traits::yes_type)));
};
いろいろなところでマクロ設定すれば良いよなどと指摘されているが、うまくいかずに断念。
#define __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES 0
トライアル2: boost機能部分をラップするライブラリ経由で使う
ヘッダのコンパイルが通らなかったからといって、あきらめるのは早すぎる!ということで、boostの必要部分をラップするライブラリlibwrapper.aを作って、再チャレンジ。注意点としては、インクルードするラッパーライブラリのヘッダの中でboostのヘッダファイルを呼ばないように気をつけること。どうしても、boostのクラスインスタンスがクラスの変数で必要な場合は、ソースファイルの中でstatic宣言などして、回避した。
ヘッダファイルをソースにコピーし、mmファイルにインクルードし、Build Settingsを以下のように書き換える。
- Other Linker Flag
- -Llib
- -lwrapper
- -L/usr/local/lib
- -lboost_thread-mt
- -lboost_system-mt
- -lboost_date_time-mt
- -lc++
このとき、xcodeprojと並列のディレクトリにlibディレクトリをおき、中にlibwrapper.aを配置した。
これでビルドがうまく行った。boostを直接、使うことは難題だが、少しラップしてあげるとうまくいくらしい。めでたしめでたし。
libwrapper.aのビルド方法
上記のファイル名は仮の名前だが、ビルドをしたときのコンパイラなどの設定は以下の通り
- CMAKE_AR:FILEPATH=/usr/bin/ar
- CMAKE_CXX_COMPILER:FILEPATH=/usr/bin/c++
ビルドは、cmakeを通して行い、そのときのコンパイラ・リンカは、上記のとおりである。