Custom Meta Layers, Recipes and Images in Yocto Project (hello-world Examples)
Introduction
The standard approach for customizing a Yocto-based image is to create a custom meta-layer containing the required configurations and build extensions.
This article describes how to create a meta-layer and apply common build customizations. For additional details and advanced topics, refer to the Yocto Project Reference Manual.
This article complies with the Typographic Conventions for Toradex Documentation.
Prerequisites
An image built by following one of the articles below:
Throughout this article, the build directory is assumed to be the current working directory unless otherwise specified. All commands and relative paths are referenced from this location.
The instructions in this article target NXP-based System on Modules (SoMs). When working with TI-based modules, replace the linux-toradex recipe with linux-toradex-ti and use the corresponding meta layers. Make sure to adjust the instructions accordingly.
Yocto Directory Structure
After completing the build, the Yocto workspace will have the following structure:
.
├── build/
│ ├── buildhistory/
│ ├── cache/
│ ├── conf/
│ ├── deploy/
│ └── tmp/
├── export
└── layers/
├── meta-arm/
├── meta-freescale/
├── meta-ti/
(... other layers)
└── openembedded-core/
By the end of this article, you will have created a custom meta-layer in the layers directory. This layer contains recipes, configurations, and appends to existing recipes, enabling customization of the output image.
For details about each Yocto directory, refer to the Yocto Source Directory Structure documentation.
Create a Meta-Layer
To run bitbake commands, source the environment setup script for your Yocto build environment:
$ source export
$ source setup-environment
After running the source command, the shell changes to the build directory. Run all bitbake commands from this shell session to ensure the environment is properly configured.
To create a custom meta-layer, follow the instructions below:
-
Use the
bitbake-layerscommand to create a layer from an existing template:$ bitbake-layers create-layer ../layers/meta-customerThe new meta-layer will be generated with an example recipe:
meta-customer
├── COPYING.MIT
├── README
├── conf
│ └── layer.conf
└── recipes-example
└── example
└── example_0.1.bb -
Update the
BBLAYERSvariable inconf/bblayers.confto include the created layer.Do not replace the entire file, only append the new layer path to the existing
BBLAYERSvariable, as highlighted below:bblayers.conf# LAYER_CONF_VERSION is increased each time build/conf/bblayers.conf
# changes incompatibly
LCONF_VERSION = "7"
BBPATH = "${TOPDIR}"
BBFILES ?= ""
BBLAYERS_NXP ?= " \
${TOPDIR}/../layers/meta-toradex-nxp \
${TOPDIR}/../layers/meta-freescale \
${TOPDIR}/../layers/meta-freescale-3rdparty \
"
BBLAYERS_TI ?= " \
${TOPDIR}/../layers/meta-toradex-ti \
${TOPDIR}/../layers/meta-arm/meta-arm-toolchain \
${TOPDIR}/../layers/meta-arm/meta-arm \
${TOPDIR}/../layers/meta-ti/meta-ti-bsp \
${TOPDIR}/../layers/meta-ti/meta-ti-extras \
"
BBLAYERS ?= " \
${BBLAYERS_NXP} \
${BBLAYERS_TI} \
\
${TOPDIR}/../layers/meta-toradex-bsp-common \
\
${TOPDIR}/../layers/meta-openembedded/meta-oe \
${TOPDIR}/../layers/meta-openembedded/meta-filesystems \
${TOPDIR}/../layers/meta-openembedded/meta-networking \
${TOPDIR}/../layers/meta-openembedded/meta-multimedia \
${TOPDIR}/../layers/meta-openembedded/meta-python \
${TOPDIR}/../layers/meta-freescale-distro \
${TOPDIR}/../layers/meta-toradex-demos \
${TOPDIR}/../layers/meta-qt5 \
${TOPDIR}/../layers/meta-security/meta-tpm \
\
${TOPDIR}/../layers/meta-toradex-distro \
${TOPDIR}/../layers/meta-yocto/meta-poky \
${TOPDIR}/../layers/openembedded-core/meta \
${TOPDIR}/../layers/meta-customer \
"warningThe
bitbake-layerscommand can be used to add a layer toconf/bblayers.conf, but it updates the file with absolute paths. To keep the setup portable, add the layer manually as shown above, using relative paths. -
Initialize a Git repository for the new layer. This step is required for Torizon builds, but optional for standard Yocto builds.
$ cd ../layers/meta-customer
$ git init
$ git add .
$ git commit -m "Initial Commit" -m "Add meta-customer from template"On Torizon OS, all custom layers must be version-controlled with Git, as OSTree includes layer revision information. If a layer is not initialized as a Git repository, BitBake will fail with an error similar to the following:
WARNING: Failed to get layers information. Exception: <class 'bb.process.ExecutionError'>
WARNING: torizon-core-docker-1.0-r0 do_image_ostreecommit: Failed to get layers information. Exception: <class 'bb.process.ExecutionError'>
ERROR: torizon-core-docker-1.0-r0 do_image_ostreecommit: Execution of '/workdir/build-torizon/tmp-torizon/work/apalis_imx8-tdx-linux/torizon-core-docker/1.0-r0/temp/run.do_image_ostreecommit.290621' failed with exit code 1:
error: Parsing oe.layers=None : 0:expected value
WARNING: exit code 1 from a shell command.
Working With Non-Git Revision Systems
Toradex only supports Git for revision control with OSTree, and therefore for Torizon. If you use a different version control system, consider the following workarounds:
-
Initialize a local only Git repository for the custom layer, without linking it to a remote repository.
-
Mirror the project to a Git repository and use the repository for builds. This approach provides proper layer revision information in OSTree, which is important for enabling over-the-air (OTA) updates.
-
Add support for your version control system by modifying image_type_torizon.bbclass file. This file defines how layer revision information is extracted for OSTree, and can be edited to support a specific revision control system. Toradex is open to reviewing and accepting patches that add support for additional revision control systems.
These workarounds are not officially supported by Toradex.
For the best compatibility with Torizon tools and systems, especially when using OTA update features, it is highly recommended to use Git for revision control.
Third-Party Meta-Layers
In addition to creating custom meta-layers, existing layers may be included in the build to provide additional packages, configurations, or features. The OpenEmbedded Layer Index is a web interface that provides a list of available layers and recipes that can be added to an image.
When adding a layer, make sure to check the compatibility with other layers in the build, as well as with the Arm architecture used in Toradex's modules. Some layers or recipes may target different architectures.
Refer to the Java Virtual Machine documentation for an example of adding the OpenJDK meta-layer to a custom image.
Create a Recipe
After creating a meta-layer, create a hello-world recipe as shown below. The double directory structure hello-world/hello-world/ is intentional: the top-level directory contains the recipe, while the subdirectory contains the source files.
$ cd ../layers/meta-customer/
$ mkdir -p recipes-customer/hello-world/hello-world
$ touch recipes-customer/hello-world/hello-world_1.0.0.bb
$ touch recipes-customer/hello-world/hello-world/hello-world.c
Update the hello-world_1.0.0.bb recipe file with the following content:
# Package summary
SUMMARY = "Hello, world!"
# License
LICENSE = "MIT"
# License checksum file is always required
LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
# hello-world.c from local file
SRC_URI = "file://hello-world.c"
# Set LDFLAGS options provided by the build system
TARGET_CC_ARCH += "${LDFLAGS}"
# Change source directory to workdirectory where hello-world.c is
S = "${WORKDIR}"
# Compile hello-world from sources, no Makefile
do_compile() {
${CC} -Wall hello-world.c -o hello-world
}
# Install binary to final directory /usr/bin
do_install() {
install -d ${D}${bindir}
install -m 0755 ${S}/hello-world ${D}${bindir}
}
Yocto Project also provides the devtool and recipetool tools to create or modify recipes. Refer to the Yocto Project Reference Manual for more details.
After updating the recipe, modify the hello-world.c source file as follows:
#include <stdio.h>
int main(int argc, char **argv) {
printf("Hello, world!\n");
return 0;
}
After creating the recipe and providing the source file, add the package to the image by appending it to the IMAGE_INSTALL variable in the image configuration file, as shown below:
IMAGE_INSTALL:append = " hello-world"
After adding the package to the image configuration, build the package with the command below. Make sure to run this command from the build directory, where the environment is properly set up:
$ bitbake hello-world
Add Packages to the Image
Unlike most desktop Linux distributions, images built with the Yocto Project typically do not include a package manager. To add a package to an image, the following steps are required:
-
Provide a recipe for the package:
OpenEmbedded provides a large collection of ready-to-use recipes in
../layers/openembedded-core/meta. To check whether a recipe for the desired package already exists, run the following commands:$ cd ../layers/openembedded-core/meta
$ find . -iname "*<package-name>*"If no suitable recipe is found, a new one must be created. Refer to the Create a Recipe section for instructions.
-
Include the recipe in the image:
Once a recipe is available, it must be added to the
IMAGE_INSTALLvariable. Recipe filenames typically follow the format<package-name>_<version>.bb. To install the latest available version, only<package-name>should be specified.To add the package provided by the latest version of the
vimrecipe, add the following line to the image configuration:local.confIMAGE_INSTALL:append = " vim"
After updating the configuration, build or rebuild the image:
$ bitbake <image>
Customize the Kernel
This section describes how to modify the Linux Kernel using Yocto on the Toradex BSP. The following modifications are covered:
- Add a device tree to the Kernel
- Apply a Kernel configuration
- Enable an additional Kernel module
During development, building the Kernel from source can reduce iteration time before integrating changes into the Yocto build. Refer to the Build the Kernel from Source documentation for more information.
To modify the Kernel in Yocto, create a .bbappend file in the meta-customer layer. This file extends the existing Kernel recipe with additional instructions.
At the meta-customer layer, run the following commands to create the required directory structure and the .bbappend file:
$ cd ../layers/meta-customer
$ mkdir -p recipes-kernel/linux/linux-toradex/linux-toradex
$ touch recipes-kernel/linux/linux-toradex/linux-toradex_%.bbappend
Update the .bbappend file as shown below. The ${THISDIR}/${PN} variable expands to the directory corresponding to the recipe name.
FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
$ cd ../layers/meta-customer
$ mkdir -p recipes-kernel/linux/linux-toradex-ti/linux-toradex-ti
$ touch recipes-kernel/linux/linux-toradex-ti/linux-toradex-ti_%.bbappend
Update the .bbappend file as shown below. The ${THISDIR}/${PN} variable expands to the directory corresponding to the recipe name.
FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
To apply changes to a specific kernel version, replace % in the .bbappend filename with the target version.
For example, to target version 5.15, name the .bbappend file as shown below:
recipes-kernel/linux/linux-toradex/linux-toradex_5.15%.bbappendrecipes-kernel/linux/linux-toradex-ti/linux-toradex-ti_5.15%.bbappend
The following subsections describe how to apply additional Kernel customizations. A complete .bbappend example for an NXP-based module is provided below.
Additional files included in the recipe must be listed in the SRC_URI variable using the file:// prefix. This prefix instructs BitBake to search for these files in the paths defined by FILESEXTRAPATHS. Therefore, all referenced files should be placed in the ../layers/meta-customer/recipes-kernel/linux/linux-toradex directory.
FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
# Prevent the use of in-tree defconfig
unset KBUILD_DEFCONFIG
CUSTOM_DEVICETREE = "my-custom-devicetree-file.dts"
SRC_URI += " \
file://${CUSTOM_DEVICETREE} \
file://custom-display.patch \
file://defconfig \
"
do_configure:append() {
# For arm32 bit devices
# cp ${WORKDIR}/${CUSTOM_DEVICETREE} ${S}/arch/arm/boot/dts
# For arm64 bit freescale/NXP devices
cp ${WORKDIR}/${CUSTOM_DEVICETREE} ${S}/arch/arm64/boot/dts/freescale
}
Add a Patch to the Kernel
To apply a patch to the Kernel, follow the instructions below:
-
Add a
.patchfile in the../layers/meta-customer/recipes-kernel/linux/linux-toradexdirectory. It is possible to generate the patch usinggit difforgit format-patch, or create it manually. The example below shows a patch that adds a custom display mode to thepanel-simpledriver. Ensure the file name ends with the.patchextension.custom-display.patchdiff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index e817a71062dbb..2d9f1ca8a04bb 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -2053,6 +2053,31 @@ static const struct panel_desc winstar_wf35ltiacd = {
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
};
+static const struct drm_display_mode custom_display_mode = {
+ .clock = 6410,
+ .hdisplay = 320,
+ .hsync_start = 320 + 20,
+ .hsync_end = 320 + 20 + 30,
+ .htotal = 320 + 20 + 30 + 38,
+ .vdisplay = 240,
+ .vsync_start = 240 + 4,
+ .vsync_end = 240 + 4 + 3,
+ .vtotal = 240 + 4 + 3 + 15,
+ .vscan = 60,
+ .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
+};
+
+static const struct panel_desc custom_display = {
+ .modes = &custom_display_mode,
+ .num_modes = 1,
+ .bpc = 8,
+ .size = {
+ .width = 80,
+ .height = 63,
+ },
+ .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
+};
+
static const struct of_device_id platform_of_match[] = {
{
.compatible = "ampire,am-480272h3tmqw-t01h",
@@ -2271,6 +2296,9 @@ static const struct of_device_id platform_of_match[] = {
.compatible = "winstar,wf35ltiacd",
.data = &winstar_wf35ltiacd,
}, {
+ .compatible = "custom,display",
+ .data = &custom_display,
+ }, {
/* sentinel */
}
}; -
Append the
.patchfile to theSRC_URIvariable in the.bbappendfile, as shown below:linux-toradex_%.bbappendSRC_URI += " \
file://custom-display.patch \
"BitBake applies files listed in
SRC_URIwith thefile://prefix to the Kernel build process.
Customize the Kernel Configuration
Modify the Kernel Configuration
The following steps describe how to apply additional Kernel configurations.
-
Generate a Kernel configuration using an interactive menu to visualize the
CONFIG_options with thebitbakecommand shown below. If a.cfgfile is already available, skip to step 3.$ bitbake -c menuconfig virtual/kernel -
Save the configuration changes and generate a configuration fragment:
$ bitbake -c diffconfig virtual/kernelBitBake outputs the path to the generated configuration fragment in a
NOTE:message. Copy the resultingfragment.cfgfile to the../layers/meta-customer/recipes-kernel/linux/linux-toradexdirectory.$ cp <path-to-fragment>/fragment.cfg ../layers/meta-customer/recipes-kernel/linux/linux-toradexfragment.cfgCONFIG_LOCALVERSION="-test-version" -
Update the
.bbapendfile to include the configuration fragment in theSRC_URIvariable, as shown below:linux-toradex_%.bbappendunset KBUILD_DEFCONFIG
SRC_URI += " \
file://fragment.cfg \
" -
Build the image and deploy it to the module using the Toradex Easy Installer. After boot, verify the applied configuration:
# uname -r
6.6.119-test-version-7.5.0-devel
Use a Custom Complete Kernel Configuration
The following steps describe how to use a custom defconfig instead of the default configuration.
-
Generate a Kernel configuration using an interactive menu to visualize the
CONFIG_options with thebitbakecommand shown below. If a.cfgfile is already available, skip to step 3.$ bitbake -c menuconfig virtual/kernel -
Save the configuration changes and generate a configuration file:
$ bitbake -c diffconfig virtual/kernelBitBake outputs the path to the generated configuration file in a
NOTE:message. Copy the resultingdefconfigfile to the../layers/meta-customer/recipes-kernel/linux/linux-toradexdirectory.$ cp <path-to-defconfig>/defconfig ../layers/meta-customer/recipes-kernel/linux/linux-toradex -
Update the
.bbapendfile to include thedefconfigfile in theSRC_URIvariable, as shown below:linux-toradex_%.bbappendunset KBUILD_DEFCONFIG
SRC_URI += " \
file://defconfig \
"Some Toradex modules use in-tree
defconfigfiles. UnsettingKBUKBUILD_DEFCONFIGensures that the custom configuration takes precedence.
Customize the Image
Customize U-Boot Environment Variables
The following steps describe how to customize U-Boot environment variables in a Yocto build. This example modifies the bootdelay variable from 1 to 3, increasing the time available to interrupt the boot process.
-
Create a
.bbappendfile for the U-Boot recipe:$ cd ../layers/meta-customer
$ mkdir -p recipes-bsp/u-boot/files
$ touch recipes-bsp/u-boot/files/bootdelay.cfg
$ touch recipes-bsp/u-boot/u-boot-toradex_%.bbappend -
Update the
.cfgand the.bbappendfiles to modify the defaultbootdelayvalue for the target machine:bootdelay.cfgCONFIG_BOOTDELAY=3u-boot-toradex_%.bbappendFILESEXTRAPATHS:prepend := "${THISDIR}/files:"
SRC_URI += " file://bootdelay.cfg "
UBOOT_CONFIG_FRAGMENTS += " bootdelay.cfg" -
Build the image and deploy it to the module using the Toradex Easy Installer. After boot, verify the modified
bootdelayvalue:> printenv bootdelay
bootdelay=3
Add a Custom Device Tree
The following steps describe how to add a custom Device Tree to a Yocto build. This example targets the Verdin iMX8M Plus SoM.
-
Add a custom Device Tree to the
../layers/meta-customer/recipes-kernel/linux/linux-toradexdirectory. Modifying themodelproperty from a default Device Tree can help verify that the custom version is applied correctly:imx8mp-verdin-wifi-dev-custom.dts// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
/*
* Copyright 2022 Toradex
*/
/dts-v1/;
#include "imx8mp-verdin.dtsi"
#include "imx8mp-verdin-wifi.dtsi"
#include "imx8mp-verdin-dev.dtsi"
/ {
model = "Customized Verdin iMX8M Plus WB on Verdin Development Board";
compatible = "toradex,verdin-imx8mp-wifi-dev",
"toradex,verdin-imx8mp-wifi",
"toradex,verdin-imx8mp",
"fsl,imx8mp";
}; -
Create a machine configuration fragment,
<machine>-extra.conf, in the custom layer to include the custom Device Tree in the build. This file should be placed in the../layers/meta-customer/conf/machinedirectory. This file extends the machine configuration by appending the custom Device Tree toKERNEL_DEVICETREEvariable.$ cd ../layers/meta-customer
$ mkdir -p conf/machine
$ touch conf/machine/<machine>-extra.conf<machine>-extra.confKERNEL_DEVICETREE:append = " freescale/imx8mp-verdin-wifi-dev-custom.dts" -
Include the configuration fragment in the layer configuration by adding the following line to the end of
../layers/meta-customer/conf/layer.conf:conf/layer.confinclude conf/machine/verdin-imx8mp-extra.conf -
Configure U-Boot to load the custom Device Tree. Create a
.bbappendfile for the U-Boot recipe and modify thedo_configuretask:$ cd ../layers/meta-customer
$ mkdir -p recipes-bsp/u-boot
$ touch recipes-bsp/u-boot/u-boot-toradex_%.bbappendu-boot-toradex_%.bbappenddo_configure:append() {
# Remove existing fdtfile, if present
sed -i '/"fdtfile=.*\\0" \\/d' ${S}/include/configs/verdin-imx8mp.h
# Add custom fdtfile
sed -i 's/\("fdt_board=.*\\0" \\\)/\0\n "fdtfile=my-custom-devicetree.dtb\\0" \\/' ${S}/include/configs/verdin-imx8mp.h
} -
Build the image and deploy it to the module using the Toradex Easy Installer. After boot, verify the applied Device Tree:
# dmesg | grep "Machine model"
[ 0.000000] Machine model: Customized Verdin iMX8M Plus WB on Verdin Development Board
Add a Custom Device Tree Overlay
The following steps describe how to add and apply a custom Device Tree Overlay to a Yocto build. This subsection assumes a ready-to-use overlay.
To include the overlay in the image, create a .bbappend file to extend the device tree overlay recipe.
-
In the
meta-customerlayer, create the required directory structure, copy the overlay source file, and create the.bbappendfile:$ cd ../layers/meta-customer
$ mkdir -p recipes-kernel/linux/device-tree-overlays
$ cp <path-to-overlay>/<overlay>.dts recipes-kernel/linux/device-tree-overlays/
$ touch recipes-kernel/linux/device-tree-overlays_%.bbappend -
Update the
.bbappendfile as shown below:warningAdding overlays to the
TEZI_EXTERNAL_KERNEL_DEVICETREEvariable overrides the default overlays for the SoM. To retain them, explicitly list the required overlays or modify the recipe to include all overlays, as implemented intoradex-devicetree.bbclass.device-tree-overlays_%.bbappendFILESEXTRAPATHS:prepend := "${THISDIR}/${BPN}:"
CUSTOM_OVERLAYS_SOURCES = " \
<overlay>.dts \
"
CUSTOM_OVERLAYS_BINARIES = " \
<overlay>.dtbo \
"
SRC_URI += " \
file://<overlay>.dts \
"
# Overlays to deploy to the image
TEZI_EXTERNAL_KERNEL_DEVICETREE += " \
${CUSTOM_OVERLAYS_BINARIES} \
"
# Overlays enabled by default
TEZI_EXTERNAL_KERNEL_DEVICETREE_BOOT += " \
${CUSTOM_OVERLAYS_BINARIES} \
"
do_collect_overlays:prepend() {
for DTS in ${CUSTOM_OVERLAYS_SOURCES}; do
cp ${WORKDIR}/${DTS} ${S}
done
} -
Build the image and deploy it to the module using the Toradex Easy Installer. After boot, verify that the custom overlay is present in the
bootdirectory and listed inoverlays.txt:# ls /boot/overlays
<other-overlays> <overlay>.dtbo
# cat /boot/overlays.txt
fdt_overlays=<other-overlays> <overlay>.dtbo
Add a Custom Kernel Module
The following steps describe how to build an image with a custom kernel module. This example targets the Verdin iMX8M Plus SoM.
Although integrating code directly into the Linux kernel is generally preferred, building an out-of-tree module may be required in some cases, for example when the code is not GPLv2-compatible.
-
In the
meta-customerlayer, create a directory for the module and its recipe. The../layers/meta-customer/recipes-kernel/hello-mod/filesdirectory will contain the module source code and theMakefile, while the../layers/meta-customer/recipes-kernel/hello-moddirectory will contain the recipe file.$ cd ../layers/meta-customer
$ mkdir -p recipes-kernel/hello-mod/files
$ touch recipes-kernel/hello-mod/files/hello.c
$ touch recipes-kernel/hello-mod/files/Makefile
$ touch recipes-kernel/hello-mod/hello-mod_1.0.bb -
Place the module source code and required
Makefilein the directory. The example below shows a basic "Hello, World!" module.hello.c#include <linux/module.h>
int init_module(void) {
printk("Hello, World!\n");
return 0;
}
void cleanup_module(void) {
printk("Goodbye, Cruel World!\n");
}
MODULE_LICENSE("GPL");Makefileobj-m := hello.o
SRC := $(shell pwd)
all:
$(MAKE) -C $(KERNEL_SRC) M=$(SRC)
modules_install:
$(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install
clean:
rm -f *.o *~ core .depend .*.cmd *.ko *.mod.c
rm -f Module.markers Module.symvers modules.order
rm -rf .tmp_versions Modules.symversinfoIn the
Makefileabove, each command line under a target must begin with a tab character. Replacing tabs with spaces will cause build errors. -
Update the
hello-mod_1.0.bbrecipe file as shows below. Alternatively, the source code can be fetched from a remote repository.
The
inherit modulemarks the recipe as a kernel module recipe. Therefore, BitBake knows how to use the Makefile and source files to compile the module, without requiring manual build instructions.hello-mod_1.0.bbSUMMARY = "Example of how to build an external Linux kernel module"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
inherit module
SRC_URI = " \
file://Makefile \
file://hello.c \
"
S = "${WORKDIR}"
# The inherit of module.bbclass will automatically name module packages with
# "kernel-module-" prefix as required by the oe-core build environment.
RPROVIDES:${PN} += "kernel-module-hello"
KERNEL_MODULE_AUTOLOAD += " hello"hello-mod_1.0.bbSUMMARY = "Example of how to build an external Linux kernel module"
LICENSE = "GPLv2"
LIC_FILES_CHKSUM = "file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263"
inherit module
SRCREV = "4f082b755fdf2ef8da30adf2dfbca6fc0745cd2f"
SRC_URI = " \
git://github.com/toradex/hello-mod.git;branch=main;protocol=https \
"
PV = "1.0+git${SRCPV}"
S = "${WORKDIR}/git"
RPROVIDES_${PN} += "kernel-module-hello"infoDepending on the module build system, adjustments to the recipe may be required, such as overriding the
do_compiletask or modifying theMakefile. Refer to the Yocto Project documentation for more information. -
Create a machine configuration fragment,
<machine>-extra.conf, in the custom layer to include the module in the build. This file should be placed in the../layers/meta-customer/conf/machinedirectory. In the<machine>-extra.conffile, append the module name to theMACHINE_EXTRA_RDEPENDSvariable.$ cd ../layers/meta-customer
$ mkdir -p conf/machine
$ touch conf/machine/<machine>-extra.conf<machine>-extra.confMACHINE_EXTRA_RDEPENDS += " hello-mod" -
Build the image and deploy it to the module using the Toradex Easy Installer. After boot, verify the module functionality.
The
hellomodule should be loaded automatically. It is possible to stop it withrmmod helloand start it again withmodprobe hello, as shown below:# lsmod | grep hello
hello 12288 0
# dmesg | grep Hello
[ 4.644885] Hello, World!
# rmmod hello
[ 215.797946] Goodbye, Cruel World!
Create an Image
Toradex provides reference images that can be built and deployed for hardware evaluation, especially the tdx-reference-minimal-image. These images enable root access by default and are not hardened, and are therefore not intended for production use without additional customization. For production deployments, create a custom image as described in the following steps.
This section describes how to create a custom image with Yocto using the previously created meta-customer layer.
-
Create a directory for custom image recipes in the
meta-customerlayer and add a recipe file for the custom image:$ cd ../layers/meta-customer
$ mkdir -p recipes-images/images
$ touch recipes-images/images/custom-console-image.bbcustom-console-image.bbSUMMARY = "My Custom Image"
DESCRIPTION = "This is my customized image containing a simple hello-world"
LICENSE = "MIT"
inherit core-image
export IMAGE_BASENAME = "Custom-Console-Image"
MACHINE_NAME ?= "${MACHINE}"
IMAGE_NAME = "${MACHINE_NAME}_${IMAGE_BASENAME}"
SYSTEMD_DEFAULT_TARGET = "graphical.target"
IMAGE_LINGUAS = "en-us"
ROOTFS_PKGMANAGE_PKGS ?= '${@oe.utils.conditional("ONLINE_PACKAGE_MANAGEMENT", "none", "", "${ROOTFS_PKGMANAGE}", d)}'
IMAGE_INSTALL:append = " \
packagegroup-boot \
packagegroup-basic \
udev-extra-rules \
${ROOTFS_PKGMANAGE_PKGS} \
weston weston-init wayland-terminal-launch \
hello-world \
"
IMAGE_DEV_MANAGER = "udev"
IMAGE_INIT_MANAGER = "systemd"
IMAGE_INITSCRIPTS = " "
IMAGE_LOGIN_MANAGER = "busybox shadow" -
Build and deploy the image to the module using the Toradex Easy Installer. After boot, verify that the image is working as expected.
$ bitbake custom-console-image