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

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

Кросс‑компиляция нативных библиотек для Android в Termux: от исходного кода до ELF‑модуля

Пошаговое руководство по кросс‑компиляции нативных библиотек для Android в Termux: настройка toolchain, сборка .so и подготовка ELF‑модуля в зависимости от ABI.

Termux стал де-факто стандартом для разработки на Android: оболочка, пакеты, удобные сборочные цепочки. Однако когда задача выходит за рамки простых скриптов и упирается в нативные компоненты (.c/.cpp), возникает вопрос: как собрать библиотеку так, чтобы она корректно работала на Android и имела нужный формат артефакта.

В этой статье — практичный и юридически корректный (в рамках общих принципов разработки) подход к кросс‑компиляции нативных библиотек для Android в Termux: от исходного кода до итогового ELF‑модуля (.so) под конкретный ABI (arm64-v8a, armeabi-v7a, x86_64 и т.д.).

Материал ориентирован на типовой пайплайн: подготовка окружения, выбор ABI, сборка через NDK toolchain, проверка артефакта и разбор распространённых проблем.

Термины и целевой результат

Под нативной библиотекой в контексте Android обычно понимают shared object — файл вида libname.so. Формально это ELF‑модуль, содержащий код для конкретной архитектуры.

Ключевые точки:

  • ABI (Application Binary Interface) определяет архитектуру и соглашения вызовов (например, arm64-v8a).
  • NDK toolchain — компилятор и системные заголовки/линковка, рассчитанные под Android.
  • Кросс‑компиляция означает, что сборка выполняется на одной платформе (Termux на Android), но бинарник нацелен на ABI/SDK/ABI‑настройки Android так, как ожидает загрузчик.

Предварительные требования

Для устойчивой сборки рекомендовано заранее определиться с тремя параметрами:

  • ABI (например, arm64-v8a или armeabi-v7a).
  • Минимальный API level (например, 21 для arm64 обычно удобно).
  • Тип сборки: CMake/Autotools/прямой вызов компилятора.

Также учитывайте, что Android‑платформа строго ограничивает набор системных вызовов и доступность некоторых API — именно поэтому обычно используют Android NDK.

Шаг 1. Подготовка Termux и базовых пакетов

Обновите пакеты и установите базовые утилиты. В разных сборках Termux названия пакетов могут незначительно отличаться, но логика сохраняется.

pkg update && pkg upgrade -y
pkg install -y git wget curl tar unzip clang lld cmake make autoconf automake libtool pkg-config

Примечание: для кросс‑компиляции под Android обычно потребуется NDK. Termux сам по себе может выступать лишь как среда запуска сборочных скриптов и линковки, но toolchain корректнее брать из NDK.

Шаг 2. Получение и раскладка Android NDK

Есть два типовых сценария:

  • Использовать NDK, который уже установлен (например, в составе Android Studio).
  • Скачать NDK и разархивировать вручную.

Для Termux удобно иметь NDK в доступной директории, например /data/data/.../files/ или в вашей рабочей папке.

Примерно это выглядит так (подставьте URL/путь под вашу ситуацию):

mkdir -p ~/android
cd ~/android
# Скачивание NDK (пример, используйте актуальный URL)
wget -O ndk.zip "https://example.com/android-ndk-rXX.zip"
unzip ndk.zip -d ndk

После распаковки проверьте, где лежит toolchain:

ls ~/android/ndk//toolchains/llvm/prebuilt//bin/

Внутри NDK путь к компиляторам будет примерно таким: .../toolchains/llvm/prebuilt/host-tag/bin.

Шаг 3. Выбор ABI и настройка параметров сборки

Выберите ABI и целевой API level. Пример ниже показывает схему установки переменных под arm64-v8a.

NDK_ROOT=~/android/ndk/ndk-bundle  # подставьте фактический путь
API=21
ABI=arm64-v8a

# Для архитектур NDK соответствия выглядят так:
# arm64-v8a   -> aarch64-linux-android
# armeabi-v7a  -> armv7a-linux-androideabi
# x86_64       -> x86_64-linux-android
# i686         -> i686-linux-android

TARGET_TRIPLE=aarch64-linux-android

Далее нужно найти путь к бинарникам clang в NDK. Типичный хост‑тег для Android‑устройств может отличаться. Универсальнее — извлечь его автоматически.

