all
Stage 10

Yocto Layers

Understand the Yocto Project layer architecture — bblayers.conf, meta-* layer structure, layer.conf and BBPATH, creating a custom meta-layer with BSP support, machine configuration files, and managing layer compatibility.

10 min read
57683 chars

Layer Architecture Overview

{:.gc-basic}

Basic

A layer in the Yocto Project is simply a directory that contains a conf/layer.conf file. That one file is what makes BitBake treat the directory as a layer. Everything else — recipes, classes, machine configs, patches — is optional and organised by convention.

Layers exist to enforce separation of concerns:

Layer type What it contains Who maintains it
OE-core (meta/) Core recipes: libc, gcc, busybox, core image classes OpenEmbedded project
Distro (meta-poky/) Distribution policy: libc choice, default features, naming Yocto Project
BSP (meta-raspberrypi/) Machine configs, kernel recipes, bootloader Board/SoC vendor or community
Application (meta-myproduct/) Product-specific recipes, images, custom packages Your team

This separation means you can update the BSP layer (e.g., pull a new meta-raspberrypi with a security fix) without touching your application layer, and vice versa.

Standard Layers in Poky

# After cloning Poky:
git clone https://git.yoctoproject.org/poky.git -b scarthgap
ls poky/
# bitbake/       ← BitBake engine
# meta/          ← OE-core (thousands of recipes)
# meta-poky/     ← Poky distro configuration
# meta-yocto-bsp/← Reference BSP for a few boards (BeagleBone, genericx86)
# scripts/       ← oe-init-build-env, devtool, wic, etc.

Layer Naming Convention

By convention (not enforcement) layers are named meta-<purpose>:

meta-raspberrypi    ← BSP for Raspberry Pi
meta-openembedded   ← Large collection of extra recipes
meta-qt6            ← Qt6 framework and applications
meta-security       ← Security hardening recipes
meta-mycompany      ← Your company namespace
meta-myproduct      ← Your specific product

bblayers.conf

{:.gc-basic}

Basic

build/conf/bblayers.conf tells BitBake which layers to include in the build. It is the first file BitBake reads after bitbake.conf.

Structure

# build/conf/bblayers.conf

BBLAYERS ?= " \
  /home/dev/poky/meta \
  /home/dev/poky/meta-poky \
  /home/dev/poky/meta-yocto-bsp \
  /home/dev/meta-openembedded/meta-oe \
  /home/dev/meta-openembedded/meta-python \
  /home/dev/meta-openembedded/meta-networking \
  /home/dev/meta-raspberrypi \
  /home/dev/meta-myproduct \
  "

Always use absolute paths. Relative paths cause hard-to-debug failures on CI systems or when the build directory is moved.

Managing Layers with bitbake-layers

# Show currently active layers with their priorities
bitbake-layers show-layers
# layer                 path                          priority
# =================================================================
# meta                  /home/dev/poky/meta           5
# meta-poky             /home/dev/poky/meta-poky      5
# meta-raspberrypi      /home/dev/meta-raspberrypi    9
# meta-myproduct        /home/dev/meta-myproduct      10

# Add a layer (modifies bblayers.conf)
bitbake-layers add-layer /home/dev/meta-myproduct

# Remove a layer
bitbake-layers remove-layer /home/dev/meta-myproduct

# Show all available recipes across all layers
bitbake-layers show-recipes

# Show which layer provides a specific recipe
bitbake-layers show-recipes curl

# Show all .bbappend files and which recipe they append
bitbake-layers show-appends

Layer Compatibility

# Check if layers are compatible with your Yocto release (e.g., scarthgap)
bitbake-layers layerindex-show-depends meta-raspberrypi

# Each layer declares compatible releases:
# LAYERSERIES_COMPAT_meta-raspberrypi = "kirkstone langdale mickledore nanbield scarthgap"

Layer Directory Structure

{:.gc-mid}

Intermediate

A complete BSP + application layer looks like this:

meta-myproduct/
├── conf/
│   ├── layer.conf              ← REQUIRED: makes this a layer
│   ├── machine/
│   │   └── myboard.conf        ← machine-specific variables
│   └── distro/
│       └── mydistro.conf       ← distribution policy
├── recipes-bsp/
│   └── u-boot/
│       └── u-boot_%.bbappend   ← U-Boot customisation
├── recipes-core/
│   └── images/
│       └── myproduct-image.bb  ← custom image recipe
├── recipes-kernel/
│   └── linux/
│       ├── linux-yocto_%.bbappend
│       └── files/
│           └── myboard.cfg     ← kernel config fragment
├── recipes-myapp/
│   └── myapp/
│       ├── myapp_1.4.2.bb
│       └── files/
│           ├── 0001-fix-cross.patch
│           └── myapp.service
├── classes/
│   └── mycompany-signing.bbclass  ← custom build class
└── files/
    └── common-patches/

