スタンドアロン ツールチェーン

Android NDK で提供されるツールチェーンを個別に使用するか、既存の IDE でプラグインとして使用することができます。 この柔軟性は、独自のビルドシステムが既にあり、ビルドシステムのサポートを Android に追加するためにクロスコンパイラを呼び出す機能のみが必要な場合に有用です。

ツールチェーンの選択

最初に、スタンドアロン ツールチェーンがターゲットとするプロセッサ アーキテクチャを決定する必要があります。 これは --arch フラグで設定します。

Sysroot の選択

次に、sysroot を定義する必要があります。 sysroot はターゲットのシステム ヘッダーやライブラリがあるディレクトリです。 sysroot を定義するには、ネイティブ サポートのターゲットとする Android API レベルを知る必要があります。使用できるネイティブ API は、Android API レベルによって異なります。

Android API レベル向けのネイティブ API のライブラリは、$NDK/platforms/ の下にあります。また、各 API レベル ディレクトリには、さまざまな CPU とアーキテクチャ用のサブディレクトリが含まれています。 ヘッダーは $NDK/sysroot にあります。

Android API レベルとそれらの API レベルでサポートされる各ネイティブ API の詳細については、ネイティブ API をご覧ください。

ツールチェーンの作成

NDK が提供している make_standalone_toolchain.py スクリプトを使用すると、カスタマイズされたツールチェーンのインストールをコマンドラインから実行できます。

これは以前の make-standalone-toolchain.sh に置き換わる新しいツールです。 Python で再実装されたため、Windows ユーザーがツールを実行するために Cygwin または MSYS をインストールする必要がありません。

スクリプトは $NDK/build/tools/ ディレクトリにあります($NDK は NDK のインストール ルート)。

このスクリプトの使用例は次のとおりです。

$NDK/build/tools/make_standalone_toolchain.py \
    --arch arm --api 21 --install-dir /tmp/my-android-toolchain

このコマンドによって /tmp/my-android-toolchain/ という名前のディレクトリが作成され、そこに android-21/arch-arm sysroot のコピーと、32 ビット ARM ターゲットのツールチェーン バイナリのコピーが入ります。

ツールチェーン バイナリはホスト固有のパスに依存していない、またはそのようなパスを含まないことに注意してください。 つまり、ツールチェーン バイナリは任意の場所にインストールすることができ、必要なら移動することもできます。

--arch 引数は必須ですが、API レベルはデフォルトでは特定のアーキテクチャでサポートされる最小レベル(現時点で、32 ビット アーキテクチャでは 16、64 ビット アーキテクチャでは 21)に設定されます。

r18 以上では、すべてのスタンドアロン ツールチェーンは Clang と libc++ を使用します。 静的な実行可能ファイルをビルドする場合以外は、デフォルトで libc++ 共有ライブラリが使用されます。 静的ライブラリの使用を強制するにはリンク時に -static-libstdc++ を渡します。 この動作は通常のホスト ツールチェーンの動作と一致しています。

C++ ライブラリ サポートの説明にあるとおり、libc++ へのリンク時にはしばしば -latomic を渡す必要があります。

なお、--install-dir オプションを省略すると、ツールによって現在のディレクトリに $TOOLCHAIN_NAME.tar.bz2 という名前の圧縮ファイルが作成されることに注意してください。 --package-dir を使用すると、圧縮ファイルを異なるディレクトリに置くことができます。

その他のオプションと詳細については、--help を使用してください。

Clang の使用

Clang バイナリは自動的にスタンドアロン ツールチェーンに組み込まれます。

ラッパー スクリプトとして clang および clang++ という名前の 2 つのスクリプトがあり、<install-dir>/bin に入っています。 これらのスクリプトは正しいアーキテクチャ フラグを指定して clang バイナリを呼び出します。 つまり、これらのスクリプトは何も変更しなくても機能するはずであり、これらのスクリプトを指すように CC および CXX 環境変数を設定するだけで、独自のビルドでこれらのスクリプトを使用できるようになるはずです。

Clang を呼び出す gcc および g++ という名前の 2 つのラッパー スクリプトもあります。 NDK に GCC は含まれなくなりましたが、これらのスクリプトにより GCC を明示的に参照するビルドファイルに一定のレベルの互換性が提供されます。 もちろん、Clang でサポートされていないコマンドライン オプションをビルドファイルで使用している場合は、それらのオプションを削除するか置き換える必要があります。

ARM での Clang のターゲット

ARM 向けにビルドするとき、Clang は、-march=armv7-a または -mthumb コンパイラ フラグの有無に基づいてターゲットを変更します。

表 1. 指定可能な -march 値とその結果のターゲット。

-march 結果のターゲット
-march=armv7-a armv7-none-linux-androideabi
-mthumb thumb-none-linux-androideabi
-march=armv7-a-mthumb の両方 thumbv7-none-linux-androideabi

必要に応じて、独自の -target でオーバーライドすることもできます。

