CMake

El NDK de Android admite el uso de CMake a fin de compilar código C y C++ para tu app. En esta página, se analiza cómo usar CMake con el NDK a través de ExternalNativeBuild o del complemento de Gradle para Android, o cuando se invoca directamente a CMake.

El archivo de la cadena de herramientas de CMake

El NDK admite CMake a través de un archivo de cadena de herramientas. Los archivos de cadena de herramientas son archivos de CMake que personalizan el comportamiento de la cadena de herramientas para la compilación de forma cruzada. El archivo de cadena de herramientas que se usa para el NDK se encuentra en el NDK en <NDK>/build/cmake/android.toolchain.cmake.

Los parámetros de compilación, como ABI, minSdkVersion, etc., se muestran en la línea de comandos cuando se invoca cmake. Para obtener una lista de argumentos compatibles, consulta la sección Argumentos de la cadena de herramientas.

Uso

Gradle

El uso del archivo de la cadena de herramientas de CMake es automático cuando se usa externalNativeBuild. Consulta la guía Cómo agregar código C y C++ a tu proyecto para obtener más información.

Línea de comandos

Cuando compiles con CMake fuera de Gradle, se deben pasar a CMake el archivo de la cadena de herramientas y sus argumentos. Por ejemplo:

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

Argumentos de la cadena de herramientas

Se pueden pasar los siguientes argumentos al archivo de la cadena de herramientas de CMake. Si compilas con Gradle, agrega argumentos a android.defaultConfig.externalNativeBuild.cmake.arguments como se describe en los documentos de ExternalNativeBuild. Si compilas desde la línea de comandos, pasa argumentos a CMake con -D. Por ejemplo, para hacer que armeabi-v7a compile siempre con compatibilidad con Neon, pasa -DANDROID_ARM_NEON=TRUE.

ANDROID_ABI

La ABI de destino. Para obtener información sobre las ABI compatibles, consulta ABI de Android.

Gradle

Gradle proporciona automáticamente este argumento. No establezcas este argumento de manera explícita en tu archivo build.gradle. Para controlar los objetivos de ABI en Gradle, usa abiFilters como se describe en ABI de Android.

Línea de comandos

CMake compila para un solo objetivo por compilación. Para orientar a más de una ABI de Android, debes compilar una vez por cada ABI. Se recomienda usar diferentes directorios de compilación para cada ABI a fin de evitar colisiones entre compilaciones.

Valor Notas
armeabi-v7a
armeabi-v7a with NEON Igual que -DANDROID_ABI=armeabi-v7a -DANDROID_ARM_NEON=ON.
arm64-v8a
x86
x86_64

ANDROID_ARM_MODE

Especifica si se deben generar instrucciones arm o thumb para armeabi-v7a. No tiene ningún efecto en otras ABI. Para obtener más información, consulta la documentación de ABI de Android.

Valor Notas
arm
thumb Comportamiento predeterminado.

ANDROID_ARM_NEON

Habilita o inhabilita NEON para armeabi-v7a. No tiene ningún efecto en otras ABI. El valor predeterminado es "true" para API (minSdkVersion o ANDROID_PLATFORM) nivel 23 o más reciente; en caso contrario, es "false". Para obtener más información, consulta la documentación de Neon.

Valor Notas
TRUE Predeterminado para API nivel 23 o superior.
FALSE Predeterminado para API nivel 22 o inferior.

ANDROID_LD

Selecciona qué vinculador se va a usar. Por el momento, lld es de uso experimental para el NDK y se puede habilitar con este argumento.

Valor Notas
lld Habilita lld.
default Usa el vinculador predeterminado para la ABI determinada.

ANDROID_NATIVE_API_LEVEL

Alias para ANDROID_PLATFORM.

ANDROID_PLATFORM

Especifica el nivel mínimo de API compatible con la app o biblioteca. Este valor corresponde al objeto minSdkVersion de la app.

Gradle

Cuando se usa el complemento de Gradle para Android, este valor se establece automáticamente para que coincida con el objeto minSdkVersion de la app y no se debe configurar de forma manual.

Línea de comandos

Cuando se invoca directamente a CMake, este valor se establece de forma predeterminada en el nivel de API más bajo compatible con el NDK en uso. Por ejemplo, con NDK r20, este valor se establece de forma predeterminada en la API nivel 16.

