Search by Tags

Custom meta layers, recipes and images in Yocto Project (hello-world examples)


Article updated at 09 Jun 2020
Subscribe for this article updates


This article describes how you can create a new meta layer, how you can add your own hello-world application in a recipe and how you can create your own image in Yocto Project / OpenEmbedded (from now on only called Yocto Project in this article). We don't go into details, it should only give you an easy introduction on how to start. For further details please read the Yocto Project Mega-Manual.

This article complies to the Typographic Conventions for Torizon Documentation.


  • Compile a Toradex reference image for the Yocto Project, according to OpenEmbedded (core).
    • For starting we recommend compiling the console-tdx-image.

Create a meta layer

Once you have an image compiled as proposed in the section Prerequisites above, create a new meta-customer layer:

Note: bitbake-layers create-layer PATH creates a new layer with a basic directory structure.

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

The new meta layer will be generated with an example recipe:

├── conf
│   └── layer.conf
└── recipes-example
    └── example

3 directories, 4 files

After that you can add the newly created layer to the Yocto Project environment in conf/bblayers.conf:

# LAYER_CONF_VERSION is increased each time build/conf/bblayers.conf
# changes incompatibly
  ${TOPDIR}/../layers/meta-toradex-nxp \
  ${TOPDIR}/../layers/meta-freescale \
  ${TOPDIR}/../layers/meta-freescale-3rdparty \
  ${TOPDIR}/../layers/meta-toradex-tegra \
  ${TOPDIR}/../layers/meta-toradex-bsp-common \
  ${TOPDIR}/../layers/meta-openembedded/meta-oe \
  ${TOPDIR}/../layers/meta-openembedded/meta-filesystems \
  ${TOPDIR}/../layers/meta-openembedded/meta-gnome \
  ${TOPDIR}/../layers/meta-openembedded/meta-xfce \
  ${TOPDIR}/../layers/meta-openembedded/meta-initramfs \
  ${TOPDIR}/../layers/meta-openembedded/meta-networking \
  ${TOPDIR}/../layers/meta-openembedded/meta-multimedia \
  ${TOPDIR}/../layers/meta-openembedded/meta-python \
  ${TOPDIR}/../layers/meta-lxde \
  ${TOPDIR}/../layers/meta-browser \
  ${TOPDIR}/../layers/meta-qt5 \
  ${TOPDIR}/../layers/meta-qt5-extra \
  ${TOPDIR}/../layers/meta-rust \
  ${TOPDIR}/../layers/meta-freescale-distro \
  ${TOPDIR}/../layers/meta-toradex-demos \
  ${TOPDIR}/../layers/meta-toradex-distro \
  ${TOPDIR}/../layers/meta-yocto/meta-poky \
  ${TOPDIR}/../layers/openembedded-core/meta \
  ${TOPDIR}/../layers/layers/meta-customer \

Warning: There would also be a command to add a new layer to bblayer.conf: bitbake-layers add-layer. But this includes the meta layer with absolute paths, which can be avoided by adding it manually.

Create a recipe

Now that we have a meta layer we can create a custom recipe e.g. a hello-world: Note: Having hello-world/hello-world/ is on purpose. The top folder is used for the recipe, while the subfolder is used for the sources.

$ cd layers/meta-customer/
$ mkdir -p recipes-customer/hello-world/hello-world

Create a recipe file recipes-customer/hello-world/

# Package summary
SUMMARY = "Hello World"
# License, for example 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.cpp"
# Change source directory to workdirectory where hello-world.cpp is
S = "${WORKDIR}"
# Compile hello-world from sources, no Makefile
do_compile() {
    ${CXX} -Wall hello-world.cpp -o hello-world
# Install binary to final directory /usr/bin
do_install() {
    install -d ${D}${bindir}
    install -m 0755 ${S}/hello-world ${D}${bindir}

Note: Yocto Project also provides the tools devtool and recipetool to create or change recipes. See the dev-manual for more details.

Add the hello world sources to recipes-customer/hello-world/hello-world/hello-world.cpp:

#include <stdio.h>
int main(int argc, char *argv[]){
    printf("Hello world!\n");
    return 0;

After creating your recipe and providing the sources, you would be able to build the package:

$ cd build/
$ bitbake hello-world

Add the package to an existing image

To add a recipe to an existing image, you can add the additional packages to be installed to build/conf/local.conf. In the following example we add the hello-world from the chapter Create a recipe

IMAGE_INSTALL_append = " hello-world" After that you can rebuild your image e.g. the console-tdx-image. Now it will contain hello-world under /usr/bin/hello-world.

$ bitbake console-tdx-image

Create an image

Toradex provides some reference images which can be built on their own or then directly be installed with the Toradex Easy Installer. But these images are considered reference images and should not be used in products directly, instead one should derive a custom image from them.

Using the meta layer created above, we create a recipe folder for our custom images:

$ cd layers/meta-customer/
$ mkdir -p recipes-images/images/

In that folder, we can create recipes and include-files to create one or multiple images. E.g. we can create a simple console image similar to the console-tdx-image containing the hello-world from the chapter Create a recipe. For that we create the recipes-images/images/

SUMMARY = "My Custom Image"
DESCRIPTION = "This is my customized image containing a simple hello-world"
inherit core-image
#start of the resulting deployable tarball name
export IMAGE_BASENAME = "Custom-Console-Image"
ROOTFS_PKGMANAGE_PKGS ?= '${@oe.utils.conditional("ONLINE_PACKAGE_MANAGEMENT", "none", "", "${ROOTFS_PKGMANAGE}", d)}'
IMAGE_INSTALL_append = " \
    packagegroup-boot \
    packagegroup-basic \
    udev-extra-rules \
    timestamp-service \
    weston weston-init wayland-terminal-launch \
    hello-world \
IMAGE_LOGIN_MANAGER = "busybox shadow"

Finally, we can build the image with:

$ cd build/
$ bitbake custom-console-image