Android Dev Summit, October 23-24: two days of technical content, directly from the Android team. Sign-up for livestream updates.

CMake の設定

CMake ビルド スクリプトは書式なしテキスト ファイルで、名前は CMakeLists.txt にする必要があります。CMake ビルド スクリプトには、CMake が C / C++ ライブラリのビルドに使用するコマンドを含めます。ネイティブ ソースの CMake ビルド スクリプトがない場合は、作成して適切な CMake コマンドを含める必要があります。

このセクションでは、ネイティブ ライブラリの作成時に使用するソースを CMake に指示するために、ビルド スクリプトに含める必要がある基本的なコマンドについて説明します。詳しくは、CMake コマンドの公式ドキュメントをご覧ください。

新しい CMake ビルド スクリプトを作成した後、Gradle の設定で CMake プロジェクトをビルド依存関係として含め、Gradle がネイティブ ライブラリをビルドしてアプリの APK にパッケージ化できるようにする必要があります。

注: プロジェクトで ndk-build を使用する場合、CMake ビルド スクリプトの作成は不要です。Gradle の設定Android.mk ファイルへのパスを指定するだけで、既存のネイティブ ライブラリ プロジェクトを含めることができます。

CMake ビルド スクリプトの作成

CMake ビルド スクリプトとして使用できる書式なしテキスト ファイルを作成するには、次の手順を行います。

  1. IDE の左側にある [Project] ペインを開き、プルダウン メニューの [Project] ビューを選択します。
  2. your-module のルート ディレクトリを右クリックして、[New] > [File] を選択します。

    注: ビルド スクリプトは任意の場所に作成できます。ただし、ビルド スクリプトを設定するときは、ネイティブ ソース ファイルとライブラリのパスにはビルド スクリプトの場所に対する相対パスを指定してください。

  3. ファイル名に「CMakeLists.txt」と入力し、[OK] をクリックします。

これで、CMake コマンドを追加してビルド スクリプトを設定できるようになりました。ネイティブ ソースコードからネイティブ ライブラリを作成するように CMake に指示するには、cmake_minimum_required() コマンドと add_library() コマンドをビルド スクリプトに追加します。

    # Sets the minimum version of CMake required to build your native library.
    # This ensures that a certain set of CMake features is available to
    # your build.

    cmake_minimum_required(VERSION 3.4.1)

    # Specifies a library name, specifies whether the library is STATIC or
    # SHARED, and provides relative paths to the source code. You can
    # define multiple libraries by adding multiple add_library() commands,
    # and CMake builds them for you. When you build your app, Gradle
    # automatically packages shared libraries with your APK.

    add_library( # Specifies the name of the library.
                 native-lib

                 # Sets the library as a shared library.
                 SHARED

                 # Provides a relative path to your source file(s).
                 src/main/cpp/native-lib.cpp )
    

ヒント: ソースファイルからネイティブ ライブラリを作成するように CMake に指示する方法と同様に、add_executable() コマンドを使用して、ソースファイルから実行可能ファイルを作成するように CMake に指示することができます。ただし、ネイティブ ソースからの実行可能ファイルの作成はオプションであり、ネイティブ ライブラリを作成して APK にパッケージ化することでほとんどのプロジェクト要件は満たされます。

add_library() を使用してソースファイルまたはライブラリを CMake ビルド スクリプトに追加すると、プロジェクトを同期した後に Android Studio の [Project] ビューに関連するヘッダー ファイルも表示されます。ただし、コンパイル時に CMake がヘッダー ファイルを特定できるようにするには、include_directories() コマンドを CMake ビルド スクリプトに追加して、ヘッダーへのパスを指定する必要があります。

    add_library(...)

    # Specifies a path to native header files.
    include_directories(src/main/cpp/include/)
    

CMake で使用するライブラリ ファイルの命名規則は次のとおりです。

liblibrary-name.so

たとえば、ビルド スクリプトで共有ライブラリの名前を「native-lib」と指定すると、CMake によって libnative-lib.so というファイルが作成されます。ただし、このライブラリを Java または Kotlin コードで読み込む場合は、CMake ビルド スクリプトで指定した名前を使用します。

    static {
        System.loadLibrary("native-lib");
    }
    

注: CMake ビルド スクリプト内のライブラリの名前変更または削除を行う場合は、Gradle が変更を適用する前に、あるいは古いバージョンのライブラリを APK から削除する前に、プロジェクトのクリーンを実行する必要があります。その場合、メニューバーで [Build] > [Clean Project] を選択します。

Android Studio は、[Project] ペインの cpp グループにソースファイルとヘッダーを自動的に追加します。複数の add_library() コマンドを使用して、CMake の追加のライブラリを定義すると、他のソースファイルからビルドできるようになります。

NDK API の追加

Android NDK では、有用なネイティブ API とライブラリのセットを提供しています。これらの API を使用するには、プロジェクトの CMakeLists.txt スクリプト ファイルに NDK ライブラリを含めます。

ビルド済みの NDK ライブラリは Android プラットフォームにすでに存在するため、ビルドしたり APK にパッケージ化したりする必要はありません。NDK ライブラリはすでに CMake の検索パスに含まれているため、ローカルの NDK のインストールでライブラリの場所を指定する必要もありません。必要なのは、使用するライブラリの名前を CMake に指定して、ネイティブ ライブラリとリンクさせることだけです。

