What is Yocto?
The Yocto Project is an open-source collaboration for creating custom Linux distributions for embedded systems. Key components:
- BitBake — Task executor and scheduler (like make on steroids)
- OpenEmbedded — Build framework with metadata
- Poky — Reference distribution
- Layers — Collections of recipes and configurations
- Recipes — Instructions to build packages (.bb files)
Getting Started
# Clone Poky (reference distribution)
git clone git://git.yoctoproject.org/poky
cd poky
# Checkout a stable branch (e.g., kirkstone)
git checkout kirkstone
# Initialize build environment
source oe-init-build-env
# Build a minimal image
bitbake core-image-minimal
BitBake Basics
Building Images
# Build minimal console image
bitbake core-image-minimal
# Build image with SSH and basic tools
bitbake core-image-base
# Build full image with X11
bitbake core-image-sato
# Build SDK for cross-compilation
bitbake -c populate_sdk core-image-minimal
Building Individual Packages
# Build a specific package
bitbake busybox
bitbake linux-yocto
bitbake u-boot
# Build only the recipe (no dependencies)
bitbake -b ../meta/recipes-core/busybox/busybox_1.35.0.bb
Recipe Tasks
BitBake executes tasks in order. Common tasks:
# Fetch sources
bitbake busybox -c fetch
# Unpack sources
bitbake busybox -c unpack
# Patch sources
bitbake busybox -c patch
# Configure build
bitbake busybox -c configure
# Compile
bitbake busybox -c compile
# Install to staging
bitbake busybox -c install
# Package
bitbake busybox -c package
# Deploy to image
bitbake busybox -c deploy
Cleaning and Rebuilding
# Clean build directory (keeps downloads)
bitbake busybox -c clean
# Clean everything including downloads
bitbake busybox -c cleanall
# Clean and rebuild
bitbake busybox -c cleansstate
bitbake busybox
# Force rebuild from scratch
bitbake -f busybox
Inspecting Recipes
oe-pkgdata-util
# Find which recipe provides a file
oe-pkgdata-util find-path /usr/bin/curl
# List files in a package
oe-pkgdata-util list-pkg-files curl
# Find package that contains a file
oe-pkgdata-util lookup-pkg curl
# List all packages from a recipe
oe-pkgdata-util list-pkgs -p curl
bitbake-layers
# Show all layers
bitbake-layers show-layers
# Show recipes in a layer
bitbake-layers show-recipes
# Find a recipe
bitbake-layers show-recipes | grep busybox
# Add a layer
bitbake-layers add-layer ../meta-mylayer
# Remove a layer
bitbake-layers remove-layer ../meta-mylayer
# Check layer compatibility
bitbake-layers show-overlayed
bitbake Environment
# Show full environment for a recipe
bitbake -e busybox | less
# Find specific variable
bitbake -e busybox | grep ^SRC_URI=
bitbake -e busybox | grep ^WORKDIR=
# Show all variables for an image
bitbake -e core-image-minimal | grep ^IMAGE_INSTALL=
Kernel Development
Kernel Configuration
# Open kernel menuconfig
bitbake linux-yocto -c menuconfig
# Save config as defconfig
bitbake linux-yocto -c savedefconfig
# View kernel config diff from default
bitbake linux-yocto -c diffconfig
# Generate config fragment
# (Useful for layer customizations)
bitbake linux-yocto -c kernel_configme
Kernel Development Workflow
# Enter kernel development shell
bitbake linux-yocto -c devshell
# Rebuild kernel only (after manual changes)
bitbake linux-yocto -C compile
# Deploy kernel without full image rebuild
bitbake linux-yocto -c deploy
Image Types
# Common image formats configured in local.conf
IMAGE_FSTYPES = "tar.bz2 ext4 wic"
# Create UBI image (for NAND flash)
IMAGE_FSTYPES = "ubi ubifs"
# Create JFFS2 image
IMAGE_FSTYPES = "jffs2"
# WIC image (partition layout)
IMAGE_FSTYPES = "wic wic.bmap"
UBI/UBIFS for NAND Flash
# In local.conf or image recipe
MKUBIFS_ARGS = "-m 2048 -e 126976 -c 2047"
UBINIZE_ARGS = "-m 2048 -p 128KiB -s 2048"
# Build UBI image
bitbake core-image-minimal
# Output: tmp/deploy/images/machine/core-image-minimal-machine.ubi
Using devtool
devtool simplifies recipe development:
# Modify existing recipe (extracts source for editing)
devtool modify busybox
# Build modified recipe
devtool build busybox
# Create patch and update recipe
devtool finish busybox ../meta-mylayer
# Create new recipe from source
devtool add myapp https://github.com/user/myapp.git
# Reset devtool workspace
devtool reset busybox
Important Variables
# In conf/local.conf
# Target machine
MACHINE = "raspberrypi4"
# Distribution
DISTRO = "poky"
# Number of parallel tasks
BB_NUMBER_THREADS = "8"
# Number of parallel make jobs
PARALLEL_MAKE = "-j 8"
# Extra packages to include
IMAGE_INSTALL:append = " vim curl wget"
# Package format
PACKAGE_CLASSES = "package_ipk"
# Download directory (shared across builds)
DL_DIR = "/opt/yocto/downloads"
# Shared state cache
SSTATE_DIR = "/opt/yocto/sstate-cache"
# Build artifacts
TMPDIR = "${TOPDIR}/tmp"
Creating a Custom Layer
# Create layer structure
bitbake-layers create-layer ../meta-mylayer
cd ../meta-mylayer
# Structure:
# meta-mylayer/
# ├── conf/
# │ └── layer.conf
# ├── recipes-example/
# │ └── example/
# │ └── example_0.1.bb
# └── README
# Add layer to build
cd ../build
bitbake-layers add-layer ../meta-mylayer
Example Recipe
# meta-mylayer/recipes-myapp/myapp/myapp_1.0.bb
SUMMARY = "My custom application"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=..."
SRC_URI = "https://example.com/myapp-${PV}.tar.gz"
SRC_URI[sha256sum] = "..."
inherit autotools
# Or for simple Makefile projects:
inherit cmake
Debugging Builds
# Verbose output
bitbake -v busybox
# Debug output
bitbake -D busybox
# Very debug
bitbake -DD busybox
# Show what would be built
bitbake -n busybox
# Show task dependencies
bitbake -g busybox
# Creates task-depends.dot
# Enter shell in build directory
bitbake busybox -c devshell
# Continue after failure
bitbake -k core-image-minimal
# Parse only (check for errors)
bitbake -p
Tips & Best Practices
- Use shared download and sstate directories across builds
- Create a custom layer for all modifications
- Use
:appendand:removeinstead of overwriting variables - Keep local.conf minimal; put customizations in layers
- Use recipe version suffixes for multiple versions
# Good: Append to variables
IMAGE_INSTALL:append = " vim"
# Bad: Override entire variable
IMAGE_INSTALL = "packagegroup-core-base vim"
# Use bbappend for modifications
# meta-mylayer/recipes-core/busybox/busybox_%.bbappend
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
SRC_URI:append = " file://my-config.cfg"
Resources
Need help with embedded Linux development? Contact us for consulting.