2015-08-05 ,

Boost.TestをAndroid NDKで使う(android-ndk-r10e)

Android上でBoost.Testを使ったテストをしてみました。

Android NDKでは通常のAndroidアプリケーションではない、main()から始まるネイティブの実行ファイル(つまりWindowsで言うところのコンソールアプリと言えば良い?)をビルドできるようになっています。これを使えばAndroid端末上でテストを実行できます。

以下に例を書いておきます。hello_testというディレクトリを作って、以下のファイルを用意し、run.shを実行するとテストをビルドして端末へアップロードして実行します。ライブラリをビルドするのは面倒くさいので、Boostはヘッダーだけの使用にとどめてあります。

hello_test/jni/Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_CPP_FEATURES += exceptions
LOCAL_CPP_FEATURES += rtti
LOCAL_MODULE := hello_test #←実行ファイル名になる。

# ソースファイルはワイルドカードで取得してみる。
# LOCAL_PATHはjniディレクトリを指している。
# カレントディレクトリは一つ上なので注意。
# LOCAL_SRC_FILESにはjniディレクトリからの相対パスで指定する必要がある。
SRC_FILES = $(wildcard $(LOCAL_PATH)/*.cpp)
LOCAL_SRC_FILES := $(SRC_FILES:$(LOCAL_PATH)/%=%)

# Boost C++ Libraryヘッダーファイルへのパスを指定する。
LOCAL_C_INCLUDES += c:/boost_he_no_path_wo_shiteisuru/boost_1_56_0

# これが無いとAndroid 5.0以降で実行できない。
LOCAL_CFLAGS += -pie -fPIE
LOCAL_LDFLAGS += -pie -fPIE

include $(BUILD_EXECUTABLE) #実行ファイルをビルドする。

実行ファイルを生成するには、最後に include $(BUILD_EXECUTABLE) を指定するのがミソです。

LOCAL_MODULE は実行ファイルの名前になります。

Boostのヘッダーへのパスは LOCAL_C_INCLUDES で指定してください。

実行時に"error: only position independent executables (PIE) are supported" というエラーが出ることがあります。Android 5.0以降だと出るようです。 -pie -fPIE というオプションを指定すると大丈夫なようです。

hello_test/jni/Application.mk

APP_ABI := all
APP_STL := c++_static
APP_PLATFORM := android-14 #低いとコンパイルが通らない

APP_PLATFORM を指定しなかったり、APIレベルが低いと必要な関数が無いためにコンパイルエラーにとなります。

hello_test/jni/main.cpp

#define BOOST_TEST_MAIN
#include <boost/test/included/unit_test.hpp>

hello_test/jni/test_hoge.cpp

#define BOOST_TEST_NO_LIB
#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_SUITE(hoge_test)

BOOST_AUTO_TEST_CASE(test1)
{
    int a = 1;
    int b = 2;
    BOOST_CHECK_EQUAL(a + b, 3);
    BOOST_CHECK_EQUAL(a - b, -1);
    BOOST_CHECK_EQUAL(a / b, 0);
}

BOOST_AUTO_TEST_CASE(test2)
{
    double a = 1.0;
    double b = 2.0;

    BOOST_CHECK_EQUAL(a + b, 3.0);
    BOOST_CHECK_EQUAL(a - b, -1.0);
    BOOST_CHECK_EQUAL(a / b, 0.5);
}

BOOST_AUTO_TEST_SUITE_END()

hello_test/run.sh

#!/usr/bin/env bash

dir=/data/local/tmp/hello_test
bin=hello_test

# Build
ndk-build

# Detect Device's ABI
abi=$(adb shell getprop ro.product.cpu.abi | cut -d, -f1 | tr -d '\r')
echo "abi=$abi"

# Make directory
echo "mkdir $dir"
adb shell "mkdir $dir 2>/dev/null"

# Upload
adb push libs/$abi/$bin $dir

# Execute
adb shell "chmod 755 $dir/$bin"
adb shell $dir/$bin

# Delete
adb shell rm $dir/$bin
adb shell rmdir $dir

接続している端末のABIを取得するには、 adb shell getprop ro.product.cpu.abi を実行すればよいみたいです。カンマ区切りで複数列挙される場合があります。

/data/local/tmp というディレクトリにアップロードして実行し、終わったら削除します。