We detected you are likely not from a Russian-speaking region. Would you like to switch to the international version of the site?

  Назад к списку статей

Оптимизация сборки и кросс‑компиляции C/C++ проектов в Termux с использованием Clang, CMake и Ninja

Профессиональный гайд по оптимизации сборки и кросс‑компиляции C/C++ в Termux: Clang, CMake, Ninja, sysroot, LTO, ThinLTO и практические шаблоны конфигурации.

Termux — удобная среда для разработки на Android: полноценный пользовательский Linux, быстрые итерации, гибкая настройка toolchain и возможность автоматизировать сборку через CMake и Ninja. Однако для проектов среднего и крупного масштаба важны два направления: оптимизация производительности сборки (время компиляции, параллелизм, кэширование) и предсказуемость результата (одинаковые флаги, контролируемые настройки, корректная сборка под нужную архитектуру).

Ниже — практический подход, ориентированный на Clang + CMake + Ninja, а также на кросс‑компиляцию с использованием sysroot и аккуратной схемы флагов.

Базовая подготовка окружения в Termux

Начните с обновления пакетов и установки набора инструментов. Важно, чтобы CMake и Ninja были доступны в системе, а компилятор — именно Clang.

pkg update
pkg upgrade
pkg install clang cmake ninja make pkg-config python git

Для некоторых проектов дополнительно потребуются: zlib, openssl, libcurl, SDL и т.п. Их устанавливайте по фактическим зависимостям проекта.

Выбор генератора и “быстрый” профиль сборки

Для быстрой итеративной работы чаще всего удобны:

  • Ninja как генератор (минимальные оверхеды).
  • Release для финальных замеров, Debug для отладки.
  • Раздельные build-директории под разные профили и цели (host/target).

Пример стартовой конфигурации CMake:

cmake -S . -B build-release \
  -G Ninja \
  -DCMAKE_BUILD_TYPE=Release \
  -DCMAKE_C_COMPILER=clang \
  -DCMAKE_CXX_COMPILER=clang++ \
  -DCMAKE_C_FLAGS="" \
  -DCMAKE_CXX_FLAGS=""

Сборка с параллелизмом:

cmake --build build-release --target all -j "$(nproc)"

Оптимизация времени сборки

Чтобы ускорить сборку на мобильном устройстве, обычно выигрывают три подхода: параллелизм, минимизация лишней перестройки и (по возможности) кэширование.

1) Параллельность и лимит процессов

Да, -j $(nproc) часто работает отлично, но на некоторых устройствах при максимальном значении возможны деградации из‑за конкуренции за CPU/память. Практика: начинать с -j близко к количеству ядер и при необходимости уменьшать (например, на 1–2 меньше).

cmake --build build-release -- -j 4

2) Контроль повторной конфигурации

Старайтесь использовать отдельные директории build для разных комбинаций:

  • Release vs Debug
  • Host vs Target
  • разные наборы флагов (LTO/без LTO)

Это уменьшает риск “сломанной” инкрементальности и лишних пересборок.

3) Стабилизация CMake-параметров

Если вы меняете флаги компилятора, убедитесь, что они передаются одинаково на каждую конфигурацию. Для воспроизводимости используйте toolchain-файл и/или явно задавайте флаги через CMake cache.

Кэш компиляций (опционально)

Если ваш проект большой, можно подключить ccache. Это не “ускорение железом”, но часто драматически сокращает время повторных сборок при одинаковых исходниках и флагах.

Установка:

pkg install ccache

Пример интеграции (через переменные окружения или параметры CMake). Для CMake удобно так:

export CCACHE_DIR="$HOME/.ccache"
export CCACHE_MAXSIZE=5G
export CC="ccache clang"
export CXX="ccache clang++"

cmake -S . -B build-release -G Ninja -DCMAKE_BUILD_TYPE=Release \
  -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++

Проверьте статистику:

ccache -s

Настройка Clang-флагов для производительности

Для Release-профиля типичный набор — оптимизации, строгая сборка и (опционально) LTO. Учитывайте: LTO может увеличить время финальной сборки, но ускорить запуск и/или уменьшить размер.

Базовый набор флагов