Se aceptan múltiples formatos para este parámetro:

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

El formato $API_LETTER te permite especificar android-N sin la necesidad de determinar el número asociado con esa versión. Ten en cuenta que en algunas versiones se aumentó el nivel de API, pero no el de letra. Se pueden especificar estas API agregando el sufijo -MR1. Por ejemplo, la API nivel 25 es android-N-MR1.

ANDROID_STL

Especifica qué STL usar para esta app. Para obtener más información, consulta Compatibilidad de la biblioteca C++. De forma predeterminada, se usará c++_static.

Valor Notas
c++_shared La variante de biblioteca compartida de libc++.
c++_static La variante de biblioteca estática de libc++.
none No hay compatibilidad con la biblioteca C++ estándar.
system La STL del sistema.

Cómo comprender el comando de compilación CMake

Para depurar problemas de compilación de CMake, es útil conocer los argumentos de compilación específicos que usa Gradle cuando realiza compilaciones de forma cruzada para Android.

El complemento de Gradle para Android guarda los argumentos de compilación que utiliza a fin de ejecutar una compilación de CMake para cada par de ABI y tipo de compilación en el cmake_build_command.txt. Estos archivos están en el siguiente directorio:

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

En el siguiente fragmento, se muestra un ejemplo de los argumentos de CMake para compilar una versión depurable de la muestra de hello-jni que se orienta a la arquitectura armeabi-v7a.

Executable : ${HOME}/Android/Sdk/cmake/3.6.3155560/bin/cmake
    arguments :
    -H${HOME}/Dev/github-projects/googlesamples/android-ndk/hello-jni/app/src/main/cpp
    -B${HOME}/Dev/github-projects/googlesamples/android-ndk/hello-jni/app/.cxx/cmake/arm7Debug/armeabi-v7a
    -GAndroid Gradle - Ninja
    -DANDROID_ABI=armeabi-v7a
    -DANDROID_NDK=${HOME}/Android/Sdk/ndk-bundle
    -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=${HOME}/Dev/github-projects/googlesamples/android-ndk/hello-jni/app/build/intermediates/cmake/arm7/debug/obj/armeabi-v7a
    -DCMAKE_BUILD_TYPE=Debug
    -DCMAKE_MAKE_PROGRAM=${HOME}/Android/Sdk/cmake/3.6.3155560/bin/ninja
    -DCMAKE_TOOLCHAIN_FILE=${HOME}/Android/Sdk/ndk-bundle/build/cmake/android.toolchain.cmake
    -DANDROID_NATIVE_API_LEVEL=23
    -DANDROID_TOOLCHAIN=clang
    jvmArgs :
    

Cómo usar bibliotecas compiladas previamente

Para obtener instrucciones sobre cómo usar bibliotecas compiladas previamente con CMake, consulta la documentación de add_library sobre destinos IMPORTED en el manual de CMake.

Compatibilidad con YASM en CMake

Con el NDK, CMake es compatible con la compilación de código ensamblado escrito en YASM para ejecutarse en arquitecturas x86 y x86-64. YASM es un ensamblador de código abierto para las arquitecturas x86 y x86-64, que se basa en el ensamblador NASM.

Para compilar el código ensamblado con CMake, realiza los siguientes cambios en el objeto CMakeLists.txt de tu proyecto:

  1. Llama a enable_language con el valor establecido en ASM_NASM.
  2. Si estás compilando una biblioteca compartida, llama a add_library; si estás compilando un archivo binario ejecutable, llama a add_executable{.external}. En los argumentos, pasa una lista de archivos de origen que conste de archivos .asm para el programa de ensamblaje en YASM y archivos .c para las bibliotecas o funciones de C asociadas.

En el siguiente fragmento, se muestra cómo puedes configurar el objeto CMakeLists.txt para compilar un programa YASM como una biblioteca compartida.

cmake_minimum_required(VERSION 3.6.0)

    enable_language(ASM_NASM)

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

Para ver un ejemplo de cómo compilar un programa YASM como ejecutable, consulta la prueba de yasm en el repositorio git del NDK.

Cómo informar problemas

Si tienes problemas con el NDK o su archivo de cadena de herramientas de CMake, infórmalo a través del registro de problemas de android-ndk/ndk en GitHub.