Termux давно стал удобной средой для разработки и автоматизации. Когда проект состоит из нескольких библиотек, требуется воспроизводимая сборка, а также периодическая пересборка с разными флагами (например, Debug/Release), ручное выполнение команд быстро превращается в рутину.
Ниже — практический подход к автоматизации сборки и кросс‑компиляции C/C++ проектов для Android ARM64 с помощью CMake и Ninja прямо из Termux. Мы сделаем:
- подготовку toolchain для Android‑ARM64;
- единый скрипт конфигурации и сборки;
- организацию build‑директорий;
- настройки флагов, install‑шага и логирования.
Предварительные требования
Убедитесь, что у вас установлены необходимые пакеты Termux. Терминалы и команды могут отличаться в зависимости от версии Termux и архитектуры устройства, но логика одна.
Установим базовые инструменты сборки:
pkg update
pkg install -y clang cmake ninja git make python
Для кросс‑компиляции C/C++ под Android ARM64 также часто нужен NDK. На практике есть два пути:
- использовать готовый NDK и toolchain файл;
- собрать окружение под вашу задачу и хранить NDK локально в проекте.
Рекомендуемый подход для автоматизации: хранить путь к NDK явно в переменных окружения или в конфигурационном файле проекта.
Структура проекта и идея “одного входа”
Хорошая автоматизация начинается с простой структуры:
- toolchain/ — файлы toolchain CMake;
- scripts/ — скрипты сборки;
- build/ — папки сборки по профилям (release/debug).
Например:
my-project/
toolchain/
scripts/
CMakeLists.txt
src/ ...
Мы реализуем сборку командой вида:
./scripts/build-android-arm64.sh --build-type Release./scripts/build-android-arm64.sh --build-type Debug
Скрипт сам сделает конфигурацию, сборку Ninja и (опционально) install‑шаг.
Подготовка NDK и toolchain для Android ARM64
Предположим, что NDK уже скачан и распакован. Пусть путь будет, например:
export ANDROID_NDK_HOME=$HOME/ndk/android-ndk-r26b
Для CMake создадим toolchain файл. В папке toolchain/ создайте файл, например android-arm64.cmake.
Важно: конкретные имена исполняемых файлов и layout NDK могут слегка отличаться по версиям. Ниже — рабочая стартовая схема для распространённых NDK.
mkdir -p toolchain
cat > toolchain/android-arm64.cmake <<'EOF'
# Toolchain file for Android ARM64 cross-compilation
# Ожидается, что ANDROID_NDK_HOME задано в окружении
if(NOT DEFINED ENV{ANDROID_NDK_HOME})
message(FATAL_ERROR "ANDROID_NDK_HOME is not set")
endif()
set(ANDROID_NDK $ENV{ANDROID_NDK_HOME})
# Минимальная версия API (подстройте под задачу)
if(NOT DEFINED ANDROID_PLATFORM)
set(ANDROID_PLATFORM android-24)
endif()
set(CMAKE_SYSTEM_NAME Android)
set(CMAKE_SYSTEM_VERSION ${ANDROID_PLATFORM})
# Архитектура
set(ANDROID_ABI arm64-v8a)
# Указываем компилятор из LLVM toolchain NDK
set(CMAKE_C_COMPILER ${ANDROID_NDK}/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android${ANDROID_PLATFORM_LEVEL}-clang)
set(CMAKE_CXX_COMPILER ${ANDROID_NDK}/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android${ANDROID_PLATFORM_LEVEL}-clang++)
# Но часто PLATFORM android-24 – это строка. Удобнее задать уровень явно.
# Поэтому зададим ANDROID_PLATFORM_LEVEL как число, если его нет.
if(NOT DEFINED ANDROID_PLATFORM_LEVEL)
# грубое извлечение цифр: android-24 -> 24
string(REGEX REPLACE "^android-" "" ANDROID_PLATFORM_LEVEL "${ANDROID_PLATFORM}")
endif()
# Исправим пути компиляторов после вычисления уровня
set(CMAKE_C_COMPILER ${ANDROID_NDK}/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android${ANDROID_PLATFORM_LEVEL}-clang)
set(CMAKE_CXX_COMPILER ${ANDROID_NDK}/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android${ANDROID_PLATFORM_LEVEL}-clang++)
# Корень sysroot
set(CMAKE_SYSROOT ${ANDROID_NDK}/toolchains/llvm/prebuilt/linux-x86_64/sysroot)
set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
set(CMAKE_LIBRARY_ARCHITECTURE ${ANDROID_ABI})
# CMake режимы
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_ANDROID_ARCH_ABI ${ANDROID_ABI})
set(CMAKE_ANDROID_NDK ${ANDROID_NDK})
# Параметры поиска
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
# Сборка под Android обычно требует отключать некоторые host-специфичные штуки.
# Дополнительно можно настроить rpath и прочее, но это зависит от проекта.
EOF
Важное замечание: путь prebuilt/linux-x86_64 может отличаться (например, darwin-x86_64 или linux-aarch64). В NDK папка toolchains/llvm/prebuilt/ содержит конкретный таргет-хост. Если Termux работает на вашем устройстве Android (ARM), то NDK может быть распакован с хостом “linux-x86_64” (содержит бинарники x86_64), и тогда их исполнение на ARM без соответствующих возможностей будет проблемным.
В реальных сценариях Termux кросс‑компиляция обычно требует, чтобы в NDK были доступны исполняемые бинарники на архитектуре хоста. Практически: выбирайте NDK, подходящий для вашего хоста, или используйте сборку через корректную среду/контейнер/CI. В этой статье мы фокусируемся на механике CMake/Ninja и автоматизации, но обязательно проверьте совместимость toolchain с вашим “host” окружением.
Скрипт автоматической конфигурации и сборки
Создадим скрипт scripts/build-android-arm64.sh. Он будет:
- принимать параметры;
- формировать build‑директорию;
- вызывать CMake с Ninja;
- выполнять сборку;
- при необходимости делать install.
mkdir -p scripts
cat > scripts/build-android-arm64.sh <<'EOF'
#!/data/data/com.termux/files/usr/bin/bash
set -euo pipefail
BUILD_TYPE="Release"
ANDROID_PLATFORM="android-24"
DO_INSTALL="false"
usage() {
echo "Usage: $0 [--build-type Debug|Release] [--android-platform android-24|android-26] [--install]"
}
while [[ $# -gt 0 ]]; do
case "$1" in
--build-type)
BUILD_TYPE="$2"
shift 2
;;
--android-platform)
ANDROID_PLATFORM="$2"
shift 2
;;
--install)
DO_INSTALL="true"
shift 1
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown argument: $1"
usage
exit 1
;;
esac
done
# Убедимся, что NDK задан
: "${ANDROID_NDK_HOME:?Please set ANDROID_NDK_HOME to your Android NDK path}"
# Корень проекта: предполагаем, что скрипт лежит в scripts/
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
TOOLCHAIN_FILE="${ROOT_DIR}/toolchain/android-arm64.cmake"
# build dir: build/android-arm64--
BUILD_DIR="${ROOT_DIR}/build/android-arm64-${ANDROID_PLATFORM}-${BUILD_TYPE}"
mkdir -p "${BUILD_DIR}"
CMAKE_ARGS=(
-G Ninja
-DCMAKE_TOOLCHAIN_FILE="${TOOLCHAIN_FILE}"
-DCMAKE_BUILD_TYPE="${BUILD_TYPE}"
-DANDROID_PLATFORM="${ANDROID_PLATFORM}"
)
# Часто полезно явно ограничить сборку только тем, что нужно.
# Если у проекта есть опции (например WITH_TESTS), добавьте их сюда.
echo "[INFO] Configure: ${BUILD_DIR}"
cmake -S "${ROOT_DIR}" -B "${BUILD_DIR}" "${CMAKE_ARGS[@]}"
echo "[INFO] Build (Ninja): ${BUILD_DIR}"
ninja -C "${BUILD_DIR}"
if [[ "${DO_INSTALL}" == "true" ]]; then
# install prefix: build/<...>/install
INSTALL_DIR="${BUILD_DIR}/install"
echo "[INFO] Install to: ${INSTALL_DIR}"
ninja -C "${BUILD_DIR}" install DESTDIR="${INSTALL_DIR}"
fi
echo "[DONE] Build finished."
EOF
chmod +x scripts/build-android-arm64.sh
Пример вызова скрипта
Перед первым запуском задайте путь к NDK:
export ANDROID_NDK_HOME=$HOME/ndk/android-ndk-r26b
Соберём Release:
./scripts/build-android-arm64.sh --build-type Release --android-platform android-24 --install
Соберём Debug:
./scripts/build-android-arm64.sh --build-type Debug --android-platform android-24
Настройки CMakeLists: чтобы кросс‑сборка была “правильной”
В целом CMake‑проекты сами неплохо кросс‑компилируются, но есть типовые места, где кросс‑сборка ломается:
- проверки, которые выполняются на хосте (try_run);
- поиск пакетов через
find_package(нужно, чтобы они были доступны для target); - использование библиотек “host” вместо “target”.
На практике полезно:
- для внешних зависимостей использовать vendored сборку или заранее собранные Android‑артефакты;
- избегать
try_runи предпочтительно использоватьtry_compileили ручные параметры.
Небольшой фрагмент (пример для параметров проекта):
# Пример: если проект поддерживает отключение тестов
option(WITH_TESTS "Build tests" OFF)
if(WITH_TESTS)
add_subdirectory(tests)
endif()
Оптимизация под Android: компилятор, флаги, LTO
Для Android часто хотят аккуратно управлять оптимизациями, бинарным размером и отладкой. В зависимости от вашего проекта можно добавлять:
- флаги оптимизации;
- контроль отладочной информации;
- LTO (link-time optimization) — осторожно, т.к. может увеличивать время сборки.
Пример внесения флагов в CMake (универсальный подход):
if(ANDROID)
# Базовые настройки
add_compile_options(-fPIC)
# Пример: можно включить LTO через опции проекта
option(ENABLE_LTO "Enable LTO" OFF)
if(ENABLE_LTO)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON)
endif()
endif()
Вызов скрипта тогда можно дополнить параметром, если ваш проект принимает -DENABLE_LTO=ON.
Логи, воспроизводимость и “быстрый повтор”
Автоматизация ценна тем, что результаты воспроизводимы. Для этого удобно:
- использовать фиксированную версию NDK;
- фиксировать API level через
ANDROID_PLATFORM; - сохранять команды конфигурации;
- контролировать переменные окружения.
Мини‑улучшение в скрипт: логировать команду CMake и Ninja. Например, можно добавить перенаправление stdout/stderr в файл в build‑директории.
cmake -S "${ROOT_DIR}" -B "${BUILD_DIR}" "${CMAKE_ARGS[@]}"
|& tee "${BUILD_DIR}/cmake-config.log"
И аналогично для сборки:
ninja -C "${BUILD_DIR}" |& tee "${BUILD_DIR}/build.log"
Типовые проблемы и как их диагностировать
- Не находится компилятор: проверьте, что toolchain файл указывает на существующий
-clangи-clang++. - Ошибки sysroot: убедитесь, что в
CMAKE_SYSROOTкорректный путь. Для разных NDK иногда меняется layout. - Сборка идет, но не линкуется: проверьте, какие библиотеки подхватываются. Убедитесь, что нет “host” зависимостей.
- try_run ломает конфигурацию: в кросс‑сценариях лучше отказаться от выполнения на хосте и заменить на try_compile или задать значения вручную.
Заключение
Автоматизация сборки и кросс‑компиляции C/C++ под Android ARM64 в Termux с использованием CMake и Ninja позволяет быстро и воспроизводимо получать артефакты для разных профилей (Debug/Release) и уровней API. Ключевые элементы решения — корректный toolchain, единый скрипт конфигурации/сборки и дисциплина в настройках проекта (особенно по зависимостям и поведению проверок в CMake).
Если вам нужно адаптировать скрипт под конкретный NDK, репозиторий и зависимости (например, OpenSSL, Boost, протоколы и т.п.), команда РыбинскЛАБ поможет: консультации и настройка CI/сборочных пайплайнов, правка CMake под кросс‑среды и сопровождение процесса сборки для ваших Android‑ARM64 целей.