Ведущий эксперт РыбинскЛАБ: Усачёв Денис Евгеньевич.
Зачем портировать C/C++ в Termux и что обычно «ломается»
Termux удобен для разработки и тестирования, но при переносе библиотек C/C++ с «обычной» настольной сборки на мобильную среду часто возникают предсказуемые проблемы: отличия в ABI, отсутствие нужных системных библиотек, нетривиальные зависимости (например, сборка из исходников вместо пакета), различия в путях к include/lib, а также особенности динамической загрузки на Android.
В этой статье разберём практический подход к портированию библиотек с нестандартными зависимостями в Termux с опорой на CMake и Meson: как настроить toolchain, как организовать зависимости, как заставить сборочные системы находить нужные заголовки/библиотеки и как системно устранять типовые ошибки.
Подготовка Termux: базовые зависимости и ориентиры
Начните с актуального окружения и инструментов сборки. Для Termux удобнее всего использовать репозитории пакетов Termux, а нестандартные зависимости — собирать в отдельный префикс (например, в $PREFIX или в выделенную директорию /data/data/.../prefix).
pkg update
pkg upgrade
pkg install clang make ninja-build cmake meson pkg-config git python curl
Если библиотека зависит от дополнительных компонентов (например, libssl, libcurl, zlib, libpng), сначала попытайтесь поставить их через pkg install. Когда пакета нет или требуется нестандартная версия/конфигурация — переходите к сборке из исходников.
Общий принцип: все зависимости должны попадать в один «префикс»
Чтобы сборка в Termux была воспроизводимой, избегайте «смешивания» артефактов из разных источников в произвольных местах. Практика: собирайте зависимости с одним префиксом (например, $HOME/prefix) и затем собирайте целевую библиотеку, указывая:
- пути поиска заголовков:
-I/ переменныеCPATH,CMAKE_INCLUDE_PATH; - пути поиска библиотек:
-L/ переменныеLIBRARY_PATH,CMAKE_LIBRARY_PATH; - и переменную окружения для компоновщика/линковщика при необходимости.
В Termux обычно используется $PREFIX (обычно /data/data/com.termux/files/usr). Однако если вы хотите отделить «ваши» библиотеки от системных, создайте отдельный префикс. Пример:
export PREFIX_LOCAL="$HOME/prefix"
mkdir -p "$PREFIX_LOCAL"/ {include,lib,bin,share}
Дальше вы будете собирать зависимости с установкой в этот префикс.
Toolchain и sysroot: как не наступать на ABI
На Android/Termux критично собирать под «правильную» архитектуру. В Termux обычно доступны соответствующие компиляторы clang. Для большинства случаев достаточно использовать стандартные переменные окружения Termux и настройки, которые поддерживает ваша сборочная система.
Однако при нестандартных сценариях (например, когда библиотека пытается использовать системные пути Linux, которых нет в Android) может понадобиться toolchain-файл. Для CMake и Meson подход отличается.
Портирование через CMake: базовая схема
Для CMake в Termux обычно удобен out-of-source build. Библиотека может требовать:
- указать
-DCMAKE_INSTALL_PREFIXдля установки в нужный префикс; - помочь найти зависимости через
PKG_CONFIG_PATH,CMAKE_PREFIX_PATH,CMAKE_LIBRARY_PATH; - при необходимости отключить тесты/утилиты, если они тянут лишние зависимости.
Шаблон:
export PREFIX_LOCAL="$HOME/prefix"
export PKG_CONFIG_PATH="$PREFIX_LOCAL/lib/pkgconfig:$PKG_CONFIG_PATH"
export CMAKE_PREFIX_PATH="$PREFIX_LOCAL:$CMAKE_PREFIX_PATH"
# Пример: сборка целевой библиотеки
cd /path/to/libsrc
mkdir -p build-cmake && cd build-cmake
cmake .. \
-G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX="$PREFIX_LOCAL" \
-DBUILD_SHARED_LIBS=ON \
-DBUILD_TESTING=OFF \
-DCMAKE_PREFIX_PATH="$CMAKE_PREFIX_PATH" \
-DCMAKE_LIBRARY_PATH="$PREFIX_LOCAL/lib" \
-DCMAKE_INCLUDE_PATH="$PREFIX_LOCAL/include"
ninja
ninja install
Ключевой момент: PKG_CONFIG_PATH и CMAKE_PREFIX_PATH — первые инструменты, к которым стоит обращаться, если CMake не находит библиотеку.
Как «лечить» поиск зависимостей в CMake
Часто проблема выглядит так: CMake пишет, что не найден Foo или FooConfig.cmake, хотя вы его уже собрали. Варианты решения:
- pkg-config: убедитесь, что у зависимости есть
.pcи что он установлен в$PREFIX_LOCAL/lib/pkgconfig(аPKG_CONFIG_PATHсодержит этот путь). - конфигурационные файлы CMake: если есть
FooConfig.cmake, то проверьте, куда они установлены (частоlib/cmake/Fooилиshare/Foo). ТогдаCMAKE_PREFIX_PATHдолжен указывать префикс, в котором лежитlib/cmake. - ручные подсказки: иногда достаточно передать
-DFOO_INCLUDE_DIRи-DFOO_LIBRARY(зависит от проекта).
Если проект использует кастомный модуль поиска, может помочь просмотр CMakeLists.txt и модулей в cmake/, чтобы понять, какие переменные он ожидает.
Портирование через Meson: настройка через .ini/переменные и prefix
Meson в Termux часто работает проще, особенно если вы используете pkg-config для определения зависимостей. Основной подход:
- out-of-source build;
- установка в
--prefix(или-Dprefixв зависимости от проекта); - указание путей через
PKG_CONFIG_PATHи/или переменные Meson (зависит от проекта).
Шаблон:
export PREFIX_LOCAL="$HOME/prefix"
export PKG_CONFIG_PATH="$PREFIX_LOCAL/lib/pkgconfig:$PKG_CONFIG_PATH"
cd /path/to/libsrc
meson setup build-meson \
--prefix "$PREFIX_LOCAL" \
--buildtype release \
-Dtests=false \
-Dexamples=false
meson compile -C build-meson
meson install -C build-meson
Если проект поддерживает флаги вроде -Ddefault_library=both или аналогичные — используйте их, но точные названия зависят от конкретного проекта.
Нестандартные зависимости: когда pkg-config не помогает
Сложнее всего, когда зависимость не предоставляет .pc файл или не устанавливает конфиги в ожидаемые директории. Тогда вам придётся:
- собрать зависимость с нужными параметрами, чтобы установить заголовки/библиотеки в стандартные места;
- создать недостающие метаданные (например,
.pcфайл) вручную; - или подсказать сборочной системе пути (CMake:
-D..._INCLUDE_DIR, Meson: черезcpp_args/link_argsили через переменные проекта).
Простой и практичный способ для Meson — иногда задать параметры компилятора и линковщика на уровне конфигурации проекта, если он это поддерживает. Для CMake — часто задаются кастомные переменные.
Пример: локальная сборка зависимости в префикс
Рассмотрим универсальный сценарий: зависимость поставляется исходниками и её нужно встроить в ваш prefix.
export PREFIX_LOCAL="$HOME/prefix"
export PATH="$PREFIX_LOCAL/bin:$PATH"
export LD_LIBRARY_PATH="$PREFIX_LOCAL/lib:$LD_LIBRARY_PATH"
# Допустим, у зависимости CMake
cd /path/to/dep
mkdir -p build-dep && cd build-dep
cmake .. \
-G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX="$PREFIX_LOCAL" \
-DBUILD_TESTING=OFF
ninja
ninja install
После этого целевая библиотека должна начать находить зависимость по pkg-config (если он доступен) и/или по CMAKE_PREFIX_PATH.
Динамические библиотеки на Android/Termux: проверка линковки
После сборки проверьте, что бинарники/шейред-либы корректно ссылаются на нужные .so и что они доступны во время запуска. На практике удобно смотреть зависимости через readelf или ldd (если доступно). Например:
# Локально проверьте, куда смотрит загрузчик
readelf -d /path/to/your/library.so | grep -E 'NEEDED|RPATH|RUNPATH'
# Для запуска вы можете временно задать путь к библиотекам
export LD_LIBRARY_PATH="$PREFIX_LOCAL/lib:$LD_LIBRARY_PATH"
/path/to/your/binary --help
Если проект использует RPATH/RUNPATH — настройте корректно. Иначе — управляйте LD_LIBRARY_PATH в окружении при тестах.
Типовые ошибки и что делать
- “не найден Foo”: проверьте
PKG_CONFIG_PATHи наличиеfoo.pc. ЕслиfooConfig.cmake— проверьтеCMAKE_PREFIX_PATHи где установлены cmake-модули. - несовместимая архитектура: значит зависимость собрана не под вашу ABI. В Termux убедитесь, что вы используете один и тот же toolchain и не подтягиваете бинарники с другого окружения.
- undefined references: обычно означает, что линковщик не увидел одну из библиотек или выбрана неверная версия/режим (static/shared). Проверьте порядок линковки и опции проекта.
- не те флаги компиляции: иногда проекты по умолчанию включают SIMD/ASM, которые не поддерживаются в вашей конфигурации. В CMake/Meson отключайте проблемные опции.
Хорошая практика: после каждого изменения пересобирать только то, что нужно, и хранить лог конфигурации (CMakeCache, meson-log) для последующего анализа.
Полезная организация проекта: скрипты сборки и кэш артефактов
Чтобы ускорить перенос, заведите структуру:
deps/<name>/— исходники и build под зависимость;build/<target>/— build целевой библиотеки;prefix/— общий префикс для установки.
А затем управляйте переменными окружения в одном месте, чтобы не было рассинхрона.
Meson vs CMake: как выбрать подход
Если проект — «современный», часто Meson быстрее даёт понятную диагностику через логи конфигурации. Если проект сложный и использует кастомные CMake-модули поиска, CMake может быть удобнее благодаря большему числу стандартов вокруг Find.cmake и *Config.cmake.
На практике нередко приходится комбинировать: зависимости собрать через один инструмент, а целевую библиотеку — через другой (или наоборот). Ключ — единый prefix и корректные метаданные (pkg-config / cmake config).
Локальная сеть через VPN (только для задач разработки/тестирования)
Иногда при разработке на Termux удобно поднимать локальное взаимодействие с ПК (например, для тестирования сервисов). Если используете VPN, делайте это только для организации локальной сети между устройством и вашим ПК, а не для обхода блокировок. Параметры зависят от выбранного VPN-решения и вашей сети.
Заключение
Портирование C/C++ библиотек в Termux с нестандартными зависимостями — это дисциплина управления префиксами, корректный поиск зависимостей (через PKG_CONFIG_PATH, CMAKE_PREFIX_PATH и установочные директории), а также системный подход к диагностики сборки. Начните с единообразного prefix, собирайте зависимости в него, затем собирайте целевой проект в out-of-source режиме. Для CMake чаще всего «магия» начинается с PKG_CONFIG_PATH и CMAKE_PREFIX_PATH, для Meson — с pkg-config и логов конфигурации.
Нужна помощь с портированием конкретной библиотеки под Termux (CMake/Meson, toolchain, нестандартные зависимости, отладка линковки и поиска пакетов)? Обратитесь в РыбинскЛАБ — мы поможем подготовить рабочий билд-процесс, консультации по конфигурации и устранение типовых проблем.