CMake

O Android NDK oferece suporte ao uso do CMake (link em inglês) para criar o código C e C++ do app. Esta página discute como usar o CMake com o NDK pelo ExternalNativeBuild do Plug-in do Android para Gradle ou ao invocar o CMake diretamente.

O arquivo do conjunto de ferramentas do CMake

O NDK é compatível com o CMake graças a um arquivo do conjunto de ferramentas (link em inglês). Esses arquivos são do CMake e personalizam o comportamento do conjunto de ferramentas para compilação cruzada. O arquivo do conjunto de ferramentas usado para o NDK está localizado no NDK em <NDK>/build/cmake/android.toolchain.cmake.

Parâmetros de compilação como ABI, minSdkVersion etc. são fornecidos na linha de comando ao invocar cmake. Para ver uma lista de argumentos compatíveis, consulte a seção Argumentos do conjunto de ferramentas.

O "novo" arquivo do conjunto de ferramentas

NDKs anteriores testaram uma nova implementação do arquivo do conjunto de ferramentas que reduziria as diferenças de comportamento entre usar o arquivo do conjunto de ferramentas do NDK e usando o suporte integrado ao CMake. Isso acabou exigindo uma quantidade significativa de trabalho (o que não foi concluído), mas não melhorou realmente o comportamento, Por isso, não procuramos mais por isso.

O "novo" arquivo do conjunto de ferramentas tem regressões de comportamento em comparação com o arquivo do conjunto de ferramentas. O comportamento padrão é o fluxo de trabalho recomendado. Se você estiver usando -DANDROID_USE_LEGACY_TOOLCHAIN_FILE=OFF, recomendamos remover essa sinalização do seu build. O novo arquivo do conjunto de ferramentas nunca atingiu a paridade com o legado do conjunto de ferramentas. Portanto, há regressões de comportamento prováveis.

Embora não seja recomendável usar o novo arquivo do conjunto de ferramentas, não há planeja removê-lo do NDK. Isso corrompe os builds que dependem do diferenças de comportamento entre os arquivos novos e legados do conjunto de ferramentas; infelizmente renomeamos a opção para deixar claro que "legado" é, na verdade, recomendado, isso prejudicaria os usuários dessa opção. Se você está satisfeito com o novo arquivo do conjunto de ferramentas que você não precisa migrar, mas saiba que todos os bugs foram encontrados comportamento do arquivo do novo conjunto de ferramentas provavelmente não será corrigido e, em vez precisará migrar.

Uso

Gradle

O uso do arquivo do conjunto de ferramentas do CMake é automático ao usar externalNativeBuild. Consulte o guia Adicionar código C e C++ ao seu projeto do Android Studio para saber mais.

Linha de comando

Ao criar com o CMake fora do Gradle, o próprio arquivo do conjunto de ferramentas e os respectivos argumentos precisam ser transmitidos para o CMake. Exemplo:

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

Argumentos do conjunto de ferramentas

Os argumentos a seguir podem ser transmitidos para o arquivo do conjunto de ferramentas do CMake. Se estiver criando com o Gradle, adicione argumentos ao android.defaultConfig.externalNativeBuild.cmake.arguments, conforme descrito nos documentos do ExternalNativeBuild (link em inglês). Se estiver criando a partir da linha de comando, transmita argumentos para o CMake com -D. Por exemplo, para forçar o armeabi-v7a a não criar com o Neon. transmita -DANDROID_ARM_NEON=FALSE.

ANDROID_ABI

ABI desejada. Para ver informações sobre as ABIs compatíveis, consulte ABIs do Android.

Gradle

O Gradle fornece esse argumento automaticamente. Não defina esse argumento explicitamente no seu arquivo build.gradle. Para controlar quais ABIs o Gradle visa, use abiFilters conforme descrito em ABIs do Android.

Linha de comando

O CMake cria para um único destino por build. Para segmentar mais de uma ABI do Android, é necessário criar uma vez por ABI. É recomendável usar diretórios de compilação diferentes para cada ABI de modo a evitar colisões entre builds.

Valor Observações
armeabi-v7a
armeabi-v7a with NEON Igual a armeabi-v7a.
arm64-v8a
x86
x86_64

ANDROID_ARM_MODE

Especifica se serão geradas instruções de arm ou thumb para armeabi-v7a. Não tem efeito para outras ABIs. Para saber mais, consulte a documentação ABIs do Android.

Valor Observações
arm
thumb Comportamento padrão.

ANDROID_NATIVE_API_LEVEL

Alias para ANDROID_PLATFORM.

