CMake

Android NDK は、CMake を使用した C および C++ のアプリコードのコンパイルをサポートしています。このページでは NDK で CMake を使用する方法として、Android Gradle プラグインの ExternalNativeBuild を介す場合と、CMake を直接呼び出す場合を説明します。

CMake ツールチェーン ファイル

NDK は CMake をツールチェーン ファイルを使ってサポートします。ツールチェーン ファイルはクロスコンパイルでのツールチェーンの動作をカスタマイズする CMake ファイルです。NDK で使用されるツールチェーン ファイルは NDK 内の <NDK>/build/cmake/android.toolchain.cmake にあります。

ABI、minSdkVersion などのビルド パラメータは、cmake を呼び出すときにコマンドラインで指定します。サポートされる引数のリストについては、ツールチェーンの引数のセクションをご覧ください。

Usage

Gradle

externalNativeBuild を使用したとき、CMake ツールチェーン ファイルが自動的に使用されます。詳細については、Android Studio のプロジェクトへの C / C++ コードの追加に関するガイドをご覧ください。

コマンドライン

CMake を使って Gradle の外部でビルドする場合、ツールチェーン ファイルそのものとその引数を CMake に渡す必要があります。次に例を示します。

$ cmake \
    -DCMAKE_TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake \
    -DANDROID_ABI=$ABI \
    -DANDROID_PLATFORM=android-$MINSDKVERSION \
    $OTHER_ARGS

ツールチェーンの引数

以下の引数を、CMake ツールチェーン ファイルに渡すことができます。Gradle を使用してビルドする場合は、ExternalNativeBuild ドキュメントに記載のように、引数を android.defaultConfig.externalNativeBuild.cmake.arguments に指定します。コマンドラインからビルドする場合は、-D を指定して CMake に引数を渡します。たとえば、armeabi-v7a に対して NEON サポートを使用してビルドしないようにするには、-DANDROID_ARM_NEON=FALSE を渡します。

ANDROID_ABI

ターゲットとする ABI です。サポートされている ABI については、Android ABI に関するガイドをご覧ください。

Gradle

Gradle はこの引数を自動的に提供します。この引数を build.gradle ファイル内で明示的に設定しないでください。ABI Gradle が何をターゲットにするかを管理するには、Android ABI に関するガイドに記載のように、abiFilters を使用します。

コマンドライン

CMake はビルドごとに 1 つのターゲットに対してビルドします。複数の Android ABI をターゲットにするには、ABI ごとにビルドする必要があります。ビルド間の競合を回避するには、ABI ごとに異なるビルド ディレクトリを使用することをおすすめします。

Notes
armeabi-v7a
armeabi-v7a with NEON armeabi-v7a と同じ。
arm64-v8a
x86
x86_64

ANDROID_ARM_MODE

armeabi-v7a の ARM 命令と Thumb 命令のどちらを生成するかを指定します。他の ABI には影響しません。詳細については、Android ABI に関するドキュメントをご覧ください。

arm
thumb デフォルト動作。

ANDROID_ARM_NEON

armeabi-v7a の NEON を有効または無効にします。他の ABI には影響しません。API レベル(minSdkVersion または ANDROID_PLATFORM)23 以降のデフォルトは true です。それ以外のデフォルトは false です。詳細については、NEON サポートのドキュメントをご覧ください。

TRUE API レベル 23 以降でのデフォルト。
FALSE API レベル 22 以前でのデフォルト。

ANDROID_LD

使用するリンカーを選択します。lld は現在 NDK での試験運用版で、この引数で有効にできます。

Notes
lld lld を有効にする。
default 指定した ABI のデフォルトのリンカーを使用する。

ANDROID_NATIVE_API_LEVEL

ANDROID_PLATFORM のエイリアスです。

ANDROID_PLATFORM

アプリまたはライブラリでサポートされる最小の API レベルを指定します。この値はアプリの minSdkVersion に対応します。

Gradle

Android Gradle プラグインを使用する場合、この値はアプリの minSdkVersion に一致するように自動的に設定されるので、手動では設定しないでください。

コマンドライン

CMake を直接呼び出す場合、この値のデフォルトは、使用中の NDK でサポートされる最小の API レベルです。たとえば、NDK r20 の場合、この値はデフォルトで API レベル 16 になります。

このパラメータに指定できる形式は複数あります。

  • android-$API_LEVEL
  • $API_LEVEL
  • android-$API_LETTER

$API_LETTER 形式を使用すると、android-N を指定できるので、そのリリースに関連付けられた番号を特定する必要はありません。API 番号が増えても文字が変わらなかったリリースもあるのでご注意ください。その場合の API は、-MR1 サフィックスを追加して指定できます。たとえば、API レベル 25 は android-N-MR1 です。

ANDROID_STL

このアプリに使用する STL を指定します。詳細については、C++ ライブラリ サポートをご覧ください。デフォルトでは c++_static が使用されます。

Notes
c++_shared libc++ の共有ライブラリ バリアント。
c++_static libc++ の静的ライブラリ バリアント。
none C++ 標準ライブラリのサポートなし。
system system STL

