Терминальная среда Termux отлично подходит для разработки и сборки проектов, но когда речь заходит о кросс‑компиляции C/C++ под Android (ARMv7/ARM64/x86/x86_64), возникает вопрос: как корректно использовать clang и ndk-toolchain. В этой статье мы разберём практический и системный подход — от подготовки инструментов до сборки типового проекта и диагностики ошибок.
Зачем нужна кросс‑компиляция в Termux
В Termux вы можете компилировать программы под архитектуру вашего устройства, но при кросс‑компиляции можно:
- собрать бинарники для другой архитектуры (например, ARM64 на x86_64 устройствах и наоборот);
- фиксировать инструментальную цепочку (версии clang/stdlib/ABI);
- использовать стандартные параметры Android NDK (sysroot, API level, ABI);
- ускорить сборку и повысить воспроизводимость.
Что подготовить заранее
Нам понадобятся:
- Termux (желательно актуальная версия);
- Android NDK (комплект инструментов с ndk-build/clang toolchain);
- clang в Termux (в некоторых сценариях можно собрать и без него, но для унификации используем подход с clang);
- базовые пакеты: build-essential, cmake/autotools (по проекту).
Дальше будем считать, что у вас уже скачан NDK и вы понимаете, под какую ABI хотите собирать.
Установка зависимостей в Termux
Обновите индексы пакетов и поставьте базовые инструменты:
pkg update -y
pkg upgrade -y
pkg install -y clang lld make cmake ninja autoconf automake libtool pkg-config python
Проверка, что clang доступен:
clang --version
Подключение Android NDK toolchain
Самый практичный путь — использовать clang, входящий в NDK, потому что он «знает» про Android sysroot, ABI и совместимость. Предположим, что NDK лежит в:
NDK=/data/data/com.termux/files/home/android-ndk
Вам нужно указать корректный путь к вашему NDK. Далее будем использовать переменные для API level и ABI.
Выбор ABI и API level
Android ABI задаёт таргетную архитектуру. Типичные значения:
- arm64-v8a
- armeabi-v7a
- x86_64
- x86
API level обычно выбирают в пределах 21–34 в зависимости от требований. В примерах ниже возьмём android API 24 как рабочую основу.
API=24
Концепция: sysroot и target‑triple
В NDK важно использовать правильный target‑triple (например, aarch64-linux-android) и sysroot. Обычно NDK обеспечивает это автоматически, но в ручных командных строках мы должны указать параметры явно или через готовые обёртки.
Дальше покажем два подхода:
- через прямой вызов clang с параметрами NDK;
- через CMake Toolchain файл (удобнее для проектов на CMake).
Подход 1: ручной clang + NDK toolchain (универсально)
Рассмотрим простейший случай: компиляция одного .c/.cpp файла. Пусть проект содержит main.cpp. Мы создадим сборочную папку и соберём бинарник под нужный ABI.
Выберите ABI. Например, arm64-v8a:
ABI=arm64-v8a
Настройте параметры для arm64:
TRIPLE=aarch64-linux-android
CLANG=$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/clang
SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot
Важно: путь prebuilt/linux-x86_64 зависит от того, под какой хост платформой вы распаковали NDK. Если NDK скачан на другой ОС — скорректируйте путь к prebuilt. В Termux вы обычно используете NDK из файловой системы устройства, но структура prebuilt внутри архива всё равно соответствует платформе, с которой вы распаковали NDK.
Собрать:
mkdir -p build/$ABI
$CLANG --target=$TRIPLE$API \
--sysroot=$SYSROOT \
-fPIC -O2 -Wall \
-c main.cpp -o build/$ABI/main.o
$CLANG --target=$TRIPLE$API \
--sysroot=$SYSROOT \
build/$ABI/main.o -o build/$ABI/app \
-Wl,--gc-sections
Если вы собираете C++ и хотите явно указать стандарт:
$CLANG --target=$TRIPLE$API --sysroot=$SYSROOT \
-std=c++17 -O2 -fPIC -Wall \
-c main.cpp -o build/$ABI/main.o
Подход 2: CMake Toolchain файл для кросс‑компиляции
Если ваш проект использует CMake (или вы хотите перевести сборку на CMake), то лучше создать Toolchain файл. Он позволит CMake автоматически проставить нужные параметры.
Создадим файл android-toolchain-$ABI.cmake в домашней директории Termux.
Пример для arm64-v8a:
ABI=arm64-v8a
API=24
TRIPLE=aarch64-linux-android
TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin
SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot
cat > ~/android-toolchain-$ABI.cmake <<'EOF'
set(CMAKE_SYSTEM_NAME Android)
set(CMAKE_SYSTEM_VERSION 1)
# Variables injected by wrapper
set(TARGET_TRIPLE "${TRIPLE}")
set(ANDROID_API "${API}")
set(NDK_ROOT "${NDK}")
set(LLVM_PREBUILT "${LLVM_PREBUILT}")
set(CMAKE_C_COMPILER "${TOOLCHAIN}/clang")
set(CMAKE_CXX_COMPILER "${TOOLCHAIN}/clang++")
set(CMAKE_C_FLAGS "--target=${TRIPLE}${API} --sysroot=${SYSROOT}")
set(CMAKE_CXX_FLAGS "--target=${TRIPLE}${API} --sysroot=${SYSROOT}")
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_FIND_ROOT_PATH "${SYSROOT}")
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
EOF
Этот скрипт содержит переменные ${TRIPLE}, ${API} и прочие, поэтому перед запуском убедитесь, что экспортировали их корректно. Если предпочитаете более «жёсткий» шаблон, можно подставить значения прямо в файл (без переменных).
Далее сборка:
mkdir -p build-cmake/$ABI
cd build-cmake/$ABI
cmake ../.. \
-DCMAKE_TOOLCHAIN_FILE=~/android-toolchain-$ABI.cmake \
-DCMAKE_BUILD_TYPE=Release
cmake --build . -j$(nproc)
После успешной сборки вы получите артефакты в каталоге сборки, соответствующие вашему ABI.
Проверка результатов и базовая диагностика
Первое, что стоит сделать — убедиться, что бинарник соответствует архитектуре. В Termux можно использовать file, но при необходимости установите file:
pkg install -y file
file build/$ABI/app
Типовые ошибки:
- Не найден sysroot / ошибки libc: проверьте путь к
sysrootи target‑triple. - Символы не находятся / несовместимость ABI: убедитесь, что собираете и линковку с тем же target.
- Проблемы с зависимостями (zlib/openssl/etc.): соберите их также под Android (тем же ABI/API), либо подключайте корректные статические библиотеки.
- «undefined reference to __android_log_*»: добавьте нужные системные библиотеки (часто
log).
Пример: сборка статической библиотеки и линковка с Android log
Допустим, у вас есть libhello, и вы хотите линковать приложение с android log. В CMake это обычно делается так:
# CMakeLists.txt (фрагмент)
add_library(hello STATIC hello.cpp)
add_executable(app main.cpp)
target_link_libraries(app PRIVATE hello log)
Если вы собираете вручную через clang, то на этапе линковки нужно добавить -llog и корректные флаги линковщика. Конкретные детали зависят от проекта, но общий принцип такой:
$CLANG --target=$TRIPLE$API --sysroot=$SYSROOT \
build/$ABI/main.o build/$ABI/libhello.a \
-llog -Wl,--gc-sections \
-o build/$ABI/app
Рекомендации для воспроизводимости
- Фиксируйте версию NDK и API level (например,
API=24). - Храните toolchain файлы в папке проекта или рядом с ними.
- Держите отдельные build-каталоги по ABI:
build/arm64-v8a,build/armeabi-v7a. - Собирайте все зависимости под те же ABI/API (или используйте заведомо подготовленные Android-версии).
Если вам требуется локальная тестовая инфраструктура (например, чтобы быстро раздавать артефакты на устройства в рамках вашей локальной сети), можно развернуть её через VPN для создания локальной сети — это не связано с обходом блокировок, а только с удобством коммуникации между узлами.
Частые вопросы
Можно ли использовать clang из Termux вместо clang из NDK?
Технически иногда можно, но чаще проще и надёжнее использовать clang/clang++ из самого NDK, чтобы гарантировать корректные пути к sysroot и совместимость с Android.
Почему CMake не находит заголовки/библиотеки?
Обычно потому что включены неверные CMAKE_FIND_ROOT_PATH и режимы поиска. Toolchain файл должен ограничивать поиск в сторону sysroot для target-библиотек и заголовков.
Как ускорить сборку?
Используйте -j$(nproc) и режим Release. Для CMake также включайте Ninja, если применимо.
Заключение
Кросс‑компиляция C/C++ в Termux с использованием clang и ndk‑toolchain становится предсказуемой, если вы правильно задаёте target‑triple, sysroot и собираете зависимости согласованно по ABI и API level. Для универсальных задач удобен прямой вызов clang, а для проектов на CMake — toolchain файл, который стандартизирует параметры сборки.
Если вам нужна помощь с настройкой toolchain под ваш проект, портированием сборки или подбором конфигурации под нужные ABI — обращайтесь в РыбинскЛАБ. Мы поможем организовать стабильный процесс кросс‑сборки и диагностику проблем на вашей стороне.