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 pattern → collection 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?
BBLAYERSis a space-separated list of absolute paths to layer directories, defined inbuild/conf/bblayers.conf. BitBake reads this variable at startup to discover all active layers. Each path must point to a directory containingconf/layer.conf. The order of paths inBBLAYERSmatters only in edge cases — the real priority is determined byBBFILE_PRIORITY_*in each layer’slayer.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 higherBBFILE_PRIORITYvalue, ignoring the lower-priority one. If priorities are equal, the result is non-deterministic..bbappendfiles 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
.bbappendfile in your layer. For example, to modifycurl: createmeta-myproduct/recipes-support/curl/curl_%.bbappend. The%wildcard matches any version, making the append version-agnostic. Inside, setFILESEXTRAPATHS:prependif you need to add local files, then append toSRC_URIfor patches, override variables, or append to task functions with:append. This is always preferable to copying the.bbfile 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_COMPATdeclares 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 withBB_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>.confcontains 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 (notlocal.conf) because it is shared across all developers and CI systems building for that board —local.confis developer-local and git-ignored. Any developer who setsMACHINE = "myboard"in theirlocal.confautomatically 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 |