Roll your own IoT Linux with Buildroot

Getting Small

© Lead Image © khunaspix, and

© Lead Image © khunaspix, and

Article from Issue 263/2022

Whether you need a tiny OS for 1MB of flash memory or a complex Linux with a graphical stack, you can quickly set up a working operating system using Buildroot.

To put together a Linux-based IoT system, you need a quick and easy approach to getting a base system up and running. And while you are at it, you also need to keep an eye on the flash footprint – some IoT platforms only have 64MB flash memory. You will want to keep control of the software included in the system, and you'll want to be able to add your own applications easily. Last but not least, you will need to pay attention to security and comply with both open source and proprietary licenses.

The Buildroot build system [1] will help you with these tasks. Buildroot, which emerged in the early 2000s from the µClinux and Busybox projects, focuses on creating systems with a minimal footprint. Buildroot is easier to use and conceptually simpler than Yocto (see the article on Yocto starting on p. 16 of this issue). If you don't need Yocto's expansive capabilities, with its modular layer system and other advanced features, and you just want to generate an OS for an embedded device, Buildroot is often the better choice.

Buildroot can generate:

  • a cross-compilation toolchain
  • a root file system
  • a Linux kernel image
  • a bootloader for the target device

A selection tool based on the menu system of the Linux kernel lets you specify the required packages and the associated configuration options. This menu-driven approach helps ensure you have the components you need and makes it easy to leave out any components you don't need to minimize the flash footprint.

Once you decide which packages to include, Buildroot helps with downloading, patching, configuring, compiling, and finally installing each package (Figure 1). In addition, you can generate some metadata if so desired: a manifest of installed packages, license information (legal-info), the footprint of each package (graph-size), and the dependencies between the components (graph-depends). All packages are built from the source code, which gives you maximum control over the configuration.

Figure 1: After downloading and patching the packages, some configuration and compilation work is required before you can install.

Unlike Ubuntu Core and Linux from Scratch, Buildroot relies on cross-compiling, which means the build happens on a processor architecture that is different from the system on which the build will eventually run. For example, you can build on a computer with an x86 architecture, even though the target system is an ARM. For many processor architectures in the embedded space, cross-compiling is the only realistic way to compile, because the target system is often far too slow and does not have enough memory. Additionally, cross-compiling lets you work with a different standard C library (such as Musl or uClibc) and a different Linux kernel.

However, cross-compiling presents a few challenges. Much of the work done by Buildroot is to overcome these challenges through special compilation options or source code patches. Cross-compiling requires a special toolchain consisting of the compiler, linker, and assembler for the target system, the Linux kernel headers, the C and C++ standard libraries, and optionally the cross-debugger. Buildroot creates this toolchain and optimizes it for the target platform as part of the build process. Alternatively, you can load and use an existing toolchain, such as the ARM GNU toolchain or the Bootlin toolchain.


One of the most important principles of Buildroot is flexibility. You need to be able to make all kinds of tweaks to the system to get exactly the results you require. The distribution primarily achieves this through a selection of packages. For example, Buildroot offers several basic options for the init system (systemd, classic SysVinit, its stripped-down Busybox version, or OpenRC) and more than 10 different web servers. Buildroot supports the Glibc, Musl, and uClibc C libraries. On top of this, 15 different root file systems are available. In addition to classic options like ext4 and embedded-specific variants like UBIFS for NAND flash, the file system options include a RAM file system that is linked into the Linux kernel.

You can store your choice of packages in a configuration file, which, in turn, can reference a number of other files that further specify the requirements. Some packages, such as the Linux kernel, have their own configuration file. There are also a number of items that are too complicated to save in the configuration file, including file ownership and permissions, as well as user names and passwords. You can define separate files for these items. Using rootfs, you then copy a directory structure (the rootfs overlay) and run a script after creating all the packages. The additional configuration files are usually stored in the boards/ directory.

Figure 2 shows the configuration files used in an example. Two different variants exist, each with a defconfig: bmax_b1 and raspberrypi4_64. The two variants share most of the rootfs overlay in the common/ directory, the user-defined table, and a post-build script that generates version and platform information. The two boards require slightly different configurations for the graphics stack though, and this is why they each have their own rootfs overlays.

Figure 2: Two versions of the configuration files, each with a defconfig: bmax_b1 and raspberrypi4_64.

To help you get started, Buildroot comes with configurations for around 230 recent SBCs (Single Board Computers) and SoMs (System-on-Modules) and about 40 configurations for simulations in Qemu. These are minimal configurations containing just a toolchain, a kernel, a bootloader, and a busybox. If required, the configurations might include firmware, for example, for a WiFi chip or a GPU. You then upload the results – usually an SD card image – directly to the board. Use the SD card to boot the device and access a shell, which you can adapt to your needs if necessary. As long as you know which CPU variant you are dealing with, and which bootloader and kernel options (device tree) you need to use, you can quite easily set up a basic configuration.

