Configura CMake

Uno script di build CMake è un file di testo normale a cui devi assegnare un nome CMakeLists.txt e che include i comandi utilizzati da CMake per creare le tue librerie C/C++. Se le tue origini native non dispongono già di uno script di build CMake, devi crearne uno tu e includere i comandi CMake appropriati. Per informazioni su come installare CMake, consulta Installazione e configurazione di NDK e CMake.

Questa sezione illustra alcuni comandi di base da includere nello script di build per indicare a CMake le origini da utilizzare durante la creazione della tua libreria nativa. Per saperne di più, leggi la documentazione ufficiale sui comandi CMake.

Dopo aver configurato un nuovo script di build CMake, devi configurare Gradle per includere il progetto CMake come dipendenza per la build, in modo che Gradle crei e pacchetti la tua libreria nativa con l'APK della tua app.

Nota: se il progetto utilizza ndk-build, non è necessario creare uno script di build CMake. Puoi semplicemente configurare Gradle per includere il tuo progetto di libreria nativa esistente fornendo un percorso al tuo file Android.mk.

Creare uno script di build CMake

Per creare un file di testo normale da utilizzare come script di build di CMake, procedi come segue:

  1. Apri il riquadro Progetto sul lato sinistro dell'IDE e seleziona la visualizzazione Progetto dal menu a discesa.
  2. Fai clic con il tasto destro del mouse sulla directory principale di your-module e seleziona Nuovo > File.

    Nota:puoi creare lo script di build in qualsiasi posizione. Tuttavia, durante la configurazione dello script di build, i percorsi dei file di origine e delle librerie nativi sono relativi alla posizione dello script di build.

  3. Inserisci "CMakeLists.txt" come nome file e fai clic su OK.

Ora puoi configurare lo script di build aggiungendo i comandi CMake. Per indicare a CMake di creare una libreria nativa dal codice sorgente nativo, aggiungi i comandi cmake_minimum_required() e add_library() allo script di build:

# 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 )

Suggerimento: in modo simile a come puoi indicare a CMake di creare una libreria nativa a partire dai file di origine, puoi utilizzare il comando add_executable() per indicare a CMake di creare invece un eseguibile dai file di origine. Tuttavia, la creazione di file eseguibili dalle origini native è facoltativa e la creazione di librerie native da pacchettizzare nell'APK soddisfa la maggior parte dei requisiti di progetto.

Quando aggiungi un file o una libreria di origine allo script di build di CMake utilizzando add_library(), Android Studio mostra anche i file di intestazione associati nella visualizzazione Progetto dopo la sincronizzazione del progetto. Tuttavia, per consentire a CMake di individuare i file di intestazione durante la compilazione, devi aggiungere il comando include_directories() allo script di build di CMake e specificare il percorso delle intestazioni:

add_library(...)

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

La convenzione utilizzata da CMake per assegnare un nome al file della tua libreria è la seguente:

liblibrary-name.so

Ad esempio, se specifichi "native-lib" come nome della libreria condivisa nello script di build, CMake crea un file denominato libnative-lib.so. Tuttavia, quando carichi questa libreria nel codice Java o Kotlin, utilizza il nome specificato nello script di build CMake:

Kotlin

companion object {
    init {
        System.loadLibrary("native-lib");
    }
}

Java

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

Nota: se rinomini o rimuovi una libreria nello script di build di CMake, devi pulire il progetto prima che Gradle applichi le modifiche o rimuova la versione precedente della libreria dall'APK. Per ripulire il progetto, seleziona Crea > Pulisci progetto dalla barra dei menu.

Android Studio aggiunge automaticamente le intestazioni e i file di origine al gruppo cpp nel riquadro Progetto. Se utilizzi più comandi add_library(), puoi definire librerie aggiuntive per consentire a CMake di creare da altri file di origine.

Aggiungi API NDK

L'NDK di Android fornisce un insieme di API e librerie native che potresti trovare utili. Puoi utilizzare una qualsiasi di queste API includendo le librerie NDK nel file di script CMakeLists.txt del tuo progetto.

Sulla piattaforma Android esistono già librerie NDK predefinite, quindi non è necessario crearle o pacchettizzarle nel tuo APK. Poiché le librerie NDK fanno già parte del percorso di ricerca di CMake, non è necessario specificare la posizione della libreria nell'installazione NDK locale: è sufficiente fornire a CMake il nome della libreria che vuoi utilizzare e collegarla alla tua libreria nativa.

