Introduction

Building Linux for embedded devices is fundamentally different from installing a distribution on a desktop or server. Embedded systems have constrained storage, limited RAM, custom hardware, and specific real-time requirements. Rather than installing a general-purpose distribution, embedded developers build a custom Linux image containing exactly the kernel configuration, libraries, and applications their device needs — nothing more, nothing less.

Three open-source build systems dominate the embedded Linux landscape: the Yocto Project (with its Poky reference distribution), Buildroot, and OpenEmbedded. Each takes a different approach to cross-compilation, package management, and image construction, and the choice between them has significant implications for development workflow, build time, and maintainability.

Feature Comparison Table

FeatureYocto Project (Poky)BuildrootOpenEmbedded
Stars447 (Poky)3,497453 (OE-Core)
LanguagePython (BitBake)Makefile + KconfigPython (BitBake)
LicenseGPL v2GPL v2MIT
First Release201020052003
Build SystemBitBakeMake + menuconfigBitBake
Package FormatRPM/Deb/IPKNone (full rebuild)RPM/Deb/IPK
Package ManagerYes (opkg/rpm)No (full-image)Yes (opkg/rpm)
Incremental BuildsYes (shared state cache)No (always clean build)Yes (shared state cache)
Layer ArchitectureYes (hierarchical layers)No (br2-external)Yes (hierarchical layers)
SDK GenerationYes (standard + extensible)Limited (toolchain)Yes (standard)
License ComplianceBuilt-in manifestLegal-info outputBuilt-in manifest
Image Types20+ formats15+ formats15+ formats
Test Frameworkptest, oe-selftestruntime testsptest
Learning CurveSteepModerateSteep
Build Time (minimal)30-60 min5-10 min30-60 min
Docker SupportYes (CROPS containers)Yes (Dockerfile)Yes (CROPS containers)

Buildroot: Fast, Simple, and Purpose-Built

Buildroot is the most approachable of the three build systems. It uses Linux’s familiar Kconfig interface (make menuconfig) for configuration and produces a complete root filesystem, kernel, bootloader, and toolchain in a single build pass.

Docker-Based Buildroot Environment

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
version: "3.8"
services:
  buildroot:
    image: ubuntu:22.04
    volumes:
      - ./buildroot:/opt/buildroot
      - ./output:/opt/output
    working_dir: /opt/buildroot
    command: |
      bash -c "
        apt-get update && apt-get install -y build-essential cpio unzip rsync bc wget             libncurses-dev bison flex file
        wget https://buildroot.org/downloads/buildroot-2024.02.tar.gz
        tar xf buildroot-2024.02.tar.gz --strip-components=1
        make raspberrypi4_64_defconfig
        make -j$(nproc)
        cp output/images/sdcard.img /opt/output/
      "
    restart: "no"

Adding Custom Packages in Buildroot

