В первой статье мы разобрались с базовыми терминами: что такое 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 файла из указанного *_defconfig -
make 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— вызов меню конфигурации Linux -
make 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.
Спасибо за уделённое время. Ещё увидимся!
ссылка на оригинал статьи https://habr.com/ru/articles/925804/
Добавить комментарий