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

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 バイナリは自動的にスタンドアロン ツールチェーンに組み込まれます。

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

Clang を呼び出す gcc および g++ という名前の 2 つのラッパー スクリプトもあります。NDK には GCC が含まれなくなりましたが、この 2 つのラッパー スクリプトは、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)をリンカーに指定する必要があります。

1 つ目のフラグは、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 スクリプトが含まれないことが多いため、そのプロジェクトのドキュメントに沿ってブートストラップを行う必要があります。