CMake

Android NDK prend en charge l'utilisation de CMake pour compiler du code C et C++ pour votre application. Cette page explique comment utiliser CMake avec le NDK via le ExternalNativeBuild du plug-in Android Gradle ou lorsque vous appelez directement CMake.

Fichier de chaîne d'outils CMake

Le NDK est compatible avec CMake grâce à un fichier de chaîne d'outils. Les fichiers de chaîne d'outils sont des fichiers CMake qui personnalisent le comportement de la chaîne d'outils pour la compilation croisée. Le fichier de chaîne d'outils utilisé pour le NDK se trouve dans celui-ci, à l'emplacement <NDK>/build/cmake/android.toolchain.cmake.

Les paramètres de compilation comme ABI, minSdkVersion, etc. sont fournis dans la ligne de commande lors de l'appel de cmake. Pour obtenir la liste des arguments acceptés, consultez la section Arguments de la chaîne d'outils.

Utilisation

Gradle

L'utilisation du fichier de chaîne d'outils CMake est automatique lorsque vous utilisez externalNativeBuild. Pour en savoir plus, consultez le guide Ajouter du code C et C++ à votre projet d'Android Studio.

Ligne de commande

Lorsque vous compilez votre projet avec CMake en dehors de Gradle, le fichier de chaîne d'outils et ses arguments doivent être transmis à CMake. Par exemple :

$ cmake \
    -DCMAKE_TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake \
    -DANDROID_ABI=$ABI \
    -DANDROID_PLATFORM=android-$MINSDKVERSION \
    $OTHER_ARGS

Arguments de la chaîne d'outils

Les arguments suivants peuvent être transmis au fichier de chaîne d'outils CMake. Si vous compilez votre projet avec Gradle, ajoutez des arguments à android.defaultConfig.externalNativeBuild.cmake.arguments, comme décrit dans la documentation sur ExternalNativeBuild. Si vous compilez votre projet à partir de la ligne de commande, transmettez les arguments à CMake avec -D. Par exemple, pour forcer armeabi-v7a à ne pas compiler avec la compatibilité avec Neon, transmettez -DANDROID_ARM_NEON=FALSE.

ANDROID_ABI

ABI cible. Pour en savoir plus sur les ABI compatibles, consultez ABI Android.

Gradle

Gradle fournit automatiquement cet argument. Ne le définissez pas de manière explicite dans votre fichier build.gradle. Pour contrôler les ABI ciblées par Gradle, utilisez abiFilters comme décrit dans ABI Android.

Ligne de commande

La compilation CMake prévoit une seule cible par build. Pour cibler plusieurs ABI Android, vous devez effectuer une compilation pour chaque ABI. Il est recommandé d'utiliser des répertoires de compilation différents pour chaque ABI afin d'éviter les conflits entre les builds.

Valeur Notes
armeabi-v7a
armeabi-v7a with NEON Équivalent à armeabi-v7a.
arm64-v8a
x86
x86_64

ANDROID_ARM_MODE

Indique s'il faut générer des instructions arm ou thumb pour armeabi-v7a. N'a aucun effet pour les autres ABI. Pour en savoir plus, consultez la documentation sur les ABI Android.

Valeur Remarques
arm
thumb Comportement par défaut

ANDROID_ARM_NEON

Active ou désactive NEON pour armeabi-v7a. N'a aucun effet pour les autres ABI. La valeur par défaut est "true" pour le niveau d'API (minSdkVersion ou ANDROID_PLATFORM) 23 ou version ultérieure. Sinon, la valeur "false" est renvoyée. Pour en savoir plus, consultez le document Compatibilité avec Neon.

Valeur Remarques
TRUE Valeur par défaut pour le niveau d'API 23 ou version ultérieure
FALSE Valeur par défaut pour le niveau d'API 22 ou version antérieure

ANDROID_LD

Sélectionne l'éditeur de liens à utiliser. lld est actuellement en phase expérimentale pour le NDK et peut être activé avec cet argument.

Valeur Remarques
lld Active l'utilisation de lld.
default Utilise l'éditeur de liens par défaut pour l'ABI donnée.

ANDROID_NATIVE_API_LEVEL

Alias pour ANDROID_PLATFORM

ANDROID_PLATFORM

Spécifie le niveau d'API minimal accepté par l'application ou la bibliothèque. Cette valeur correspond à la minSdkVersion de l'application.

Gradle

Lorsque vous utilisez le plug-in Android Gradle, cette valeur est définie automatiquement pour correspondre à la minSdkVersion de l'application et ne doit pas être définie manuellement.

Ligne de commande

Lorsque vous appelez directement CMake, cette valeur est définie par défaut sur le niveau d'API le plus bas accepté par le NDK utilisé. Par exemple, avec NDK r20, cette valeur est définie par défaut sur le niveau d'API 16.

