Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Buildroot: Building Embedded Linux Systems

Buildroot is a simple, efficient tool for generating complete embedded Linux systems through cross-compilation. It produces a root filesystem image, a kernel image, a bootloader, and optionally a toolchain — all from a single make invocation. This chapter covers configuration, package management, custom overlays, cross-compilation, and output image generation.


1. Buildroot vs Alternatives

FeatureBuildrootYoctoOpenWrt
Build systemMakeBitBake (Python)Make
ComplexityLowHighMedium
Package count~3000~3500 (core)~8000
Root FS formatRead-only (ext4, squashfs)Read-write or read-onlySquashfs + overlay
ReproducibilityGoodExcellentGood
Learning curveGentleSteepModerate
Best forSimple, fixed-function devicesComplex, multi-image productsRouters / networking

2. Getting Started

2.1 Prerequisites

# Debian/Ubuntu
sudo apt install build-essential git cmake \
    bc cpio file unzip wget \
    libncurses-dev python3 python3-pip \
    rsync

2.2 Download and Extract

wget https://buildroot.org/downloads/buildroot-2024.02.tar.xz
tar xf buildroot-2024.02.tar.xz
cd buildroot-2024.02

2.3 Minimal Build

make qemu_arm_vexpress_defconfig   # pick a defconfig
make                                # build everything (30-60 min first time)

Output appears in output/images/.


3. Configuration System (menuconfig)

Buildroot uses the Linux kernel’s Kconfig system. The main configuration interface is menuconfig.

make menuconfig

3.1 Key Menu Sections

├── Target options            # Architecture, ABI, FPU
├── Build options             # Parallel jobs, ccache, download dir
├── Toolchain                 # Internal, external, or custom
├── System configuration      # Hostname, init system, root password
├── Kernel                    # Linux kernel version and config
├── Target packages           # Libraries, applications, services
├── Filesystem images         # ext4, squashfs, cpio, etc.
├── Bootloaders               # U-Boot, Barebox, GRUB
└── Host utilities            # Tools built for the build host

3.2 Target Options

For an ARM Cortex-A9 board:

Target Architecture (ARM)  --->
Target Binary Format (ELF) --->
Target Architecture Variant (cortex-A9) --->
Floating point strategy (NEON/VFPv4) --->

3.3 Saving and Loading Configurations

# Save current config
make savedefconfig DEFCONFIG=myboard_defconfig

# Restore a defconfig
cp myboard_defconfig configs/
make myboard_defconfig
make

4. Toolchain Configuration

Buildroot builds its own cross-compiler from source:

Toolchain type (Buildroot toolchain) --->
    Toolchain (Custom toolchain) --->
    GCC compiler version (13.x) --->
    C library (glibc) --->
    Kernel Headers (Linux 6.6.x) --->

The toolchain is installed in output/host/bin/:

output/host/bin/arm-linux-gnueabihf-gcc --version

4.2 External Toolchain

Use a pre-built toolchain (e.g., ARM GNU Toolchain, Linaro):

Toolchain type (External toolchain) --->
    Toolchain (Linaro ARM 2023.10) --->

4.3 Using the Toolchain Outside Buildroot

# Extract the SDK
make sdk
tar xf output/images/arm-buildroot-linux-gnueabihf_sdk-buildroot.tar.xz \
    -C /opt/

# Use it
export PATH=/opt/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin:$PATH
arm-linux-gnueabihf-gcc -o hello hello.c

5. Package Management

5.1 Enabling Packages

make menuconfig
# Navigate to Target packages → Libraries → ...
# Enable: [*] zlib
# Enable: [*] openssl

Or directly edit .config:

BR2_PACKAGE_ZLIB=y
BR2_PACKAGE_OPENSSL=y

5.2 Package Structure

Each package is defined in a directory under package/:

package/
└── myapp/
    ├── myapp.mk        # Makefile fragment
    ├── myapp.hash      # Hash verification
    └── Config.in       # Kconfig entry

5.3 Writing a Package (myapp.mk)