NDK ライブラリを特定して変数にそのパスを保存できるように、CMake ビルド スクリプトに find_library() コマンドを追加します。この変数を使用して、ビルド スクリプトの他の部分で NDK ライブラリを参照します。次のサンプルでは、Android 固有のログ サポート ライブラリを特定し、log-lib にそのパスを保存しています。

    find_library( # Defines the name of the path variable that stores the
                  # location of the NDK library.
                  log-lib

                  # Specifies the name of the NDK library that
                  # CMake needs to locate.
                  log )
    

ネイティブ ライブラリで log ライブラリの関数を呼び出すには、CMake ビルド スクリプトで target_link_libraries() コマンドを使用してライブラリをリンクする必要があります。

    find_library(...)

    # Links your native library against one or more other native libraries.
    target_link_libraries( # Specifies the target library.
                           native-lib

                           # Links the log library to the target library.
                           ${log-lib} )
    

NDK の一部のライブラリは、ビルドしてネイティブ ライブラリにリンクする必要があるソースコードとして提供されています。CMake ビルド スクリプトで add_library() コマンドを使用することで、そのソースコードをネイティブ ライブラリにコンパイルできます。ローカルの NDK ライブラリへのパスを指定するには、ANDROID_NDK パス変数を使用します。これは、Android Studio が自動的に定義します。

次のコマンドは、NativeActivity のライフサイクル イベントとタップ入力を管理する android_native_app_glue.c を静的ライブラリにビルドして、native-lib にリンクするよう CMake に指示します。

    add_library( app-glue
                 STATIC
                 ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c )

    # You need to link static libraries against your shared native library.
    target_link_libraries( native-lib app-glue ${log-lib} )
    

その他のビルド済みライブラリの追加

ビルド済みライブラリを追加する方法は、別のネイティブ ライブラリを CMake でビルドするよう指定する場合と同様です。ただし、ライブラリはビルド済みであるため、IMPORTED フラグを使用して、プロジェクトへのインポートのみを実行するよう CMake に指示する必要があります。

    add_library( imported-lib
                 SHARED
                 IMPORTED )
    

次に、以下のように set_target_properties() コマンドを使用して、ライブラリへのパスを指定する必要があります。

一部のライブラリでは、特定の CPU アーキテクチャに対応した個別のパッケージやアプリケーション バイナリ インターフェース(ABI)を提供しており、それらを別のディレクトリにまとめています。このアプローチにより、ライブラリは特定の CPU アーキテクチャを活用でき、デベロッパーは必要なバージョンのライブラリのみを使用できます。複数の ABI バージョンのライブラリを CMake ビルド スクリプトに追加する場合、ライブラリのバージョンごとに複数のコマンドを記述する必要はありません。ANDROID_ABI パス変数を使用できます。この変数は、NDK がサポートするデフォルトの ABI のリストを使用するか、手動で Gradle を設定してフィルタした ABI のリストを使用します。次に例を示します。

    add_library(...)
    set_target_properties( # Specifies the target library.
                           imported-lib

                           # Specifies the parameter you want to define.
                           PROPERTIES IMPORTED_LOCATION

                           # Provides the path to the library you want to import.
                           imported-lib/src/${ANDROID_ABI}/libimported-lib.so )
    

コンパイル時に CMake でヘッダー ファイルを特定するには、include_directories() コマンドでヘッダー ファイルへのパスを指定する必要があります。

    include_directories( imported-lib/include/ )
    

注: たとえば、imported-lib の依存関係であるビルド済みライブラリを追加するときなど、ビルド時の依存関係ではないビルド済みライブラリをパッケージ化する場合は、次の手順でライブラリをリンクする必要はありません。

独自のネイティブ ライブラリにビルド済みライブラリをリンクするには、CMake ビルド スクリプトの target_link_libraries() コマンドにそのライブラリを追加します。

    target_link_libraries( native-lib imported-lib app-glue ${log-lib} )
    

ビルド済みライブラリを APK にパッケージ化するには、.so ファイルへのパスを含めるように sourceSets ブロックを指定して、手動で Gradle を設定する必要があります。APK をビルドした後、APK Analyzer で、Gradle が APK にパッケージ化するライブラリを確認することができます。

他の CMake プロジェクトを含める

複数の CMake プロジェクトをビルドしてその出力を Android プロジェクトに含めると、1 つの CMakeLists.txt ファイルを最上位の CMake ビルド スクリプト(Gradle にリンクするビルド スクリプト)として使用し、そのビルド スクリプトの依存関係として CMake プロジェクトを追加できます。以下の最上位の CMake ビルド スクリプトでは、add_subdirectory() コマンドを使用して別の CMakeLists.txt ファイルをビルド依存関係として指定し、他のビルド済みライブラリと同様にその出力に対してリンクしています。

    # Sets lib_src_DIR to the path of the target CMake project.
    set( lib_src_DIR ../gmath )

    # Sets lib_build_DIR to the path of the desired output directory.
    set( lib_build_DIR ../gmath/outputs )
    file(MAKE_DIRECTORY ${lib_build_DIR})

    # Adds the CMakeLists.txt file located in the specified directory
    # as a build dependency.
    add_subdirectory( # Specifies the directory of the CMakeLists.txt file.
                      ${lib_src_DIR}

                      # Specifies the directory for the build outputs.
                      ${lib_build_DIR} )

    # Adds the output of the additional CMake build as a prebuilt static
    # library and names it lib_gmath.
    add_library( lib_gmath STATIC IMPORTED )
    set_target_properties( lib_gmath PROPERTIES IMPORTED_LOCATION
                           ${lib_build_DIR}/${ANDROID_ABI}/lib_gmath.a )
    include_directories( ${lib_src_DIR}/include )

    # Links the top-level CMake build output against lib_gmath.
    target_link_libraries( native-lib ... lib_gmath )