Termux — мощная среда для сборки программ на Android, однако для инженерных задач часто требуется больше: собрать одно и то же приложение под разные целевые архитектуры (например, aarch64 и armv7) и сохранить повторяемость. В этой статье разберём подход к реализации мульти‑архитектурных кросс‑компиляций в Termux с опорой на clang‑toolchain и multilib‑support, чтобы вы могли уверенно управлять ABI, sysroot и флагами линковщика.
Материал ориентирован на разработчиков и инженеров, которым важны воспроизводимость сборок, аккуратное управление зависимостями и понятная структура проекта.
Концепция: clang, multilib и sysroot
Кросс‑компиляция в Termux на практике состоит из трёх ключевых компонентов:
- Toolchain на базе clang: компилятор и сопутствующие инструменты (ассемблер/линкер), которые умеют собирать код для нужной архитектуры.
- multilib‑поддержка: наличие библиотек и runtime-компонентов под разные ABI/архитектуры в рамках одной toolchain.
- sysroot: корневая директория с заголовками и библиотеками, соответствующая целевому окружению (обычно Android‑ABI).
Важно понимать: multilib отвечает за то, что инструментам доступны нужные версии библиотек для разных целевых ABI, а sysroot определяет, какие именно заголовки и библиотеки вы используете при компиляции и линковке.
Подготовка Termux и архитектурные профили
Начните с базовой подготовки среды. Далее мы создадим профили сборки, чтобы переключение целевой архитектуры было управляемым и воспроизводимым.
Базовые шаги в Termux зависят от вашей схемы установки toolchain. В типичном сценарии вы используете репозитории Termux и/или пакеты с clang и библиотеками. Ниже приведён пример общего каркаса, который подойдёт для настройки (адаптируйте названия пакетов под вашу конфигурацию Termux):
pkg update
pkg install clang lld cmake ninja make gitДалее зададим переменные окружения и структуру проекта. Рекомендуется хранить настройки сборки в репозитории, чтобы команда могла повторить результаты на другой машине.
mkdir -p ~/build-multi/{aarch64,armv7}/{sysroot,build}
mkdir -p ~/toolchains
cd ~/build-multiДля удобства создайте файлы профилей. Например, env-aarch64.sh и env-armv7.sh. Их задача — выставить ABI‑специфичные переменные: ARCH, TRIPLE, путь к SYSROOT и базовые CFLAGS/LDFLAGS.
Выбор target: GNU triplet/LLVM triple и ABI
В clang целевая архитектура задаётся через target (LLVM triple). Для Android встречаются типичные варианты (точный triple зависит от версии toolchain и вашей sysroot‑структуры). Практический принцип такой:
- Для 64‑битного ARM используйте тройку для
aarch64. - Для 32‑битного ARM выбирайте ABI, например hard‑float (
armv7a+gnueabihfили эквивалент, в зависимости от набора библиотек).
Пример профиля для aarch64 (вставьте корректные тройки и пути под вашу sysroot):
cat > ~/build-multi/env-aarch64.sh <<'EOF'
export ARCH=aarch64
export TRIPLE=aarch64-linux-android
export SYSROOT=$HOME/build-multi/aarch64/sysroot
export COMMON_FLAGS="--target=${TRIPLE} -fPIC"
export CFLAGS="${COMMON_FLAGS} -O2"
export LDFLAGS="${COMMON_FLAGS} -fuse-ld=lld --sysroot=${SYSROOT}"
EOFПрофиль для armv7 (hard-float) — аналогично:
cat > ~/build-multi/env-armv7.sh <<'EOF'
export ARCH=armv7
export TRIPLE=armv7a-linux-androideabi
export SYSROOT=$HOME/build-multi/armv7/sysroot
export COMMON_FLAGS="--target=${TRIPLE} -fPIC -mthumb"
export CFLAGS="${COMMON_FLAGS} -O2 -march=armv7-a"
export LDFLAGS="${COMMON_FLAGS} -fuse-ld=lld --sysroot=${SYSROOT}"
EOFЕсли вы используете multilib‑support, ключевой смысл в том, чтобы при переключении профиля toolchain находил библиотечные компоненты под нужный ABI, а sysroot предоставлял заголовки и системные .so/.a.
Сборка: один проект — два артефакта
Рассмотрим общий сценарий с CMake. Даже если ваш проект использует autotools или makefile, подход остаётся тем же: вы задаёте target и sysroot, затем используете соответствующие компоновочные флаги.
Подготовьте скелет сборки CMake (пример):
# Предположим, что исходники лежат в ~/src/your_project
cd ~/src/your_project
# CMake будет использовать переменные окружения из профилей
# и сформирует корректные флаги сборки.Сборка под aarch64:
source ~/build-multi/env-aarch64.sh
cmake -S . -B ~/build-multi/aarch64/build
-G Ninja
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_SYSROOT=${SYSROOT}
-DCMAKE_C_COMPILER=clang
-DCMAKE_CXX_COMPILER=clang++
-DCMAKE_C_FLAGS="${CFLAGS} --sysroot=${SYSROOT}"
-DCMAKE_EXE_LINKER_FLAGS="${LDFLAGS}"
-DCMAKE_SHARED_LINKER_FLAGS="${LDFLAGS}"
cmake --build ~/build-multi/aarch64/build -- -j$(nproc)Сборка под armv7:
source ~/build-multi/env-armv7.sh
cmake -S . -B ~/build-multi/armv7/build
-G Ninja
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_SYSROOT=${SYSROOT}
-DCMAKE_C_COMPILER=clang
-DCMAKE_CXX_COMPILER=clang++
-DCMAKE_C_FLAGS="${CFLAGS} --sysroot=${SYSROOT}"
-DCMAKE_EXE_LINKER_FLAGS="${LDFLAGS}"
-DCMAKE_SHARED_LINKER_FLAGS="${LDFLAGS}"
cmake --build ~/build-multi/armv7/build -- -j$(nproc)Обратите внимание на два момента:
- Ключевой набор флагов должен быть одинаковым по логике, но адаптированным под разные ABIs.
- Артефакты лучше хранить в отдельных директориях, чтобы исключить пересечения конфигураций.
Линковка, статические/динамические зависимости и порядок библиотек
На Android нередко встречаются различия между статическими (.a) и динамическими (.so) зависимостями. При кросс‑сборке следуйте правилам:
- Убедитесь, что каждая библиотека соответствует целевой архитектуре.
- Если используете static linking, проверьте, что runtime-компоненты доступны под ваш ABI.
- Порядок библиотек на линковке иногда критичен: особенно при использовании
--as-neededи при наличии сложных зависимостей.
Практический пример ручной линковки (фрагмент) через clang++ и lld:
clang++ --target=${TRIPLE} --sysroot=${SYSROOT} -fuse-ld=lld
-shared -Wl,--no-undefined
-o libyour.so build/your.o
-L${SYSROOT}/lib -landroid -llogВ реальном проекте зависимости могут отличаться. Главное — чтобы библиотечные пути были согласованы с целевым SYSROOT и выбранным ABI.
Что даёт multilib: быстрые переключения без переустановок
multilib‑support обычно позволяет держать в toolchain наборы библиотек/заголовков для нескольких ABI и быстро переключаться без полной пересборки toolchain. На практике вы получаете:
- Стабильное использование одной базы toolchain (clang/lld).
- Переключение архитектуры через
--targetи корректныйSYSROOT. - Сокращение времени на настройку, если sysroot и lib‑наборы подобраны под ваш сценарий.
Однако multilib не отменяет необходимость корректного sysroot: без него вы рискуете получить несовместимые заголовки или библиотеки.
Проверка результата: валидация ABI и метаданных
После сборки стоит проверить, что артефакт действительно собран под нужный target. В Termux можно использовать инструменты уровня binutils (если доступны) или проверить библиотечные атрибуты через readelf/objdump (при наличии в вашей конфигурации).
# Пример: проверка типа ELF и архитектуры
readelf -h path/to/libyour.so | headОриентируйтесь на то, что для aarch64 и armv7 будут разные значения машинного кода (e_machine) и class (ELF64 vs ELF32).
Автоматизация: сборка всех архитектур одной командой
Чтобы упростить жизнь, сделайте скрипт, который по очереди запускает сборку для профилей и складывает результат в общий каталог.
cat > ~/build-multi/build-all.sh <<'EOF'
#!/data/data/com.termux/files/usr/bin/bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SRC_DIR="$HOME/src/your_project"
OUT_DIR="$HOME/build-multi/artifacts"
mkdir -p "${OUT_DIR}"
for arch in aarch64 armv7; do
echo "=== Building ${arch} ==="
source "${ROOT_DIR}/env-${arch}.sh"
build_dir="$ROOT_DIR/${arch}/build"
rm -rf "$build_dir"
mkdir -p "$build_dir"
cmake -S "${SRC_DIR}" -B "$build_dir"
-G Ninja
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_SYSROOT="${SYSROOT}"
-DCMAKE_C_COMPILER=clang
-DCMAKE_CXX_COMPILER=clang++
-DCMAKE_C_FLAGS="${CFLAGS} --sysroot=${SYSROOT}"
-DCMAKE_EXE_LINKER_FLAGS="${LDFLAGS}"
-DCMAKE_SHARED_LINKER_FLAGS="${LDFLAGS}"
cmake --build "$build_dir" -- -j$(nproc)
# Пример копирования .so (адаптируйте под вашу структуру)
find "$build_dir" -maxdepth 3 -type f -name "*.so" -print -exec cp {} "${OUT_DIR}/" ;
done
echo "Done. Artifacts in: ${OUT_DIR}"
EOF
chmod +x ~/build-multi/build-all.sh
~/build-multi/build-all.shТакой подход повышает воспроизводимость и уменьшает риск “перемешивания” конфигураций.
Частые проблемы и как их диагностировать
Ниже — типовые ошибки, с которыми сталкиваются при кросс‑компиляции в мульти‑арх режиме:
- Несовместимая архитектура библиотек: вы собрали под
armv7, но подключилиaarch64.so. Решение — проверять совпадение ABI. - Не найден sysroot-заголовок/библиотека: неправильно задан
--sysrootили пути в-L. Решение — выровнятьCMAKE_SYSROOTи реальные пути. - Ошибка неопределённых ссылок: неверный порядок библиотек или недоступные зависимости под целевой ABI. Решение — корректировать набор
-lи флаги линковщика (--no-undefinedпомогает выявлять проблему). - Неправильный ABI для armv7: hard/soft-float несоответствие. Решение — обеспечить консистентный triple и библиотечные наборы.
Ограничения и корректный контур использования VPN
Если вам нужно организовать доступ к ресурсам разработки (например, внутреннему серверу сборки или Git‑хранилищу через защищённое соединение), допускается использование VPN для создания локальной сети. Это не предназначено для обхода блокировок и должно соответствовать правилам вашей организации и действующему законодательству РФ.
Заключение
Мульти‑архитектурная кросс‑компиляция в Termux на базе clang‑toolchain и multilib‑support становится практичной, если вы строго разносите конфигурации по архитектурам, задаёте корректный --target, поддерживаете согласованный SYSROOT и контролируете ABI‑совместимость зависимостей. Такой подход позволяет получать набор артефактов для разных платформ из одной кодовой базы и с понятной логикой сборки.
Если вам нужна помощь с настройкой toolchain, подбором sysroot, организацией сборки CMake/Make под несколько ABI или аудитом флагов и зависимостей, обращайтесь в РыбинскЛАБ — мы поможем выстроить стабильный процесс кросс‑сборки под ваши требования.