> ## Content Index
> Fetch the complete content index at: https://www.smallstepsystems.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Setting Up Yocto Projects with kas
- URL: https://www.smallstepsystems.com/setting-up-yocto-projects-with-kas/
- Published: 2022-06-24T15:10:22.000Z
- Updated: 2026-05-26T11:47:45.000Z
- Description: Kas makes Yocto builds simple. Based on a YAML configuration file, kas starts a container, clones the layer repositories, initialises the conf files and starts building. Each Yocto version builds only on specific host Linux versions. The kas container frees Yocto builds from this restriction.
- Author: Burkhard Stubert
- Tags: Embedded Linux, yocto, embedded systems, kas, repo

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](https://www.smallstepsystems.com/qt-embedded-systems-1-build-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` and `local.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](https://kas.readthedocs.io/en/latest/index.html?ref=smallstepsystems.com) 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](https://developer.toradex.com/hardware/verdin-som-family/modules/verdin-imx8m-mini/?ref=smallstepsystems.com) and [Verdin iMX8M Plus](https://developer.toradex.com/hardware/verdin-som-family/modules/verdin-imx8m-plus/?ref=smallstepsystems.com). Like most other SoM and SoC vendors, Toradex don't provide kas configuration files. However, they provide [repo manifest files](https://git.toradex.com/cgit/toradex-manifest.git/?ref=smallstepsystems.com). 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](https://source.android.com/setup/develop/repo?ref=smallstepsystems.com). We follow the description in the section [Repo and Git](https://developer.toradex.com/linux-bsp/how-to/build-yocto/build-a-reference-image-with-yocto-projectopenembedded/?ref=smallstepsystems.com#repo-and-git) to install the repo tool and git on our build computer. The section [First-time configuration](https://developer.toradex.com/linux-bsp/how-to/build-yocto/build-a-reference-image-with-yocto-projectopenembedded/?ref=smallstepsystems.com#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](https://developer.toradex.com/linux-bsp/in-depth/toradex-embedded-linux-support-strategy/?ref=smallstepsystems.com)). At the time of this writing, the last released BSP version is 5.6.0 (see also [the list of available tags](https://git.toradex.com/cgit/toradex-manifest.git/refs/tags?ref=smallstepsystems.com)). 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 and `dunfell` 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 branches `dunfell-5.x.y` and `dunfell`. This revision is close to the HEAD and contains the latest fixes or improvements. The manifest is the candidate to become the next `default.xml`.
- `tdxref/default.xml` points to a certain revision in the branches `dunfell-5.x.y` and `dunfell`. This revision is typically older than the ones in `integration.xml` and `next.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](https://git.toradex.com/cgit/toradex-manifest.git/refs/tags?ref=smallstepsystems.com)).

```
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](https://developer-archives.toradex.com/verdin-sample-phase-over?ref=smallstepsystems.com) 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](https://kas.readthedocs.io/en/latest/userguide.html?ref=smallstepsystems.com#dependencies-installation) 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 type `run-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 type `kas` 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 type `kas-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](https://dev.to/paulasantamaria/introduction-to-yaml-125f?ref=smallstepsystems.com), 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](https://developer.toradex.com/linux-bsp/how-to/build-yocto/build-a-reference-image-with-yocto-projectopenembedded/?ref=smallstepsystems.com) 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

- [Accessing Private Git Repositories from Docker Containers](https://www.smallstepsystems.com/accessing-private-git-repositories-from-docker-containers/). The source code of proprietary applications and Yocto layers is kept in private git repositories. I describe how to clone private git repositories from inside a Docker container.
- [Github repository](https://github.com/bstubert/eu-terminal-distro?ref=smallstepsystems.com) 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](https://github.com/siemens/kas?ref=smallstepsystems.com) on Github.
- Siemens: [Kas User Guide](https://kas.readthedocs.io/en/latest/userguide.html?ref=smallstepsystems.com#dependencies-installation). Everything you need to about kas as a user and a developer.
- Paula Santamaria: [Introduction to YAML](https://dev.to/paulasantamaria/introduction-to-yaml-125f?ref=smallstepsystems.com). A brief introduction into YAML. Good enough to understand the YAML in the kas project configuration files.