################################################################################
#
# myapp
#
################################################################################

MYAPP_VERSION = 1.2.3
MYAPP_SITE = https://example.com/releases
MYAPP_SOURCE = myapp-$(MYAPP_VERSION).tar.gz
MYAPP_LICENSE = MIT
MYAPP_LICENSE_FILES = LICENSE

# Dependencies
MYAPP_DEPENDENCIES = zlib openssl

# Build system: autotools, cmake, generic
MYAPP_CONF_OPTS = -DENABLE_TESTS=OFF

# Install init script
define MYAPP_INSTALL_INIT_SYSV
    $(INSTALL) -D -m 0755 $(MYAPP_PKGDIR)/S99myapp \
        $(TARGET_DIR)/etc/init.d/S99myapp
endef

$(eval $(cmake-package))

5.4 Package Config (Config.in)

config BR2_PACKAGE_MYAPP
    bool "myapp"
    depends on BR2_PACKAGE_ZLIB
    select BR2_PACKAGE_OPENSSL
    help
        My custom application for the embedded device.
        
        https://example.com/myapp

Reference it from the parent Config.in:

source "$BR2_EXTERNAL_MYBOARD_PATH/package/myapp/Config.in"

5.5 Rebuilding a Single Package

# Clean and rebuild
make myapp-dirclean
make myapp

# Rebuild only (no clean)
make myapp-rebuild

# Show build log
make myapp-show-log

6. Custom Overlays

Overlays let you add files to the root filesystem without modifying packages.

6.1 Root Filesystem Overlay

Create a directory tree mirroring the target’s root filesystem:

board/mycompany/myboard/rootfs_overlay/
├── etc/
│   ├── hostname
│   ├── network/
│   │   └── interfaces
│   └── fstab
├── usr/
│   └── share/
│       └── myapp/
│           └── config.json
└── var/
    └── lib/
        └── myapp/

Configure in menuconfig:

System configuration → Root filesystem overlay directories:
    board/mycompany/myboard/rootfs_overlay

Or in .config:

BR2_ROOTFS_OVERLAY="board/mycompany/myboard/rootfs_overlay"

6.2 Post-Build Scripts

Run custom scripts after the filesystem is assembled:

# post_build.sh
#!/bin/bash
TARGET_DIR=$1

# Remove unnecessary files
rm -rf ${TARGET_DIR}/usr/share/doc
rm -rf ${TARGET_DIR}/usr/share/man

# Set permissions
chmod 700 ${TARGET_DIR}/root
BR2_ROOTFS_POST_BUILD_SCRIPT="board/mycompany/myboard/post_build.sh"

6.3 Post-Image Scripts

Run after images are generated (e.g., to create a firmware bundle):

# post_image.sh
#!/bin/bash
IMAGES_DIR=$1

# Create a combined firmware image
cat ${IMAGES_DIR}/u-boot.bin \
    ${IMAGES_DIR}/zImage \
    ${IMAGES_DIR}/rootfs.ext4 \
    > ${IMAGES_DIR}/firmware.img
BR2_ROOTFS_POST_IMAGE_SCRIPT="board/mycompany/myboard/post_image.sh"

7. Cross-Compilation Workflow

7.1 Build Flow Diagram

flowchart TD
    A[".config / menuconfig"] --> B["Download Sources"]
    B --> C["Extract & Patch"]
    C --> D["Configure (./configure / cmake)"]
    D --> E["Cross-Compile"]
    E --> F["Install to staging/"]
    F --> G["Install to target/"]
    G --> H["Generate Root FS Image"]
    H --> I["output/images/"]
    
    subgraph Host Tools
        J["cmake, pkg-config, m4"]
    end
    subgraph Cross Tools
        K["arm-linux-gnueabihf-gcc"]
    end
    J --> D
    K --> E

7.2 Build Stages

StageDirectoryPurpose
build/output/build/<pkg>-<ver>/Build artifacts
staging/output/staging/Cross-compiled libraries + headers
target/output/target/Root filesystem contents
host/output/host/Host tools + cross-compiler

