いそのーBoostビルドしようぜー
(2011/12/26現在のNDKはr7、boostは1.48.0です。また開発環境はWindows機、AndroidAPIレベルは8としています。)
C++を使ってでのAndroidのアプリの開発はGoogleの配布しているNative Development Kitを用いることで難なく行うことができますが、含まれているgccのバージョンが4.4.3であるため中々ヒャッハーすることができませんでした。
という訳でCrystaX .NETにて配布されているカスタマイズされたNDKを使い、ついでにboostもビルドして使ってみたのでメモっておきます。NDKについても初心者なので間違ったこと書いている可能性大です><
はじめに
NDKでもBoost使いたいってメモなので、CygwinやAndroid SDK、Eclipseなどの環境は既に整えられているものとします。(ちなみに私はEclipse 日本語化 | MergeDoc ProjectのUltimate入れました。)
NDKについてもちょっとググっておいて下さい。
材料はこちら
Android NDK-r7(少々)
Improved Android NDK-r7
Boost 1.48.0
私はAndroid NDKをCドライブ直下に置いたので、それぞれのパスはC:/android-ndk-r7、C:/android-ndk-r7-crystax-3となっています。
CygwinはC:/cygwinに置いているので、boostのパスはC:/cygwin/usr/include/boost_1_48_0となっています。自分の環境に合わせて適宜読み替えて下さい。
単純にBoost!
まずは単純にgcc4.6.3とboostライブラリ(ヘッダオンリー)を使ってみます。
プロジェクトの作り方はAndroid JNIプロジェクトをゼロから作る(UsefullCode.net)、C++での開発方法はAndroid NDKでC++を利用する(UsefullCode.net)を参考に作成してください。
jniディレクトリは
こんな感じになっていれば平気です。kotatu.cppは読み替えて下さい。こたつ!こたつ!
C++のコードをEclipseを使って書く予定が無いのであれば、Android NDKを使う(アプリの高速化) « Tech Boosterが参考になります。
Eclipseで丸々開発を行うのであれば、そらとぶくじら。 EclipseからAndroid NDK/JNIをスマートにビルドする方法。を参考に設定しておくと便利です。
もちろん ANDROID_NDK_ROOT はC:/android-ndk-r7-crystax-3に変えて下さい。
またコードの補完のために、プロジェクトのプロパティを開き[C/C++ 一般]→[パス及びシンボル]のインクルード タブにあるGNU C++に以下のように追加しておくと良いです(お好みで)。
さて、Application.mkはこんな感じになります。
Application.mk
APP_STL := gnustl_static APP_CPPFLAGS += -frtti APP_CPPFLAGS += -fexceptions APP_CPPFLAGS += -std=gnu++0x APP_TOOLCHAIN_VERSION := 4.6.3 APP_USE_CPP0X := true
現時点でのAndroid.mkはこんなところです。
Android.mk
LOCAL_PATH := $(call my-dir) # アプリ include $(CLEAR_VARS) LOCAL_MODULE := kotatu LOCAL_LDLIBS := -llog LOCAL_C_INCLUDES += /usr/include/boost_1_48_0 LOCAL_SRC_FILES := kotatu.cpp include $(BUILD_SHARED_LIBRARY)
これである程度ヒャッハー出来るようになります。
ですがthreadやfilesystemなどのリンクが必要なライブラリは使うことができません。という訳でビルドしましょう!
Android用にBoostをビルドする
試行錯誤中なのでアドバイス下さい!
まずはbootstrapを実行してb2.exeを作っておきます。
次にuser_config.jamを編集します。C:/cygwin/usr/include/boost_1_48_0/tools/build/v2 にあります。
これが中々よく分からない・・・。Tips & Tricks: Building Boost with NDK R5 - Code Xperimentsを参考に書きました。
とりあえず以下のものをuser_config.jamに付け足して下さい。
user_config.jam
# アンドロイド用 modules.poke : NO_BZIP2 : 1 ; ANDROID_NDK = C:/android-ndk-r7-crystax-3 ; ANDROID_NDK_OFFICIAL = C:/android-ndk-r7 ; using gcc : android : $(ANDROID_NDK)/toolchains/arm-linux-androideabi-4.6.3/prebuilt/windows/bin/arm-linux-androideabi-g++ : <cxxflags>-I$(ANDROID_NDK)/sources/cxx-stl/gnu-libstdc++/include/4.6.3 <cxxflags>-I$(ANDROID_NDK)/sources/cxx-stl/gnu-libstdc++/libs/armeabi/4.6.3/include <cxxflags>-I$(ANDROID_NDK)/platforms/android-8/arch-arm/usr/include <cxxflags>-I$(ANDROID_NDK_OFFICIAL)/platforms/android-8/arch-arm/usr/include <cxxflags>-D__ARM_ARCH_5__ <cxxflags>-D__ARM_ARCH_5T__ <cxxflags>-D__ARM_ARCH_5E__ <cxxflags>-D__ARM_ARCH_5TE__ <cxxflags>-DNDEBUG <cxxflags>-D_REENTRANT <cxxflags>-D_GLIBCXX__PTHREADS <cxxflags>-D_LITTLE_ENDIAN <cxxflags>-DBOOST_NO_FENV_H #<cxxflags>-DBOOST_FILESYSTEM_VERSION=2 <cxxflags>-std=gnu++0x <cxxflags>-g <cxxflags>-mthumb <cxxflags>-msoft-float <cxxflags>-mtune=xscale <cxxflags>-march=armv5te <cxxflags>-Wa,--noexecstack <cxxflags>-Wall <cxxflags>-pthread <cxxflags>-frtti <cxxflags>-fexceptions <cxxflags>-fpic #<cxxflags>-fomit-frame-pointer <cxxflags>-fno-strict-aliasing <cxxflags>-ffunction-sections <cxxflags>-funwind-tables <cxxflags>-fstack-protector <architecture>arm <find-static-library>c <xdll-path>$(ANDROID_NDK)/platforms/android-8/arch-arm/usr/lib/ <library-path>$(ANDROID_NDK)/platforms/android-8/arch-arm/usr/lib/ <archiver>$(ANDROID_NDK)/toolchains/arm-linux-androideabi-4.6.3/prebuilt/windows/bin/arm-linux-androideabi-ar <ranlib>$(ANDROID_NDK)/toolchains/arm-linux-androideabi-4.6.3/prebuilt/windows/bin/arm-linux-androideabi-ranlib ;
(アドバイスを頂いたので書き換えました。ありがとうございます。ただいくつか上手くいかなかったのでそこだけそのままです。)
今までの工程ではまったく公式のNDKを使っていなかったのですが、ここでインクルードパスに追加しています。
wchar.hがカスタマイズ版に入っていないので苦肉の策・・・。きもちわるいでござる。
BOOST_FILESYSTEM_VERSION=2も付け足したほうが良いかもしれません。v3が使えないので。
またいくつかのboostのコードに変更を加えなければいけません・・・
Wt - Installing Wt on Android - Redmineを参考にします。
boost/asio/detail/fenced_block.hpp
28行目と57行目
#elif defined(__GNUC__) && defined(__arm__)
を
#elif defined(__GNUC__) && defined(__arm__) && !defined(__thumb__)
に変更。
37行目と66行目
&& !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__)
を
&& !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) && !defined(__ANDROID__)
に変更。
boost/asio/detail/socket_types.hpp
126行目あたり
const int max_addr_v4_str_len = INET_ADDRSTRLEN;
を
#ifdef INET_ADDRSTRLEN const int max_addr_v4_str_len = INET_ADDRSTRLEN; #else const int max_addr_v4_str_len = 16; #endif
に変更。
boost/asio/ip/impl/address_v6.ipp
13行目あたりの空白に
#ifndef IN6_IS_ADDR_MULTICAST #define IN6_IS_ADDR_MULTICAST(a) (((__const uint8_t *) (a))[0] == 0xff) #endif #ifndef IN6_IS_ADDR_MC_NODELOCAL #define IN6_IS_ADDR_MC_NODELOCAL(a) \ (IN6_IS_ADDR_MULTICAST(a) \ && ((((__const uint8_t *) (a))[1] & 0xf) == 0x1)) #endif #ifndef IN6_IS_ADDR_MC_GLOBAL #define IN6_IS_ADDR_MC_GLOBAL(a) \ (IN6_IS_ADDR_MULTICAST(a) \ && ((((__const uint8_t *) (a))[1] & 0xf) == 0xe)) #endif
を追加。
libs/filesystem/v2/src/v2_operations.cpp
61行目
# if !defined(__APPLE__) && !defined(__OpenBSD__)
を
# if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__ANDROID__)
に変更。
66行目付近
#ifdef __OpenBSD__ # include <sys/param.h> #endif
を
#ifdef __OpenBSD__ # include <sys/param.h> #elif __ANDROID__ # include <sys/vfs.h> #endif
に変更。
1272行目付近
long tmp = ::pathconf( "/", _PC_NAME_MAX );
を
#ifdef __ANDROID__ long tmp = 4096; #if 0 { int fd = open( "/", O_RDONLY ); if (fd >= 0) { tmp = ::fpathconf( fd, _PC_NAME_MAX ); close(fd); } } #endif #else long tmp = ::pathconf( "/", _PC_NAME_MAX ); #endif
に変更。
libs/filesystem/v3/src/operations.cpp
83行目
# if !defined(__APPLE__) && !defined(__OpenBSD__)
を
# if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__ANDROID__)
に変更。
88行目付近
# ifdef __OpenBSD__ # include <sys/param.h> # endif
を
# ifdef __OpenBSD__ # include <sys/param.h> # elif __ANDROID__ # include <sys/vfs.h> # endif
に変更。
220行目付近
# define BOOST_RESIZE_FILE(P,SZ)(::truncate(P, SZ)== 0)
を
#ifndef __ANDROID__ # define BOOST_RESIZE_FILE(P,SZ)(::truncate(P, SZ)== 0) #else int BOOST_RESIZE_FILE(const char *path, off_t size) { int retval = -1; int fd = open(path, O_WRONLY); if (fd != -1) retval = ftruncate(fd, size); close(fd); return retval; } #endif
に変更。
・・・と、大体こんな感じにすると良いようです。
ではビルドしてみましょう。
カレントディレクトリをC:/cygwin/usr/include/boost_1_48_0に移し
cd /usr/include/boost_1_48_0
以下のように打ち込んで下さい。
./b2 --without-python --without-serialization toolset=gcc-android link=static runtime-link=static target-os=linux --stagedir=android
(2012/1/22 訂正)
鬱陶しい警告が出ますが、最終的にC:/cygwin/usr/include/boost_1_48_0/android/lib にライブラリが生成されているはずです。
ではリンクするためにAndroid.mkを書き換えます。
Android.mk
# パスをメモっておく PROJECT_LOCAL_PATH := $(call my-dir) # ビルド済み LOCAL_PATH := /usr/include/boost_1_48_0/android/lib # thread include $(CLEAR_VARS) LOCAL_MODULE := libboost_thread LOCAL_SRC_FILES := libboost_thread.a include $(PREBUILT_STATIC_LIBRARY) # system include $(CLEAR_VARS) LOCAL_MODULE := libboost_system LOCAL_SRC_FILES := libboost_system.a include $(PREBUILT_STATIC_LIBRARY) # filesystem include $(CLEAR_VARS) LOCAL_MODULE := libboost_filesystem LOCAL_SRC_FILES := libboost_filesystem.a include $(PREBUILT_STATIC_LIBRARY) # アプリ LOCAL_PATH := $(PROJECT_LOCAL_PATH) include $(CLEAR_VARS) LOCAL_MODULE := kotatu LOCAL_LDLIBS := -llog LOCAL_C_INCLUDES += /usr/include/boost_1_48_0 LOCAL_STATIC_LIBRARIES := libboost_thread LOCAL_STATIC_LIBRARIES += libboost_system LOCAL_STATIC_LIBRARIES += libboost_filesystem LOCAL_SRC_FILES := kotatu.cpp include $(BUILD_SHARED_LIBRARY)
ひとまずthreadとsystemとfilesystemをリンクしてみた図。他にリンクを追加する場合も同じように1つずつ書いていきます。
これでうまくいくはず!
まとめ
もっと簡単な方法無いんですか!
ひとまず自分の環境ではこれでうまく出来ました。
ですが不安たっぷりなのでなにかありましたらぜひ教えて下さいorz