Buildroot's flexibility even allows it to incorporate non-standard features. For instance, you could include a read-only root filesystem with a separate writable partition, kernel and rootfs updates, along with A-B swapping between two partitions, and verified booting using a trusted hardware root. All of this is possible, but it can involve some hard work in individual cases.

Some projects use Buildroot to build a more managed and therefore less flexible distribution. They include SkiffOS, DahliaOS, Recalbox, Batocera Linux, and Home Assistant Operating System, among others. These distros are designed for specific use cases and make use of Buildroot's flexibility.

Your Own Applications

To generate a working product, an application needs to deliver the functionality of the IoT device. Sometimes this is limited to a few scripts such as PHP files that you use through the web server and are simply part of the rootfs overlay. However, you will usually need to compile and install one or more custom components.

Buildroot offers two approaches to compiling your own components. You will often set up separate package definitions for each of your components, consisting of just a few lines, especially if one of the supported build systems is used (Figure 1). For C/C++, these are Meson, Cmake, the Qmake autotools, and Waf. Other languages have language-specific build systems: Go for Golang, Cargo for Rust, Rebar for Erlang, Luarocks for Lua, MB or EUMM for Perl. Python plays a special role because it supports several build systems with Distutils, Setuptools, Pep517, Flit, and Maturin. The comprehensive Buildroot manual [2] explains how to create a package definition and which variables you need to use to fine-tune the build process.

Developers often look to avoid mixing their own package definitions with Buildroot's open source packages. The BR2_EXTERNAL mechanism supports this desire by allowing the user to add custom package definitions to those belonging to Buildroot. Additionally, you can store your configuration and other files, such as the rootfs overlay, in the same BR2_EXTERNAL repository. This keeps all your customizations neatly in one place.

Sometimes it is more convenient to compile application code outside of Buildroot. For example, in larger projects, you might find software developers who do not work with Buildroot on a daily basis. Also, it is easier to compile from an IDE if you are working directly with a build system that the development environment supports. This is why Buildroot provides an SDK containing the cross-compilation toolchain, all configured libraries, and the host tools. After all, you will need some of these host tools for the build. pkg-config, for example, defines the compile options of a library, and protoc generates the code for a Google protobuf definition. The SDK is available as a tarball that you can unpack anywhere. If you set up the IDE to use the SDK's cross-compiler, you can compile and debug directly from it.


Once an IoT system is developed, updates and new generations will usually follow. It is important to maintain the underlying distribution with fixes for security issues and new features.

Buildroot has been around since 2001, making it one the oldest IoT build tools, and the project's continuity definitely makes it a proven product. Since 2009, the developers have kept to a fixed release schedule of four releases per year: 20XX.02, 20XX.05, 20XX.08, and 20XX.11. Each release goes through a one-month stabilization period, during which only fixes take place; the release is then maintained (bug fixes and security updates) for three months. A minor version is released about every month. The 20XX.02 release is an LTS (Long Term Support) release that will be maintained for a little over a year and again has minor releases added monthly.

Buildroot is community-driven, with about 100 people contributing to each release and a total of 1,500 changes per release. The community mainly communicates via the mailing list ( and on IRC #buildroot on Open and Free Technology Community (OFTC). Twice a year, a developer meeting is held, with problems and new features on the agenda. In addition, the community discusses and decides on controversial changes in this scope. There is no controlling company behind the distribution. However, some companies and freelance consultants offer services related to Buildroot. These companies help customers get the operating system running on the IoT platform with all the necessary features. See the Buildroot website for more information.

The developers provide some tools to help you maintain buildroot. You can use make pkg-stats to keep the packages in Buildroot up to date. Calling make pkg-stats collects version information about the packages you select, searches for newer versions on the network, checks for Common Vulnerabilities and Exposures (CVE) reported via the NIST National Vulnerability Database, and prints the results in HTML and JSON. This report appears weekly for all packages [3]. Run it for your own configuration if you want a personalized report.

Further testing goes on continuously – 440 tests a week. The 270 configurations for SBCs, SoMs, and Qemu are bundled with Buildroot are also created weekly. Finally, there are 10 build servers that steadily generate arbitrary configurations. The reports from these servers are available online [4].

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy Linux Magazine

Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

  • Yocto

    The Yocto project gives you all the tools you'll need to build a custom Linux for IoT device.

  • SSH Reverse Tunnels

    We’ll show you a practical project for monitoring home energy usage with SSH and OpenWrt.

  • Specialty Distros

    In the Linux world, form follows function. A specialty distro is a Linux-based system designed to serve a specific role. We look at some classic examples.

  • Flash Filesystems

    Whirring machines with rotating stacks of disks are out. The elegant tablets and smartphones of today’s digital generation house flash memory that saves space and energy. We explain the characteristics of flash chips and suggest appropriate Linux filesystems.

  • Linux from Scratch

    If you really want to learn about Linux, build it from scratch.

comments powered by Disqus