Makefile では gccg++ を、clangclang++ に置き換えます。 疑問がある場合は、コンパイラの呼び出し時に次のオプションを使用して正しく動作していることを確認してください。

  • -v を使用すると、コンパイラのドライバの問題と関連するコマンドを出力できます。
  • -### を使用すると、暗黙的に事前定義されたものを含めてコマンドライン オプションを出力できます。
  • -x c < /dev/null -dM -E を使用すると、事前定義されたプリプロセッサ定義を出力できます。
  • -save-temps を使用すると、プリプロセッサで処理された *.i または *.ii ファイルを比較できます。

ABI の互換性

デフォルトでは、ARM Clang スタンドアロン ツールチェーンは armeabi-v7a ABI をターゲットにします。 この設定をオーバーライドするには、適切な -march または -target オプションを渡します。

16 ビット Thumb-2 命令の生成を強制するには、-mthumb コンパイラ フラグを使用することをおすすめします。 省略すると、ツールチェーンは 32 ビット ARM 命令を出力します。

NEON 命令を使用するには、-mfpu コンパイラ フラグを次のように使用する必要があります: -mfpu=neon

この設定は ARM 仕様に従って VFPv3-D32 の使用を強制することに注意してください。

また、次の 2 つのフラグをリンカーに指定する必要があります: -march=armv7-a -Wl,--fix-cortex-a8

最初のフラグは、armv7-a 向けに調整されたツールチェーン ライブラリを選択するようにリンカーに指示します。 2 番目のフラグは、一部の Cortex-A8 実装の CPU バグを回避するために必要です。

その他の ABI をターゲットにする場合は、特定のコンパイラ フラグを使用する必要はありません。

ABI サポートの詳細については、ABI をご覧ください。

警告と制限事項

Windows サポート

Windows バイナリは Cygwin に依存していません。 依存関係がないため、動作が高速になります。 ただし、Windows バイナリの場合、C:/foo/bar とは異なる cygdrive/c/foo/bar などの Cygwin パス仕様を認識しないというデメリットがあります。

例外、RTTI、STL

ツールチェーン バイナリはデフォルトで C++ 例外と RTTI をサポートします。 ソースをビルドするときに C++ 例外と RTTI を無効にするには(たとえば、より軽量のマシンコードを生成するため)、-fno-exceptions-fno-rtti を使用します。

C++ STL サポート

スタンドアロン ツールチェーンには、C++ 標準テンプレート ライブラリ(STL)の実装が含まれています。

  • libc++ の静的ライブラリ バージョンを取得するには -static-libstdc++ を使用します。 このようにすると、必要なすべての C++ STL コードが最終バイナリに組み込まれます。 単一の共有ライブラリまたは実行可能ファイルのみを生成する場合はこの方法が最適ですので、おすすめします。

  • デフォルトでは libc++ の共有ライブラリ バージョンが使用されます。 共有ライブラリに対してリンクするには、追加のフラグは必要ありません。 アプリには libc++_shared.so をパッケージする必要があります。そうしないとコードが読み込まれません。

    表 2 は、各アーキテクチャでの、このファイルの場所を示しています。

    表 2. 指定可能な -march 値とその結果のターゲット。

    ツールチェーン 場所
    arm $TOOLCHAIN/arm-linux-androideabi/lib/
    arm64 $TOOLCHAIN/aarch64-linux-android/lib/
    x86 $TOOLCHAIN/i686-linux-android/lib/
    x86_64 $TOOLCHAIN/x86_64-linux-android/lib/

スタンドアロン ツールチェーンを使用してオープンソース プロジェクトをビルドする

このようなツールチェーンの例について考えます。

# Create an arm64 API 26 libc++ toolchain.
$NDK/build/tools/make_standalone_toolchain.py \
  --arch arm64 \
  --api 26 \
  --install-dir=my-toolchain

これを使用して一般的なオープンソース プロジェクトをビルドするための環境をセットアップする方法は次のとおりです。

# Add the standalone toolchain to the search path.
export PATH=$PATH:`pwd`/my-toolchain/bin

# Tell configure what tools to use.
target_host=aarch64-linux-android
export AR=$target_host-ar
export AS=$target_host-clang
export CC=$target_host-clang
export CXX=$target_host-clang++
export LD=$target_host-ld
export STRIP=$target_host-strip

# Tell configure what flags Android requires.
export CFLAGS="-fPIE -fPIC"
export LDFLAGS="-pie"

カスタム ビルド システムのあるプロジェクト

一例として、上記の手順を実行した後に toybox をビルドする方法を次に示します。

git clone https://github.com/landley/toybox.git
cd toybox
make defconfig && make

autoconf を使用するプロジェクト

あるいは、autoconf ベースのプロジェクトの場合は次のようになります。

tar zxvf make-4.2.tar.gz
cd make-4.2
./configure --host=$target_host && make

autoconf ベースのプロジェクトはクロスコンパイルのサポートが大幅に変わることに注意してください。 また、autoconf ベースのプロジェクトの git clone を実行した場合、チェックインされた configure スクリプトが含まれないことが多いため、ブートストラップを行うためにそのプロジェクトのドキュメントに従う必要があります。