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 |
Gerenciar flags do compilador
Se você precisar passar sinalizações específicas ao compilador ou vinculador para sua compilação, consulte a documentação do CMake para saber mais sobre set_target_compile_options e as família de opções relacionada. O comando "veja também" na parte inferior da página tem algumas pistas úteis.
Em geral, a prática recomendada é aplicar flags do compilador como as
escopo disponível. Sinalizações que você quer aplicar a todos os destinos (como
-Werror
) são inconvenientes para a repetição por módulo, mas isso raramente deve ser feito
aplicados globalmente (CMAKE_CXX_FLAGS
), já que podem ter efeitos indesejados em
dependências de terceiros em seu projeto. Para esses casos, as sinalizações podem ser
aplicado no escopo do diretório (add_compile_options
).
Para um subconjunto restrito de sinalizações do compilador, elas também podem ser definidas no build.gradle.
usando cppFlags
ou propriedades semelhantes. Você não deveria fazer isso. Sinalizações
transmitidos pelo Gradle ao CMake terão comportamentos de precedência surpreendentes,
casos que substituem sinalizações passadas implicitamente pela implementação que são
necessários para criar códigos do Android. Sempre prefira processar o comportamento do CMake
diretamente no CMake. Se você precisar controlar flags do compilador de acordo com o buildType
do AGP,
Consulte Trabalhar com tipos de build do AGP no CMake.
Trabalhar com tipos de build do AGP no CMake
Se você precisar personalizar o comportamento do CMake para um buildType
personalizado do Gradle, use esse
de build para transmitir uma flag extra do CMake (não uma flag do compilador) que seu
Os scripts de build do CMake podem ler. Por exemplo, se você tiver "sem custo financeiro", e "premium"
variantes de build controladas pelo build.gradle.kts e você precisa transmitir
esses dados ao CMake:
android {
buildTypes {
free {
externalNativeBuild {
cmake {
arguments.add("-DPRODUCT_VARIANT_PREMIUM=OFF")
}
}
}
premium {
externalNativeBuild {
cmake {
arguments.add("-DPRODUCT_VARIANT_PREMIUM=ON")
}
}
}
}
}
Em seguida, no CMakeLists.txt:
if (DPRODUCT_VARIANT_PREMIUM)
# Do stuff for the premium build.
else()
# Do stuff for the free build.
endif()
Você decide o nome da variável, mas evite qualquer item com
ANDROID_
, APP_
ou CMAKE_
para evitar colisão ou confusão com
as sinalizações existentes.
Consulte o exemplo de limpadores NDK (link em inglês).
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:
- Chame
enable_language
(link em inglês) com o valor definido comoASM_NASM
. - Chame
add_library
ouadd_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.