Yocto Image Customization
Learn how to customize Yocto images for your embedded projects, including adding custom packages, configurations, and system services.
Introduction
Yocto image customization allows you to create tailored embedded Linux images for your specific hardware and application requirements. This guide covers various customization techniques for the Rock 5B+ platform.
Image Types and Selection
1. Standard Image Types
# Core images
core-image-minimal # Minimal system
core-image-base # Basic system with tools
core-image-sato # X11-based system
core-image-weston # Wayland-based system
# Development images
core-image-sdk # SDK for development
core-image-toolchain # Cross-compilation tools
core-image-dev # Development tools
# Specialized images
core-image-rt # Real-time system
core-image-multilib # Multi-library support
2. Custom Image Recipe
# custom-image.bb
DESCRIPTION = "Custom embedded image for Rock 5B+"
LICENSE = "MIT"
inherit core-image
# Base packages
IMAGE_INSTALL = "packagegroup-core-boot"
IMAGE_INSTALL += "kernel-modules"
IMAGE_INSTALL += "udev"
# Custom packages
IMAGE_INSTALL += "custom-app"
IMAGE_INSTALL += "custom-service"
IMAGE_INSTALL += "custom-config"
# Development packages
IMAGE_INSTALL += "packagegroup-core-tools-debug"
IMAGE_INSTALL += "gdb gdbserver"
IMAGE_INSTALL += "strace tcpdump"
# Network packages
IMAGE_INSTALL += "packagegroup-core-networking"
IMAGE_INSTALL += "openssh openssh-sftp-server"
IMAGE_INSTALL += "ntp ntpdate"
# Graphics packages
IMAGE_INSTALL += "packagegroup-core-x11"
IMAGE_INSTALL += "xserver-xorg"
IMAGE_INSTALL += "xterm"
# Audio packages
IMAGE_INSTALL += "packagegroup-core-audio"
IMAGE_INSTALL += "alsa-utils"
IMAGE_INSTALL += "pulseaudio"
# System configuration
IMAGE_INSTALL += "custom-systemd-units"
IMAGE_INSTALL += "custom-scripts"
IMAGE_INSTALL += "custom-firmware"
Package Groups
1. Creating Package Groups
# packagegroup-custom.bb
DESCRIPTION = "Custom package group for embedded system"
LICENSE = "MIT"
inherit packagegroup
PACKAGES = "${PN}"
RDEPENDS_${PN} = " \
custom-app \
custom-service \
custom-config \
packagegroup-core-boot \
packagegroup-core-networking \
packagegroup-core-tools-debug \
"
# Optional packages
RDEPENDS_${PN} += "${@bb.utils.contains('DISTRO_FEATURES', 'x11', 'packagegroup-core-x11', '', d)}"
RDEPENDS_${PN} += "${@bb.utils.contains('DISTRO_FEATURES', 'audio', 'packagegroup-core-audio', '', d)}"
2. Conditional Package Groups
# packagegroup-custom-optional.bb
DESCRIPTION = "Optional packages for custom system"
LICENSE = "MIT"
inherit packagegroup
PACKAGES = "${PN}"
# Graphics packages
RDEPENDS_${PN} += "${@bb.utils.contains('DISTRO_FEATURES', 'x11', 'packagegroup-core-x11', '', d)}"
RDEPENDS_${PN} += "${@bb.utils.contains('DISTRO_FEATURES', 'wayland', 'packagegroup-core-wayland', '', d)}"
# Audio packages
RDEPENDS_${PN} += "${@bb.utils.contains('DISTRO_FEATURES', 'audio', 'packagegroup-core-audio', '', d)}"
# Network packages
RDEPENDS_${PN} += "${@bb.utils.contains('DISTRO_FEATURES', 'wifi', 'packagegroup-core-wifi', '', d)}"
RDEPENDS_${PN} += "${@bb.utils.contains('DISTRO_FEATURES', 'bluetooth', 'packagegroup-core-bluetooth', '', d)}"
System Configuration
1. Custom Systemd Units
# custom-systemd-units.bb
DESCRIPTION = "Custom systemd units for embedded system"
LICENSE = "MIT"
inherit systemd
SYSTEMD_SERVICE_${PN} = "custom-app.service"
SYSTEMD_SERVICE_${PN} += "custom-service.service"
FILES_${PN} += "${systemd_system_unitdir}/custom-app.service"
FILES_${PN} += "${systemd_system_unitdir}/custom-service.service"
do_install() {
install -d ${D}${systemd_system_unitdir}
install -m 0644 ${WORKDIR}/custom-app.service ${D}${systemd_system_unitdir}/
install -m 0644 ${WORKDIR}/custom-service.service ${D}${systemd_system_unitdir}/
}
2. Systemd Service Files
# custom-app.service
[Unit]
Description=Custom Application
After=network.target
Wants=network.target
[Service]
Type=simple
User=root
Group=root
WorkingDirectory=/opt/custom-app
ExecStart=/opt/custom-app/custom-app
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
3. Custom Scripts
# custom-scripts.bb
DESCRIPTION = "Custom scripts for embedded system"
LICENSE = "MIT"
inherit allarch
FILES_${PN} = "${bindir}/custom-init"
FILES_${PN} += "${sysconfdir}/init.d/custom-service"
do_install() {
install -d ${D}${bindir}
install -d ${D}${sysconfdir}/init.d
install -m 0755 ${WORKDIR}/custom-init ${D}${bindir}/
install -m 0755 ${WORKDIR}/custom-service ${D}${sysconfdir}/init.d/
}
File System Customization
1. Custom Directories
# custom-filesystem.bb
DESCRIPTION = "Custom filesystem structure"
LICENSE = "MIT"
inherit allarch
FILES_${PN} = "${localstatedir}/custom-app/"
FILES_${PN} += "${sysconfdir}/custom-app/"
FILES_${PN} += "${datadir}/custom-app/"
do_install() {
# Create custom directories
install -d ${D}${localstatedir}/custom-app
install -d ${D}${localstatedir}/log/custom-app
install -d ${D}${sysconfdir}/custom-app
install -d ${D}${datadir}/custom-app
# Set permissions
chmod 755 ${D}${localstatedir}/custom-app
chmod 755 ${D}${localstatedir}/log/custom-app
chmod 755 ${D}${sysconfdir}/custom-app
chmod 755 ${D}${datadir}/custom-app
}
2. Configuration Files
# custom-config.bb
DESCRIPTION = "Custom configuration files"
LICENSE = "MIT"
inherit allarch
FILES_${PN} = "${sysconfdir}/custom-app.conf"
FILES_${PN} += "${sysconfdir}/custom-app.d/"
do_install() {
install -d ${D}${sysconfdir}
install -d ${D}${sysconfdir}/custom-app.d
install -m 0644 ${WORKDIR}/custom-app.conf ${D}${sysconfdir}/
install -m 0644 ${WORKDIR}/*.conf ${D}${sysconfdir}/custom-app.d/
}
3. Firmware and Drivers
# custom-firmware.bb
DESCRIPTION = "Custom firmware for embedded system"
LICENSE = "MIT"
inherit allarch
FILES_${PN} = "${nonarch_base_libdir}/firmware/custom/"
FILES_${PN} += "${nonarch_base_libdir}/firmware/custom-driver/"
do_install() {
install -d ${D}${nonarch_base_libdir}/firmware/custom
install -d ${D}${nonarch_base_libdir}/firmware/custom-driver
install -m 0644 ${WORKDIR}/*.bin ${D}${nonarch_base_libdir}/firmware/custom/
install -m 0644 ${WORKDIR}/*.fw ${D}${nonarch_base_libdir}/firmware/custom-driver/
}
Boot Configuration
1. Bootloader Configuration
# custom-bootloader.bb
DESCRIPTION = "Custom bootloader configuration"
LICENSE = "MIT"
inherit deploy
FILES_${PN} = "${DEPLOY_DIR_IMAGE}/u-boot.img"
FILES_${PN} += "${DEPLOY_DIR_IMAGE}/u-boot.cfg"
do_deploy() {
install -d ${D}${DEPLOY_DIR_IMAGE}
install -m 0644 ${WORKDIR}/u-boot.img ${D}${DEPLOY_DIR_IMAGE}/
install -m 0644 ${WORKDIR}/u-boot.cfg ${D}${DEPLOY_DIR_IMAGE}/
}
2. Kernel Configuration
# custom-kernel.bb
DESCRIPTION = "Custom kernel configuration"
LICENSE = "MIT"
inherit kernel
# Kernel configuration
KERNEL_CONFIG_COMMAND = "oe_runmake_call -C ${S} O=${B} olddefconfig"
KERNEL_CONFIG_COMMAND += " && oe_runmake_call -C ${S} O=${B} menuconfig"
# Custom kernel patches
SRC_URI += "file://0001-custom-kernel-patch.patch"
SRC_URI += "file://0002-enable-custom-driver.patch"
# Kernel modules
KERNEL_MODULE_AUTOLOAD += "custom-driver"
KERNEL_MODULE_AUTOLOAD += "custom-sensor"
3. Device Tree Customization
# custom-device-tree.bb
DESCRIPTION = "Custom device tree for Rock 5B+"
LICENSE = "MIT"
inherit deploy
FILES_${PN} = "${DEPLOY_DIR_IMAGE}/custom.dtb"
FILES_${PN} += "${DEPLOY_DIR_IMAGE}/custom-overlay.dtbo"
do_deploy() {
install -d ${D}${DEPLOY_DIR_IMAGE}
install -m 0644 ${WORKDIR}/custom.dtb ${D}${DEPLOY_DIR_IMAGE}/
install -m 0644 ${WORKDIR}/custom-overlay.dtbo ${D}${DEPLOY_DIR_IMAGE}/
}
Network Configuration
1. Network Services
# custom-network.bb
DESCRIPTION = "Custom network configuration"
LICENSE = "MIT"
inherit allarch
FILES_${PN} = "${sysconfdir}/network/"
FILES_${PN} += "${sysconfdir}/netplan/"
do_install() {
install -d ${D}${sysconfdir}/network
install -d ${D}${sysconfdir}/netplan
install -m 0644 ${WORKDIR}/interfaces ${D}${sysconfdir}/network/
install -m 0644 ${WORKDIR}/custom.yaml ${D}${sysconfdir}/netplan/
}
2. SSH Configuration
# custom-ssh.bb
DESCRIPTION = "Custom SSH configuration"
LICENSE = "MIT"
inherit allarch
FILES_${PN} = "${sysconfdir}/ssh/"
do_install() {
install -d ${D}${sysconfdir}/ssh
install -m 0644 ${WORKDIR}/sshd_config ${D}${sysconfdir}/ssh/
install -m 0600 ${WORKDIR}/ssh_host_rsa_key ${D}${sysconfdir}/ssh/
install -m 0644 ${WORKDIR}/ssh_host_rsa_key.pub ${D}${sysconfdir}/ssh/
}
Security Configuration
1. Firewall Rules
# custom-firewall.bb
DESCRIPTION = "Custom firewall configuration"
LICENSE = "MIT"
inherit allarch
FILES_${PN} = "${sysconfdir}/iptables/"
do_install() {
install -d ${D}${sysconfdir}/iptables
install -m 0644 ${WORKDIR}/iptables.rules ${D}${sysconfdir}/iptables/
install -m 0755 ${WORKDIR}/iptables-restore ${D}${sysconfdir}/iptables/
}
2. User Management
# custom-users.bb
DESCRIPTION = "Custom user accounts"
LICENSE = "MIT"
inherit allarch
FILES_${PN} = "${sysconfdir}/passwd"
FILES_${PN} += "${sysconfdir}/group"
FILES_${PN} += "${sysconfdir}/shadow"
do_install() {
install -d ${D}${sysconfdir}
install -m 0644 ${WORKDIR}/passwd ${D}${sysconfdir}/
install -m 0644 ${WORKDIR}/group ${D}${sysconfdir}/
install -m 0600 ${WORKDIR}/shadow ${D}${sysconfdir}/
}
Performance Optimization
1. System Tuning
# custom-tuning.bb
DESCRIPTION = "System performance tuning"
LICENSE = "MIT"
inherit allarch
FILES_${PN} = "${sysconfdir}/sysctl.conf"
FILES_${PN} += "${sysconfdir}/limits.conf"
do_install() {
install -d ${D}${sysconfdir}
install -m 0644 ${WORKDIR}/sysctl.conf ${D}${sysconfdir}/
install -m 0644 ${WORKDIR}/limits.conf ${D}${sysconfdir}/
}
2. Memory Management
# custom-memory.bb
DESCRIPTION = "Memory management configuration"
LICENSE = "MIT"
inherit allarch
FILES_${PN} = "${sysconfdir}/cgroup/"
FILES_${PN} += "${sysconfdir}/systemd/system/"
do_install() {
install -d ${D}${sysconfdir}/cgroup
install -d ${D}${sysconfdir}/systemd/system
install -m 0644 ${WORKDIR}/cgroup.conf ${D}${sysconfdir}/cgroup/
install -m 0644 ${WORKDIR}/memory.service ${D}${sysconfdir}/systemd/system/
}
Testing and Validation
1. Image Testing
# custom-image-test.bb
DESCRIPTION = "Custom image testing"
LICENSE = "MIT"
inherit core-image
# Test packages
IMAGE_INSTALL += "packagegroup-core-tools-test"
IMAGE_INSTALL += "custom-test-suite"
# Test configuration
IMAGE_INSTALL += "custom-test-config"
IMAGE_INSTALL += "custom-test-scripts"
2. Validation Scripts
# custom-validation.bb
DESCRIPTION = "Image validation scripts"
LICENSE = "MIT"
inherit allarch
FILES_${PN} = "${bindir}/validate-image"
FILES_${PN} += "${bindir}/test-system"
do_install() {
install -d ${D}${bindir}
install -m 0755 ${WORKDIR}/validate-image ${D}${bindir}/
install -m 0755 ${WORKDIR}/test-system ${D}${bindir}/
}
Best Practices
1. Image Organization
- Use descriptive names
- Group related packages
- Maintain consistent structure
- Document customizations
2. Performance Considerations
- Minimize image size
- Optimize boot time
- Reduce memory usage
- Improve responsiveness
3. Security
- Implement proper access controls
- Use secure configurations
- Regular security updates
- Monitor system integrity
Conclusion
Yocto image customization is essential for creating tailored embedded systems. By following this guide and implementing the provided examples, you can create robust and efficient custom images for your projects.
Remember to:
- Test customizations thoroughly
- Document your changes
- Use version control
- Follow best practices
Resources
Happy customizing! 🔧