В первой статье мы разобрались с базовыми терминами: что такое Embedded Linux, чем он отличается от обычного дистрибутива, из чего состоит, как происходит его загрузка и с помощью каких инструментов всё это можно собрать.
Надеюсь, что те, кого эта тема зацепила, уже обзавелись платой с SoC на борту — без неё часть шагов будет упущена, а удовольствие от результата будет неполным.
Пришло время перейти от теории к практике!
Оглавление
3. Знакомство с Buildroot
3.1. Подготовка
Buildroot — это многокомпонентная система, для работы которой необходимо подготовить рабочее окружение. К тому же результат сборки надо будет где-то запускать. Поэтому давайте сначала подготовим всё необходимое.
3.1.1. Необходимое оборудование
Список оборудования довольно скромный:
Одноплатный компьютер с SoC на борту
Карта MicroSD
Переходник USB-MicroSD
Переходник USB-UART
Провода для соединения переходника и одноплатника
Поскольку мы только знакомимся с технологией, лучше всего взять плату с поддержкой Buildroot «из коробки». В моём случае это OrangePi PC от компании Sunxi на базе SoC Allwinner H3 архитектуры ARM.
3.1.2. Рабочее окружение
Собирать EL можно почти где угодно, но я рекомендую использовать ПК с ОС Linux, где рабочее окружение Buildroot будет развёрнуто на файловой системе ext4. В моём случае это Ubuntu 22.04 LTS.
Чтобы не засорять основную систему, сборку Embedded Linux мы будем выполнять в Docker-контейнере.
Если эта технология вам не знакома, не переживайте: нужные команды для настройки окружения приведены ниже. От вас требуется лишь установить Docker на свою ОС, следуя официальному гайду.
В процессе работы мы будем «общаться» с нашим одноплатником по UART, поэтому ставим на свою ОС какую-нибудь подходящую утилиту. В моём случае, это minicom
:
sudo apt install -y minicom; \
sudo usermod -aG dialout $USER; \
newgrp dialout
Также желательно сразу всё оформить в виде репозитория, поэтому нужно установить git
:
sudo apt install -y git
Теперь создадим рабочую директорию, необходимые поддиректории, обернем всё это в git
-репозиторий и скачаем Buildroot:
mkdir -p "$HOME"/buildroot-builder/{docker,output}; \
cd "$HOME"/buildroot-builder; \
git init -b master; \
git submodule add --depth=1 https://github.com/buildroot/buildroot.git buildroot; \
git -C buildroot fetch --depth=1 origin tag 2025.05; \
git -C buildroot checkout 2025.05; \
cat > .gitignore << 'EOF'
/output
/buildroot/*
*.old
EOF
git add buildroot docker .gitignore .gitmodules
Последний релиз Buildroot на июль 2025 года
В целях последующего ознакомления со структурой компонентов и их настройки, скачаем ещё и U-Boot с Linux:
git clone --depth=1 -b v2025.07 https://github.com/u-boot/u-boot.git u-boot; \
git clone --depth=1 -b v6.15 https://github.com/torvalds/linux.git linux
Используемые версии — последние стабильные релизы Linux и U-Boot на июль 2025 года
Создадим Docker-образ. В моём случае основой для него служит образ Debian 11:
cat > docker/Dockerfile << 'EOF'
FROM debian:11
ARG UID=1000
ARG GID=1000
ARG USERNAME=builder
RUN apt update && \
apt install -y sudo git && \
groupadd -g ${GID} ${USERNAME} && \
useradd -m -u ${UID} -g ${GID} -s /bin/bash ${USERNAME} && \
echo "${USERNAME} ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
USER ${USERNAME}
WORKDIR /host
EOF
docker build --build-arg UID=$(id -u) --build-arg GID=$(id -g) --tag buildroot-builder-image -f docker/Dockerfile docker
Запускаем контейнер:
docker run --name buildroot-builder -v /home/$USER/buildroot-builder:/host -it buildroot-builder-image /bin/bash
Для любителей графики
Если хочется пробросить в контейнер графику (например, для make gconfig
или make xconfig
):
echo "xhost +SI:localuser:$USER" >> ~/.xprofile; \
source ~/.xprofile; \
docker run --name buildroot-builder -v /home/$USER/buildroot-builder:/host -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix -it buildroot-builder-image /bin/bash
На Host-системе должен быть запущен X-сервер!
Сноска для незнакомых с Docker:
После вызова
docker run
вы попадаете в консоль контейнера.Чтобы выйти в Host-систему, используйте
exit
.Чтобы снова зайти в контейнер, используйте
docker start -i buildroot-builder
Установим в контейнер несколько базовых утилит:
sudo apt update && sudo apt install -y mc nano
mc
— для удобной навигации по директориямnano
— для изменения текстовых файлов (да простят меня любители Vim)
Несмотря на обширный список зависимостей U-Boot, Linux и Buildroot, вручную нужно устанавливать только зависимости для последнего — остальное он загрузит, соберёт и установит автоматически.
Поскольку сначала мы будем практиковаться с настройкой U-Boot и Linux отдельно от Buildroot, часть их зависимостей придётся установить вручную:
sudo apt install -y flex bison
Установка минимального набора пакетов:
sudo apt install -y build-essential libncurses-dev debianutils pkg-config \
diffutils findutils binutils patch bzip2 unzip rsync make bash \
gzip perl cpio file gawk wget sed gcc g++ tar bc
Установка опциональных пакетов:
sudo apt install -y openssh-client default-jdk python3-pip subversion \
mercurial graphviz python3 dblatex curl cvs git w3m; \
pip install matplotlib asciidoc argparse aiohttp bazaar
Для тех, кто пробросил в контейнер графику и планирует использовать make gconfig
или make xconfig
, нужно доставить следующие пакеты:
sudo apt install -y qtbase5-dev-tools libqt5widgets5 libglib2.0-dev \
libgtk2.0-dev libglade2-dev qtbase5-dev libqt5gui5 qt5-qmake
Также зададим переменную окружения BR2_EXTERNAL, чтобы Buildroot знал об использовании внешнего слоя. О данном механизме модификации Buildroot поговорим чуть позже, а пока просто создадим минимальную структуру внешнего слоя в директории external:
echo "export BR2_EXTERNAL=/host/external" >> ~/.bashrc; \
source ~/.bashrc; \
mkdir -p "$BR2_EXTERNAL"/{board/test,configs}; \
cd "$BR2_EXTERNAL"; \
touch external.mk; \
cat > external.desc << 'EOF'
name: TEST_EXTERNAL_LAYER
desc: Test external layer for Buildroot practice
EOF
cat > Config.in << 'EOF'
menu "Test external layer options"
endmenu
EOF
На этом подготовка рабочего окружения завершена. Перед тем как приступить к сборке, давайте взглянем на содержимое скачанных проектов.
3.2. Структура компонентов
Если вы уже заглянули в содержимое u-boot, linux или buildroot, то наверняка удивились обилию директорий и файлов в них. Не переживайте, необходимости досконально разбирать структуры компонентов нет (по крайней мере, на текущем этапе), но узнать про ключевые директории и файлы необходимо.
3.2.1. U-Boot
-
arch — «архитектурозависимый» код, расположенный в соответствующей поддиректории (arm, x86 и т.д.). Внутри:
dts — файлы описания оборудования Device Tree (*.dts, *.dtsi)
board — «платозависимый» код. Директории названы по вендору (sunxi, nvidia и т.п.). Внутри — специфический для конкретных плат код начальной инициализации, настройки питания и прочего
configs — типовые конфигурации U-Boot (*_defconfig)
doc — официальная документация. Онлайн-версия
drivers — драйверы различных периферийных устройств (UART, SPI и т.д.)
3.2.2. Linux
Documentation — официальная документация. Онлайн-версия
-
arch — «архитектурозависимый» код, расположенный в соответствующей поддиректории (arm, x86 и т.д.). Внутри:
boot/dts — файлы описания оборудования Device Tree (*.dts, *.dtsi)
configs — типовые конфигурации Linux (*_defconfig)
drivers — драйверы различных устройств (сеть, шины, графика, звук и т.д.)
3.2.3. Buildroot
board — скрипты, патчи и настройки под конкретные платы
configs — типовые конфигурации Buildroot (*_defconfig)
docs — официальная документация. Онлайн-версия
package — пакеты, доступные для сборки через Buildroot
3.2.4. External Layer
Как вы понимаете, любые изменения, внесённые непосредственно в u-boot, linux или buildroot, просто затеряются в обилии файлов и директорий. Да и тащить в свой репозиторий всё содержимое исходников — не самое удачное решение.
Для решения этой проблемы в Buildroot есть решение — External Tree, или же Внешний слой.
На практике внешний слой — это просто директория со своими конфигурациями, дополнительными пакетами, патчами, драйверами, файлами Device Tree и прочим. Особых требований к структуре внешнего слоя нет, но официальная документация рекомендует придерживаться этого варианта.
Во время подготовки рабочего окружения мы создали его минимальную структуру. Сейчас в ней не хватает конфигурационных файлов для U-Boot, Linux и Buildroot. Давайте разберёмся, что это за файлы и как их создавать.
3.3. Настройка компонентов
Каждый из компонентов, будь то Buildroot, Linux или U-Boot, может быть настроен посредством переменных make
. Эти переменные хранятся в файлах, которые можно разделить на несколько видов:
Настройки по умолчанию — распределены по различным файлам компонента
Текущие настройки — хранятся в файле .config
Файлы *_defconfig — настройки, отличные от настроек по умолчанию
Для создания последних двух существует набор правил make
:
make board_defconfig
— создание .config файла из указанного *_defconfigmake savedefconfig
— создание *_defconfig файла из .config
Если вы не знакомы с
make
, не переживайте. Подробно мы разберём его устройство позже. Пока просто учтите: вызыватьmake
нужно из корня соответствующего компонента.
Для изменения .config файла компонента существуют различные интерактивные меню:
make menuconfig
— текстовый интерфейс на базе curses.make nconfig
— текстовый интерфейс на базе ncurses.make gconfig
— графический интерфейс на базе GTK+.make xconfig
— графический интерфейс на базе Qt.
Я буду использовать menuconfig как самый универсальный и лёгкий в использовании вариант.
Давайте попробуем создать .config файл компонента и поменять его конфигурацию при помощи menuconfig.
3.3.1. Знакомство с menuconfig
Предлагаю начать с u-boot. Как я упоминал ранее, моя плата от компании Sunxi называется OrangePi PC с SoC архитектуры ARM на борту.
Переходим в u-boot и создаём .config файл:
cd /host/u-boot; \
make orangepi_pc_defconfig
Теперь можно вызвать меню конфигурации:
make menuconfig
Перед нами открылся интерфейс с различными группами настроек. Управление довольно простое:
Стрелки вверх и вниз — перемещение между пунктами.
Стрелки влево и вправо или Tab — переключение между меню и кнопками снизу (Select, Exit, Help и т.д.).
Enter — выбор пункта или подтверждение действия.
Двойное нажатие Esc — возврат на уровень выше или выход из меню.
Внесения изменений в конфигурацию не будут зафиксированы, пока вы не нажмёте кнопку Save и не укажете файл для записи настроек.
Это меню одинаково для всех компонентов, поэтому можете поэкспериментировать: полистайте меню, измените несколько настроек, загляните в Help как в главном меню, так и в каком-либо из подменю, попробуйте воспользоваться функцией поиска, сохраните результат в /host/u-boot/.config, откройте меню ещё раз и убедитесь, что настройки действительно изменились.
Закончили? Тогда вот небольшая задачка для закрепления материала: включите в состав Linux поддержку сетевого USB драйвера Realtek RTL8152/RTL8153 как built-in. У Linux есть особенность: при вызове make
нужно указать архитектуру:
cd /host/linux; \
make ARCH=arm sunxi_defconfig; \
make ARCH=arm menuconfig
Задача выполнена? В таком случае можно смело удалять директории u-boot и linux — они больше не понадобятся:
cd /host; \
rm -rf linux u-boot
Вслед за ними удаляем их зависимости:
sudo apt remove -y flex bison && sudo apt autoremove -y
А как в дальнейшем настраивать Linux и U-Boot? Через Buildroot, конечно же.
3.3.2. Настройка через Buildroot
Переходим в buildroot и создаём копию нужного нам *_defconfig файла во внешнем слое, после чего создаём .config файл:
cd /host/buildroot; \
cp configs/orangepi_pc_defconfig ../external/configs/test_defconfig; \
make O=../output test_defconfig
Параметр
O=
задаёт выходную директорию сборки Buildroot
Теперь нам доступны правила make
для настройки компонентов:
make linux-menuconfig
— вызов меню конфигурации Linuxmake uboot-menuconfig
— вызов меню конфигурации U-Boot
Убедитесь, что соответствующий компонент включён в конфигурацию Buildroot. Иначе вызов команды завершится с ошибкой.
При первом вызове этих правил придётся дождаться загрузки компонента и настройки его рабочего окружения.
Перед сборкой предлагаю изменить по одному параметру в каждом компоненте:
-
u-boot
make O=../output uboot-menuconfig
-
Boot options
-
Autoboot options
(5) delay in seconds before automatically booting
[*] Stop autobooting via specific input key / string
(Bye U-Boot in %d...\n) Autoboot stop prompt
[*] Enable Ctrl-C autoboot interruption
-
Сохраните конфигурацию в файл
/host/external/board/test/u-boot.config
-
-
linux
make O=../output linux-menuconfig
-
General setup
(HelloLinux) Local version - append to kernel release
Сохраните конфигурацию в файл
/host/external/board/test/linux.config
-
-
buildroot
make O=../output menuconfig
-
System configuration
(Hello Buildroot!) System banner
-
Kernel
Kernel configuration (Using a custom (def)config file)
($(BR2_EXTERNAL)/board/test/linux.config) Configuration file path
-
Bootloaders
-
U-Boot
U-Boot configuration (Using a custom (def)config file)
($(BR2_EXTERNAL)/board/test/u-boot.config) Configuration file path
-
Сохраните конфигурацию в файл
/host/output/.config
-
Компоненты настроены — теперь можно обновить *_defconfig файл Buildroot во внешнем слое:
make O=../output savedefconfig
Настройка завершена. Переходим к следующему этапу — сборке.
4. Первый шаг
4.1. От make до образа
Думаю на примере make uboot-menuconfig
и make linux-menuconfig
вы уже успели оценить подход Buildroot: всё необходимое было скачано, настроено, собрано и установлено автоматически.
Для сборки всех компонентов достаточно одной команды — и немного терпения. Этой командой является уже знакомый нам make
.
4.1.1. Сборка системы
Итак, запустим сборку системы:
cd /host/buildroot; \
make O=../output
Если вы следовали рекомендациям по выбору платы и настройке компонентов, беспокоиться не о чем: всё должно собраться без ошибок.
Конечно, не всегда всё проходит гладко. Иногда могут возникнуть ошибки сборки из-за нестабильной версии какого-либо пакета, проблем с конфигурацией или неожиданного поведения сторонних утилит. У Buildroot есть несколько инструментов для устранения подобных проблем — мы рассмотрим их позже.
Что касается времени сборки, оно зависит от множества факторов: скорости интернет-соединения, объёма оперативной памяти, частоты работы процессора, скорости диска и количества ядер. Особенно долго сборка проходит в первый раз — Buildroot скачивает и компилирует все пакеты с нуля.
Сборка успешно завершена? В таком случае, предлагаю сделать первый коммит в наш репозиторий:
cd "$HOME"/buildroot-builder; \
git add external; \
git commit -m "First step"; \
git tag FirstStep
А теперь давайте взглянем на содержимое выходной директории.
4.1.2. Структура выходной директории
В ней можно найти несколько ключевых директорий:
build — скачанные исходники и промежуточные файлы сборки всех пакетов
host — изолированная среда для программ, необходимых Host-системе во время сборки. В ней расположены тулчейн, утилиты, библиотеки и заголовочные файлы
target — корневая файловая система Target-системы. Всё, что находится в этой директории, будет доступно на целевом устройстве
images — директория с артефактами сборки
Именно images нас интересует больше всего.
4.1.3. Артефакты сборки
Список артефактов зависит от конфигурации компонентов, но в случае OrangePi PC с базовыми настройками он выглядит так:
genimage.cfg — конфигурационный файл для сборки sdcard.img
rootfs.* — корневая файловая система
sdcard.img — образ для записи на SD-карту
sun8i-h3-orangepi-pc.dtb — скомпилированный Device Tree
u-boot-sunxi-with-spl.bin — исполняемый файл U-Boot с SPL
u-boot.bin — исполняемый файл U-Boot
zImage — сжатое ядро Linux
Подробнее о том, какой файл за что отвечает, поговорим потом. Пока что нас интересует только sdcard.img.
4.2. Подготовка к запуску
До запуска осталось всего 2 шага: запись образа на SD-карту и подключение платы к ПК.
4.2.1. Запись на SD-карту
Обычно команда для записи образа на SD-карту находится в readme.txt файле по пути buildroot/board/<плата>.
В случае OrangePi PC это файл buildroot/board/orangepi/orangepi-pc/readme.txt. Команда в нем выглядит так:
sudo dd if=output/images/sdcard.img of=/dev/sdX
Давайте подключим SD-карту к нашему ПК при помощи переходника MicroSD-USB и откроем в основной ОС еще один терминал. Вызовите lsblk
и найдите в списке свою SD-карту. В моем случае, это /dev/sdb.
Убедитесь, что найденный диск именно SD-карта! В противном случае вы можете повредить данные на другом диске!
Получается следующая команда:
sudo umount /dev/sdb*; \
sudo dd of=/dev/sdb if="$HOME"/buildroot-builder/output/images/sdcard.img bs=1M status=progress; \
sudo sync
bs — количество данных, записываемых единовременно.
status=progess — вывод процесса записи
Можно отключать SD-карту от ПК и подключать её к плате.
4.2.2. Подключение платы к ПК
Подключиться к первому попавшемуся UART на плате не получится — нужно будет найти правильный. Обычно, на платах он выведен отдельной группой пинов: RX, TX и GND. На OrangePi PC они находятся между HDMI и разъемом питания.
Обычно, UART работает на скорости 115200 бод, 8 бит данных, 1 стоп-бит, без протокола контроля четности и без управления потоком данных.
Все параметры эти параметры UART и его пины можно найти в файлах *.dts и *.dtsi. Device Tree — сложная тема, поэтому детальнее мы разберем её позднее.
Соединяем плату с UART-USB переходником: RX платы с TX переходника и наоборот. GND соединяем 1 к 1.
Выполните на ПК команду:
watch -n 1 -t ls /dev/ttyUSB* /dev/ttyACM*
Подключите переходник к ПК. Запущенная команда выведет путь до переходника. В моем случае, это /dev/ttyUSB0.
Для завершения работы команды
watch
нажмите Ctrl+C
Ранее мы устанавливали minicom
. Вызываем его, передав путь до найденного устройства и скорость UART:
minicom -D /dev/ttyUSB0 -b 115200
Теперь нам надо настроить наш порт:
Нажмите Ctrl+A, O
Перейдите во вкладку Serial Port Setup
-
Настройте порт при помощи нажатия на клавиатуре соответствующей буквы. Настройки должны быть следующими:
E - Bps/Par/Bits: 115200 8N1
F - Hardware Flow Control : No
G - Software Flow Control: No
Сохраните настройки как конфигурацию по умолчанию, выбрав Save setup as dlf
Закройте меню конфигурации, выбрав Exit
Всё готово для запуска платы.
4.3. Первый запуск
Подайте на плату питание. Если всё настроено и подключено правильно, вы увидите в терминале:
Процесс загрузки U-Boot
Сообщение Bye U-Boot in 5...
Процесс загрузки ядра
Появление нашего приветственного баннера системы Hello Buildroot!
Предлагаю войти в систему. Пользователь — root, пароль не требуется.
Осталось проверить последнюю настройку. Давайте выведем версию ядра:
uname -r
Рядом с версией ядра вы увидите HelloLinux — это означает, что все наши настройки применились корректно.
Для выхода из
minicom
нажмите Ctrl+A, X.
Поздравляю: вы настроили, собрали и запустили собственную Embedded Linux-систему!
Первый шаг на этом нелёгком пути сделан. Дальше — больше.
Итог
Итак, мы подготовили рабочее окружение при помощи Docker, разобрали структуру U-Boot, Linux, Buildroot и его внешнего слоя, настроили, собрали и запустили Embedded Linux на своей плате.
Прежде чем вы начнёте играть со своей новой «игрушкой», скажу пару слов о следующей главе.
Если коротко — мы пойдём вглубь. Нас ждёт подробный разбор основ, на которых строится Buildroot: bash
, make
и KConfig. Что это такое, как это работает, зачем нужно и какие возможности это открывает.
Теории будет много — но без неё в Embedded никуда.
А пока — оставляю вас наедине с вашей платой. Поиграйте с ней: изучите структуру файловой системы, попробуйте разные команды, загляните в системные директории — например, в /proc.
Спасибо за уделённое время. Ещё увидимся!