Android NDK supporta l'utilizzo di CMake per compilare il codice C e C++ per la tua applicazione. Questa pagina spiega come utilizzare CMake con l'NDK tramite ExternalNativeBuild
del plug-in Gradle per Android o quando si invoca CMake direttamente.
Il file della toolchain CMake
L'NDK supporta CMake tramite un file toolchain. I file della toolchain sono file CMake
che personalizzano il comportamento della toolchain per la compilazione incrociata. Il file toolchain utilizzato per l'NDK si trova nell'NDK all'indirizzo <NDK>/build/cmake/android.toolchain.cmake
.
I parametri di build come ABI, minSdkVersion
e così via vengono forniti nella riga di comando
quando si richiama cmake
. Per un elenco degli argomenti supportati, consulta la sezione Argomenti della toolchain.
Il "nuovo" file toolchain
In precedenza, gli NDK hanno sperimentato una nuova implementazione del file toolchain che riduceva le differenze di comportamento tra l'utilizzo del file toolchain dell'NDK e l'utilizzo del supporto integrato di CMake. Ciò ha richiesto un impegno significativo di lavoro (che non è stato completato), ma non ha effettivamente migliorato il comportamento, pertanto non lo stiamo più perseguendo.
Il file toolchain "nuovo" presenta regressioni del comportamento rispetto al file toolchain "legacy". Il comportamento predefinito è il flusso di lavoro consigliato. Se utilizzi -DANDROID_USE_LEGACY_TOOLCHAIN_FILE=OFF
, ti consigliamo di rimuovere questo flag dalla build. Il nuovo file toolchain non ha mai raggiunto la parità con il file toolchain precedente, pertanto sono probabili regressioni del comportamento.
Sebbene sconsigliamo di utilizzare il nuovo file toolchain, al momento non sono previsti piani per rimuoverlo dall'NDK. In questo modo, le build che si basano sulle differenze di comportamento tra i file di toolchain nuovi e legacy e, sfortunatamente, rinominare l'opzione per chiarire che "legacy" è in realtà consigliato impedirebbe anche agli utenti di questa opzione. Se utilizzi il nuovo file toolchain, non è necessaria la migrazione, ma tieni presente che i bug segnalati relativi al comportamento del nuovo file toolchain probabilmente non verranno corretti e dovrai eseguire la migrazione.
Utilizzo
Gradle
L'utilizzo del file toolchain CMake è automatico quando si utilizza
externalNativeBuild
. Per ulteriori informazioni, consulta la guida di Android Studio Aggiungere codice C e C++ al progetto.
Riga di comando
Quando esegui la compilazione con CMake al di fuori di Gradle, il file della toolchain e i relativi argomenti devono essere passati a CMake. Ad esempio:
$ cmake \
-DCMAKE_TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=$ABI \
-DANDROID_PLATFORM=android-$MINSDKVERSION \
$OTHER_ARGS
Argomenti della toolchain
I seguenti argomenti possono essere passati al file della toolchain CMake. Se crei
con Gradle, aggiungi argomenti a
android.defaultConfig.externalNativeBuild.cmake.arguments
come descritto nella
documentazione relativa a External NativeBuild. Se esegui la compilazione dalla riga di comando, passa gli argomenti a CMake con -D
. Ad esempio, per forzare armeabi-v7a a non eseguire il build con il supporto di Neon, passa -DANDROID_ARM_NEON=FALSE
.
ANDROID_ABI
L'ABI target. Per informazioni sulle ABI supportate, vedi ABI Android.
Gradle
Gradle fornisce questo argomento automaticamente. Non impostare esplicitamente questo
argomento nel file build.gradle
. Per controllare quali ABI sono scelte come target da Gradle,
utilizza abiFilters
come descritto in ABI Android.
Riga di comando
Crea build per un singolo target per ogni build. Per scegliere come target più di un ABI Android, devi eseguire la compilazione una volta per ABI. È consigliabile utilizzare directory di build diverse per ogni ABI al fine di evitare collisioni tra le build.
Valore | Note |
---|---|
armeabi-v7a |
|
armeabi-v7a with NEON |
Uguale a armeabi-v7a . |
arm64-v8a |
|
x86 |
|
x86_64 |
ANDROID_ARM_MODE
Specifica se generare istruzioni arm o thumb per armeabi-v7a. Non ha alcun effetto per altre ABI. Per ulteriori informazioni, consulta la documentazione sulle ABI Android.
Valore | Note |
---|---|
un braccio | |
pollice | Comportamento predefinito. |
ANDROID_NATIVE_API_LEVEL
Alias per ANDROID_PLATFORM.
ANDROID_PLATFORM
Specifica il livello API minimo supportato dall'applicazione o dalla libreria. Questo valore corrisponde al minSdkVersion
dell'applicazione.
Gradle
Quando utilizzi il plug-in Gradle per Android, questo valore viene impostato automaticamente in modo da corrispondere a minSdkVersion
dell'applicazione e non deve essere impostato manualmente.
Riga di comando
Quando invochi CMake direttamente, questo valore è impostato per impostazione predefinita sul livello API più basso supportato dall'NDK in uso. Ad esempio, con NDK r20 questo valore è impostato in modo predefinito sul livello API 16.
Per questo parametro sono accettati più formati:
android-$API_LEVEL
$API_LEVEL
android-$API_LETTER
Il formato $API_LETTER
consente di specificare android-N
senza dover determinare il numero associato alla release. Tieni presente che alcune release hanno ricevuto un aumento dell'API senza un aumento delle lettere. Queste API possono essere specificate
aggiungendo il suffisso -MR1
. Ad esempio, il livello API 25 è android-N-MR1
.
ANDROID_STL
Specifica quale STL utilizzare per questa applicazione. Per ulteriori informazioni, consulta Supporto delle librerie C++. Per impostazione predefinita, verrà utilizzato c++_static
.
Valore | Note |
---|---|
c++_shared | La variante della libreria condivisa di libc++. |
c++_static | La variante della libreria statica di libc++. |
nessuno | Nessun supporto della libreria standard C++. |
di infotainment | L'STL di sistema |
Gestire i flag del compilatore
Se devi passare flag specifici al compilatore o al linker per la tua build, consulta la documentazione di CMake per set_target_compile_options e la relativa famiglia di opzioni. La sezione "Vedi anche" in fondo a questa pagina presenta alcuni indizi utili.
In generale, la best practice consiste nell'applicare i flag del compilatore come ambito più limitato disponibile. I flag che vuoi applicare a tutti i target (ad esempio -Werror
) sono scomodi da ripetere per modulo, ma raramente devono essere applicati a livello globale (CMAKE_CXX_FLAGS
), in quanto potrebbero avere effetti indesiderati sulle dipendenze di terze parti nel progetto. In questi casi, i flag possono essere applicati a livello di directory (add_compile_options
).
Per un sottoinsieme ristretto di flag del compilatore, questi possono essere impostati anche nel file build.gradle utilizzando cppFlags
o proprietà simili. Non devi farlo. I flag
passati a CMake da Gradle avranno comportamenti di precedenza sorprendenti, in alcuni
casi sostituendo i flag passati implicitamente dall'implementazione che sono
obbligatori per la compilazione del codice Android. Preferisci sempre gestire il comportamento di CMake
direttamente in CMake. Se devi controllare i flag del compilatore per AGP buildType
, consulta Lavorare con i tipi di build AGP in CMake.
Utilizzare i tipi di build AGP in CMake
Se devi personalizzare il comportamento di CMake in base a un Gradle buildType
personalizzato, utilizza questo tipo di compilazione per passare un ulteriore flag CMake (non un flag del compilatore) che gli script di compilazione CMake possano leggere. Ad esempio, se hai varianti di build "free" e "premium" controllate da build.gradle.kts e devi passare questi dati a CMake:
android {
buildTypes {
free {
externalNativeBuild {
cmake {
arguments.add("-DPRODUCT_VARIANT_PREMIUM=OFF")
}
}
}
premium {
externalNativeBuild {
cmake {
arguments.add("-DPRODUCT_VARIANT_PREMIUM=ON")
}
}
}
}
}
Poi, in CMakeLists.txt:
if (DPRODUCT_VARIANT_PREMIUM)
# Do stuff for the premium build.
else()
# Do stuff for the free build.
endif()
Il nome della variabile è a tua scelta, ma assicurati di evitare qualsiasi elemento con un prefisso ANDROID_
, APP_
o CMAKE_
per evitare conflitti o confusione con i flag esistenti.
Per un esempio, consulta l'esempio di igienizzanti NDK.
Informazioni sul comando di compilazione CMake
Durante il debug dei problemi di compilazione di CMake, è utile conoscere gli argomenti di compilazione specifici utilizzati da Gradle durante la compilazione incrociata per Android.
Il plug-in Android Gradle salva gli argomenti di compilazione utilizzati per eseguire una compilazione CMake per ogni coppia di ABI e tipo di build in build_command.txt
. Questi file si trovano nella seguente
directory:
<project-root>/<module-root>/.cxx/cmake/<build-type>/<ABI>/
Lo snippet seguente mostra un esempio degli argomenti CMake per compilare una release di debug del sample hello-jni
che ha come target l'architettura armeabi-v7a
.
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
Utilizzare librerie predefinite
Se la libreria predefinita che devi importare è distribuita come AAR, segui la documentazione sulle dipendenze di Studio per importarla e utilizzarla. Se non utilizzi AGP, puoi seguire la pagina https://google.github.io/prefab/example-workflow.html, ma è probabile che sia molto più semplice eseguire la migrazione ad AGP.
Per le librerie non distribuite come AAR, consulta la documentazione add_library
relativa ai IMPORTED
target nel manuale di CMake per istruzioni sull'utilizzo delle librerie predefinite con CMake.
Creazione di codice di terze parti
Esistono diversi modi per compilare il codice di terze parti all'interno del progetto CMake e l'opzione più adatta dipende dalla tua situazione. Spesso l'opzione migliore è non farlo affatto. Puoi invece creare un AAR per la libreria e utilizzarlo nella tua applicazione. Non è necessariamente necessario pubblicare l'AAR. Può essere interno al progetto Gradle.
Se questa opzione non è disponibile:
- Il fornitore (ovvero copia) l'origine di terze parti nel tuo repository e utilizza add_subdirectory per compilarlo. Questo funziona solo se anche l'altra libreria è creata con CMake.
- Definisci un ExternalProject.
- Crea la libreria separatamente dal progetto e segui le istruzioni riportate nell'articolo Utilizza le librerie predefinite per importarla come predefinita.
Supporto YASM in CMake
L'NDK fornisce il supporto di CMake per la compilazione del codice assembly scritto in YASM da eseguire su architetture x86 e x86-64. YASM è un assembler open source per le architetture x86 e x86-64, basato sull'assembler NASM.
Per compilare il codice assembly con CMake, apporta le seguenti modifiche al CMakeLists.txt
del progetto:
- Chiama
enable_language
con il valore impostato suASM_NASM
. - A seconda che tu stia creando una libreria condivisa o un codice eseguibile, chiama
add_library
oadd_executable
. Negli argomenti, passa un elenco di file di origine composti dai file.asm
per il programma Assembly in YASM e dai file.c
per le librerie o le funzioni C associate.
Lo snippet seguente mostra come configurare CMakeLists.txt
per compilare un programma YASM come libreria condivisa.
cmake_minimum_required(VERSION 3.6.0)
enable_language(ASM_NASM)
add_library(test-yasm SHARED jni/test-yasm.c jni/print_hello.asm)
Per un esempio di come compilare un programma YASM come eseguibile, consulta yasm test nel repository git NDK.
Segnalare problemi
Se riscontri problemi con l'NDK o con il relativo file toolchain CMake, segnalali tramite il tracker dei problemi android-ndk/ndk su GitHub. Per problemi relativi a Gradle o del plug-in Gradle di Android, segnala un bug di Studio.