Android NDK поддерживает использование CMake для компиляции кода C и C++ для вашего приложения. На этой странице обсуждается, как использовать CMake с NDK через ExternalNativeBuild
подключаемого модуля Android Gradle или при непосредственном вызове CMake.
Файл набора инструментов CMake
NDK поддерживает CMake через файл цепочки инструментов . Файлы цепочки инструментов — это файлы CMake, которые настраивают поведение цепочки инструментов для кросс-компиляции. Файл цепочки инструментов, используемый для NDK, находится в NDK по адресу <NDK>/build/cmake/android.toolchain.cmake
.
Параметры сборки, такие как ABI, minSdkVersion
и т. д., передаются в командной строке при вызове cmake
. Список поддерживаемых аргументов см. в разделе «Аргументы Toolchain» .
«Новый» файл инструментальной цепочки
Ранее NDK экспериментировали с новой реализацией файла цепочки инструментов, которая позволила бы уменьшить различия в поведении между использованием файла цепочки инструментов NDK и использованием встроенной поддержки CMake. В конечном итоге это потребовало значительного объема работы (которая не была завершена), но на самом деле не улучшило поведение, поэтому мы больше не занимаемся этим.
Поведение «нового» файла цепочки инструментов ухудшилось по сравнению с «устаревшим» файлом цепочки инструментов. Поведение по умолчанию — это рекомендуемый рабочий процесс. Если вы используете -DANDROID_USE_LEGACY_TOOLCHAIN_FILE=OFF
, мы рекомендуем удалить этот флаг из вашей сборки. Новый файл цепочки инструментов так и не достиг четности с устаревшим файлом цепочки инструментов, поэтому возможны регрессии поведения.
Хотя мы не рекомендуем использовать новый файл цепочки инструментов, в настоящее время нет планов удалять его из NDK. Это нарушит работу сборок, основанных на различиях в поведении между новыми и устаревшими файлами набора инструментов, и, к сожалению, переименование опции, чтобы было ясно, что на самом деле рекомендуется «устаревшая версия», также нарушит работу пользователей этой опции. Если вы успешно используете новый файл цепочки инструментов, вам не нужно мигрировать, но знайте, что любые ошибки, обнаруженные в поведении нового файла цепочки инструментов, вероятно, не будут исправлены, и вместо этого вам придется выполнить миграцию.
Использование
Градл
Использование файла цепочки инструментов CMake происходит автоматически при использовании externalNativeBuild
. Дополнительную информацию см . в разделе «Добавление кода C и C++» Android Studio в руководство по проекту .
Командная строка
При сборке с помощью CMake вне Gradle сам файл набора инструментов и его аргументы должны быть переданы в CMake. Например:
$ cmake \
-DCMAKE_TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=$ABI \
-DANDROID_PLATFORM=android-$MINSDKVERSION \
$OTHER_ARGS
Аргументы инструментальной цепочки
Следующие аргументы можно передать в файл цепочки инструментов CMake. При сборке с помощью Gradle добавьте аргументы в android.defaultConfig.externalNativeBuild.cmake.arguments
, как описано в документации ExternalNativeBuild . При сборке из командной строки передайте аргументы CMake с помощью -D
. Например, чтобы заставить Armeabi-v7a не создавать поддержку Neon, передайте -DANDROID_ARM_NEON=FALSE
.
ANDROID_ABI
Целевой ABI. Информацию о поддерживаемых ABI см. в разделе Android ABI .
Градл
Gradle предоставляет этот аргумент автоматически. Не указывайте этот аргумент явно в файле build.gradle
. Чтобы контролировать целевые ABI Gradle, используйте abiFilters
, как описано в Android ABI .
Командная строка
CMake строит для одной цели в каждой сборке. Чтобы настроить таргетинг на несколько Android ABI, необходимо создать один ABI для каждого ABI. Рекомендуется использовать разные каталоги сборки для каждого ABI, чтобы избежать конфликтов между сборками.
Ценить | Примечания |
---|---|
armeabi-v7a | |
armeabi-v7a with NEON | То же, что и armeabi-v7a . |
arm64-v8a | |
x86 | |
x86_64 |
ANDROID_ARM_MODE
Указывает, следует ли генерировать инструкции руки или большого пальца для Armeabi-v7a. Не оказывает влияния на другие ABI. Дополнительную информацию см. в документации Android ABI .
Ценить | Примечания |
---|---|
рука | |
большой палец | Поведение по умолчанию. |
ANDROID_NATIVE_API_LEVEL
Псевдоним для ANDROID_PLATFORM .
ANDROID_PLATFORM
Указывает минимальный уровень API, поддерживаемый приложением или библиотекой. Это значение соответствует minSdkVersion
приложения.
Градл
При использовании подключаемого модуля Android Gradle это значение автоматически устанавливается в соответствии с minSdkVersion
приложения, и его не следует задавать вручную.
Командная строка
При прямом вызове CMake это значение по умолчанию равно самому низкому уровню API, поддерживаемому используемым NDK. Например, в NDK r20 это значение по умолчанию равно уровню API 16.
Для этого параметра принимаются несколько форматов:
-
android-$API_LEVEL
-
$API_LEVEL
-
android-$API_LETTER
Формат $API_LETTER
позволяет указать android-N
без необходимости определять номер, связанный с этой версией. Обратите внимание, что некоторые выпуски получили увеличение API без увеличения буквы. Эти API можно указать, добавив суффикс -MR1
. Например, уровень API 25 — android-N-MR1
.
ANDROID_STL
Указывает, какой STL использовать для этого приложения. Дополнительные сведения см. в разделе Поддержка библиотек C++ . По умолчанию будет использоваться c++_static
.
Ценить | Примечания |
---|---|
c++_общий | Вариант общей библиотеки libc++ . |
c++_static | Вариант статической библиотеки libc++ . |
никто | Нет поддержки стандартной библиотеки C++. |
система | Система СТЛ |
Управление флагами компилятора
Если вам нужно передать определенные флаги компилятору или компоновщику для вашей сборки, обратитесь к документации CMake для set_target_compile_options и связанного семейства параметров. В разделе «см. также» внизу страницы есть несколько полезных подсказок.
В общем, лучше всего применять флаги компилятора как самую узкую доступную область применения. Флаги, которые вы хотите применить ко всем вашим целям (например, -Werror
), неудобно повторять для каждого модуля, но их все же редко следует применять глобально ( CMAKE_CXX_FLAGS
), поскольку они могут иметь нежелательные последствия для сторонних зависимостей в вашем проекте. . В таких случаях флаги можно применять в области каталога ( add_compile_options
).
Для узкого подмножества флагов компилятора их также можно установить в файле build.gradle с помощью cppFlags
или аналогичных свойств. Не следует этого делать. Флаги, передаваемые в CMake из Gradle, будут иметь удивительное поведение приоритета, в некоторых случаях переопределяя флаги, неявно переданные реализацией, которые необходимы для создания кода Android. Всегда предпочитайте обрабатывать поведение CMake непосредственно в CMake. Если вам нужно управлять флагами компилятора для каждого buildType
AGP, см. раздел Работа с типами сборки AGP в CMake .
Работа с типами сборки AGP в CMake
Если вам нужно адаптировать поведение CMake к пользовательскому buildType
Gradle, используйте этот тип сборки для передачи дополнительного флага CMake (а не флага компилятора), который могут читать ваши сценарии сборки CMake. Например, если у вас есть «бесплатные» и «премиум» варианты сборки, которые контролируются вашим build.gradle.kts, и вам необходимо передать эти данные в CMake:
android {
buildTypes {
free {
externalNativeBuild {
cmake {
arguments.add("-DPRODUCT_VARIANT_PREMIUM=OFF")
}
}
}
premium {
externalNativeBuild {
cmake {
arguments.add("-DPRODUCT_VARIANT_PREMIUM=ON")
}
}
}
}
}
Затем в вашем CMakeLists.txt:
if (DPRODUCT_VARIANT_PREMIUM)
# Do stuff for the premium build.
else()
# Do stuff for the free build.
endif()
Имя переменной зависит от вас, но убедитесь, что вы избегаете чего-либо с префиксом ANDROID_
, APP_
или CMAKE_
, чтобы избежать конфликта или путаницы с существующими флагами.
Пример см. в образце Sanitizers NDK .
Понимание команды сборки CMake
При отладке проблем сборки CMake полезно знать конкретные аргументы сборки, которые Gradle использует при кросс-компиляции для Android.
Плагин Android Gradle сохраняет аргументы сборки, которые он использует для выполнения сборки CMake для каждой пары ABI и типа сборки, в build_command.txt
. Эти файлы находятся в следующем каталоге:
<project-root>/<module-root>/.cxx/cmake/<build-type>/<ABI>/
В следующем фрагменте показан пример аргументов CMake для создания отлаживаемой версии примера hello-jni
предназначенной для архитектуры 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
Используйте готовые библиотеки
Если предварительно созданная библиотека, которую вам необходимо импортировать, распространяется как AAR, следуйте документации по зависимостям Studio, чтобы импортировать и использовать ее. Если вы не используете AGP, вы можете следовать https://google.github.io/prefab/example-workflow.html, но, вероятно, перейти на AGP гораздо проще.
Для библиотек, которые не распространяются как AAR, инструкции по использованию готовых библиотек с CMake см. в документации add_library
относительно IMPORTED
целей в руководстве CMake .
Создание стороннего кода
Существует несколько способов создания стороннего кода в рамках вашего проекта CMake, и какой вариант работает лучше всего, будет зависеть от вашей ситуации. Лучшим вариантом часто будет не делать этого вообще. Вместо этого создайте AAR для библиотеки и используйте его в своем приложении. Вам не обязательно публиковать этот AAR. Он может быть внутренним для вашего проекта Gradle.
Если это не вариант:
- Продайте (т. е. скопируйте) сторонний исходный код в свой репозиторий и используйте add_subdirectory для его сборки. Это работает только в том случае, если другая библиотека также собрана с помощью CMake.
- Определите внешний проект .
- Создайте библиотеку отдельно от вашего проекта и следуйте инструкциям «Использовать готовые библиотеки», чтобы импортировать ее как готовую.
Поддержка YASM в CMake
NDK обеспечивает поддержку CMake для создания ассемблерного кода, написанного на YASM, для работы на архитектурах x86 и x86-64. YASM — это ассемблер с открытым исходным кодом для архитектур x86 и x86-64, основанный на ассемблере NASM.
Чтобы создать ассемблерный код с помощью CMake, внесите следующие изменения в CMakeLists.txt
вашего проекта:
- Вызовите
enable_language
со значением, установленным вASM_NASM
. - В зависимости от того, создаете ли вы общую библиотеку или исполняемый двоичный файл, вызовите
add_library
илиadd_executable
. В качестве аргументов передайте список исходных файлов, состоящий из файлов.asm
для программы сборки в YASM и файлов.c
для связанных библиотек или функций C.
В следующем фрагменте показано, как можно настроить CMakeLists.txt
для создания программы YASM в качестве общей библиотеки.
cmake_minimum_required(VERSION 3.6.0)
enable_language(ASM_NASM)
add_library(test-yasm SHARED jni/test-yasm.c jni/print_hello.asm)
Пример того, как создать программу YASM в виде исполняемого файла, см. в тесте yasm в репозитории NDK git.
Сообщить о проблемах
Если у вас возникнут какие-либо проблемы с NDK или его файлом набора инструментов CMake, сообщите о них через систему отслеживания проблем android-ndk/ndk на GitHub. В случае проблем с Gradle или плагином Android Gradle вместо этого сообщите об ошибке Studio .