スタンドアロン ツールチェーン(非推奨)

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

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

Clang を呼び出す gccg++ という名前のラッパー スクリプトもあります。 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 では clangclang++ を、gccg++ に置き換えます。不安な場合は、コンパイラの呼び出し時に次のオプションを使用して正しく動作していることを確認してください。

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