L'NDK per Android supporta l'utilizzo di CMake per compilare il codice C e C++ per la tua applicazione. Questa pagina illustra come utilizzare
CMake con l'NDK tramite ExternalNativeBuild del plug-in Android Gradle o quando
richiami 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 in
<NDK>/build/cmake/android.toolchain.cmake.
I parametri di build come ABI, minSdkVersion e così via vengono forniti nella riga di comando quando viene richiamato cmake. Per un elenco degli argomenti supportati, consulta la sezione
Argomenti della toolchain.
Il file della toolchain "nuova"
Le versioni precedenti dell'NDK hanno sperimentato una nuova implementazione del file toolchain che ridurrebbe le differenze di comportamento tra l'utilizzo del file toolchain dell'NDK e l'utilizzo del supporto CMake integrato. Ciò ha richiesto una quantità significativa di lavoro (che non è stato completato), ma non ha migliorato il comportamento, quindi non stiamo più lavorando a questo.
Il file della toolchain "nuova" presenta regressioni del comportamento rispetto al file della toolchain "legacy". Il comportamento predefinito è il workflow consigliato. Se utilizzi -DANDROID_USE_LEGACY_TOOLCHAIN_FILE=OFF, ti consigliamo di rimuovere questo flag dalla build. Il nuovo file della toolchain non ha mai raggiunto la parità con il file della toolchain legacy, quindi è probabile che si verifichino regressioni del comportamento.
Anche se sconsigliamo l'utilizzo del nuovo file toolchain, al momento non è previsto di rimuoverlo dall'NDK. In questo modo, le build che si basano sulle differenze di comportamento tra i file della toolchain nuovi e legacy non funzionerebbero più e, sfortunatamente, rinominare l'opzione per chiarire che "legacy" è in realtà consigliata interromperebbe anche gli utenti di questa opzione. Se utilizzi il nuovo file della toolchain, non devi eseguire la migrazione, ma tieni presente che i bug segnalati relativi al comportamento del nuovo file della toolchain probabilmente non verranno corretti e dovrai eseguire la migrazione.
Utilizzo
Gradle
L'utilizzo del file della toolchain CMake è automatico quando utilizzi
externalNativeBuild. Per ulteriori informazioni, consulta la guida Aggiungere codice C e C++ al progetto di Android Studio.
Riga di comando
Quando crei con CMake al di fuori di Gradle, il file della toolchain stesso 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
È possibile passare i seguenti argomenti al file della toolchain CMake. Se crei
con Gradle, aggiungi argomenti a
android.defaultConfig.externalNativeBuild.cmake.arguments come descritto nella
documentazione di ExternalNativeBuild. Se esegui la build dalla riga di comando, trasmetti gli argomenti a
CMake con -D. Ad esempio, per forzare la compilazione di armeabi-v7a senza il supporto di Neon, passa -DANDROID_ARM_NEON=FALSE.
ANDROID_ABI
L'ABI di destinazione. Per informazioni sulle ABI supportate, vedi ABI Android.
Gradle
Gradle fornisce questo argomento automaticamente. Non impostare in modo esplicito questo
argomento nel file build.gradle. Per controllare le ABI di destinazione di Gradle,
utilizza abiFilters come descritto in ABI Android.
Riga di comando
CMake esegue la compilazione per una singola destinazione per build. Per scegliere come target più di un'ABI Android, devi eseguire la build una volta per ogni ABI. È consigliabile utilizzare directory di build diverse per ogni ABI per evitare conflitti 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 per il braccio o il pollice per armeabi-v7a. Non ha alcun effetto per le altre ABI. Per saperne di più, consulta la documentazione relativa alle ABI di Android.
| Valore | Note |
|---|---|
| braccio | |
| pollice | Comportamento predefinito. |
ANDROID_NATIVE_API_LEVEL
Alias di ANDROID_PLATFORM.
ANDROID_PLATFORM
Specifica il livello API minimo supportato dall'applicazione o dalla libreria. Questo
valore corrisponde a minSdkVersion dell'applicazione.
Gradle
Quando utilizzi il plug-in Android per Gradle, questo valore viene impostato automaticamente in modo che corrisponda a minSdkVersion dell'applicazione e non deve essere impostato manualmente.
Riga di comando
Quando viene richiamato direttamente CMake, questo valore viene impostato per impostazione predefinita sul livello API più basso supportato dall'NDK in uso. Ad esempio, con NDK r20 questo valore è impostato per impostazione predefinita sul livello API 16.
Per questo parametro sono accettati più formati:
android-$API_LEVEL$API_LEVELandroid-$API_LETTER
Il formato $API_LETTER ti consente di specificare android-N senza dover
determinare il numero associato a quella release. Tieni presente che alcune uscite
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, vedi Supporto
della libreria 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 per la libreria standard C++. |
| di infotainment | L'STL di sistema |
Gestisci 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 famiglia di opzioni correlate. La sezione "Vedi anche" in fondo alla pagina contiene alcuni indizi utili.
In generale, la best practice consiste nell'applicare i flag del compilatore con l'ambito più ristretto
disponibile. I flag che vuoi applicare a tutti i tuoi 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 tuo progetto. Per questi casi, i flag possono essere
applicati a livello di directory (add_compile_options).
Per un sottoinsieme ristretto di flag del compilatore, possono essere impostati anche nel file build.gradle
utilizzando cppFlags o proprietà simili. Non dovresti farlo. I flag
trasferiti a CMake da Gradle avranno comportamenti di precedenza sorprendenti, in alcuni
casi sostituendo i flag trasferiti implicitamente dall'implementazione che sono
necessari per la creazione del codice Android. Preferisci sempre gestire il comportamento di CMake
direttamente in CMake. Se devi controllare i flag del compilatore per AGP buildType,
consulta Utilizzare 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 buildType Gradle personalizzato, utilizza questo
tipo di compilazione per passare un flag CMake aggiuntivo (non un flag del compilatore) che gli
script di build CMake possono leggere. Ad esempio, se hai varianti di build "senza costi" e "premium" controllate da build.gradle.kts e devi trasmettere 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 dipende da te, 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, vedi Sanitizers NDK sample.
Comprendere il comando di compilazione CMake
Quando esegui il debug dei problemi di compilazione di CMake, è utile conoscere gli argomenti di compilazione specifici che Gradle utilizza durante la compilazione incrociata per Android.
Il plug-in Android per Gradle salva gli argomenti di build che utilizza per eseguire una build CMake per ogni coppia di ABI e tipo di compilazione nel file build_command.txt. Questi file si trovano nella seguente
directory:
<project-root>/<module-root>/.cxx/cmake/<build-type>/<ABI>/
Il seguente snippet mostra un esempio degli argomenti CMake per creare una versione di debug dell'esempio hello-jni destinato all'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 viene distribuita come AAR, segui le istruzioni relative alle dipendenze di Studio per importarle e utilizzarle. Se non utilizzi AGP, puoi seguire https://google.github.io/prefab/example-workflow.html, ma è molto più facile eseguire la migrazione ad AGP.
Per le librerie non distribuite come AAR, per istruzioni sull'utilizzo di librerie precompilate
con CMake, consulta la add_librarydocumentazione relativa ai target IMPORTED
nel manuale di CMake.
Creazione di codice di terze parti
Esistono diversi modi per creare codice di terze parti nell'ambito del progetto CMake e l'opzione migliore dipende dalla tua situazione. Spesso l'opzione migliore è non farlo affatto. Crea invece un AAR per la libreria e utilizzalo nella tua applicazione. Non è necessario pubblicare questo AAR. Può essere interno al progetto Gradle.
Se questa opzione non è disponibile:
- Copia l'origine di terze parti nel tuo repository e utilizza add_subdirectory per compilarla. Questa operazione funziona solo se anche l'altra libreria è creata con CMake.
- Definisci un ExternalProject.
- Crea la libreria separatamente dal progetto e segui le istruzioni riportate in Utilizzare librerie precompilate per importarla come libreria precompilata.
Supporto di YASM in CMake
L'NDK fornisce il supporto di CMake per la creazione di codice assembly scritto in YASM da eseguire su architetture x86 e x86-64. YASM è un assembler open source per architetture x86 e x86-64, basato sull'assembler NASM.
Per creare codice assembly con CMake, apporta le seguenti modifiche al file
CMakeLists.txt del progetto:
- Chiama
enable_languagecon il valore impostato suASM_NASM. - A seconda che tu stia creando una libreria condivisa o un binario eseguibile, chiama
add_libraryoadd_executable. Negli argomenti, trasmetti un elenco di file di origine costituiti dai file.asmper il programma di assemblaggio in YASM e dai file.cper le librerie o le funzioni C associate.
Il seguente snippet mostra come potresti configurare CMakeLists.txt per
creare 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 creare un programma YASM come eseguibile, consulta il test yasm nel repository git dell'NDK.
Segnalare problemi
Se riscontri problemi con l'NDK o il relativo file della toolchain CMake, segnalali tramite lo strumento di monitoraggio dei problemi android-ndk/ndk su GitHub. Per problemi relativi a Gradle o al plug-in Android per Gradle, segnala un bug di Studio.