Buildroot uses a br2-external tree to add custom packages without modifying upstream:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# Create external tree structure
mkdir -p my-external/package/myapp
cat > my-external/external.mk << 'EOF'
include $(sort $(wildcard $(BR2_EXTERNAL_MYEXT_PATH)/package/*/*.mk))
EOF

cat > my-external/Config.in << 'EOF'
menu "My Company Packages"
source "$BR2_EXTERNAL_MYEXT_PATH/package/myapp/Config.in"
endmenu
EOF

# Build with external tree
make BR2_EXTERNAL=../my-external myapp_defconfig
make -j$(nproc)

Buildroot excels for single-purpose embedded devices where you know exactly what software the device needs. Its build-from-source approach produces minimal images (as small as 5-10MB for a basic system), and its simplicity makes it the preferred choice for quick prototyping and proof-of-concept builds.

Yocto Project: Enterprise-Grade with Full Lifecycle Management

The Yocto Project is an industrial-strength build system built around BitBake and a layered architecture. Unlike Buildroot’s monolithic approach, Yocto separates metadata into layers (BSP layer, distribution layer, application layer) that can be maintained independently and combined as needed.

Yocto with CROPS Containers (Docker)

The Yocto Project provides official CROPS (Cross-Platform Development System) Docker containers for reproducible builds:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
version: "3.8"
services:
  crops-poky:
    image: crops/poky:ubuntu-22.04
    container_name: yocto-build
    volumes:
      - ./yocto-workdir:/workdir
    working_dir: /workdir
    environment:
      - MACHINE=qemuarm64
      - DISTRO=poky
    command: |
      bash -c "
        git clone -b scarthgap git://git.yoctoproject.org/poky /workdir/poky
        cd /workdir/poky
        source oe-init-build-env build
        bitbake core-image-minimal
      "
    stdin_open: true
    tty: true

Layer Management with BitBake

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# Initialize Yocto build environment
git clone -b scarthgap git://git.yoctoproject.org/poky
cd poky
source oe-init-build-env build-qemuarm64

# Add application layers
bitbake-layers add-layer ../meta-openembedded/meta-oe
bitbake-layers add-layer ../meta-openembedded/meta-python
bitbake-layers add-layer ../meta-openembedded/meta-networking

# Configure machine and distribution
echo 'MACHINE = "qemuarm64"' >> conf/local.conf
echo 'DISTRO = "poky"' >> conf/local.conf

# Build image with custom packages
echo 'IMAGE_INSTALL:append = " python3 nginx iperf3"' >> conf/local.conf
bitbake core-image-full-cmdline

Yocto SDK for Application Development

One of Yocto’s strongest features is its extensible SDK, which allows application developers to build and test software against the exact same sysroot used in the production image:

1
2
3
4
5
6
7
8
9
# Generate the SDK
bitbake core-image-full-cmdline -c populate_sdk

# Install SDK on development machine
./tmp/deploy/sdk/poky-glibc-x86_64-core-image-full-cmdline-aarch64-qemuarm64-toolchain-*.sh

# Use the SDK
source /opt/poky/4.3/environment-setup-aarch64-poky-linux
$CC hello.c -o hello

OpenEmbedded: The Foundation Beneath Yocto

OpenEmbedded (OE) and Yocto are often confused, but understanding their relationship is crucial. OpenEmbedded provides the metadata layer (openembedded-core or meta-openembedded) that defines how to build thousands of packages. The Yocto Project provides the build system (BitBake, Poky reference distribution, CROPS containers, documentation) that uses OpenEmbedded metadata.

Building with Pure OpenEmbedded

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Clone OE-Core (the minimal OpenEmbedded build system)
git clone -b scarthgap git://git.openembedded.org/openembedded-core oe-core
cd oe-core

# Initialize build
source oe-init-build-env build

# Configure and build
echo 'MACHINE = "qemuarm64"' >> conf/local.conf
echo 'DISTRO = "nodistro"' >> conf/local.conf
bitbake core-image-minimal

Key Differences from Yocto

When building with pure OpenEmbedded (without Poky), you get:

  • Minimal metadata: Only oe-core packages, no Poky-specific policies
  • No reference distribution: The nodistro policy applies fewer patches and configuration defaults
  • Full control: You define your own distribution policy, init system preference, and C library choice
  • No commercial support: Unlike Yocto, which has multiple commercial vendors, pure OE is community-supported

OpenEmbedded is the right choice when you need complete control over every aspect of your distribution policy and don’t need Yocto’s reference implementation or certification program.

Build System Selection Guide

ScenarioRecommended System
Prototype / PoCBuildroot
Single-purpose IoT deviceBuildroot
Product with long maintenance lifecycleYocto
Multiple hardware variants from one codebaseYocto
Need OTA package updates on deviceYocto
Need complete distro control without reference policiesOpenEmbedded
Team with existing Yocto expertiseYocto
Minimal image sizeBuildroot
License compliance toolingYocto

Self-Hosted Build Infrastructure

For teams building embedded Linux images, self-hosted build infrastructure is essential. Here is a complete setup using a self-hosted GitLab CI runner:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# .gitlab-ci.yml for embedded Linux image builds
stages:
  - build
  - test
  - deploy

yocto-build:
  stage: build
  image: crops/poky:ubuntu-22.04
  script:
    - source poky/oe-init-build-env build
    - bitbake core-image-full-cmdline
  artifacts:
    paths:
      - build/tmp/deploy/images/
    expire_in: 30 days
  tags:
    - embedded-runner

buildroot-build:
  stage: build
  image: ubuntu:22.04
  script:
    - make raspberrypi4_64_defconfig
    - make -j$(nproc)
  artifacts:
    paths:
      - output/images/sdcard.img
    expire_in: 30 days
  tags:
    - embedded-runner

FAQ

Do I need to learn both Yocto and OpenEmbedded?

No. Yocto uses OpenEmbedded metadata under the hood, so learning Yocto gives you OpenEmbedded knowledge by default. The reverse is not always true — Yocto adds tooling (CROPS, eSDK, Toaster, documentation) on top of OE that you would not learn from pure OE. Start with Yocto (Poky) and explore pure OE later if you need the extra control.

How long does a typical Yocto build take?

A minimal Yocto image (core-image-minimal) takes 30-60 minutes on a modern 16-core machine for the first build. Subsequent builds with the shared state cache are much faster (2-10 minutes). Buildroot’s make raspberrypi4_64_defconfig completes in 5-10 minutes for a full build. Build time scales with the number of packages — a core-image-full-cmdline Yocto build with the X server and desktop takes 2-4 hours on initial build.

Can I switch from Buildroot to Yocto mid-project?

Technically possible but practically difficult. The two systems have incompatible build architectures: Buildroot produces a monolithic image, while Yocto produces a package feed plus image. Migrating a complex Buildroot project means recreating your package recipes, configuration fragments, and customizations in BitBake format. If you anticipate future complexity (OTA updates, multiple hardware variants, compliance requirements), start with Yocto from day one.

What is the minimum storage for each build system?

Downloaded source tarballs and build artifacts consume significant disk space. Buildroot uses 5-15GB for a typical build. Yocto with core-image-full-cmdline uses 30-50GB (including shared state cache). A full Yocto build with meta-openembedded and a desktop image can consume 80-120GB. Always provision at least 100GB for a Yocto build server.

Which build system produces the smallest images?

Buildroot produces the smallest images because it strips everything by default and builds from source without package management overhead. A minimal Buildroot image can be as small as 3-5MB. Yocto’s core-image-minimal is typically 6-10MB. The difference is small but meaningful for devices with 4-8MB SPI flash storage.

How do I handle proprietary kernel modules and closed-source components?

All three systems support proprietary components through local source mirrors and private layer/external tree mechanisms. In Yocto, create a private layer with LICENSE_FLAGS = "commercial" for your proprietary recipes. In Buildroot, use a private br2-external tree. Both approaches keep proprietary code separate from open-source components, simplifying license compliance audits.


💰 想测试你的市场判断力?我用 Polymarket 做预测市场交易——这是全球最大的预测市场平台,从大选结果到技术监管时间线,什么都可以押注。和赌博不同,这是真正的信息市场:你懂的信息越多,胜率越高。我靠预测技术相关事件的走向已经赚了不少。用我的邀请链接注册:Polymarket.com