conf/layer.conf Anatomy

# meta-myproduct/conf/layer.conf

# Add this layer's directory to the BitBake search path
BBPATH .= ":${LAYERDIR}"

# Tell BitBake where to find recipes and appends in this layer
BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \
            ${LAYERDIR}/recipes-*/*/*.bbappend"

# Collection name (must be unique across all layers)
BBFILE_COLLECTIONS += "myproduct"

# File patterncollection mapping (used for priority)
BBFILE_PATTERN_myproduct = "^${LAYERDIR}/"

# Priority: higher number wins when multiple layers have the same recipe
BBFILE_PRIORITY_myproduct = "10"

# Which Yocto releases this layer is tested with
LAYERSERIES_COMPAT_myproduct = "scarthgap"

# Layers this layer depends on (bitbake-layers can check this)
LAYERDEPENDS_myproduct = "core raspberrypi"

# Layer version (used by dependent layers to check compatibility)
LAYERVERSION_myproduct = "1"

Recipe Category Directories

The recipes-*/ naming is a convention that makes BBFILES glob patterns work:

recipes-bsp/       ← bootloaders, firmware, board-specific tools
recipes-connectivity/ ← bluetooth, wifi, modems
recipes-core/      ← images, base system, init scripts
recipes-extended/  ← shells, utilities beyond core
recipes-gnome/     ← GNOME desktop components
recipes-kernel/    ← Linux kernel, kernel modules
recipes-multimedia/ ← audio, video, codecs
recipes-myapp/     ← your application packages
recipes-python/    ← Python packages not in OE-core
recipes-support/   ← libraries and utilities supporting others

Creating a Custom Layer

{:.gc-mid}

Intermediate

Using bitbake-layers create-layer

# Source the environment first
source poky/oe-init-build-env build/

# Create a new layer in the parent directory
bitbake-layers create-layer ../meta-myproduct

# What was created:
ls ../meta-myproduct/
# conf/layer.conf
# COPYING.MIT
# README
# recipes-example/
#   example/
#     example_0.1.bb

# Add it to the build
bitbake-layers add-layer ../meta-myproduct

# Verify
bitbake-layers show-layers | grep myproduct
# meta-myproduct  /home/dev/meta-myproduct  6

Minimum Viable layer.conf

