Skip to main content
Version: BSP 7.x.y

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.

info

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
info

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:

  1. Use the bitbake-layers command to create a layer from an existing template:

    $ bitbake-layers create-layer ../layers/meta-customer

    The 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
  2. Update the BBLAYERS variable in conf/bblayers.conf to include the created layer.

    Do not replace the entire file, only append the new layer path to the existing BBLAYERS variable, 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 \
    "
    warning

    The bitbake-layers command can be used to add a layer to conf/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.

  3. 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.

warning

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:

hello-world_1.0.0.bb
# 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}
}
info

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:

hello-world.c
#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:

local.conf
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:

  1. 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.

  2. Include the recipe in the image:

    Once a recipe is available, it must be added to the IMAGE_INSTALL variable. 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 vim recipe, add the following line to the image configuration:

    local.conf
    IMAGE_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
tip

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.

linux-toradex_%.bbappend
FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
info

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%.bbappend
  • recipes-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.

linux-toradex_%.bbappend
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:

  1. Add a .patch file in the ../layers/meta-customer/recipes-kernel/linux/linux-toradex directory. It is possible to generate the patch using git diff or git format-patch, or create it manually. The example below shows a patch that adds a custom display mode to the panel-simple driver. Ensure the file name ends with the .patch extension.

    custom-display.patch
    diff --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 */
    }
    };
  2. Append the .patch file to the SRC_URI variable in the .bbappend file, as shown below:

    linux-toradex_%.bbappend
    SRC_URI += "                \
    file://custom-display.patch \
    "

    BitBake applies files listed in SRC_URI with the file:// prefix to the Kernel build process.

Customize the Kernel Configuration

Modify the Kernel Configuration

The following steps describe how to apply additional Kernel configurations.

  1. Generate a Kernel configuration using an interactive menu to visualize the CONFIG_ options with the bitbake command shown below. If a .cfg file is already available, skip to step 3.

    $ bitbake -c menuconfig virtual/kernel
  2. Save the configuration changes and generate a configuration fragment:

    $ bitbake -c diffconfig virtual/kernel

    BitBake outputs the path to the generated configuration fragment in a NOTE: message. Copy the resulting fragment.cfg file to the ../layers/meta-customer/recipes-kernel/linux/linux-toradex directory.

    $ cp <path-to-fragment>/fragment.cfg ../layers/meta-customer/recipes-kernel/linux/linux-toradex
    fragment.cfg
    CONFIG_LOCALVERSION="-test-version"
  3. Update the .bbapend file to include the configuration fragment in the SRC_URI variable, as shown below:

    linux-toradex_%.bbappend
    unset KBUILD_DEFCONFIG

    SRC_URI += " \
    file://fragment.cfg \
    "
  4. 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.

  1. Generate a Kernel configuration using an interactive menu to visualize the CONFIG_ options with the bitbake command shown below. If a .cfg file is already available, skip to step 3.

    $ bitbake -c menuconfig virtual/kernel
  2. Save the configuration changes and generate a configuration file:

    $ bitbake -c diffconfig virtual/kernel

    BitBake outputs the path to the generated configuration file in a NOTE: message. Copy the resulting defconfig file to the ../layers/meta-customer/recipes-kernel/linux/linux-toradex directory.

    $ cp <path-to-defconfig>/defconfig ../layers/meta-customer/recipes-kernel/linux/linux-toradex
  3. Update the .bbapend file to include the defconfig file in the SRC_URI variable, as shown below:

    linux-toradex_%.bbappend
    unset KBUILD_DEFCONFIG

    SRC_URI += " \
    file://defconfig \
    "

    Some Toradex modules use in-tree defconfig files. Unsetting KBUKBUILD_DEFCONFIG ensures 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.

  1. Create a .bbappend file 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
  2. Update the .cfg and the .bbappend files to modify the default bootdelay value for the target machine:

    bootdelay.cfg
    CONFIG_BOOTDELAY=3
    u-boot-toradex_%.bbappend
    FILESEXTRAPATHS:prepend := "${THISDIR}/files:"

    SRC_URI += " file://bootdelay.cfg "

    UBOOT_CONFIG_FRAGMENTS += " bootdelay.cfg"
  3. Build the image and deploy it to the module using the Toradex Easy Installer. After boot, verify the modified bootdelay value:

    > 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.

  1. Add a custom Device Tree to the ../layers/meta-customer/recipes-kernel/linux/linux-toradex directory. Modifying the model property 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";
    };
  2. 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/machine directory. This file extends the machine configuration by appending the custom Device Tree to KERNEL_DEVICETREE variable.

    $ cd ../layers/meta-customer
    $ mkdir -p conf/machine
    $ touch conf/machine/<machine>-extra.conf
    <machine>-extra.conf
    KERNEL_DEVICETREE:append = " freescale/imx8mp-verdin-wifi-dev-custom.dts"
  3. 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.conf
    include conf/machine/verdin-imx8mp-extra.conf
  4. Configure U-Boot to load the custom Device Tree. Create a .bbappend file for the U-Boot recipe and modify the do_configure task:

    $ cd ../layers/meta-customer
    $ mkdir -p recipes-bsp/u-boot
    $ touch recipes-bsp/u-boot/u-boot-toradex_%.bbappend
    u-boot-toradex_%.bbappend
    do_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
    }
  5. 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.

  1. In the meta-customer layer, create the required directory structure, copy the overlay source file, and create the .bbappend file:

    $ 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
  2. Update the .bbappend file as shown below:

    warning

    Adding overlays to the TEZI_EXTERNAL_KERNEL_DEVICETREE variable 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 in toradex-devicetree.bbclass.

    device-tree-overlays_%.bbappend
    FILESEXTRAPATHS: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
    }
  3. 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 boot directory and listed in overlays.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.

  1. In the meta-customer layer, create a directory for the module and its recipe. The ../layers/meta-customer/recipes-kernel/hello-mod/files directory will contain the module source code and the Makefile, while the ../layers/meta-customer/recipes-kernel/hello-mod directory 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
  2. Place the module source code and required Makefile in 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");
    Makefile
    obj-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.symvers
    info

    In the Makefile above, each command line under a target must begin with a tab character. Replacing tabs with spaces will cause build errors.

  3. Update the hello-mod_1.0.bb recipe file as shows below. Alternatively, the source code can be fetched from a remote repository.


    The inherit module marks 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.bb
    SUMMARY = "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"
    info

    Depending on the module build system, adjustments to the recipe may be required, such as overriding the do_compile task or modifying the Makefile. Refer to the Yocto Project documentation for more information.

  4. 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/machine directory. In the <machine>-extra.conf file, append the module name to the MACHINE_EXTRA_RDEPENDS variable.

    $ cd ../layers/meta-customer
    $ mkdir -p conf/machine
    $ touch conf/machine/<machine>-extra.conf
    <machine>-extra.conf
    MACHINE_EXTRA_RDEPENDS += " hello-mod"
  5. Build the image and deploy it to the module using the Toradex Easy Installer. After boot, verify the module functionality.


    The hello module should be loaded automatically. It is possible to stop it with rmmod hello and start it again with modprobe 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

warning

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.

  1. Create a directory for custom image recipes in the meta-customer layer 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.bb
    custom-console-image.bb
    SUMMARY = "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"
  2. 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
Send Feedback!