HOST_TAG=$(ls "$NDK_ROOT/toolchains/llvm/prebuilt" | head -n 1)
CLANG_BIN="$NDK_ROOT/toolchains/llvm/prebuilt/$HOST_TAG/bin"

CC="$CLANG_BIN/${TARGET_TRIPLE}${API}-clang"
CXX="$CLANG_BIN/${TARGET_TRIPLE}${API}-clang++"
STRIP="$CLANG_BIN/${TARGET_TRIPLE}-strip"

echo $CC
echo $CXX

Если конкретный ${TARGET_TRIPLE}${API}-clang не находится, проверьте доступные бинарники в каталоге $CLANG_BIN и скорректируйте шаблон именования. В разных версиях NDK формат может слегка варьироваться.

Шаг 4. Сборка библиотеки CMake (типовой современный сценарий)

Если ваша библиотека использует CMake, это самый удобный путь. Рассмотрим общую структуру:

  • создаём отдельную директорию сборки;
  • передаём toolchain параметры;
  • собираем;
  • проверяем, что появилась .so.

Примерно так:

PROJECT_ROOT=~/src/mylib
BUILD_DIR=$PROJECT_ROOT/build-android-$ABI
rm -rf "$BUILD_DIR"
mkdir -p "$BUILD_DIR"

cd "$BUILD_DIR"

cmake "$PROJECT_ROOT" \
  -DCMAKE_BUILD_TYPE=Release \
  -DCMAKE_SYSTEM_NAME=Android \
  -DCMAKE_SYSTEM_VERSION=$API \
  -DANDROID_ABI=$ABI \
  -DANDROID_PLATFORM=android-$API \
  -DCMAKE_C_COMPILER="$CC" \
  -DCMAKE_CXX_COMPILER="$CXX" \
  -DCMAKE_STRIP="$STRIP" \
  -DBUILD_SHARED_LIBS=ON \
  -DCMAKE_POSITION_INDEPENDENT_CODE=ON

Запуск сборки:

cmake --build . -- -j$(nproc)

Ожидаемый результат: файл вида libmylib.so (путь зависит от проекта). Часто он оказывается в $BUILD_DIR/lib/ или $BUILD_DIR/<subdir>/.

find "$BUILD_DIR" -name ".so" -maxdepth 6

Шаг 5. Сборка библиотеки с Autotools (если CMake нет)

Для Autotools обычно применяется схема configure → make с указанием cross tools и host triplet. Пример (концептуальный):

PROJECT_ROOT=~/src/mylib
BUILD_DIR=~/tmp/build-autotools-$ABI
rm -rf "$BUILD_DIR" && mkdir -p "$BUILD_DIR"
cd "$BUILD_DIR"

# Псевдо-значения: подстройте под ваш проект
HOST=$TARGET_TRIPLE

"$PROJECT_ROOT/configure" \
  --host="$HOST" \
  --build=$(uname -m)-linux-gnu \
  CC="$CC" \
  CXX="$CXX" \
  CFLAGS="-fPIC -O2" \
  CXXFLAGS="-fPIC -O2" \
  --enable-shared \
  --disable-static

make -j$(nproc)

find . -name ".so" -maxdepth 4

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

Шаг 6. Проверка ELF‑модуля под нужный ABI

Кросс‑компиляция считается успешной, когда:

  • появился .so;
  • архитектура внутри ELF соответствует ABI;
  • зависимости корректно найдены (в рамках вашего механизма загрузки/упаковки).

Проверка архитектуры ELF:

# file обычно покажет архитектуру
file path/to/libmylib.so

# readelf поможет посмотреть заголовки
readelf -h path/to/libmylib.so
readelf -A path/to/libmylib.so || true

# ldd на Android часто не работает как на Linux, поэтому ориентируйтесь на readelf
readelf -d path/to/libmylib.so | grep -E "NEEDED|RPATH|RUNPATH"

Если вы видите несоответствие ABI (например, arm64‑устройство, а библиотека собрана под ARMv7), приложение/нагрузка загрузчика обычно завершится ошибкой.

Шаг 7. Упаковка .so в структуру для Android‑проекта

