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 を呼び出すときにコマンドラインで指定します。サポートされる引数のリストについては、ツールチェーンの引数のセクションをご覧ください。

「新しい」ツールチェーン ファイル

以前の NDK では、新しいツールチェーン ファイルの新しい実装がテストされていました。 を使用すると、NDK のツールチェーン ファイルを使用した際の動作の違いが 組み込みの CMake サポートを使用します。最終的には かなり多くの労力を (未完了の作業)はあるものの、実際には動作の改善にはならなかった この取り組みはやめています

「新しい」ツールチェーン ファイルに「レガシー」と比較して動作が回帰する ツールチェーン ファイルです。デフォルトの動作は推奨ワークフローです。もし フラグを使用-DANDROID_USE_LEGACY_TOOLCHAIN_FILE=OFFしている場合は、このフラグを おすすめします。新しいツールチェーン ファイルが従来のものと同等になることはなかった 動作が回帰する可能性があります。

新しいツールチェーン ファイルは使用しないことをおすすめしますが、現在のところ、 NDK から削除することを計画しています。変更すると、 新しいツールチェーン ファイルと以前のツールチェーン ファイルの動作の違い 「レガシー」がはっきりわかるよう実際には おすすめします。「 移行する必要はありませんが、報告済みのバグは 新しいツールチェーン ファイルの動作に対する修正はおそらく修正されず、 移行する必要があります

使用方法

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 ごとに異なるビルド ディレクトリを使用することをおすすめします。

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_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 が使用されます。

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

コンパイラ フラグを管理する

ビルドのコンパイラまたはリンカーに特定のフラグを渡す必要がある場合は、 CMake のドキュメントで set_target_compile_options と 関連オプション群が含まれます。「参照」というセクションに いくつか見てみましょう。

一般的には、最も狭い範囲のフラグとしてコンパイラ フラグを適用することをおすすめします。 あります。すべてのターゲットに適用するフラグ( -Werror など)は、モジュールごとに繰り返すには不便ですが、 グローバルに適用(CMAKE_CXX_FLAGS) 依存関係が存在します。このような場合、フラグに ディレクトリ スコープ(add_compile_options)で適用されました。

コンパイラ フラグの狭いサブセットの場合は、build.gradle cppFlags または同様のプロパティを使用してこのファイルを実行します。これは行ってはいけません。フラグ Gradle から CMake に渡されるものは、予期しない動作を優先します。 実装によって暗黙的に渡されたフラグをオーバーライドするケース。 Android コードのビルドに必要です。CMake の動作を常に優先する CMake で作成します。AGP buildType ごとにコンパイラ フラグを制御する必要がある場合は、 CMake で AGP ビルドタイプを操作するをご覧ください。

CMake で AGP ビルドタイプを操作する

CMake の動作をカスタムの Gradle buildType に合わせて調整する必要がある場合は、それを使用します。 ビルドタイプを使用して、追加の CMake フラグ(コンパイラ フラグではない)を渡して、 CMake ビルド スクリプトが読み取れる。たとえば、「無料」の「premium」 build.gradle.kts によって制御されるビルド バリアント。 CMake に追加します。

android {
    buildTypes {
        free {
            externalNativeBuild {
                cmake {
                    arguments.add("-DPRODUCT_VARIANT_PREMIUM=OFF")
                }
            }
        }
        premium {
            externalNativeBuild {
                cmake {
                    arguments.add("-DPRODUCT_VARIANT_PREMIUM=ON")
                }
            }
        }
    }
}

次に、CMakeLists.txt で次のようにします。

if (DPRODUCT_VARIANT_PREMIUM)
  # Do stuff for the premium build.
else()
  # Do stuff for the free build.
endif()

変数の名前は任意ですが、 競合や混同を避けるために、ANDROID_APP_CMAKE_ の接頭辞を使用します。 使用できます。

例については、Sanitizers NDK サンプルをご覧ください。

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 のバグを報告してください。