Termux — мощная среда для разработки под Android, где можно разворачивать инструментальную цепочку, собирать проекты на C/C++ и автоматизировать повторяемые задачи. Когда требуется собрать Android‑нативную библиотеку (JNI/NDK‑ориентированную) с использованием CMake и Ninja, на практике важно обеспечить: единообразную структуру сборки, предсказуемые параметры toolchain, корректную изоляцию артефактов по архитектурам и вариантам (Debug/Release), а также воспроизводимость команд.
В этой статье я покажу подход к автоматизации сборки и кросс‑компиляции под Android из Termux: подготовка зависимостей, выбор схемы toolchain, написание кросс‑компиляционных конфигураций для CMake, настройка Ninja и создание скриптов, которые можно запускать в один-два шага.
Требования и общая архитектура процесса
Цель — получать библиотеки .so для нужных ABI (например, arm64-v8a, armeabi-v7a, x86_64) без ручной рутины. Ключевые компоненты:
- Среда Termux для сборки и запуска генератора/компилятора.
- Android NDK (toolchain) для кросс‑компиляции.
- CMake как система генерации сборки.
- Ninja как быстрый генератор.
- Скрипты (bash) для: выбора ABI, подготовки build‑директорий, запуска CMake, запуска сборки и упаковки результатов.
Логика сборки обычно такая:
- Определяем ABI, API level, тип сборки (Debug/Release).
- Настраиваем переменные CMake: компилятор, sysroot, target triple, флаги.
- Генерируем build‑файлы Ninja через CMake.
- Запускаем сборку Ninja.
- Собираем артефакты в папку
out/и фиксируем версию окружения.
Подготовка окружения в Termux
Начнем с базовой подготовки пакетов. В Termux установите необходимые инструменты: CMake, Ninja, компилятор (для хостовых утилит) и вспомогательные пакеты. Конкретные названия пакетов могут зависеть от версии Termux/репозиториев, но общий принцип такой:
pkg update
pkg upgrade
pkg install cmake ninja-build clang llvm
pkg install git curl unzipДальше нужен Android NDK. На практике NDK удобно хранить в доступной директории (например, внутри домашней папки Termux) и ссылаться на него переменными окружения. Допустим, вы распаковали NDK в $HOME/android-ndk.
export ANDROID_NDK_HOME="$HOME/android-ndk"Проверьте, что NDK действительно доступен:
ls "$ANDROID_NDK_HOME"Если NDK установлен корректно, можно переходить к настройке кросс‑компиляции.
Схема сборки: build‑директории по ABI и конфигурациям
Чтобы автоматизация была удобной, используйте структуру, где каждая комбинация архитектуры и конфигурации живет отдельно. Например:
project/
CMakeLists.txt
scripts/
build.sh
toolchains/
android.cmake
out/
arm64-v8a/
debug/
release/
armeabi-v7a/
debug/
release/Так вы избегаете конфликтов артефактов и упрощаете сборку многoархитектурного пакета.
Кросс‑компиляционный toolchain файл для CMake
Один из самых практичных подходов — создать toolchain file для CMake. Он описывает, как CMake должен понимать NDK, sysroot, целевую архитектуру и компоновку.
Создадим файл, например toolchains/android.cmake. Он будет использоваться в скриптах с параметрами ABI.
# toolchains/android.cmake
# Пример: кросс-компиляция Android-native библиотеки через CMake + Ninja
if(NOT DEFINED ANDROID_NDK_HOME)
message(FATAL_ERROR "ANDROID_NDK_HOME is not set")
endif()
set(CMAKE_SYSTEM_NAME Android)
set(CMAKE_ANDROID_NDK "${ANDROID_NDK_HOME}")
# Важно: задавайте API level.
# В скрипте лучше прокидывать -DANDROID_PLATFORM=android-XX
if(NOT DEFINED ANDROID_PLATFORM)
set(ANDROID_PLATFORM android-24)
endif()
set(CMAKE_ANDROID_ARCH_ABI "${ANDROID_ABI}")
set(CMAKE_ANDROID_API "${ANDROID_PLATFORM}")
# Поддержка стандартной переменной Toolchain в CMake.
# Для новых CMake достаточно корректно задать NDK + ABI + API.
# При необходимости можно расширить кастомными флагами.
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
# Ninja: обычно задается на уровне команды cmake -G Ninja.
# Здесь оставляем общие настройки.
set(CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}")Обратите внимание: переменные ANDROID_ABI и ANDROID_PLATFORM мы будем передавать из скрипта. Также корректность зависит от версии CMake и NDK; при расхождениях можно уточнять флаги компилятора/линкера, но базовая схема обычно работает.
Сборочный скрипт: сборка одной архитектуры
Теперь соберем библиотеку для заданного ABI, типа сборки и уровня API. В scripts/build.sh реализуем логику:
- Принимаем ABI и конфигурацию.
- Формируем build‑директорию.
- Запускаем CMake с генератором Ninja.
- Запускаем Ninja.
- Копируем результат в
out/.
#!/data/data/com.termux/files/usr/bin/bash
set -e
# Параметры по умолчанию
ANDROID_NDK_HOME_DEFAULT="$HOME/android-ndk"
ANDROID_NDK_HOME="${ANDROID_NDK_HOME:-$ANDROID_NDK_HOME_DEFAULT}"
ANDROID_API="${ANDROID_API:-24}"
ANDROID_ABI="${ANDROID_ABI:-arm64-v8a}"
BUILD_TYPE="${BUILD_TYPE:-Release}"
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
TOOLCHAIN_FILE="$PROJECT_DIR/toolchains/android.cmake"
OUT_ROOT="$PROJECT_DIR/out/${ANDROID_ABI}/${BUILD_TYPE,,}"
BUILD_DIR="$PROJECT_DIR/build/${ANDROID_ABI}/${BUILD_TYPE,,}"
mkdir -p "$OUT_ROOT"
mkdir -p "$BUILD_DIR"
export ANDROID_NDK_HOME
export ANDROID_ABI
# Генерация и сборка
cmake -S "$PROJECT_DIR" -B "$BUILD_DIR" -G Ninja
-DCMAKE_TOOLCHAIN_FILE="$TOOLCHAIN_FILE"
-DANDROID_PLATFORM="android-${ANDROID_API}"
-DCMAKE_BUILD_TYPE="$BUILD_TYPE"
ninja -C "$BUILD_DIR"
# Пример копирования итогов.
# В реальных проектах пути к output могут отличаться.
# Ориентируйтесь на ваши target'ы и структуру CMake.
if [ -d "$BUILD_DIR" ]; then
find "$BUILD_DIR" -maxdepth 4 -type f ( -name ".so" -o -name ".a" ) -print -exec cp -n {} "$OUT_ROOT/" ;
fi
echo "Done: ABI=$ANDROID_ABI API=$ANDROID_API BUILD_TYPE=$BUILD_TYPE -> $OUT_ROOT"Скрипт копирует .so и .a на глубине до 4 уровней. Если у вас конкретные targets (например, один my_native_lib), лучше настроить CMake так, чтобы выходы попадали в предсказуемые каталоги, и копировать уже их.
Скрипт: сборка набора ABI одной командой
Чтобы полностью закрыть задачу автоматизации, создайте скрипт, который соберет список ABI. Например scripts/build_all.sh:
#!/data/data/com.termux/files/usr/bin/bash
set -e
ANDROID_API="${ANDROID_API:-24}"
BUILD_TYPE="${BUILD_TYPE:-Release}"
# Можно расширять список
ABIS=("arm64-v8a" "armeabi-v7a" "x86_64")
for abi in "${ABIS[@]}"; do
echo "Building for $abi ..."
ANDROID_ABI="$abi" ANDROID_API="$ANDROID_API" BUILD_TYPE="$BUILD_TYPE"
"$HOME/project/scripts/build.sh"
done
echo "All builds complete."Важно: в реальном проекте укажите правильный путь к вашему scripts/build.sh. И давайте артефактам единое место out/, чтобы дальше их было легко упаковать в AAR/JAR или подхватить билдом приложения.
Интеграция с CMakeLists.txt: рекомендации по target'ам
Чтобы CMake корректно генерировал нативные библиотеки под Android, проверьте базовые моменты:
- Используйте
add_library(... SHARED ...)для .so. - Включайте
target_include_directoriesиtarget_compile_optionsдля нужных флагов. - Если есть зависимости, задавайте их через
target_link_libraries. - Для C/C++ используйте корректный стандарт (например, C++17) через
target_compile_featuresилиCMAKE_CXX_STANDARD.
Пример упрощенной секции:
cmake_minimum_required(VERSION 3.22)
project(my_native_lib LANGUAGES C CXX)
add_library(my_native_lib SHARED
src/native.cpp
)
target_compile_features(my_native_lib PRIVATE cxx_std_17)
# Если у вас есть заголовки:
target_include_directories(my_native_lib PRIVATE
include
)Если библиотека должна поддерживать разные ABI, CMake сам подхватит подходящий компилятор из toolchain файла/NDK при корректно указанных переменных ABI и API.
Запуск сборки: практические команды
Допустим, вы находитесь в Termux и уже подготовили проект. Для сборки одной архитектуры выполните:
cd $HOME/my_native_project
chmod +x scripts/build.sh scripts/build_all.sh
ANDROID_NDK_HOME="$HOME/android-ndk"
ANDROID_ABI="arm64-v8a"
ANDROID_API="24"
BUILD_TYPE="Release"
scripts/build.shДля сборки нескольких ABI сразу:
ANDROID_API="24" BUILD_TYPE="Release" scripts/build_all.shРезультаты окажутся в out/ согласно структуре, которую вы заложили.
Оптимизация скорости сборки и повторяемости
Чтобы сборка не «тянулась» бесконечно, используйте базовые улучшения:
- Никогда не пересобирайте «в одном и том же build‑каталоге» разные ABI — только через изоляцию по ABI/типу.
- Кэшируйте зависимости, если проект их скачивает; используйте стабильные версии.
- Контролируйте переменные окружения: фиксируйте
ANDROID_API, NDK версию и CMake генератор. - Логируйте вывод CMake/Ninja в файл при CI/ночных сборках.
Например, логирование можно сделать так:
ANDROID_ABI="arm64-v8a" ANDROID_API="24" BUILD_TYPE="Release"
scripts/build.sh |& tee "$HOME/my_native_project/build.log"Частые проблемы и как их диагностировать
1) CMake ругается на toolchain/ABI.
Проверьте, что переменная ANDROID_ABI соответствует ожидаемому формату: arm64-v8a, armeabi-v7a, x86_64 и т.п. Убедитесь, что ANDROID_NDK_HOME указывает на корень NDK.
2) Ошибки линковки (.so не собирается).
Проверьте, что у вас верно определены зависимости через target_link_libraries, а также что библиотека собирается как SHARED если нужен .so.
3) Несовпадение API level и поддерживаемых функций.
Если вы используете системные API, которые требуют более высокий Android API, повышайте ANDROID_API и/или корректируйте условную компиляцию.
4) Слишком долгие пересборки.
Проверьте, что меняются входные файлы и флаги. В частности, если вы генерируете CMake каждый раз в новом каталоге — это ожидаемо; если же в одном и том же каталоге и всё равно пересобирается, вероятно, меняются параметры или версии инструментов.
Про VPN (локальная сеть)
Если вам нужно организовать работу Termux и внешних устройств в рамках одной локальной сети (например, для обмена артефактами/доступа к сборочным артефактам), можно использовать VPN для создания локальной сети. При этом VPN следует настраивать строго для сетевого удобства, а не для обхода блокировок.
Заключение
Автоматизация сборки Android‑нативных библиотек в Termux через CMake и Ninja — это, прежде всего, дисциплина в настройке toolchain, изоляция build‑директорий по ABI и конфигурациям, а также грамотные скрипты, которые превращают сложный процесс кросс‑компиляции в предсказуемую последовательность команд. Следуя предложенной структуре (toolchain file + скрипты сборки одной архитектуры и набора ABI), вы быстро получите воспроизводимый конвейер и легко сможете интегрировать его в разработку и публикацию.
Если хотите, чтобы ваш проект был настроен «под ключ» (NDK/CMake/Ninja, корректная структура, скрипты, упаковка артефактов под приложение, CI‑подготовка) — обращайтесь в РыбинскЛАБ. Мы поможем оптимизировать процесс сборки и обеспечить стабильность кросс‑компиляции для Android.