dotlinux blog

Yocto Linux: Tutorial Basics

Embedded systems power everything from smart thermostats and industrial controllers to IoT devices and automotive infotainment systems. Unlike general-purpose computers, these systems require highly customized Linux distributions tailored to specific hardware constraints (e.g., limited RAM, storage, or processing power) and software requirements (e.g., minimal footprint, real-time capabilities).

The Yocto Project is an open-source framework designed to simplify the creation of such custom embedded Linux systems. It’s not a Linux distribution itself but a set of tools, metadata, and best practices that let you build a tailored Linux image for your target hardware. Whether you’re a hobbyist building a Raspberry Pi project or an engineer developing a commercial embedded product, Yocto provides the flexibility and control needed to optimize your system.

This tutorial will guide you through the basics of Yocto, from understanding its core components to building and customizing your first embedded Linux image. By the end, you’ll have the foundational knowledge to start creating your own embedded systems with Yocto.

2026-01

Table of Contents#

  1. What is the Yocto Project?
  2. Core Components of Yocto
    • Poky
    • BitBake
    • Recipes
    • Layers
    • Metadata
    • Images
  3. Setting Up Your Yocto Environment
    • Prerequisites
    • Installing Dependencies
    • Cloning Poky
    • Initializing the Build Environment
  4. Building Your First Yocto Image
    • Configuring local.conf
    • Running BitBake
    • Understanding the Build Output
  5. Customizing Your Image
    • Adding Packages
    • Creating a Custom Layer
    • Writing a Simple Recipe
  6. Flashing and Testing the Image
    • Testing with QEMU (Emulation)
    • Flashing to Physical Hardware
  7. Troubleshooting Common Issues
  8. Conclusion
  9. References

1. What is the Yocto Project?#

The Yocto Project, launched in 2010 by the Linux Foundation, is a collaborative effort to standardize embedded Linux development. Its primary goal is to enable developers to create custom, hardware-specific Linux distributions without starting from scratch.

Key Features:#

  • Customization: Tailor every aspect of the Linux image (kernel, libraries, applications) to your hardware and use case.
  • Scalability: Build tiny "minimal" images (a few MB) or full-featured systems with graphical interfaces.
  • Maintainability: Leverage versioned metadata and community layers to keep systems updated and secure.
  • Hardware Support: Supports a wide range of architectures (x86, ARM, PowerPC, RISC-V) and boards (Raspberry Pi, BeagleBone, Intel NUC, etc.).

Yocto vs. Other Tools:#

  • Buildroot: A simpler, single-tree tool for small images, but less flexible for large/complex projects.
  • Debian/Ubuntu for Embedded: Pre-built packages, but less control over footprint and customization.
  • Yocto: Balances flexibility, scalability, and maintainability, making it ideal for commercial and complex embedded systems.

2. Core Components of Yocto#

To use Yocto effectively, you need to understand its key building blocks:

Poky#

Poky is the reference distribution of the Yocto Project. It includes the minimal set of tools, metadata, and recipes needed to build a functional embedded Linux image. Think of Poky as the "starting point"—it provides the core infrastructure, and you extend it with custom layers and recipes.

BitBake#

BitBake is Yocto’s build engine. It parses metadata (recipes, configuration files) and coordinates the build process: downloading sources, applying patches, compiling code, and packaging outputs. It’s similar to make but more powerful, supporting parallel builds, dependency resolution, and cross-compilation.

Recipes#

Recipes are metadata files (with .bb or .bbappend extensions) that define how to build a package (e.g., a library, application, or kernel module). A recipe specifies:

  • Source code location (URL, Git repo).
  • Dependencies (other packages needed to build/run).
  • Build steps (configure, compile, install).
  • Patches to apply to the source code.

Example: A recipe for the hello-world application would tell BitBake where to fetch the source, how to compile it, and where to install the binary.

Layers#

Layers are modular directories that organize recipes, configuration, and other metadata. They enable you to separate customizations from core Poky code, making your project easier to maintain and share. For example:

  • meta-yocto: Core Yocto metadata.
  • meta-openembedded: Community-maintained recipes for common packages (Python, Apache, etc.).
  • meta-raspberrypi: Hardware-specific layers for Raspberry Pi boards.
  • meta-mylayer: Your custom layer for project-specific recipes.

Metadata#

