Termux — удобная среда для разработки на Android, но при попытке «собрать модуль ядра прямо в телефоне» важно сразу правильно расставить ожидания. В строгом смысле пользовательские ядровые модули — это объекты, которые должен загружать Linux-кernel. Termux не является полноценной заменой kernel-окружению, однако разработку (и часто — сборку) можно организовать прямо в Termux: подготовить toolchain на базе clang/llvm, получить корректные исходники kernel (или нужные заголовки), собрать модуль и затем отладить его в целевой среде, где действительно выполняется Linux с соответствующим kernel.
В этой статье рассмотрим безопасный, легальный и практичный подход: сборка модуля в Termux с использованием clang/llvm и последующая отладка в целевом Linux (например, в виртуальной машине или на отдельной dev-платформе), при этом вы минимизируете «магические» действия и повышаете воспроизводимость.
Ключевая идея: чем Termux полезен
Termux позволяет:
- подготовить toolchain clang/llvm;
- собрать модуль с использованием Makefile ядра;
- упаковать артефакты и перенести их на target;
- использовать средства диагностики сборки и логов;
- организовать обмен файлами и логами (локальная сеть через VPN на случай изолированных сетей — только для создания локальной сети).
Ограничения:
- Termux работает поверх Android/Linux-ABI, но не заменяет ваш целевой kernel;
- загрузка .ko требует поддержки и прав в целевой системе;
- в большинстве случаев необходимы заголовки и конфигурация ядра той системы, где модуль будет загружен.
Требования
- Android-устройство с установленным Termux.
- Доступ к исходникам ядра Linux нужной версии (или хотя бы корректные kernel headers и .config/эквивалент для сборки).
- Целевая Linux-среда (VM/плата/десктоп), совпадающая по kernel ABI/настройкам с тем, под что вы собираете.
- Доступ к модулю: загрузка через
insmod/modprobeи просмотрdmesg. - Для отладки: gdb/прочие инструменты на стороне target, а также подготовка symbolов (включение CONFIG_DEBUG_INFO в ядре/модуле при необходимости).
Подготовка окружения Termux: clang/llvm и базовые утилиты
Начнем с установки зависимостей в Termux. Уточнение: состав пакетов может отличаться в зависимости от версии репозиториев Termux.
pkg update
pkg install clang lld llvm make git cmake ninja build-essential rsyncЕсли ваша сборка потребует дополнительных инструментов (например, flex/bison для генерации, bc, perl и т.п.), добавляйте их по факту ошибки сборки.
Далее проверьте доступность toolchain:
clang --version
ld.lld --version
llvm-ar --versionПолучение исходников ядра и важность «правильного» kernel
Сборка модуля выполняется не «в вакууме». Важно, чтобы версия и конфигурация ядра на target совпадали (или были совместимы) с тем, что вы используете для сборки. Самые распространенные причины проблем:
- другая версия kernel;
- несовместимые опции конфигурации;
- отсутствие корректных headers;
- несовпадение архитектуры или ABI.
Рекомендуется брать исходники (или, как минимум, tree для сборки модулей) той же версии, которую вы будете загружать на target.
Пример: клонирование дерева ядра:
git clone https://github.com/torvalds/linux.git linux
cd linuxДалее переключитесь на точный тег/коммит нужной версии:
# пример, уточните под ваш kernel
git checkout v6.6.30Пример структуры модульного проекта
Предположим, у вас есть небольшой модуль «hello world», который компилируется как .ko. Типовая структура:
my_mod/
my_mod.c
MakefileИсходник: минимальный Linux kernel module
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
static int init my_mod_init(void)
{
pr_info("my_mod: loaded
");
return 0;
}
static void exit my_mod_exit(void)
{
pr_info("my_mod: unloaded
");
}
module_init(my_mod_init);
module_exit(my_mod_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("RybinskLAB");
MODULE_DESCRIPTION("Example module built with clang/llvm");Makefile для сборки модуля
Для корректной сборки лучше использовать стандартный подход через Makefile ядра:
obj-m += my_mod.oИ запуск сборки будет выглядеть так (см. следующий раздел).
Сборка модуля в Termux через Makefile ядра и clang/llvm
Наиболее надежный путь: использовать target tree ядра как основу для сборки модулей. В Termux вы вызываете make из каталога ядра, а исходник модуля лежит в отдельной директории.
Скопируйте модуль в tree ядра (или используйте out-of-tree сборку с M=). Для наглядности рассмотрим out-of-tree:
mkdir -p ~/build/my_mod
cp -r my_mod ~/build/my_mod/Теперь из каталога ядра:
cd ~/linux
export ARCH=arm64
export CROSS_COMPILE=
export CC=clang
export LD=ld.lld
make -C . M=$HOME/build/my_mod modulesВажно:
- Если вы собираете под ту же архитектуру, что и target,
ARCHи окружение могут быть иными. - Если архитектура отличается, потребуется кросс-компилятор/настройка, и тогда устанавливается соответствующее
CROSS_COMPILE(или вы настраиваете clang target appropriately). - В реальных проектах часто используют
make oldconfig/make defconfigи точную.config, но для модуля ключевое — корректная конфигурация/согласованность символов и ABI.
Проверьте артефакт:
ls -l $HOME/build/my_mod/.koТиповые проблемы сборки и как их диагностировать
- Несовпадение версий kernel: сигнатуры структур/символов отличаются → получите ошибки линковки или несовместимость на загрузке.
- Нет нужных заголовков/конфигурации: сборка может завершиться ошибками про отсутствующие include или опции.
- Не тот компилятор/флаги: некоторые опции ядра требуют согласованности clang/LLD и версий toolchain.
- Неправильный ARCH: модуль соберется, но не загрузится.
Подсказка для диагностики: включайте подробный вывод Make и сохраняйте лог на диск:
make -C . M=$HOME/build/my_mod modules V=1 2>&1 | tee build.logПеренос модуля на target
После сборки вам нужно загрузить .ko на систему с тем же kernel. Самый практичный вариант — rsync по локальной сети.
Пример: (на стороне target должен быть доступен ssh). Сначала определите IP target:
# на target: ip a
# затем на Termux:
rsync -avz $HOME/build/my_mod/my_mod.ko user@TARGET_IP:/home/user/Если сеть сложная и вам требуется изолированная локальная инфраструктура, допустимо использовать VPN исключительно для создания локальной сети между устройствами (не как обход блокировок).
Загрузка модуля и просмотр логов
На target выполните:
sudo insmod my_mod.ko
dmesg | tail -n 50Если модуль уже существует или были предыдущие попытки:
sudo rmmod my_mod
dmesg | tail -n 50Отладка: от симптома к источнику
Отладка kernel modules обычно строится на комбинации:
- корректных логов из
pr_info/pr_errиdmesg; - символов и трассировки ошибок;
- минимизации модификаций при каждой попытке загрузки;
- проверки версий и конфигурации kernel.
Отладочные сообщения и быстрые «контрольные точки»
Старайтесь делать отладку воспроизводимой: добавляйте сообщения в ключевые места и проверяйте их на этапе init и перед потенциально опасными участками.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
static int init my_mod_init(void)
{
pr_info("my_mod: init enter
");
/ TODO: test logic here */
pr_info("my_mod: init exit
");
return 0;
}
static void exit my_mod_exit(void)
{
pr_info("my_mod: exit
");
}
module_init(my_mod_init);
module_exit(my_mod_exit);
MODULE_LICENSE("GPL");Если загрузка падает: что проверить в первую очередь
- Логи:
dmesg -Tсразу послеinsmod. - Состояние зависимостей: если модуль зависит от других модулей — убедитесь, что они загружены.
- Совместимость по ABI: типичная причина падений после сборки «на другой машине».
- Параметры модуля: если используете
module_param, проверяйте значения.
Пример сбора более полного контекста:
sudo insmod my_mod.ko 2>/tmp/insmod.err || true
dmesg -T | tail -n 200
cat /tmp/insmod.errСимволы и подготовка к более глубокой отладке
Для продвинутой отладки вам обычно нужен gdb и symbol-пакеты на стороне target. Практически полезно убедиться, что сборка kernel и модуля содержит отладочные символы (обычно это достигается настройками конфигурации ядра).
На стороне target проверьте, что доступны символы:
# зависит от дистрибутива; один из вариантов
uname -r
# и далее — наличие -dbg пакетов или vmlinux с символамиЕсли ваш проект требует точного соответствия, согласуйте сборку kernel с теми же параметрами, под которые вы тестируете.
Организация процесса разработки в Termux: workflow
- Клонируете нужное дерево ядра/подготовленную сборочную директорию.
- Поднимаете toolchain clang/llvm в Termux.
- Пишете модуль и Makefile out-of-tree.
- Собираете модуль через
make -C ... M=... modules. - Переносите
.koна target. - Загружаете и проверяете
dmesg. - Инкрементально улучшаете код, сохраняя логи сборки и загрузки.
Почему именно clang/llvm: плюсы и нюансы
Использование clang/llvm в ядре может дать:
- удобство интеграции современных предупреждений;
- согласованность со многими toolchain-платформами;
- быстрее цикл разработки за счет предсказуемой среды сборки.
Нюанс: kernel tree может требовать определенной версии clang/LLD. Если на target вы видите несовместимость, попробуйте подобрать версию toolchain ближе к рекомендованной в документации ядра для вашей версии.
Заключение
Разработка и отладка пользовательских ядровых модулей Linux «в Termux» реальна в формате управляемой инженерной цепочки: вы собираете модуль через clang/llvm в Termux, переносите артефакт на целевую Linux-систему и выполняете загрузку/диагностику по логам и параметрам ядра. Ключ к успеху — строгая согласованность версий kernel и понимание того, что загрузка модулей происходит только в среде, где работает соответствующий kernel.
Если вы хотите ускорить цикл разработки, подобрать правильные версии toolchain под ваш kernel и выстроить reproducible workflow под команду — обратитесь в РыбинскЛАБ. Мы поможем с настройкой окружения, сборкой модулей и организацией процесса отладки.