CMake ビルドコマンドについて

CMake のビルドに関する問題をデバッグする際に、Gradle がクロスコンパイル時に Android 用に使用する各ビルド引数について知っておくと役に立ちます。

Android Gradle プラグインは、ABI とビルドタイプのペアごとに、CMake ビルドの実行に使用するビルド引数を build_command.txt に保存します。これらのファイルは、次のディレクトリにあります。

<project-root>/<module-root>/.cxx/cmake/<build-type>/<ABI>/

次のスニペットは、armeabi-v7a アーキテクチャをターゲットとする hello-jni のサンプルのデバッグ可能なリリースをビルドする CMake 引数の例を示します。

                    Executable : ${HOME}/Android/Sdk/cmake/3.10.2.4988404/bin/cmake
arguments :
-H${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/src/main/cpp
-DCMAKE_FIND_ROOT_PATH=${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/.cxx/cmake/universalDebug/prefab/armeabi-v7a/prefab
-DCMAKE_BUILD_TYPE=Debug
-DCMAKE_TOOLCHAIN_FILE=${HOME}/Android/Sdk/ndk/22.1.7171670/build/cmake/android.toolchain.cmake
-DANDROID_ABI=armeabi-v7a
-DANDROID_NDK=${HOME}/Android/Sdk/ndk/22.1.7171670
-DANDROID_PLATFORM=android-23
-DCMAKE_ANDROID_ARCH_ABI=armeabi-v7a
-DCMAKE_ANDROID_NDK=${HOME}/Android/Sdk/ndk/22.1.7171670
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/build/intermediates/cmake/universalDebug/obj/armeabi-v7a
-DCMAKE_RUNTIME_OUTPUT_DIRECTORY=${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/build/intermediates/cmake/universalDebug/obj/armeabi-v7a
-DCMAKE_MAKE_PROGRAM=${HOME}/Android/Sdk/cmake/3.10.2.4988404/bin/ninja
-DCMAKE_SYSTEM_NAME=Android
-DCMAKE_SYSTEM_VERSION=23
-B${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/.cxx/cmake/universalDebug/armeabi-v7a
-GNinja
jvmArgs :


                    Build command args: []
                    Version: 1

ビルド済みライブラリを使用する

インポートする必要があるビルド済みライブラリが AAR として配布されている場合は、Studio の依存関係に関するドキュメントに沿ってインポートし、使用します。AGP を使用していない場合は、https://google.github.io/prefab/example-workflow.html に沿って行うこともできます。ただし、AGP に移行する方がはるかに簡単になります。

AAR として配布されていないライブラリの場合、CMake でビルド済みライブラリを使用する手順については、CMake マニュアルIMPORTED ターゲットに関する add_library のドキュメントをご覧ください。

サードパーティ コードのビルド

CMake プロジェクトの一部としてサードパーティ コードをビルドする方法はいくつかありますが、最適な選択肢は状況によって異なります。この方法を行わないのが最適な選択肢となることもよくあります。代わりに、ライブラリの AAR をビルドして、アプリで使用します。その AAR は必ずしも公開する必要はありません。Gradle プロジェクトで内部的に使用できます。

上記の方法が適していない場合:

  • サードパーティのソースをリポジトリに供給(コピー)し、add_subdirectory を使用してビルドします。この方法は、もう一方のライブラリも CMake でビルドされる場合にのみ機能します。
  • ExternalProject を定義します。
  • プロジェクトとは別にライブラリをビルドし、ビルド済みライブラリを使用するの手順に沿って、ビルド済みとしてインポートします。

CMake での YASM サポート

NDK は、YASM で記述され、x86 と x86-64 アーキテクチャで実行されるアセンブリ コードをビルドする CMake サポートを提供します。YASM は、NASM アセンブラをベースとする x86 と x86-64 アーキテクチャ用のオープンソース アセンブラです。

CMake でアセンブリ コードをビルドするには、プロジェクトの CMakeLists.txt を次のように変更します。

  1. ASM_NASM に設定する値を指定して enable_language を呼び出します。
  2. 共有ライブラリをビルドするのか、実行可能なバイナリをビルドするのかに応じて、add_library または add_executable を呼び出します。YASM のアセンブリ プログラムの .asm ファイルと、関連する C ライブラリまたは関数の .c ファイルから構成されるソースファイルのリストを引数に渡します。

次のスニペットは、YASM プログラムを共有ライブラリとしてビルドする CMakeLists.txt の設定方法の例を示します。

cmake_minimum_required(VERSION 3.6.0)

enable_language(ASM_NASM)

add_library(test-yasm SHARED jni/test-yasm.c jni/print_hello.asm)

YASM プログラムを実行可能ファイルとしてビルドする方法の例については、NDK Git リポジトリの yasm test をご覧ください。

問題を報告する

NDK または CMake のツールチェーン ファイルで問題が発生した場合は、GitHub の android-ndk/ndk 公開バグトラッカーで報告してください。Gradle または Android Gradle プラグインの問題については、代わりに Studio のバグを報告してください。