Ce paramètre accepte plusieurs formats :

  • android-$API_LEVEL
  • $API_LEVEL
  • android-$API_LETTER

Le format $API_LETTER vous permet de spécifier android-N sans avoir à déterminer le numéro associé à cette version. Notez que certaines versions passent à un niveau d'API supérieur sans incrémentation de la lettre. Vous pouvez spécifier ces API en ajoutant le suffixe -MR1. Par exemple, le niveau d'API 25 correspond à android-N-MR1.

ANDROID_STL

Spécifie la STL à utiliser pour cette application. Pour en savoir plus, consultez Compatibilité avec les bibliothèques C++. La bibliothèque utilisée par défaut est c++_static.

Valeur Notes
c++_shared Variante de bibliothèque partagée de libc++
c++_static Variante de bibliothèque statique de libc++
aucune Incompatible avec les bibliothèques standards C++.
système STL système

Comprendre la commande de compilation CMake

Lors du débogage des problèmes de compilation CMake, il est utile de connaître les arguments de compilation spécifiques utilisés par Gradle lors de la compilation croisée pour Android.

Le plug-in Android Gradle enregistre les arguments utilisés pour exécuter une compilation CMake pour chaque association entre une ABI et un type de compilation dans le fichier build_command.txt. Ces fichiers se trouvent dans le répertoire suivant :

<project-root>/<module-root>/.cxx/cmake/<build-type>/<ABI>/

L'extrait de code suivant illustre l'utilisation d'arguments CMake pour créer une version débogable de l'exemple hello-jni ciblant l'architecture 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

Utiliser des bibliothèques prédéfinies

Si la bibliothèque prédéfinie que vous devez importer est distribuée en tant que fichiers AAR, suivez la documentation sur les dépendances de Studio pour les importer et les utiliser. Si vous n'utilisez pas AGP, vous pouvez suivre les instructions de la page https://google.github.io/prefab/example-workflow.html, mais il sera probablement beaucoup plus facile de migrer vers AGP.

Pour les bibliothèques qui ne sont pas distribuées en tant que fichiers AAR, consultez les instructions sur l'utilisation de bibliothèques prédéfinies avec CMake dans la documentation add_library sur les cibles IMPORTED dans le manuel CMake.

Développer un code tiers

Il existe plusieurs façons de créer du code tiers dans le cadre de votre projet CMake. L'option la plus adaptée dépend de votre situation. Souvent, la meilleure solution est de ne pas procéder ainsi. À la place, créez un fichier AAR pour la bibliothèque et utilisez-le dans votre application. Vous n'avez pas nécessairement besoin de publier ce fichier AAR. Il peut être interne à votre projet Gradle.

Si ce n'est pas possible :

  • Procurez-vous (c'est-à-dire copiez) la source tierce dans votre dépôt et utilisez add_subdirectory pour le créer. Cette méthode ne fonctionne que si l'autre bibliothèque est également créée avec CMake.
  • Définissez un ExternalProject.
  • Créez la bibliothèque séparément de votre projet et suivez la section Utiliser des bibliothèques prédéfinies pour l'importer en tant que telle.

Compatibilité avec YASM dans CMake

Le NDK assure la compatibilité de CMake avec la création de code assembleur écrit en YASM pour l'exécution sur des architectures x86 et x86-64. YASM est un assembleur Open Source destiné aux architectures x86 et x86-64. Il est basé sur l'assembleur NASM.

Pour créer du code assembleur avec CMake, apportez les modifications suivantes au fichier CMakeLists.txt de votre projet :

  1. Appelez enable_language en définissant la valeur sur ASM_NASM.
  2. Selon que vous créez une bibliothèque partagée ou un binaire exécutable, appelez add_library ou add_executable. Dans les arguments, transmettez la liste des fichiers sources comprenant les fichiers .asm pour l'assembleur en YASM, et les fichiers .c pour les bibliothèques ou fonctions C associées.

L'extrait de code suivant montre comment configurer CMakeLists.txt pour créer un programme YASM en tant que bibliothèque partagée.

cmake_minimum_required(VERSION 3.6.0)

enable_language(ASM_NASM)

add_library(test-yasm SHARED jni/test-yasm.c jni/print_hello.asm)

Pour obtenir un exemple de création d'un programme YASM en tant qu'exécutable, consultez le test yasm dans le dépôt Git NDK.

Signaler des problèmes

Si vous rencontrez des problèmes avec le NDK ou son fichier de chaîne d'outils CMake, signalez-les via l'outil de suivi des problèmes android-ndk/ndk sur GitHub. Pour les problèmes liés à Gradle ou au plug-in Android Gradle, signalez un bug Studio.