Сценарий сборки CMake — это обычный текстовый файл, который необходимо назвать CMakeLists.txt и который включает команды, которые CMake использует для сборки библиотек C/C++. Если в ваших собственных источниках еще нет сценария сборки CMake, вам необходимо создать его самостоятельно и включить соответствующие команды CMake. Чтобы узнать, как установить CMake, см. раздел Установка и настройка NDK и CMake .
В этом разделе описаны некоторые основные команды, которые следует включить в сценарий сборки, чтобы указать CMake, какие источники использовать при создании собственной библиотеки. Чтобы узнать больше, прочтите официальную документацию по командам CMake .
После настройки нового сценария сборки CMake вам необходимо настроить Gradle для включения вашего проекта CMake в качестве зависимости сборки, чтобы Gradle собирал и упаковывал вашу собственную библиотеку с APK вашего приложения.
Примечание. Если в вашем проекте используется ndk-build, вам не нужно создавать сценарий сборки CMake. Вы можете просто настроить Gradle для включения существующего проекта собственной библиотеки, указав путь к файлу Android.mk .
Создайте сценарий сборки CMake.
Чтобы создать обычный текстовый файл, который можно использовать в качестве сценария сборки CMake, выполните следующие действия:
- Откройте панель «Проект» в левой части IDE и выберите представление «Проект» в раскрывающемся меню.
- Щелкните правой кнопкой мыши корневой каталог your-module и выберите «Создать» > «Файл» .
Примечание. Вы можете создать сценарий сборки в любом месте. Однако при настройке сценария сборки пути к собственным исходным файлам и библиотекам указываются относительно местоположения сценария сборки.
- Введите «CMakeLists.txt» в качестве имени файла и нажмите «ОК» .
Теперь вы можете настроить сценарий сборки, добавив команды CMake. Чтобы указать CMake создать собственную библиотеку из собственного исходного кода, добавьте команды cmake_minimum_required() и add_library() в свой сценарий сборки:
# 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 )
Совет: Подобно тому, как вы можете указать CMake создать собственную библиотеку из исходных файлов, вы можете использовать команду add_executable() , чтобы указать CMake вместо этого создать исполняемый файл из этих исходных файлов. Однако создание исполняемых файлов из собственных источников не является обязательным, а создание собственных библиотек для упаковки в APK удовлетворяет большинству требований проекта.
Когда вы добавляете исходный файл или библиотеку в сценарий сборки CMake с помощью add_library() , Android Studio также отображает связанные файлы заголовков в представлении «Проект» после синхронизации проекта. Однако для того, чтобы CMake мог найти файлы заголовков во время компиляции, вам необходимо добавить команду include_directories() в сценарий сборки CMake и указать путь к вашим заголовкам:
add_library(...) # Specifies a path to native header files. include_directories(src/main/cpp/include/)
Соглашение, которое CMake использует для именования файла вашей библиотеки, выглядит следующим образом:
lib library-name .so Например, если вы укажете «native-lib» в качестве имени вашей общей библиотеки в сценарии сборки, CMake создаст файл с именем libnative-lib.so . Однако при загрузке этой библиотеки в код Java или Kotlin используйте имя, указанное в сценарии сборки CMake:
Котлин
companion object { init { System.loadLibrary("native-lib"); } }
Ява
static { System.loadLibrary("native-lib"); }
Примечание. Если вы переименовываете или удаляете библиотеку в сценарии сборки CMake, вам необходимо очистить проект, прежде чем Gradle применит изменения или удалит старую версию библиотеки из вашего APK. Чтобы очистить проект, выберите «Сборка» > «Очистить проект» в строке меню.
Android Studio автоматически добавляет исходные файлы и заголовки в группу cpp на панели «Проект» . Используя несколько команд add_library() , вы можете определить дополнительные библиотеки, которые CMake будет собирать из других исходных файлов.
Добавить API NDK
Android NDK предоставляет набор собственных API и библиотек, которые могут оказаться вам полезными. Вы можете использовать любой из этих API, включив библиотеки NDK в файл сценария CMakeLists.txt вашего проекта.
Готовые библиотеки NDK уже существуют на платформе Android, поэтому вам не нужно собирать их или упаковывать в APK. Поскольку библиотеки NDK уже являются частью пути поиска CMake, вам даже не нужно указывать расположение библиотеки в вашей локальной установке NDK — вам нужно только предоставить CMake имя библиотеки, которую вы хотите использовать, и ссылку это против вашей собственной родной библиотеки.
Добавьте команду find_library() в сценарий сборки CMake, чтобы найти библиотеку NDK и сохранить ее путь в виде переменной. Эту переменную вы используете для ссылки на библиотеку NDK в других частях сценария сборки. В следующем примере находится библиотека поддержки журналов, специфичная для Android , и сохраняется путь к ней в 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 )
Чтобы ваша собственная библиотека могла вызывать функции в библиотеке log , вам необходимо связать библиотеки с помощью команды target_link_libraries() в сценарии сборки 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} )
NDK также включает в себя некоторые библиотеки в качестве исходного кода, которые вам необходимо собрать и связать с вашей собственной библиотекой. Вы можете скомпилировать исходный код в собственную библиотеку, используя команду add_library() в сценарии сборки CMake. Чтобы указать путь к вашей локальной библиотеке NDK, вы можете использовать переменную пути ANDROID_NDK , которую Android Studio автоматически определяет для вас.
Следующая команда сообщает CMake собрать android_native_app_glue.c , который управляет событиями жизненного цикла NativeActivity и сенсорным вводом, в статическую библиотеку и связывает ее с 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} )
Добавьте другие готовые библиотеки
Добавление предварительно созданной библиотеки аналогично указанию другой собственной библиотеки для сборки CMake. Однако, поскольку библиотека уже собрана, вам необходимо использовать флаг IMPORTED , чтобы сообщить CMake, что вы хотите только импортировать библиотеку в свой проект:
add_library( imported-lib
SHARED
IMPORTED )
Затем вам нужно указать путь к библиотеке с помощью команды set_target_properties() , как показано ниже.
Некоторые библиотеки предоставляют отдельные пакеты для конкретных архитектур ЦП или двоичных интерфейсов приложений (ABI) и организуют их в отдельные каталоги. Этот подход помогает библиотекам использовать преимущества определенных архитектур ЦП, позволяя вам использовать только те версии библиотеки, которые вам нужны. Чтобы добавить несколько версий ABI библиотеки в сценарий сборки CMake без необходимости писать несколько команд для каждой версии библиотеки, вы можете использовать переменную пути ANDROID_ABI . Эта переменная использует список ABI по умолчанию, которые поддерживает NDK , или отфильтрованный список ABI, которые вы вручную настраиваете для использования Gradle . Например:
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 )
Чтобы CMake нашел файлы заголовков во время компиляции, вам необходимо использовать команду include_directories() и указать путь к файлам заголовков:
include_directories( imported-lib/include/ )
Примечание. Если вы хотите упаковать предварительно созданную библиотеку, которая не является зависимостью во время сборки — например, при добавлении предварительно созданной библиотеки, которая является зависимостью imported-lib , вам не нужно выполнять следующие инструкции для связывания библиотеки.
Чтобы связать предварительно созданную библиотеку с вашей собственной библиотекой, добавьте ее в команду target_link_libraries() в сценарии сборки CMake:
target_link_libraries( native-lib imported-lib app-glue ${log-lib} )
Чтобы упаковать готовую библиотеку в APK, вам необходимо вручную настроить Gradle с помощью блока sourceSets , включив в него путь к вашему файлу .so . После сборки APK вы можете проверить, какие библиотеки Gradle упаковывает в ваш APK, с помощью анализатора APK .
Включить другие проекты CMake
Если вы хотите создать несколько проектов CMake и включить их результаты в свой проект Android, вы можете использовать один файл CMakeLists.txt в качестве сценария сборки CMake верхнего уровня (который вы связываете с Gradle ) и добавлять дополнительные проекты CMake в качестве зависимостей. этого сценария сборки. Следующий сценарий сборки CMake верхнего уровня использует команду add_subdirectory() для указания другого файла CMakeLists.txt в качестве зависимости сборки, а затем связывается с его выходными данными так же, как и с любой другой предварительно созданной библиотекой.
# 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 )
Вызов CMake из командной строки
Используйте следующую команду для вызова CMake для создания проекта Ninja за пределами 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
Эта команда сгенерирует проект Ninja, который можно выполнить для создания исполняемых библиотек Android (файлы .so ). CMAKE_TOOLCHAIN_FILE необходим для использования поддержки CMake NDK. Для CMake 3.21 или более поздней версии вместо этого можно использовать встроенную поддержку NDK CMake, но необходимо использовать другую группу переменных, как описано в документации CMake по кросс-компиляции для Android .