Aggiungi il comando find_library() allo script di build di CMake per individuare una libreria NDK e archiviarne il percorso come variabile. Utilizza questa variabile per fare riferimento alla libreria NDK in altre parti dello script di build. L'esempio seguente individua la libreria di supporto dei log specifica per Android e ne archivia il percorso in 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 )

Affinché la tua libreria nativa chiami le funzioni nella libreria log, devi collegare le librerie utilizzando il comando target_link_libraries() nello script di build di CMake:

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} )

L'NDK include anche alcune librerie come codice sorgente che devi creare e collegare alla tua libreria nativa. Puoi compilare il codice sorgente in una libreria nativa utilizzando il comando add_library() nello script di build di CMake. Per fornire un percorso alla libreria NDK locale, puoi utilizzare la variabile percorso ANDROID_NDK, che Android Studio definisce automaticamente.

Il seguente comando indica a CMake di creare android_native_app_glue.c, che gestisce gli eventi del ciclo di vita di NativeActivity e l'input tocco, in una libreria statica e la collega a native-lib:

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} )

Aggiungi altre librerie predefinite

L'aggiunta di una libreria predefinita è simile alla specifica di un'altra libreria nativa da creare con CMake. Tuttavia, poiché la libreria è già creata, devi utilizzare il flag IMPORTED per comunicare a CMake che vuoi importare solo la libreria nel tuo progetto:

add_library( imported-lib
             SHARED
             IMPORTED )

Devi quindi specificare il percorso della libreria utilizzando il comando set_target_properties() come mostrato di seguito.

Alcune librerie forniscono pacchetti separati per architetture CPU specifiche, o ABI (Application Binary Interfaces), e li organizzano in directory separate. Questo approccio consente alle librerie di sfruttare alcune architetture della CPU, permettendo al contempo di utilizzare solo le versioni della libreria che preferisci. Per aggiungere più versioni ABI di una libreria allo script di build di CMake, senza dover scrivere più comandi per ogni versione della libreria, puoi utilizzare la variabile percorso ANDROID_ABI. Questa variabile utilizza un elenco delle ABI predefinite supportate da NDK o un elenco filtrato di ABI che configuri manualmente Gradle da utilizzare. Ecco alcuni esempi:

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 )

Affinché CMake possa individuare i tuoi file di intestazione durante la compilazione, devi utilizzare il comando include_directories() e includere il percorso dei file di intestazione:

include_directories( imported-lib/include/ )

Nota: se vuoi pacchettizzare una libreria predefinita che non è una dipendenza in fase di build, ad esempio quando aggiungi una libreria predefinita che è una dipendenza di imported-lib, non è necessario eseguire le seguenti istruzioni per collegare la libreria.

Per collegare la libreria predefinita alla tua libreria nativa, aggiungila al comando target_link_libraries() nello script di build di CMake:

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

Per pacchettizzare la libreria predefinita nel tuo APK, devi configurare manualmente Gradle con il blocco sourceSets per includere il percorso al file .so. Dopo aver creato l'APK, puoi verificare quali librerie Gradle vengono inserite nell'APK utilizzando lo Strumento di analisi APK.

Includi altri progetti CMake

Se vuoi creare più progetti CMake e includere i relativi output nel progetto Android, puoi utilizzare un file CMakeLists.txt come script di build CMake di primo livello (quello che colleghi a Gradle) e aggiungere altri progetti CMake come dipendenze di quello script di build. Il seguente script di build CMake di primo livello utilizza il comando add_subdirectory() per specificare un altro file CMakeLists.txt come dipendenza della build, quindi si collega al relativo output come faresti con qualsiasi altra libreria predefinita.

# 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 )

Chiamare CMake dalla riga di comando

Utilizza il seguente comando per chiamare CMake e generare un progetto Ninja al di fuori di Android Studio:

cmake
-Hpath/to/cmakelists/folder
-Bpath/to/generated/ninja/project/debug/ABI
-DANDROID_ABI=ABI                               // For example, arm64-v8a
-DANDROID_PLATFORM=platform-version-string      // For example, android-16
-DANDROID_NDK=android-sdk/ndk/ndk-version
-DCMAKE_TOOLCHAIN_FILE=android-sdk/ndk/ndk-version/build/cmake/android.toolchain.cmake
-G Ninja

Questo comando genererà il progetto Ninja che può essere eseguito per creare librerie eseguibili Android (file .so). Il CMAKE_TOOLCHAIN_FILE è necessario per utilizzare il supporto CMake di NDK. Per CMake 3.21 o versioni successive, è possibile utilizzare il supporto NDK integrato di CMake, ma è necessario utilizzare un gruppo diverso di variabili, come descritto nella documentazione di CMake Cross Compiling per Android.