Um script de compilação do CMake é um arquivo de texto simples que precisa ter o nome
CMakeLists.txt
e os comandos que o CMake usa para criar suas bibliotecas
C/C++. Se as fontes nativas ainda não têm um script de compilação do CMake, é necessário criar
e incluir um desses scripts nos comandos apropriados do
CMake. Para saber como instalar o CMake, consulte Instalar e configurar o NDK
e o CMake.
Esta seção cobre alguns comandos básicos que precisam ser incluídos no script de compilação para informar ao CMake quais origens precisam ser usadas na criação da biblioteca nativa. Para saber mais, leia a documentação oficial sobre os comandos do CMake.
Depois de configurar um novo script de compilação do CMake, você precisa configurar o Gradle para incluir seu projeto do CMake como uma dependência de build. Assim, o Gradle criará e empacotará sua biblioteca nativa junto ao APK do app.
Observação: se o projeto incluir o ndk-build, não vai ser necessário
criar um script de build do CMake. Você pode simplesmente
configurar o Gradle
para incluir o projeto de biblioteca nativa existente fornecendo um caminho para seu arquivo
Android.mk
.
Criar um script de compilação do CMake
Para criar um arquivo de texto simples que possa ser usado como script de compilação do CMake, faça o seguinte:
- Abra o painel Project no lado esquerdo do ambiente de desenvolvimento integrado e selecione a visualização Project no menu suspenso.
- Clique com o botão direito do mouse no diretório raiz do your-module e
selecione New > File.
Observação: você pode criar o script de compilação no local que quiser. No entanto, ao configurá-lo, os caminhos para os arquivos de origem e bibliotecas nativos são relativos ao local do script de compilação.
- Insira "CMakeLists.txt" como nome do arquivo e clique em OK.
Agora é possível configurar o build script adicionando comandos do CMake. Para instruir o
CMake a criar uma biblioteca nativa a partir do código-fonte nativo, adicione os comandos cmake_minimum_required()
e add_library()
ao script de compilação:
# Sets the minimum version of CMake required to build your native library. # This ensures that a certain set of CMake features is available to # your build. cmake_minimum_required(VERSION 3.4.1) # Specifies a library name, specifies whether the library is STATIC or # SHARED, and provides relative paths to the source code. You can # define multiple libraries by adding multiple add_library() commands, # and CMake builds them for you. When you build your app, Gradle # automatically packages shared libraries with your APK. add_library( # Specifies the name of the library. native-lib # Sets the library as a shared library. SHARED # Provides a relative path to your source file(s). src/main/cpp/native-lib.cpp )
Dica: assim como você pode instruir o CMake a criar uma biblioteca nativa de
arquivos de origem, use o comando
add_executable()
para instruir o CMake a criar um
arquivo executável desses arquivos de origem. No entanto, criar arquivos executáveis a partir das suas
fontes nativas é opcional, e criar bibliotecas nativas para serem incluídas no seu
APK satisfaz a maioria dos requisitos de projeto.
Quando você adiciona um arquivo ou uma biblioteca de origem ao script de compilação do CMake usando
add_library()
, o Android Studio também mostra os arquivos principais associados
na visualização Project após a sincronização do projeto. No entanto,
para que o CMake localize os arquivos principais durante o tempo de compilação, será necessário
adicionar o comando include_directories()
ao script de compilação
do CMake e especificar o caminho até os cabeçalhos:
add_library(...) # Specifies a path to native header files. include_directories(src/main/cpp/include/)
A convenção de nomenclatura usada pelo CMake para os arquivos da biblioteca é a seguinte:
liblibrary-name.so
Por exemplo, se você especificar “native-lib” como o nome da biblioteca compartilhada
no script de compilação, o CMake criará um arquivo chamado
libnative-lib.so
. No entanto, para carregar essa biblioteca no código
Java ou Kotlin, use o nome especificado no script de build do CMake:
Kotlin
companion object { init { System.loadLibrary("native-lib"); } }
Java
static { System.loadLibrary("native-lib"); }
Observação: se você renomear ou remover uma biblioteca no script de build do CMake, será necessário limpar o projeto antes que o Gradle aplique as modificações ou remova do APK a versão antiga da biblioteca. Para limpar o projeto, selecione Build > Clean Project na barra de menus.
O Android Studio adiciona automaticamente os arquivos de origem e cabeçalhos ao grupo
cpp no painel Project. Usando
vários comandos add_library()
, é possível definir outras
bibliotecas para que o CMake use outros arquivos de origem para criação.
Adicionar APIs do NDK
O Android NDK oferece um conjunto de APIs e bibliotecas nativas que podem
ser úteis. Você pode usar qualquer uma dessas APIs incluindo as bibliotecas do NDK no arquivo de script
CMakeLists.txt
do seu projeto.
Bibliotecas NDK pré-criadas já existem na plataforma Android. Portanto, você não precisa criá-las ou incluí-las no seu APK. Como as bibliotecas NDK já são uma parte do caminho de busca do CMake, você não precisa especificar a localização da biblioteca na sua instalação local do NDK. Você só precisa fornecer ao CMake o nome da biblioteca que você quer usar e vinculá-la à sua biblioteca nativa.
Adicione o comando find_library()
(link em inglês) ao script
de compilação do CMake para localizar uma biblioteca do NDK e armazenar o caminho dela como variável. Use essa
variável como referência à biblioteca do NDK em outras partes do script de compilação.
A amostra a seguir localiza a Biblioteca de Suporte de registro específica do Android
e armazena o caminho dela em log-lib
:
find_library( # Defines the name of the path variable that stores the # location of the NDK library. log-lib # Specifies the name of the NDK library that # CMake needs to locate. log )
Para que sua biblioteca nativa chame funções na biblioteca log
,
é necessário vinculá-las usando o comando target_link_libraries()
(link em inglês) no
script de compilação do CMake:
find_library(...) # Links your native library against one or more other native libraries. target_link_libraries( # Specifies the target library. native-lib # Links the log library to the target library. ${log-lib} )
O NDK também contém algumas bibliotecas como código-fonte que você precisa criar
e vincular à biblioteca nativa. Para compilar o código-fonte em uma
biblioteca nativa, use o comando add_library()
no script de compilação
do CMake. Para informar um caminho à biblioteca do NDK local, você pode usar a variável de caminho
ANDROID_NDK
, definida automaticamente
pelo Android Studio.
O comando a seguir instrui o CMake a criar
android_native_app_glue.c
, que gerencia eventos de ciclo de vida e entrada por toque de NativeActivity
,
em uma biblioteca estática e o vincula a
native-lib
:
add_library( app-glue STATIC ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c ) # You need to link static libraries against your shared native library. target_link_libraries( native-lib app-glue ${log-lib} )
Adicionar outras bibliotecas pré-compiladas
A adição de uma biblioteca pré-compilada é semelhante à especificação de outra biblioteca nativa para criação
pelo CMake. No entanto, como a biblioteca já foi criada, é necessário
usar a sinalização IMPORTED
(link em inglês) para informar ao CMake que você
só quer importar a biblioteca para o projeto:
add_library( imported-lib SHARED IMPORTED )
Em seguida, é preciso especificar o caminho para a biblioteca usando o comando
set_target_properties()
(link em inglês), conforme
mostrado abaixo.
Algumas bibliotecas fornecem pacotes separados para arquiteturas específicas de CPU ou
Interfaces binária do aplicativo (ABIs, na sigla em inglês) e
os organizam em diretórios diferentes. Essa abordagem ajuda as bibliotecas a
aproveitar determinadas arquiteturas de CPU sem impedir que você use apenas
as versões da biblioteca que quiser. Para adicionar várias versões de ABI de uma biblioteca ao
script de compilação do CMake sem ter que codificar vários comandos para
cada versão da biblioteca, use a variável
de caminho ANDROID_ABI
. Essa variável usa uma lista das ABIs padrão compatíveis com o NDK ou uma lista filtrada de
ABIs
configuradas manualmente para que o Gradle use. Exemplo:
add_library(...) set_target_properties( # Specifies the target library. imported-lib # Specifies the parameter you want to define. PROPERTIES IMPORTED_LOCATION # Provides the path to the library you want to import. imported-lib/src/${ANDROID_ABI}/libimported-lib.so )
Para que o CMake localize seus arquivos principais durante o tempo de compilação, é necessário usar
o comando include_directories()
e incluir o caminho nos
arquivos principais:
include_directories( imported-lib/include/ )
Observação: se você quiser empacotar uma biblioteca pré-compilada que não seja uma dependência de
tempo de compilação (por exemplo, ao adicionar uma biblioteca pré-compilada que seja uma
dependência de imported-lib
), não será necessário seguir
as instruções abaixo para vincular a biblioteca.
Para vincular a biblioteca pré-compilada à sua própria biblioteca nativa, adicione-a ao comando
target_link_libraries()
no script de compilação do CMake:
target_link_libraries( native-lib imported-lib app-glue ${log-lib} )
Para empacotar a biblioteca pré-compilada no seu APK, é necessário
configurar manualmente o Gradle com o bloco sourceSets
para
incluir o caminho para o arquivo .so
. Depois de criar seu APK, você
pode confirmar quais bibliotecas foram empacotadas pelo Gradle no APK usando o
APK Analyzer.
Incluir outros projetos do CMake
Se você quiser criar vários projetos do CMake e incluir as saídas deles no seu
projeto do Android, é possível usar um arquivo CMakeLists.txt
como
seu script de compilação do CMake de nível superior, ou seja, aquele que você
vincula
ao Gradle, e adicionar outros projetos do CMake como dependências desse script
de compilação. O seguinte script de compilação do CMake de nível superior usa o comando
add_subdirectory()
para especificar
outro arquivo CMakeLists.txt
como uma dependência de build e, em seguida, faz a vinculação
à saída dele da mesma forma que faria com qualquer outra biblioteca pré-compilada.
# Sets lib_src_DIR to the path of the target CMake project. set( lib_src_DIR ../gmath ) # Sets lib_build_DIR to the path of the desired output directory. set( lib_build_DIR ../gmath/outputs ) file(MAKE_DIRECTORY ${lib_build_DIR}) # Adds the CMakeLists.txt file located in the specified directory # as a build dependency. add_subdirectory( # Specifies the directory of the CMakeLists.txt file. ${lib_src_DIR} # Specifies the directory for the build outputs. ${lib_build_DIR} ) # Adds the output of the additional CMake build as a prebuilt static # library and names it lib_gmath. add_library( lib_gmath STATIC IMPORTED ) set_target_properties( lib_gmath PROPERTIES IMPORTED_LOCATION ${lib_build_DIR}/${ANDROID_ABI}/lib_gmath.a ) include_directories( ${lib_src_DIR}/include ) # Links the top-level CMake build output against lib_gmath. target_link_libraries( native-lib ... lib_gmath )
Chamar o CMake na linha de comando
Use o seguinte comando para chamar o CMake e gerar um projeto do Ninja fora do Android Studio:
cmake
-Hpath/to/cmakelists/folder
-Bpath/to/generated/ninja/project/debug/ABI
-DANDROID_ABI=ABI // For example, arm64-v8a
-DANDROID_PLATFORM=platform-version-string // For example, android-16
-DANDROID_NDK=android-sdk/ndk/ndk-version
-DCMAKE_TOOLCHAIN_FILE=android-sdk/ndk/ndk-version/build/cmake/android.toolchain.cmake
-G Ninja
Esse comando gerará o projeto Ninja que pode ser executado para criar
bibliotecas executáveis do Android (arquivos .so
). O CMAKE_TOOLCHAIN_FILE
é
necessário para usar o suporte do NDK ao CMake. No CMake 3.21 ou mais recentes, é possível usar o suporte integrado do NDK
ao CMake, mas um grupo diferente de variáveis precisa ser usado
conforme descrito na documentação sobre Compilação cruzada para Android (link em inglês) do CMake.