# meta-myproduct/conf/layer.conf
BBPATH .= ":${LAYERDIR}"
BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \
            ${LAYERDIR}/recipes-*/*/*.bbappend"
BBFILE_COLLECTIONS += "myproduct"
BBFILE_PATTERN_myproduct = "^${LAYERDIR}/"
BBFILE_PRIORITY_myproduct = "10"
LAYERSERIES_COMPAT_myproduct = "scarthgap"

Adding a First Recipe

mkdir -p ../meta-myproduct/recipes-myapp/myapp
cat > ../meta-myproduct/recipes-myapp/myapp/myapp_1.0.0.bb << 'EOF'
SUMMARY = "My embedded application"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"

SRC_URI = "git://github.com/myorg/myapp.git;protocol=https;branch=main"
SRCREV = "abc123def456abc123def456abc123def456abc1"
PV = "1.0.0+git${SRCPV}"

S = "${WORKDIR}/git"

inherit autotools

EXTRA_OECONF = "--enable-daemon"
EOF

# Build it
bitbake myapp

# Check it builds cleanly
bitbake -c cleanall myapp && bitbake myapp

Machine Configuration

{:.gc-adv}

Advanced

The machine configuration file defines everything hardware-specific. MACHINE in local.conf (or the image recipe) selects which .conf file is loaded.

# In build/conf/local.conf:
MACHINE = "myboard"
# BitBake looks for: conf/machine/myboard.conf in any layer

Full Machine Config Example

# meta-myproduct/conf/machine/myboard.conf
# Custom ARM Cortex-A53 quad-core board

#@TYPE: Machine
#@NAME: My Company Board v2
#@DESCRIPTION: Machine configuration for MyBoard rev2 with BCM2711-equivalent SoC

# Inherit a common ARM base if available
require conf/machine/include/arm/armv8a/tune-cortexa53.inc

# Kernel
PREFERRED_PROVIDER_virtual/kernel = "linux-myboard"
PREFERRED_VERSION_linux-myboard = "6.6%"
KERNEL_IMAGETYPE = "Image"       # AArch64 uncompressed
# KERNEL_IMAGETYPE = "zImage"    # ARM 32-bit compressed
KERNEL_DEVICETREE = "myvendor/myboard-v2.dtb"

# Bootloader
PREFERRED_PROVIDER_virtual/bootloader = "u-boot-myboard"
UBOOT_MACHINE = "myboard_defconfig"
UBOOT_ENTRYPOINT = "0x40200000"
UBOOT_LOADADDRESS = "0x40200000"

# Image types to produce
IMAGE_FSTYPES = "ext4 squashfs wic"
WKS_FILE = "myboard-sdcard.wks"

# Console
SERIAL_CONSOLES = "115200;ttyS0 115200;ttyAMA0"
SERIAL_CONSOLES_CHECK = "${SERIAL_CONSOLES}"

# Machine features (drives conditional recipe logic)
MACHINE_FEATURES = "apm usbgadget usbhost vfat alsa wifi bluetooth screen"
# MACHINE_FEATURES_remove = "nfs"  # disable NFS support in the kernel

# Extra packages always installed when this machine is targeted
MACHINE_EXTRA_RDEPENDS = ""
MACHINE_EXTRA_RRECOMMENDS = "kernel-modules"

# Package arch for binary caching
PACKAGE_ARCH = "${MACHINE_ARCH}"

tune-cortexa53.inc Excerpt

# poky/meta/conf/machine/include/arm/armv8a/tune-cortexa53.inc
DEFAULTTUNE ?= "cortexa53"
TUNEVALID[cortexa53] = "Enable Cortex-A53 specific processor optimizations"
TUNE_CCARGS .= "${@bb.utils.contains('TUNE_FEATURES', 'cortexa53', ' -mcpu=cortex-a53', '', d)}"
require conf/machine/include/arm/arch-armv8a.inc
MACHINEOVERRIDES =. "cortexa53:"

BSP Layer for a Custom ARM Board — Full Example

meta-myboard/
├── conf/
│   ├── layer.conf
│   └── machine/
│       └── myboard.conf
├── recipes-kernel/
│   └── linux/
│       ├── linux-myboard_6.6.bb       ← custom kernel recipe
│       ├── linux-myboard_6.6.bbappend ← or bbappend on linux-yocto
│       └── files/
│           ├── defconfig              ← base kernel config
│           ├── myboard.cfg            ← board-specific fragments
│           └── 0001-add-myboard-dts.patch
├── recipes-bsp/
│   └── u-boot/
│       ├── u-boot-myboard_2024.01.bb
│       └── files/
│           └── myboard_defconfig
└── wic/
    └── myboard-sdcard.wks

Layer Priority and BBFILE_PRIORITY

{:.gc-adv}

Advanced

How Priority Works

When multiple layers provide a recipe with the same name and version, BitBake uses BBFILE_PRIORITY to determine which one wins. Higher number = higher priority.

# Default priorities in a typical build:
meta/                5   ← OE-core (lowest — everything overrides this)
meta-poky/           5
meta-openembedded/   5
meta-raspberrypi/    9
meta-myproduct/     10   ← Your layer wins over everything

Critical: Priority only resolves conflicts between exact same-named recipes. .bbappend files from all layers are always applied regardless of priority — they accumulate.

Checking Which Recipe Wins

# Which layer is providing the curl recipe?
bitbake-layers show-recipes curl
# curl:
#   meta          8.7.1 (skipped)   ← lower priority, skipped
#   meta-myproduct  8.7.1            ← this one wins

# Show all bbappend files for curl (all are applied):
bitbake-layers show-appends | grep curl
# curl_8.7.1.bb:
#   /home/dev/meta-myproduct/recipes-support/curl/curl_%.bbappend
#   /home/dev/meta-openembedded/meta-oe/recipes-support/curl/curl_%.bbappend

LAYERDEPENDS

Declare dependencies between layers so bitbake-layers can warn when required layers are missing:

# In meta-myproduct/conf/layer.conf:
LAYERDEPENDS_myproduct = "core openembedded-layer networking-layer raspberrypi"
#                          ^^^   ^^^                ^^^               ^^^
#                   always  meta-oe collection   meta-networking    meta-raspberrypi
# Check dependency satisfaction:
bitbake-layers layerindex-show-depends meta-myproduct

LAYERSERIES_COMPAT — Yocto Release Compatibility

# Declare which Yocto releases your layer is tested with:
LAYERSERIES_COMPAT_myproduct = "kirkstone langdale mickledore nanbield scarthgap"

# BitBake will warn (not error by default) if your release isn't listed:
# WARNING: Layer myproduct is not compatible with the current version of the
# Yocto Project (5.0), layer is compatible with: kirkstone langdale

Finding Layers from the Yocto Layer Index

# Search for a layer providing a recipe
# Via web: layers.openembedded.org

# Via command line (requires internet):
bitbake-layers layerindex-fetch meta-qt6
# Clones the layer and adds it to bblayers.conf

# Show what a layer index layer provides:
bitbake-layers layerindex-show-depends meta-qt6

Interview Q&A

{:.gc-iq}

Interview Q&A

Q1 — Basic: Why should BSP layers and application layers be kept separate?

Separation allows independent versioning and maintenance. A BSP layer (meta-raspberrypi, meta-ti) tracks the hardware platform and is typically maintained by the SoC vendor or a community. An application layer tracks your product’s software. Keeping them separate means you can take a BSP security update without touching your application code, and you can port your application to a new board by swapping the BSP layer without rewriting application recipes. It also makes it easier to share BSP layers with other teams or open-source them while keeping proprietary application code private.

Q2 — Basic: What does BBLAYERS contain and where is it defined?

BBLAYERS is a space-separated list of absolute paths to layer directories, defined in build/conf/bblayers.conf. BitBake reads this variable at startup to discover all active layers. Each path must point to a directory containing conf/layer.conf. The order of paths in BBLAYERS matters only in edge cases — the real priority is determined by BBFILE_PRIORITY_* in each layer’s layer.conf, not by list position.

Q3 — Intermediate: What is the effect of BBFILE_PRIORITY?

When two layers both contain a recipe file with the same name and version (e.g., curl_8.7.1.bb), BitBake builds the one from the layer with the higher BBFILE_PRIORITY value, ignoring the lower-priority one. If priorities are equal, the result is non-deterministic. .bbappend files are not subject to priority resolution — they are all applied additively. Setting your product layer’s priority to 10 (vs OE-core’s 5) ensures that any recipe you provide overrides the upstream version.

Q4 — Intermediate: How do you override a recipe from OE-core without forking it?

Create a .bbappend file in your layer. For example, to modify curl: create meta-myproduct/recipes-support/curl/curl_%.bbappend. The % wildcard matches any version, making the append version-agnostic. Inside, set FILESEXTRAPATHS:prepend if you need to add local files, then append to SRC_URI for patches, override variables, or append to task functions with :append. This is always preferable to copying the .bb file into your layer because upstream changes (security patches, version bumps) continue to apply automatically.

Q5 — Advanced: What is the purpose of LAYERSERIES_COMPAT and what happens if it does not include your Yocto release?

LAYERSERIES_COMPAT declares which Yocto Project release codenames the layer has been tested with. By default, BitBake prints a warning if the currently active release (e.g., scarthgap) is not in the list — the build continues but you are informed the layer may have compatibility issues. You can turn this into a hard error with BB_WARN_LEVEL = "error". Before using a community layer, always check that your target Yocto release is listed, or check the layer’s git branches — most layers have a branch per Yocto release (e.g., scarthgap, kirkstone).

Q6 — Advanced: What goes into conf/machine/<board>.conf and why is it in the BSP layer rather than local.conf?

conf/machine/<board>.conf contains everything that is fixed by the hardware: CPU architecture and tuning (DEFAULTTUNE), kernel provider and image type (KERNEL_IMAGETYPE), device tree blob names, bootloader configuration, console settings (SERIAL_CONSOLES), and hardware capabilities (MACHINE_FEATURES). It belongs in the BSP layer (not local.conf) because it is shared across all developers and CI systems building for that board — local.conf is developer-local and git-ignored. Any developer who sets MACHINE = "myboard" in their local.conf automatically inherits all the correct hardware settings from the BSP layer.


References

{:.gc-ref}

References

Resource Link
Yocto Project Overview and Concepts docs.yoctoproject.org/overview-manual/
Yocto Project Board Support Packages (BSP) Guide docs.yoctoproject.org/bsp-guide/
Yocto Layer Index layers.openembedded.org
Yocto Project Quick Build docs.yoctoproject.org/brief-yoctoprojectqs/
Bootlin Yocto/OE Training bootlin.com/doc/training/yocto
OpenEmbedded Style Guide openembedded.org/wiki/Styleguide