Встраиваемые системы
Embedded Linux: Yocto и Buildroot
8 миллиардов Linux-устройств в мире - от кардиостимуляторов до Tesla Autopilot. Каждое из них собрано под конкретное железо. Как масштабировать этот процесс без превращения в хаос?
- **Automotive Grade Linux** (Toyota, Mercedes, Volkswagen) использует Yocto как единый build system для информационно-развлекательных систем - 30+ моделей автомобилей с одной кодовой базой
- **Amazon Echo** (все поколения) и **FireTV** собраны на кастомном Buildroot-derived build system с ядром, оптимизированным под Alexa Voice Service latency
- **Raspberry Pi OS** и прошивки промышленных PLC используют Device Tree overlays для поддержки сотен HAT-совместимых плат без пересборки ядра
Yocto Project: слои и рецепты
2003 год. Линус Торвальдс выпускает ядро 2.6. Никто не думает, что через 20 лет этот код будет работать на 8 миллиардах устройств - от медицинских имплантов до автомобилей Tesla. Каждое из них собирается по-своему. Yocto появился как ответ на хаос: один фреймворк, чтобы управлять всеми.
Yocto Project - это не дистрибутив. Это **инструмент для создания дистрибутивов**. Центральный механизм - BitBake build engine и система слоёв (layers). Каждый слой - набор рецептов (.bb файлов), которые описывают как собирать пакеты, патчи, конфигурации. Слои можно добавлять, убирать, переопределять - как middleware pipeline в NestJS.
BitBake параллельно собирает зависимости - как Webpack с module graph. На 16-ядерной машине полная сборка minimal image занимает 2-4 часа. Sstate-cache (shared state) позволяет переиспользовать артефакты между сборками - аналог layer caching в Docker.
Что такое 'слой' (layer) в Yocto Project?
Buildroot: простота против гибкости
Buildroot - это как Make против Gradle. Меньше возможностей, но проще понять за один день. Один Makefile, одна конфигурация через menuconfig, выход - минимальный root filesystem. Для промышленных устройств с фиксированным набором функций это часто лучший выбор.
Ключевое отличие от Yocto: Buildroot **не поддерживает incremental builds** на уровне пакетов. Изменение одной библиотеки может потребовать полной пересборки. Зато время первого освоения - часы, а не дни. Именно поэтому OpenWRT (прошивка для роутеров на 100+ млн устройств) основана на Buildroot.
Сравнение: Yocto vs Buildroot. Yocto: learning curve 2-4 недели, поддержка sstate-cache, корпоративный стандарт (Automotive Grade Linux, WindRiver). Buildroot: learning curve 2-3 дня, идеален для прототипов и небольших продуктов, активное OSS-сообщество.
Почему OpenWRT использует Buildroot вместо Yocto?
Кросс-компиляция: x86 собирает для ARM
Рабочая станция разработчика - x86_64. Целевое устройство - ARM Cortex-A53. Инструкции несовместимы. Кросс-компиляция - это когда хост-машина производит бинарники для другой архитектуры. Без неё каждую строчку кода пришлось бы компилировать прямо на медленном embedded-устройстве.
Toolchain для кросс-компиляции: `arm-linux-gnueabihf-gcc` вместо просто `gcc`. Буква 'h' в eabihf означает hard-float - вычисления с плавающей запятой через FPU, а не программную эмуляцию. На Raspberry Pi это разница в 3-5x скорости для ML-инференса с TensorFlow Lite.
Docker с --platform флагом выполняет похожую роль для контейнеров: `docker build --platform linux/arm64` на M1 Mac строит образ для ARM64. Внутри используется QEMU для эмуляции, а не нативная кросс-компиляция - отсюда более медленные builds, но более простой workflow.
Что означает 'hf' в названии тулчейна arm-linux-gnueabihf?
Device Tree: карта оборудования для ядра
На x86 BIOS и ACPI описывают ядру какое оборудование присутствует в системе. На ARM этого стандарта не было до 2011 года. Linus Torvalds назвал ситуацию 'A Fucking Embarrassment' - сотни vendor-специфичных патчей в ядре, описывающих каждую плату жёстко в коде. Device Tree исправил это.
Device Tree - это иерархическое описание оборудования в текстовом формате (DTS), которое компилируется в бинарный Blob (DTB) и передаётся загрузчиком ядру при старте. Ядро читает DTB и знает: вот I2C шина на адресах 0x3C200000, вот SPI с тремя slave-устройствами, вот UART на 115200 baud.
ML-параллель: Device Tree - это как schema для hardware конфигурации, аналогично тому как ONNX описывает граф нейросети. Оба формата разделяют description от implementation. Ядро Linux и runtime для инференса читают соответствующий 'граф' и автоматически настраивают ресурсы.
Device Tree - это конфигурация драйверов, можно менять настройки без перекомпиляции ядра
Device Tree описывает hardware topology, но изменение DTB требует перезагрузки. Параметры драйверов через module params или sysfs - другой механизм
DTB передаётся bootloader'ом ядру до инициализации и читается один раз при старте. Runtime изменения hardware topology не поддерживаются в большинстве случаев
Что произошло с описанием hardware в Linux для ARM до появления Device Tree?
Связанные темы
Embedded Linux строится на фундаменте нескольких областей CS:
- Linux Kernel Internals — Ядро Linux - это то, что Yocto и Buildroot в итоге собирают и конфигурируют
- Контейнеры — Docker --platform флаг использует QEMU cross-compilation, аналогичный Yocto подход
- Linux Kernel Drivers — Device Tree описывает оборудование, которое drivers затем инициализируют
Ключевые идеи
- **Yocto** - промышленный стандарт для сложных embedded Linux проектов: слои, рецепты, sstate-cache. Automotive, телекоммуникации, медицина. Steep learning curve оправдан масштабом.
- **Buildroot** - простота для прототипов и продуктов с фиксированным функционалом. OpenWRT, роутеры, небольшие IoT устройства. За 2-3 дня можно получить работающий образ.
- **Кросс-компиляция** - x86 хост собирает ARM/MIPS/RISC-V бинарники. Toolchain naming: `arch-vendor-os-abi` (arm-linux-gnueabihf). Hard-float vs soft-float - критично для производительности.
- **Device Tree** - стандарт описания hardware topology для ARM, заменивший board-specific C-файлы в ядре. DTS -> DTB -> bootloader -> ядро при старте системы.
Вопросы для размышления
- Для нового IoT проекта с 50 000 одинаковых устройств в год - какой инструмент выбрать: Yocto или Buildroot? Какие факторы определяют выбор?
- Device Tree позволяет использовать одно ядро на сотнях разных плат. Какие проблемы это решает и какие создаёт?
- Кросс-компиляция требует полного sysroot целевой платформы. Как это соотносится с Docker multi-stage builds для изоляции зависимостей?
Связанные уроки
- os-21-linux-internals — Знание Linux internals необходимо для понимания Yocto layers
- emb-16 — Yocto/Buildroot дают базу для написания kernel drivers
- os-19-containers — Контейнеры и Yocto - разные подходы к изоляции системного окружения
- net-47-container-networking — Embedded Linux часто использует container networking для IoT
- os-01-intro