Metadata includes all configuration files, recipes, and layers that BitBake uses to build the image. Key metadata files:

  • local.conf: Project-specific configuration (target machine, image type, build options).
  • bblayers.conf: Lists layers BitBake should include.
  • .bbclass files: Reusable code snippets (e.g., autotools.bbclass for Autotools-based projects).

Images#

An image is the final output of the Yocto build process—a binary file (e.g., .img, .tar.gz) that can be flashed to hardware. Yocto provides pre-defined image recipes for common use cases:

  • core-image-minimal: A tiny, minimal image with basic tools (e.g., sh, ls).
  • core-image-sato: A graphical image with the Sato desktop environment.
  • core-image-weston: A Wayland compositor for embedded GUIs.

3. Setting Up Your Yocto Environment#

Let’s set up Yocto on a Linux machine (Ubuntu/Debian recommended; Windows/macOS require WSL or a VM).

Prerequisites#

  • OS: Ubuntu 20.04/22.04, Debian 11, or similar (64-bit).
  • Hardware: At least 4 CPU cores, 8GB RAM, 100GB free disk space (builds are resource-intensive!).
  • Network: Internet access (to download sources and dependencies).

Step 1: Install Dependencies#

Yocto requires several build tools and libraries. Run this command to install them:

sudo apt update && sudo apt install -y \
  gawk wget git diffstat unzip texinfo gcc build-essential chrpath \
  socat cpio python3 python3-pip python3-pexpect xz-utils debianutils \
  iputils-ping python3-git python3-jinja2 libegl1-mesa libsdl1.2-dev \
  pylint3 xterm python3-subunit mesa-common-dev zstd liblz4-tool

Step 2: Clone Poky#

Poky is hosted on Git. Clone the latest stable release (we’ll use Kirkstone—LTS until 2025):

git clone git://git.yoctoproject.org/poky -b kirkstone

This creates a poky directory with the core Yocto tools and metadata.

Step 3: Initialize the Build Environment#

Navigate to the poky directory and run the oe-init-build-env script to set up the build environment:

cd poky
source oe-init-build-env
  • This creates a build directory (your workspace) with subdirectories like conf (configuration) and tmp (build outputs).
  • The script also sets environment variables (e.g., BITBAKE_HOME) and opens a shell in the build directory.

4. Building Your First Yocto Image#

Now, let’s build a minimal Linux image for emulation (QEMU x86-64).

Step 1: Configure local.conf#

The build/conf/local.conf file controls your build. Open it in a text editor:

nano conf/local.conf

Key settings to adjust:

  • MACHINE: Target hardware. For QEMU x86-64, set:
    MACHINE ??= "qemux86-64"
  • DL_DIR (Optional): Cache downloaded sources (saves bandwidth on future builds):
    DL_DIR ?= "${TOPDIR}/downloads"
  • SSTATE_DIR (Optional): Cache compiled objects (speeds up rebuilds):
    SSTATE_DIR ?= "${TOPDIR}/sstate-cache"

Step 2: Run BitBake#

Build the core-image-minimal image with BitBake:

bitbake core-image-minimal

What Happens Next?#

  • Download Phase: BitBake fetches source code for the Linux kernel, busybox, and other packages (from URLs in recipes).
  • Unpack/ Patch: Sources are uncompressed, and patches (if specified) are applied.
  • Configure/ Compile: Code is cross-compiled for the target machine (qemux86-64).
  • Package/ Image Generation: Compiled binaries are packaged into an image file (e.g., .wic or .img).

Note: The first build takes 1–3 hours (depending on your hardware and internet speed). Subsequent builds are faster due to caching.

Step 3: Locate the Build Output#

Once complete, the image is in build/tmp/deploy/images/qemux86-64/. The key file is:

  • core-image-minimal-qemux86-64.wic: A raw disk image ready for flashing/emulation.

5. Customizing Your Image#

Yocto’s power lies in customization. Let’s add a custom package and modify the image.

Adding Pre-Existing Packages#

To include a package (e.g., htop, a system monitor) in your image, edit local.conf and add it to IMAGE_INSTALL:

IMAGE_INSTALL:append = " htop"
  • :append ensures htop is added to the existing list of packages.
  • Rebuild the image with bitbake core-image-minimal to include htop.

Creating a Custom Layer#

Layers keep your customizations organized. Let’s create a layer called meta-mylayer:

# From the build directory
bitbake-layers create-layer ../meta-mylayer

This creates a meta-mylayer directory with a basic structure:

meta-mylayer/
├── conf/
│   └── layer.conf  # Defines layer priority and dependencies
├── recipes-example/
│   └── example/
│       └── example_0.1.bb  # Sample recipe
└── README

Add the Layer to bblayers.conf#

Tell BitBake to use your new layer by editing build/conf/bblayers.conf:

BBLAYERS ?= " \
  /path/to/poky/meta \
  /path/to/poky/meta-poky \
  /path/to/poky/meta-yocto-bsp \
  /path/to/meta-mylayer \  # Add this line
  "

Writing a Simple Recipe#

Let’s add a custom "hello-world" application to meta-mylayer.

Step 1: Create Recipe File#

Create meta-mylayer/recipes-example/hello/hello_0.1.bb with:

SUMMARY = "Simple Hello World application"
DESCRIPTION = "A basic C program to print 'Hello, Yocto!'"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://LICENSE;md5=08358e345d5b30e96473e6a8e0f2a095"
 
SRC_URI = "file://hello.c \
           file://LICENSE \
          "
 
S = "${WORKDIR}"  # Source directory (where BitBake unpacks files)
 
do_compile() {
    ${CC} hello.c -o hello
}
 
do_install() {
    install -d ${D}${bindir}
    install -m 0755 hello ${D}${bindir}
}

Step 2: Add Source Files#

Create the hello.c and LICENSE files in meta-mylayer/recipes-example/hello/files/:

mkdir -p meta-mylayer/recipes-example/hello/files

hello.c:

#include <stdio.h>
int main() {
    printf("Hello, Yocto!\n");
    return 0;
}

LICENSE (MIT license text):

MIT License

Permission is hereby granted, free of charge, to any person obtaining a copy...

Step 3: Include the Package in the Image#

Edit local.conf to add hello to IMAGE_INSTALL:

IMAGE_INSTALL:append = " hello"

Step 4: Rebuild the Image#

bitbake core-image-minimal

BitBake will now build your hello package and include it in the image.

6. Flashing and Testing the Image#

Once your image is built, test it with QEMU (emulation) or flash it to hardware.

Testing with QEMU#

Yocto provides a runqemu script to launch the image in QEMU. From the build directory:

runqemu qemux86-64
  • QEMU will boot your custom Linux image. Log in with username root (no password).
  • Run hello to test your custom package:
    root@qemux86-64:~# hello
    Hello, Yocto!

Flashing to Physical Hardware#

For real hardware (e.g., Raspberry Pi), use the .wic image and tools like dd or BalenaEtcher.

Example (Raspberry Pi 4, assuming MACHINE = "raspberrypi4-64"):

sudo dd if=tmp/deploy/images/raspberrypi4-64/core-image-minimal-raspberrypi4-64.wic of=/dev/sdX bs=4M status=progress
  • Replace /dev/sdX with your SD card device (check with lsblk).

7. Troubleshooting Common Issues#

Missing Dependencies#

Error: ERROR: ... requires 'foo' but 'foo' was not found.
Fix: Install missing system packages (e.g., sudo apt install foo). Check the Yocto Prerequisites for details.

Network/ Download Failures#

Error: Failed to fetch URL ....
Fix:

  • Check your internet connection.
  • If behind a proxy, set HTTP_PROXY, HTTPS_PROXY, and FTP_PROXY in local.conf.
  • Clear cached downloads: rm -rf ${DL_DIR}/<package-name>.

Recipe Errors#

Error: ERROR: ... do_compile failed.
Fix:

  • Check the build log: tmp/work/<machine>/<package>/<version>/temp/log.do_compile.
  • Clean the package and rebuild: bitbake -c cleanall <package> && bitbake <package>.

8. Conclusion#

You’ve now learned the basics of the Yocto Project: setting up the environment, building an image, customizing it with packages and layers, and testing with QEMU. Yocto’s flexibility makes it a powerful tool for embedded Linux development, but there’s much more to explore:

  • Advanced layer management (e.g., meta-openembedded for additional packages).
  • Kernel customization (patches, configuration).
  • Building SDKs for application development.
  • Security hardening (e.g., signed images, secure boot).

Start small, experiment with custom recipes, and refer to the official documentation to deepen your knowledge!

9. References#