cmake -S . -B build-release \
  -G Ninja \
  -DCMAKE_BUILD_TYPE=Release \
  -DCMAKE_C_COMPILER=clang \
  -DCMAKE_CXX_COMPILER=clang++ \
  -DCMAKE_C_FLAGS="-O3 -pipe" \
  -DCMAKE_CXX_FLAGS="-O3 -pipe"

LTO и ThinLTO

Если проект поддерживает LTO (а Clang/LLVM toolchain — чаще всего поддерживает), попробуйте ThinLTO — он часто более дружелюбен к итерациям.

cmake -S . -B build-release-lto \
  -G Ninja \
  -DCMAKE_BUILD_TYPE=Release \
  -DCMAKE_C_COMPILER=clang \
  -DCMAKE_CXX_COMPILER=clang++ \
  -DCMAKE_C_FLAGS="-O3 -pipe -flto=thin" \
  -DCMAKE_CXX_FLAGS="-O3 -pipe -flto=thin" \
  -DCMAKE_EXE_LINKER_FLAGS="-fuse-ld=lld" \
  -DCMAKE_SHARED_LINKER_FLAGS="-fuse-ld=lld" \
  -DCMAKE_MODULE_LINKER_FLAGS="-fuse-ld=lld"

Сборка:

cmake --build build-release-lto -j "$(nproc)"

Отдельные замечания по линковщику

Clang в связке с lld обычно ускоряет линковку по сравнению с более “тяжёлыми” вариантами. Если lld не установлен, проверьте и добавьте по необходимости (в зависимости от состава пакетов в вашем окружении).

Кросс‑компиляция: общая архитектура решения

Для кросс‑компиляции в Termux нужно понимать три вещи:

  • target (какая архитектура нужна: aarch64, armv7 и т.д.)
  • sysroot (набор заголовков/библиотек target-среды)
  • toolchain (компилятор и линковщик, которые умеют target)

Практический путь: использовать Clang как frontend, но обеспечить корректный sysroot и целевой triplet. На практике это часто реализуют через toolchain-файл CMake.

Подготовка sysroot

Sysroot можно собрать разными способами: использовать заранее подготовленный образ из вашего рабочего процесса, экспортировать с устройства (если допустимо в рамках вашей инфраструктуры) или подготовить из SDK/NDK. Универсальная рекомендация: хранить sysroot в проекте или в фиксированном пути, а версии — фиксировать в документации.

Важно: ниже — шаблон структуры и команд, а конкретные пути зависят от того, откуда вы берёте sysroot.

Пример toolchain-файла для CMake

Создайте файл cmake/toolchains/aarch64-linux-android-clang.cmake (пример названия) и настройте минимально необходимое:

# cmake/toolchains/aarch64-linux-android-clang.cmake

set(CMAKE_SYSTEM_NAME Android)
set(CMAKE_SYSTEM_PROCESSOR aarch64)

# Укажите путь к sysroot (заголовки и библиотеки target)
set(CMAKE_SYSROOT "/opt/sysroots/aarch64")

# Clang исполняемые файлы
set(CMAKE_C_COMPILER clang)
set(CMAKE_CXX_COMPILER clang++)

# Целевой набор (пример triplet; корректность зависит от вашего sysroot/ABI)
# Часто используют -target <triple>
set(CMAKE_C_FLAGS "-target aarch64-linux-android --sysroot=${CMAKE_SYSROOT}")
set(CMAKE_CXX_FLAGS "-target aarch64-linux-android --sysroot=${CMAKE_SYSROOT}")