ANDROID_PLATFORM

Especifica o nível mínimo da API compatível com o app ou a biblioteca. Esse valor corresponde à minSdkVersion do app.

Gradle

Ao usar o Plug-in do Android para Gradle, esse valor é definido automaticamente para corresponder à minSdkVersion do app e não pode ser definido manualmente.

Linha de comando

Ao invocar o CMake diretamente, esse valor assume como padrão a API de nível mais baixo compatível com o NDK em uso. Por exemplo, para o NDK r20, esse valor assume como padrão a API de nível 16.

Vários formatos são aceitos para esse parâmetro:

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

O formato $API_LETTER permite que você especifique android-N sem a necessidade de determinar o número associado a essa versão. Algumas versões receberam um aumento de API sem aumento de letras. Essas APIs podem ser especificadas anexando o sufixo -MR1. Por exemplo, a API de nível 25 é android-N-MR1.

ANDROID_STL

Especifica o STL que será usado para esse app. Para saber mais, consulte Compatibilidade com a biblioteca C++. Por padrão, c++_static será usado.

Valor Observações
c++_shared A variante da biblioteca compartilhada de libc++.
c++_static A variante da biblioteca estática de libc++.
none Não há suporte para a biblioteca C++ padrão.
system A STL do sistema

Entender o comando de build do CMake

Ao depurar problemas de build do CMake, é útil conhecer os argumentos de build específicos que o Gradle usa ao fazer compilação cruzada para o Android.

O Plug-in do Android para Gradle salva os argumentos de compilação usados para executar um build do CMake para cada par de ABI e tipo de build para o build_command.txt. Esses arquivos são encontrados no seguinte diretório:

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

O snippet a seguir mostra um exemplo dos argumentos do CMake para criar uma versão depurável do exemplo hello-jni (link em inglês) destinada à arquitetura 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

Usar bibliotecas pré-compiladas

Se a biblioteca pré-compilada que você precisa importar for distribuída como um AAR, siga os documentos de dependência do Studio para importar e usar essas bibliotecas. Se você não estiver usando o AGP, você pode seguir as etapas em https://google.github.io/prefab/example-lifecycle.html (link em inglês), mas é muito mais fácil migrar para o AGP.

No caso de bibliotecas que não são distribuídas como um AAR, para ver instruções sobre como usar bibliotecas pré-compiladas com o CMake, consulte a documentação add_library sobre destinos IMPORTED no manual do CMake (link em inglês).

Criar com código de terceiros

Há várias maneiras de usar código de terceiros como parte do seu projeto CMake, e a opção que funciona melhor depende da sua situação. Em geral, a melhor opção é não fazer isso. Em vez disso, crie um AAR para a biblioteca e consuma-o no aplicativo. Não é necessário publicar esse AAR. Ele pode ser interno ao seu projeto do Gradle.

Se não for possível, faça o seguinte:

  • Forneça (ou seja, copie) a fonte de terceiros no seu repositório e use add_subdirectory para criá-lo. Isso só funcionará se a outra biblioteca também for criada com o CMake.
  • Defina um ExternalProject.
  • Crie a biblioteca separada do projeto e siga as instruções da seção Usar bibliotecas pré-compiladas para que ela seja importada como pré-compilada.

Compatibilidade com YASM no CMake

O NDK oferece compatibilidade com o CMake para criação do código Assembly escrito em YASM (link em inglês) para execução em arquiteturas x86 e x86-64. O YASM é um assembler de código aberto para arquiteturas x86 e x86-64, baseado no assembler NASM.

Para criar o código Assembly com o CMake, faça as seguintes mudanças no CMakeLists.txt do projeto:

  1. Chame enable_language (link em inglês) com o valor definido como ASM_NASM.
  2. Chame add_library ou add_executable, dependendo se você está criando uma biblioteca compartilhada ou um binário executável. Nos argumentos, transmita uma lista de arquivos de origem composta pelos arquivos .asm para o programa Assembly no YASM e arquivos .c para as funções ou bibliotecas C associadas.

O snippet a seguir mostra como configurar CMakeLists.txt para criar um programa YASM como uma biblioteca compartilhada.

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 um exemplo de como criar um programa YASM como executável, consulte o teste yasm (link em inglês) no repositório git do NDK.

Denunciar problemas

Caso tenha problemas com o NDK ou o arquivo do conjunto de ferramentas do CMake, nos informe pelo Issue Tracker android-ndk/ndk no GitHub (link em inglês). Para problemas com o Gradle ou com o Plug-in do Android para Gradle, informe um bug do Studio.