Kas makes the setup of a Yocto build environment super simple and super fast. We call kas with a project configuration file: kas-container build ./eu-terminal-distro.yml
. Kas starts a Docker container, clones the layer repositories, initialises the Yocto configuration files (local.conf
and bblayers.conf
), and starts building the embedded Linux system. Most Linux BSP providers don’t make a kas configuration file available. I’ll show how to convert a repo manifest file into a kas configuration file in this post.
Introduction
In the post Qt Embedded Systems – Part 1: Building a Linux Image with Yocto, I go through the steps how to build the Linux image for a Raspberry Pi 3.
- We build a Docker container image and run a Linux shell in the container.
- We download the layer repositories as given in a repo manifest file.
- We edit the configuration files
bblayers.conf
andlocal.conf
. - We build the target Linux image in the container.
Each of the four steps consists of a couple of smaller steps that we must execute manually. Setting up a Yocto build environment this way and reaching the point where we can build the target Linux image with BitBake is a tedious process.
Given a project configuration file, kas reduces this process to a single command:
$ kas-container build project-configuration.yml
The project configuration file, which is written in YAML, is very similar to the repo manifest file. It also contains all the information needed for generating the configuration files bblayers.conf
and local.conf
– in contrast to the manifest file. The kas-container
command performs all the four steps from the traditional setup in one go. Super simple and super fast!
My target devices are the Toradex Verdin iMX8M SoMs (System on Module). The kas configuration files work for both the Verdin iMX8M Mini and Verdin iMX8M Plus. Like most other SoM and SoC vendors, Toradex don’t provide kas configuration files. However, they provide repo manifest files. I’ll describe how to create the kas configuration file from the repo manifest files.
Traditional Setup with Repo Manifests
We set up the Yocto build environment in the traditional way with the repo tool. We follow the description in the section Repo and Git to install the repo tool and git on our build computer. The section First-time configuration tells us how to prepare the Yocto build environment. We do not run the commands yet, because we must figure out which version of the Toradex Linux BSP to build.
$ cd /public/Projects/traditional
$ repo init -u https://git.toradex.com/toradex-manifest.git -b dunfell-5.x.y -m tdxref/default.xml
$ repo sync
$ . export
All the Toradex BSPs based on Yocto 3.1 LTS Dunfell have the major version 5. Toradex increment the major version when they move to a new Yocto version. They increment the minor version 5.x quarterly and the patch version 5.x.y for bug and security fixes (see also Toradex Embedded Linux Support Strategy). At the time of this writing, the last released BSP version is 5.6.0 (see also the list of available tags). The repo-init call produces the following directory structure.
# result of "repo init"
.repo/manifests/
base/
integration.xml
pinned.xml # Included by default.xml
bsp/
integration-nxp.xml
integration-tdx.xml
pinned-nxp.xml # Included by default.xml
pinned-tdx.xml # Included by default.xml
tdxref/
default.xml
integration.xml
next.xml
Passing the branch dunfell-5.x.y
to the repo-init call means that we are building the latest revision or nearly the latest revision of this branch. The manifest file defines how close the selected version is to the head of the branch. There are three manifest files for fine-tuning.
tdxref/next.xml
points to the latest revision (HEAD) of the branch of each layer:dunfell-5.x.y
for the Toradex layers anddunfell
for the other layers. As this is the bleeding edge, builds may fail.tdxref/integration.xml
points to a certain revision (commit SHA) in the branchesdunfell-5.x.y
anddunfell
. This revision is close to the HEAD and contains the latest fixes or improvements. The manifest is the candidate to become the nextdefault.xml
.tdxref/default.xml
points to a certain revision in the branchesdunfell-5.x.y
anddunfell
. This revision is typically older than the ones inintegration.xml
andnext.xml
. The manifest defines a stable build that went through more testing than the builds defined by the other manifests. This is the manifest we should use, well, by default.
Working on the development branch dunfell-5.x.y
with the default manifest is the right choice while developing a product. When we release our product, we best use a quarterly release (e.g., 5.6.0). We pass a tag (e.g., refs/tags/5.6.0
) instead of the branch to the repo-init call (see available tags).
repo init -u https://git.toradex.com/toradex-manifest.git -b refs/tags/5.6.0 -m tdxref/default.xml
The SoM revision also decides which BSP versions can be used. 1st-generation Verdin SoMs (e.g., iMX8M Mini V1.0B) only support BSP 5.1.0 and older. 2nd-generation Verdin SoMs (e.g., iMX8M Mini V1.1A and newer, iMX8M Plus V1.0B and newer) support BSP 5.2.0 and newer. The table at the end of the page Verdin Product Family Specification Update gives the details.
The repo-sync command clones the git repositories into the layers/ directory and checks out the branch and revision – as given in the manifest files. It produces the following directory structure.
# result of "repo sync"
layers/
meta-freescale
meta-freescale-3rdparty
meta-freescale-distro
meta-openembedded
meta-qt5
meta-toradex-bsp-common
meta-toradex-demos
meta-toradex-distro
meta-toradex-nxp
meta-toradex-tegra # Not needed for iMX8M
meta-yocto
openembedded-core
If the manifest says that the repository meta-toradex-distro
shall be checked out at the revision cbde028, then we can verify this as follows:
$ cd layers/meta-toradex-distro
$ git show --oneline
cbde028 (HEAD, repo/dunfell-5.x.y, m/dunfell-5.x.y) tdx-base.inc: Bump version number to 5.7.0
...
Sourcing the export
script creates the Yocto configuration files bblayers.conf
and local.conf
.
# result of ". export"
build/conf/
bblayers.conf
local.conf
The XML manifest files are the starting point for creating the kas configuration file. The directory trees under build/conf/
and layers/
are the golden reference. When kas creates the same directory trees with the same contents, the kas configuration file is correct.
Now, it’s time to run the commands from the beginning of this section – with the right branch or tag.
Installing kas
We start the installation with cloning the kas repository in any directory (e.g., /public/Projects
), where we have read and write access as a normal user.
$ cd /public/Projects
$ git clone https://github.com/siemens/kas.git
Kas is written in Python3. We must install Python3, Pip3 and some Python packages.
$ sudo apt install python3 python3-pip
$ sudo pip3 install distro jsonschema kconfiglib PyYAML
If the command
/public/Projects/kas/run-kas --help
doesn’t show any Python error messages but just the usage of run-kas
, our Python installation is OK.
The kas documentation lists four options how to use kas.
- As seen above, we can run the script
/public/Projects/kas/run-kas
from the kas repository. If we add/public/Projects/kas
to$PATH
, we can simply typerun-kas
on the command line. - We can install kas as a system Python script by running
sudo pip3 install .
in the directory/public/Projects/kas
. Then we can typekas
at the Linux prompt. - We can run kas in a container locally with the script
/public/Projects/kas/kas-container
. If we add/public/Projects/kas
to$PATH
, we can simply typekas-container
on the command line. - We can run kas in a container remotely for CI. This is out of scope for this post.
Yocto builds fail, when we run them on too old or on too new host Linux versions. Hence, the first two options will run into problems, as soon as we build target Linux systems with different Yocto versions, e.g., for the next product version or for multipe products. We avoid these problems by running the Yocto builds in a container based on a suitable Linux version. So, we choose the third option with kas-container
.
When we run kas-container
for the first time, it will build a Docker container image. It will run kas commands like shell
, checkout
and build
in the Docker container. All the kas commands take a project configuration file as an argument. So, we need to create one first.
Converting Repo Manifests into Kas Configurations
We create an empty project configuration file in YAML format, say, /public/Projects/terminal-distro/terminal-distro.yml
, and add the following properties.
header:
version: 11
distro: tdx-xwayland
build_system: oe
machine: verdin-imx8mp
target: tdx-reference-multimedia-image
header.version
is the version of the configuration format. 11 is the latest version at the time of writing. The Toradex Linux image tdx-reference-multimedia-image
is based on Toradex’s reference Linux distribution tdx-xwayland
and is built with OpenEmbedded oe
. The target image provides Wayland, Weston, Qt 5, V4L and GStreamer.
The target machine is verdin-imx8m
p for the Verdin iMX8M Plus SoM. The documentation lists 13 NXP SoMs including 2 Verdin, 5 Apalis and 6 Colibri machines for different variants of the iMX6, iMX6ULL, iMX7, iMX8, iMX8X, iMX8M Mini and iMX8M Plus. We must only change the machine to verdin-imx8mm
, apalis-imx6
or colibri-imx7
and the build produces the Linux image for the respective SoM.
Kas adds the distro
and machine
to the local configuration file build/conf/local.conf
.
MACHINE ??= "verdin-imx8mp"
DISTRO ??= "tdx-xwayland"
When we set up a Yocto build environment without kas, we would assign the distro and machine to the environment variables DISTRO
and MACHINE
, respectively, and pass the image name tdx-reference-multimedia-image
to the bitbake
call.
The manifest file tdxref/default.xml
defines which revision from which repository (remote
) the repo tool shall fetch for a given Yocto layer (project
). The entries for the meta-qt5
layer look as follows.
<remote alias="repo" fetch="https://github.com/meta-qt5" name="githq"/>
<project name="meta-qt5.git" path="layers/meta-qt5" remote="githq" revision="5ef3a0ffd3324937252790266e2b2e64d33ef34f" upstream="dunfell"/>
The corresponding entry in the kas configuration file looks like this.
repos:
meta-qt5:
url: "https://github.com/meta-qt5/meta-qt5.git"
refspec: "5ef3a0ffd3324937252790266e2b2e64d33ef34f"
path: "layers/meta-qt5"
The repository ID (here: meta-qt5
) in the project configuration is the project.name
without the file extension. The url
is the concatenation of remote.fetch
and project.name
. The refspec
is the project.revision
. The path
is the project.path
.
The above entry tells kas to clone the repository repository url
into the path
relative to the current working directory and check out the revision refspec
. We can check this by running kas in a work directory of our choice (e.g., /public/Projects/terminal-distro/
) .
$ cd /public/Projects/terminal-distro
$ kas-container checkout ./terminal-distro.yml
2021-09-17 10:20:07 - INFO - kas 2.5 started
...
2021-09-17 10:20:07 - INFO - /work$ git clone -q https://github.com/meta-qt5/meta-qt5.git /work/layers/meta-qt5
2021-09-17 10:20:10 - INFO - Repository meta-qt5 cloned
...
2021-09-17 10:20:10 - INFO - /work/layers/meta-qt5$ git checkout -q b4d24d70aca75791902df5cd59a4f4a54aa4a125 -B dunfell
2021-09-17 10:20:10 - ERROR - Did not find any init-build-env script
We ignore the error at the end for the time being, as it will eventually disappear. A quick check in layers/meta-qt5/
shows that kas checked out the correct revision of the meta-qt5
repository.
$ cd layers/meta-qt5/
$ git show --oneline
5ef3a0f (HEAD, origin/jansa/dunfell, origin/dunfell-next, origin/dunfell) qtdeclarative: Fix build with gcc-11
...
$ cd - # back to working directory
Next, we convert the layers from the manifest file base/pinned.xml
, which is included first by default.xml
.
<remote alias="repo" fetch="https://github.com/openembedded" name="oe"/>
<remote alias="repo" fetch="https://git.yoctoproject.org/git" name="yocto"/>
<project name="bitbake.git" path="layers/openembedded-core/bitbake" remote="oe" revision="0784db7dd0fef6f0621ad8d74372f44e87fef950" upstream="1.46"/>
<project name="meta-openembedded.git" path="layers/meta-openembedded" remote="oe" revision="8ff12bfffcf0840d5518788a53d88d708ad3aae0" upstream="dunfell"/>
<project name="meta-yocto" path="layers/meta-yocto" remote="yocto" revision="7e0063a8546250c4c5b9454cfa89fff451a280ee" upstream="dunfell"/>
<project name="openembedded-core.git" path="layers/openembedded-core" remote="oe" revision="add860e1a69f848097bbc511137a62d5746e5019" upstream="dunfell"/>
We add the four kas entries before meta-qt5
.
repos:
bitbake:
url: "https://github.com/openembedded/bitbake.git"
refspec: "0784db7dd0fef6f0621ad8d74372f44e87fef950"
path: "layers/openembedded-core/bitbake"
meta-openembedded:
url: "https://github.com/openembedded/meta-openembedded.git"
refspec: "8ff12bfffcf0840d5518788a53d88d708ad3aae0"
path: "layers/meta-openembedded"
meta-yocto:
url: "https://git.yoctoproject.org/git/meta-yocto.git"
refspec: "7e0063a8546250c4c5b9454cfa89fff451a280ee"
path: "layers/meta-yocto"
openembedded-core:
url: "https://github.com/openembedded/openembedded-core.git"
refspec: "add860e1a69f848097bbc511137a62d5746e5019"
path: "layers/openembedded-core"
meta-qt5:
...
Kas successfully clones the repositories bitbake
, meta-yocto
and meta-openembedded
but fails when cloning the repository openembedded-core
.
2022-06-24 13:24:42 - INFO - /work/layers/openembedded-core$ git remote set-url origin https://github.com/openembedded/openembedded-core.git
2022-06-24 13:24:42 - ERROR - Command "/work/layers/openembedded-core$ git remote set-url origin https://github.com/openembedded/openembedded-core.git" failed
--- Error summary ---
fatal: not a git repository (or any parent up to mount point /)
Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).
Cloning bitbake
creates a directory tree at layers/openembedded-core/bitbake
. Kas clones the repository openembedded-core
into this existing directory tree – and fails. If we change the order in the project configuration (openembedded-core
first and bitbake
second), the checkout works fine. We remove the layers/
directory before we run kas-container checkout
again to confirm our fix.
When checking out several repositories for the first time, we may encounter an error like this.
2022-06-24 13:28:14 - ERROR - fatal: unable to access 'https://github.com/meta-qt5/meta-qt5.git/': Could not resolve host: github.com
2022-06-24 13:28:14 - ERROR - Command "/work$ git clone -q https://github.com/meta-qt5/meta-qt5.git /work/layers/meta-qt5" failed
If the URL is correct, the error disappears by running kas again. Sometimes we need several runs.
When kas-container checkout
runs without errors, it writes the configuration file bblayers.conf
and local.conf
to the directory build/conf/
. A comparison with their “traditional” counterparts shows that they are not quite right. Let us first fix bblayers.conf
and then local.conf
.
# Traditional bblayers.conf (partial)
BBLAYERS ?= " \
${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 \
...
# New bblayers.conf (partial)
BBLAYERS ?= " \
/work/layers/meta-openembedded \
...
The new bblayers.conf
file should contain eight entries for the sublayers of the layer container meta-openembedded
instead of a single entry for the container itself. meta-openembedded
is not a layer, because it doesn’t provide a layer configuration file conf/layer.conf
. It is a layer container. We list the eight layers for meta-openembedded as follows:
meta-openembedded:
url: "https://github.com/openembedded/meta-openembedded.git"
refspec: "8ff12bfffcf0840d5518788a53d88d708ad3aae0"
path: "layers/meta-openembedded"
layers:
meta-oe:
meta-filesystems:
meta-gnome:
meta-xfce:
meta-initramfs:
meta-networking:
meta-multimedia:
meta-python:
After running kas, bblayers.conf contains the eight layers as desired. Similarly, we specify meta-poky
as the layer for the container meta-yocto
and meta
for openembedded-core
. If we forget to specify the layers, the kas build will complain about a missing conf/layer.conf
file.
ERROR: Unable to parse /work/layers/meta-openembedded/conf/layer.conf: [Errno 2] file /work/layers/meta-openembedded/conf/layer.conf not found
The bblayers.conf
file generated by kas contains an entry for bitbake
, whereas the “traditional” counterpart does not. As bitbake
is neither a layer nor a layer container but just a repository providing the bitbake
source code, we exclude the bitbake
“layer”. This removes the bitbake
entry from bblayers.conf
. Another run of kas confirms this.
bitbake:
url: "https://github.com/openembedded/bitbake.git"
refspec: "0784db7dd0fef6f0621ad8d74372f44e87fef950"
path: "layers/openembedded-core/bitbake"
layers:
bitbake: excluded
We add the remaining layers to the kas configuration based on the manifest files bsp/pinned-nxp.xml
, bsp/pinned-tdx.xml
and tdxref/default.xml
. There shouldn’t be any further problems.
Completing the Yocto Configuration Files
From the project configuration file, kas generates the two Yocto configuration files build/conf/bblayers.conf
and build/conf/local.conf
. These files are not complete yet, as a comparison with their “traditional” counterparts shows. The following entry makes kas add the missing line (marked in bold face) to the beginning of bblayers.conf
– before the definition of the layers.
bblayers_conf_header:
custom-bblayers-conf: |
POKY_BBLAYERS_CONF_VERSION = "1"
We add another three lines (marked in bold face again) to the beginning of local.conf
– before the definitions of the machine and the distro.
local_conf_header:
custom-local-conf: |
ACCEPT_FSL_EULA = "1"
DL_DIR = "/work/downloads"
SSTATE_DIR = "/work/sstate-cache"
The first line accepts the Freescale EULA automatically so that the build doesn’t end up waiting for user input. The second and third line move the downloads and sstate cache out of the build directory /work/build
so that other developers can reuse them, say, over NFS. This saves other developers from rebuilding the whole Linux image themselves. They use most of the build from the fast build server and perform only small incremental builds on their PCs.
As we have done several times before, we test the project configuration with the command
$ kas-container checkout ./terminal-distro.yml
If the command runs without any errors and if the Yocto configuration files and the directory structure are the same as the golden reference, we can build the Linux image.
Building the Linux Image
We build the Linux image specified in the project configuration file terminal-distro.yml
with the command
$ kas-container build ./terminal-distro.yml
The command runs BitBake for the image tdx-reference-multimedia-image
in a Docker container:
/build$ /work/layers/openembedded-core/bitbake/bin/bitbake -c build tdx-reference-multimedia-image
The Yocto build will take a couple of hours to finish.
We can build the SDK with the command
kas-container build ./terminal-distro.yml -c populate_sdk
Kas sets up the Yocto build environment in the container for interactive use with the command
kas-container shell ./terminal-distro.yml
We can then run Yocto commands like bitbake
from the Linux prompt inside the container.
Useful Resources
- Github repository with the complete project configuration file from this post. The README explains how to build the embedded Linux image for the Toradex Verdin iMX8M Plus.
- Kas repository on Github.
- Siemens: Kas User Guide. Everything you need to about kas as a user and a developer.
- Paula Santamaria: Introduction to YAML. A brief introduction into YAML. Good enough to understand the YAML in the kas project configuration files.
Thank you very much, a very useful post. I have never used kas before, all manual Yocto build. You made it crystal clear.
Hello sir, thank you very much for your contribution.
I followed your tutorial step by step and got some errors when building :
WARNING: wayland-protocols-1.20.imx-r0 do_fetch: Failed to fetch URL git://source.codeaurora.org/external/imx/wayland-protocols-imx.git;protocol=https;branch=wayland-protocols-imx-1.20, attempting MIRRORS if available
WARNING: libdrm-2.4.102.imx-r0 do_fetch: Failed to fetch URL git://source.codeaurora.org/external/imx/libdrm-imx.git;protocol=https;nobranch=1;branch=libdrm-imx-2.4.102, attempting MIRRORS if available
This two warning leaded to an error and the build stopped. It’s maybe something to do with codeaurora, is there a way i can change it ?
Thank you in advance.
Hi Amine,
These kind of errors are best “solved” by waiting a couple of hours or even a night and try again. Normally, they are gone by then.
My experience is that the codeaurora servers have more problems on weekends than on weekdays.
Cheers,
Burkhard