# Явно указать режим поиска библиотек
set(CMAKE_FIND_ROOT_PATH ${CMAKE_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)

# Линковка: lld часто ускоряет, но следите за совместимостью
set(CMAKE_EXE_LINKER_FLAGS "-fuse-ld=lld")
set(CMAKE_SHARED_LINKER_FLAGS "-fuse-ld=lld")

Если ваш sysroot и triple отличаются, скорректируйте значения.

Конфигурация кросс‑сборки с Ninja

Теперь конфигурируем проект:

cmake -S . -B build-target-aarch64 \
  -G Ninja \
  -DCMAKE_BUILD_TYPE=Release \
  -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/aarch64-linux-android-clang.cmake

Сборка:

cmake --build build-target-aarch64 -j "$(nproc)"

Оптимизация кросс‑компиляции: флаги без “сюрпризов”

Чтобы избежать расхождений между host и target сборками:

  • держите одинаковые Release/Debug политики
  • не добавляйте “случайные” флаги через ручной ввод — фиксируйте их в toolchain или через cache
  • следите за stdlib и runtime (особенно для C++)

Пример: добавить LTO в toolchain либо через параметры конфигурации:

cmake -S . -B build-target-aarch64-lto \
  -G Ninja \
  -DCMAKE_BUILD_TYPE=Release \
  -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/aarch64-linux-android-clang.cmake \
  -DCMAKE_C_FLAGS="-O3 -pipe -flto=thin -target aarch64-linux-android --sysroot=/opt/sysroots/aarch64" \
  -DCMAKE_CXX_FLAGS="-O3 -pipe -flto=thin -target aarch64-linux-android --sysroot=/opt/sysroots/aarch64"

Практические советы по CMake для крупных проектов

Если проект сложный, используйте следующие приёмы:

  • Старайтесь не дублировать настройки через multiple command lines — лучше централизовать в toolchain и/или preset’ах.
  • Проверяйте переменные компилятора и линковщика на старте конфигурации: чтобы убедиться, что CMake реально использует Clang и заданный sysroot.
  • Разделяйте build для разных целей, чтобы не смешивать артефакты.

Для CMake можно включать подробный вывод (полезно при диагностике toolchain):

cmake -S . -B build-target-aarch64 \
  -G Ninja \
  -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/aarch64-linux-android-clang.cmake \
  -DCMAKE_VERBOSE_MAKEFILE=ON

Запуск и проверка артефактов

После сборки убедитесь, что бинарники соответствуют целевой архитектуре. В Termux удобно использовать инструменты из пакетов (или readelf/objdump, если установлены). Например:

file build-target-aarch64/my_binary
# либо
readelf -h build-target-aarch64/my_binary

Если цель отличается от архитектуры текущего устройства, запуск будет невозможен без соответствующей среды (эмулятор/устройство другой архитектуры/CI).

Локальная сеть через VPN для командной сборки (только как пример)

Если вы хотите организовать обмен артефактами или доступ к среде сборки внутри команды, иногда используют создание локальной сети через VPN для организации взаимодействия между устройствами в рамках проекта. Это помогает, например, передавать sysroot/артефакты между машинами и синхронизировать build-потоки, не применяя VPN для обхода блокировок.

Типовой “рецепт” под ваш проект: шаблон пайплайна

Ниже — практичный шаблон, который удобно адаптировать под любой CMake-проект.

# 1) Host/Native (для текущей архитектуры)
cmake -S . -B build-host-release \
  -G Ninja \
  -DCMAKE_BUILD_TYPE=Release \
  -DCMAKE_C_COMPILER=clang \
  -DCMAKE_CXX_COMPILER=clang++

cmake --build build-host-release -j "$(nproc)"

# 2) Cross-target (например, aarch64)
cmake -S . -B build-target-release \
  -G Ninja \
  -DCMAKE_BUILD_TYPE=Release \
  -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/aarch64-linux-android-clang.cmake

cmake --build build-target-release -j "$(nproc)"

Дальше вы можете подключать LTO, ThinLTO и ccache в зависимости от требований проекта.

Заключение

Оптимизация сборки в Termux с Clang, CMake и Ninja сводится к управлению тремя рычагами: параллелизм, воспроизводимость конфигурации и рациональные флаги (включая LTO при необходимости). Для кросс‑компиляции ключ — корректный toolchain-файл и sysroot, чтобы CMake уверенно находил заголовки и библиотеки target-среды.

Если хотите быстрее довести настройки до “боевого” состояния, РыбинскЛАБ оказывает услуги по настройке Termux/CI, разработке toolchain- и CMake‑конфигураций, оптимизации сборок и устранению проблем кросс‑компиляции под ваши целевые архитектуры.

* Текст статьи подготовлен и структурирован с использованием технологий искусственного интеллекта. Проверен и доработан перед публикацией.

Нужна помощь с настройкой Termux, Linux и серверов?

Я оказываю ИТ-услуги: настройка серверов, автоматизация, безопасность, помощь с Linux и инфраструктурой. Материалы сайта — только в ознакомительных и образовательных целях.

Связаться со мной
Поддержать проект