Когда вы хотите использовать библиотеку в Android приложении, обычно размещают её в:

  • app/src/main/jniLibs/<abi>/libname.so

Примерно:

OUT_SO=/path/to/libmylib.so
ANDROID_JNILIBS=~/android-project/app/src/main/jniLibs/$ABI
mkdir -p "$ANDROID_JNILIBS"
cp "$OUT_SO" "$ANDROID_JNILIBS/$(basename "$OUT_SO")"

Далее корректность проверяется уже на стороне Android сборки и тестирования.

Распространённые ошибки и как их диагностировать

  • Linker errors (undefined references): чаще всего из-за несоответствия набора флагов или опций сборки (например, неправильные компоненты включены/исключены), либо не нашли зависимые библиотеки. Проверьте параметры линковки и порядок библиотек.
  • Отсутствие PIC: для shared object обычно требуется -fPIC. Включайте -DCMAKE_POSITION_INDEPENDENT_CODE=ON (для CMake) или CFLAGS="-fPIC ...".
  • Несовпадение ABI: проверяйте ELF заголовок через file и readelf.
  • Проблемы с Sysroot/заголовками: иногда configure/cmake пытается использовать хост‑заголовки вместо Android. Убедитесь, что указаны CMAKE_SYSTEM_NAME=Android и выбран правильный NDK/compilers.

Практический пример: мульти‑ABI сборка (серия конфигураций)

Если библиотека должна поставляться в нескольких ABI, обычно делают цикл и собирают по одному разу на ABI.

LIBSRC=~/src/mylib

build_one() {
  local ABI=$1
  local API=$2

  local TARGET_TRIPLE
  case "$ABI" in
    arm64-v8a) TARGET_TRIPLE=aarch64-linux-android ;;
    armeabi-v7a) TARGET_TRIPLE=armv7a-linux-androideabi ;;
    x86_64) TARGET_TRIPLE=x86_64-linux-android ;;
    i686) TARGET_TRIPLE=i686-linux-android ;;
    *) echo "Unknown ABI: $ABI"; return 1;;
  esac

  local HOST_TAG
  HOST_TAG=$(ls "$NDK_ROOT/toolchains/llvm/prebuilt" | head -n 1)
  local CLANG_BIN="$NDK_ROOT/toolchains/llvm/prebuilt/$HOST_TAG/bin"

  local CC="$CLANG_BIN/${TARGET_TRIPLE}${API}-clang"
  local CXX="$CLANG_BIN/${TARGET_TRIPLE}${API}-clang++"

  local BUILD_DIR=$LIBSRC/build-$ABI
  rm -rf "$BUILD_DIR" && mkdir -p "$BUILD_DIR"
  cd "$BUILD_DIR"

  cmake "$LIBSRC" \
    -DCMAKE_BUILD_TYPE=Release \
    -DCMAKE_SYSTEM_NAME=Android \
    -DCMAKE_SYSTEM_VERSION=$API \
    -DANDROID_ABI=$ABI \
    -DANDROID_PLATFORM=android-$API \
    -DCMAKE_C_COMPILER="$CC" \
    -DCMAKE_CXX_COMPILER="$CXX" \
    -DBUILD_SHARED_LIBS=ON \
    -DCMAKE_POSITION_INDEPENDENT_CODE=ON

  cmake --build . -- -j$(nproc)
}

NDK_ROOT=~/android/ndk/ndk-bundle

build_one arm64-v8a 21
build_one armeabi-v7a 21
build_one x86_64 21

После этого останется собрать все .so в нужные директории для jniLibs.

Заключение

Кросс‑компиляция нативных библиотек для Android в Termux — это управляемый процесс, если вы последовательно выбираете ABI, корректно настраиваете NDK toolchain и проверяете итоговый ELF‑модуль на соответствие архитектуре. Типовой путь выглядит так: подготовка окружения → настройка компиляторов под выбранный ABI/API → сборка (через CMake или Autotools) → проверка .so и упаковка в формат, удобный для Android‑проекта.

Если вы хотите быстрее довести проект до рабочего состояния, в РыбинскЛАБ мы помогаем с настройкой toolchain, подбором флагов сборки под конкретные ABI, диагностикой linker/ELF‑ошибок и подготовкой библиотеки для интеграции в ваше Android‑приложение.

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

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

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

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