7.3 Building a Single Package

# Configure only
make myapp-configure

# Build only
make myapp-build

# Full cycle
make myapp

7.4 Out-of-Tree Application Development

# Point pkg-config to staging
export PKG_CONFIG_SYSROOT_DIR=$(pwd)/output/staging
export PKG_CONFIG_PATH=$(pwd)/output/staging/usr/lib/pkgconfig

# Cross-compile your app
$(pwd)/output/host/bin/arm-linux-gnueabihf-gcc \
    $(pkg-config --cflags --libs openssl) \
    -o myapp src/main.c

8. Output Images

8.1 Supported Formats

Filesystem images --->
    [*] ext2/3/4 root filesystem
        ext2/3/4 variant (ext4) --->
        Filesystem size (256M) --->
    [*] squashfs root filesystem
    [*] initial RAM filesystem (cpio)
    [*] tar the root filesystem
        Compression (gzip) --->

8.2 Typical Output

ls output/images/
# Image.gz              — compressed kernel image
# rootfs.ext4           — ext4 root filesystem
# rootfs.squashfs       — read-only squashfs
# rootfs.tar.gz         — tarball of rootfs
# rootfs.cpio.gz        — initramfs
# sdcard.img            — combined SD card image (if configured)
# u-boot.bin            — bootloader

8.3 SD Card Image

# Write to SD card
sudo dd if=output/images/sdcard.img of=/dev/sdX bs=1M status=progress
sync

8.4 QEMU Testing

# For ARM versatile express
make qemu_arm_vexpress_defconfig
make

# Run
./output/host/bin/qemu-system-arm \
    -M vexpress-a9 \
    -kernel output/images/zImage \
    -dtb output/images/vexpress-v2p-ca9.dtb \
    -drive file=output/images/rootfs.ext4,if=sd \
    -append "root=/dev/mmcblk0 console=ttyAMA0" \
    -nographic

9. Board Support with board/ Directory

9.1 Custom Board Layout

board/mycompany/myboard/
├── genimage.cfg           # SD card partition layout
├── post_build.sh
├── post_image.sh
├── rootfs_overlay/
│   └── etc/
│       └── ...
├── patches/
│   └── linux/
│       └── 0001-fix-display.patch
└── defconfig

9.2 genimage.cfg — Partition Layout

image sdcard.img {
    hdimage {
        partition-table-type = "mbr"
    }

    partition boot {
        image = "boot.vfat"
        partition-type = 0x0C
        size = 64M
    }

    partition rootfs {
        image = "rootfs.ext4"
        partition-type = 0x83
    }
}

image boot.vfat {
    vfat {
        files = {
            "zImage",
            "myboard.dtb"
        }
    }
    size = 64M
}

10. External Trees (BR2_EXTERNAL)

Buildroot supports external trees to keep custom packages, board support, and configurations separate from the Buildroot source tree.

10.1 Creating an External Tree

myboard-external/
├── external.desc
├── external.mk
├── Config.in
├── configs/
│   └── myboard_defconfig
├── board/
│   └── mycompany/
│       └── myboard/
│           └── ...
└── package/
    └── myapp/
        ├── Config.in
        └── myapp.mk

external.desc:

name: MYBOARD
desc: My Company Board Support

10.2 Using the External Tree

make BR2_EXTERNAL=/path/to/myboard-external myboard_defconfig
make

11. Tips and Tricks

11.1 Speed Up Builds

# Enable ccache
BR2_CCACHE=y
BR2_CCACHE_DIR="/path/to/ccache"

# Use parallel jobs
BR2_JLEVEL=0    # 0 = auto-detect
# Generate manifest of all packages and licenses
make legal-info
ls output/legal-info/
# host-sources/  host-licenses/  manifest.csv  sources/

11.3 Reproducible Builds

# Record exact config + version
make show-info > build_info.json

# Force deterministic timestamps
BR2_REPRODUCIBLE=y

Further Reading