How to create your first recipe and enable auto-start using systemd


The Yocto Project consists of recipes, dependencies and metadata to instruct the build system how to build software packages for installation into a target Embedded system.

This tutorial will guide you through generating a basic recipe to add your application to an existing Yocto project build, including the configuration needed to launch a systemd service. Specifically we will launch our new application as a simple service which runs one time at boot.


Step 1: Generate the initial build and verify that it boots

This is a summary of the steps outlined here.

export BRANCH="warrior"
mkdir mender-qemu && cd mender-qemu
repo init -u \
           -m meta-mender-qemu/scripts/manifest-qemu.xml \
           -b ${BRANCH}
repo sync
source setup-environment qemu
MACHINE=qemux86-64 bitbake core-image-base
 ../sources/meta-mender/meta-mender-qemu/scripts/mender-qemu core-image-base

Step 2: Create a custom layer

We will create a custom layer to hold our new recipe. See this tutorial for more details on custom layers.

Please note that the tutorials on this site will re-use this layer and if you have already created this structure by following another tutorial you can skip this step.

Create a new layer called meta-stargazer using the bitbake-layers helper application:

bitbake-layers create-layer ../sources/meta-stargazer

This will create a basic structure in meta-stargazer directory:

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

3 directories, 4 files

Include the layer in our Yocto Project environment:

bitbake-layers add-layer ../sources/meta-stargazer

Step 3: Create a new recipe

We will use the recipetool utility provided by Yocto to generate a new recipe for the GNU Hello program. This package is setup for building properly with autoconf and automake, and Yocto can automatically generate recipes that use these tools.

mkdir ../sources/meta-stargazer/recipes-example/gnuhello
recipetool create \
      -o ../sources/meta-stargazer/recipes-example/gnuhello/

Now verify that it builds.

bitbake hello

Note that the recipe is setup to automatically download the sources from the GNU URL. The recipetool utility can also use URIs from source code management systems such as Git. Additionally, the source code for your recipe can be stored directly in the custom layer but it is considered Yocto best practice to keep it separate and have the recipe download it from the appropriate location.

See the Yocto Project Development Tasks Manual for more details on the recipetool utility.

Now let’s add this to our image, boot and verify that the /usr/bin/hello executable exists.

cat >> conf/local.conf <<EOF
IMAGE_INSTALL_append = " hello "
MACHINE=qemux86-64 bitbake core-image-base
 ../sources/meta-mender/meta-mender-qemu/scripts/mender-qemu core-image-base

Login as root with no password and execute the new binary:

qemux86-64 login: root
root@qemux86-64:~# ls -l /usr/bin/hello
-rwxr-xr-x    1 root     root         34976 Oct 27 12:44 /usr/bin/hello
root@qemux86-64:~# /usr/bin/hello
Hello, world!

Step 4: Modify recipe to add systemd service file.

For this hello-world application, we don’t necessarily need a service file as this application does not provide services to other parts of this system. However, for example purposes, we will create an autostart script to run hello at boot time. The output from this invocation will be available in the systemd logs using the journalctl command. This service file can also be manually invoked at runtime.

First, we will create the service file itself which is read and processed by systemd:

mkdir -p ../sources/meta-stargazer/recipes-example/gnuhello/files/
cat > ../sources/meta-stargazer/recipes-example/gnuhello/files/hello.service <<EOF
Description=GNU Hello World startup script



Now let’s add the recipe settings to integrate this into the systemd configuration for our build:

cat >> ../sources/meta-stargazer/recipes-example/gnuhello/ <<EOF
inherit systemd
SYSTEMD_SERVICE_${PN} = "hello.service"

SRC_URI_append = " file://hello.service "
FILES_${PN} += "${systemd_unitdir}/system/hello.service"

do_install_append() {
  install -d ${D}/${systemd_unitdir}/system
  install -m 0644 ${WORKDIR}/hello.service ${D}/${systemd_unitdir}/system

Now, rebuild, boot and verify that the service started and the output is visible in the systemd logs.

MACHINE=qemux86-64 bitbake core-image-base
 ../sources/meta-mender/meta-mender-qemu/scripts/mender-qemu core-image-base
root@qemux86-64:~# systemctl --no-pager status hello
● hello.service - GNU Hello World startup script
   Loaded: loaded (/lib/systemd/system/hello.service; enabled; vendor preset: enabled)
   Active: inactive (dead) since Sun 2019-10-27 13:56:09 UTC; 52s ago
  Process: 178 ExecStart=/usr/bin/hello (code=exited, status=0/SUCCESS)
 Main PID: 178 (code=exited, status=0/SUCCESS)

Oct 27 13:56:03 qemux86-64 systemd[1]: Started GNU Hello World startup script.
Oct 27 13:56:04 qemux86-64 hello[178]: Hello, world!
Oct 27 13:56:09 qemux86-64 systemd[1]: hello.service: Succeeded.

root@qemux86-64:~# journalctl -u hello --no-pager
-- Logs begin at Sun 2019-10-27 13:55:32 UTC, end at Sun 2019-10-27 13:57:43 UTC. --
Oct 27 13:56:03 qemux86-64 systemd[1]: Started GNU Hello World startup script.
Oct 27 13:56:04 qemux86-64 hello[178]: Hello, world!
Oct 27 13:56:09 qemux86-64 systemd[1]: hello.service: Succeeded.


In this tutorial we covered adding new recipes to Yocto project builds and enabling autostart services with systemd.

For further reading please visit

If this tutorial was useful to you, please press like, or leave a thank you note to the contributor who put valuable time into this and made it available to you. It will be much appreciated!