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 . Список поддерживаемых аргументов см. в разделе «Аргументы цепочки инструментов» .
Файл "новой" цепочки инструментов
В более ранних версиях NDK экспериментировали с новой реализацией файла цепочки инструментов, которая должна была уменьшить различия в поведении между использованием файла цепочки инструментов NDK и встроенной поддержкой CMake. Это потребовало значительных усилий (которые так и не были завершены), но фактически не улучшило поведение, поэтому мы больше не занимаемся этим вопросом.
В «новом» файле цепочки инструментов наблюдаются регрессии в поведении по сравнению с «устаревшим» файлом цепочки инструментов. Поведение по умолчанию соответствует рекомендуемому рабочему процессу. Если вы используете флаг -DANDROID_USE_LEGACY_TOOLCHAIN_FILE=OFF , мы рекомендуем удалить его из вашей сборки. Новый файл цепочки инструментов так и не достиг паритета с устаревшим файлом, поэтому, вероятно, существуют регрессии в поведении.
Хотя мы не рекомендуем использовать новый файл цепочки инструментов, в настоящее время планов по его удалению из NDK нет. Это нарушит работу сборок, зависящих от различий в поведении между новым и устаревшим файлами цепочки инструментов, и, к сожалению, переименование параметра с указанием на то, что рекомендуется использовать «устаревший», также нарушит работу пользователей этого параметра. Если вы успешно используете новый файл цепочки инструментов, вам не нужно переходить на него, но имейте в виду, что любые ошибки, связанные с поведением нового файла цепочки инструментов, скорее всего, не будут исправлены, и вместо этого вам потребуется перейти на него.
Использование
Грэдл
Использование файла цепочки инструментов CMake происходит автоматически при использовании externalNativeBuild . Дополнительную информацию см. в руководстве Android Studio по добавлению кода C и C++ в проект .
Командная строка
При сборке с помощью 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 . Например, чтобы принудительно отключить поддержку Neon при сборке armeabi-v7a, передайте -DANDROID_ARM_NEON=FALSE .
ANDROID_ABI
Целевой ABI. Информацию о поддерживаемых ABI см. в разделе Android ABI .
Грэдл
Gradle предоставляет этот аргумент автоматически. Не указывайте этот аргумент явно в файле build.gradle . Чтобы контролировать, какие ABI использует Gradle, используйте abiFilters как описано в разделе Android ABIs .
Командная строка
CMake выполняет сборку для одной цели за один сборочный процесс. Чтобы использовать более одного Android ABI, необходимо выполнить сборку один раз для каждого ABI. Рекомендуется использовать разные каталоги сборки для каждого ABI, чтобы избежать конфликтов между сборками.
| Ценить | Примечания |
|---|---|
armeabi-v7a | |
armeabi-v7a with NEON | Аналогично armeabi-v7a . |
arm64-v8a | |
x86 | |
x86_64 |
ANDROID_ARM_MODE
Указывает, следует ли генерировать инструкции arm или thumb для 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++_shared | Вариант библиотеки libc++ с разделяемой библиотекой. |
| c++_static | Статическая библиотека, являющаяся вариантом libc++ . |
| никто | Стандартная библиотека C++ не поддерживает этот язык. |
| система | Система STL |
Управление флагами компилятора
Если вам необходимо передать компилятору или компоновщику определенные флаги для сборки, обратитесь к документации 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. Например, если у вас есть варианты сборки "free" и "premium", которые контролируются вашим файлом 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.
Если такой возможности нет:
- Vendor (ie copy) the third-party source into your repository and use add_subdirectory to build it. This only works if the other library is also built with 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 test в репозитории NDK на GitHub.
Сообщить о проблемах
Если у вас возникнут какие-либо проблемы с NDK или файлом инструментария CMake, сообщите о них через систему отслеживания ошибок android-ndk/ndk на GitHub. В случае проблем с Gradle или плагином Android Gradle, сообщите об этом через сообщение об ошибке в Studio .