Creating MicroOS Packages with Yocto
The Yocto Project  is a build system based on OpenEmbedded  to create Linux distributions for embedded systems. Poky is the reference distribution for Yocto, and most of the time the developers create Poky derivatives for their systems, reusing and adapting the different Poky layers and recipes, and integrating their own drivers and applications.
openSUSE MicroOS is an inmutable, transactional, rolling release distribution built with the open build service (OBS) . This same build system can be used to create different distributions and packages for already existing ones (like Debian, RedHat or Arch)
In certain domains, Yocto is de-facto reference for developers and integrators, where some manufactures deploy kernel patches and drivers as board support packages (BSP) layers or bitbake recipes. Technically, OBS could be adapted to build those components, but that would not be a simple task, and no one that a Yocto developer can help with.
The other approach would be to see if it is possible to use Yocto to build packages to MicroOS, using the tools and the ecosystem that is more close to them.
Since very early, Yocto supported the integration of third party toolchains, like the Linaro, Arm or Sourcery one. Those SDKs can be downloaded and Yocto configured to use it when creating the sysroot and the distribution packages.
To configure the toolchain some meta files needs to be provided. Over time those meta files conflated into a single project, meta-arm-toolchain, as part of the meta-arm layer .
An older version of this project used this meta-arm-toolchain (a sub-layer of meta-arm), but this required to manually patch the layer so it can find some components from the MicroOS cross compiler. Also the approach of this layer is to re-package certain libraries from the cross compiler and make it available to the target system. This is the correct approach for a distribution that will be compiled form scratch, but not for a distribution that has already binary packages available.
Another problem of the old approach was that the user needs to manually feed the MicroOS libraries that constitute the dependencies of a recipe, deploying then into the sysroot without a clear mechanism.
This initial approach was used to validate the idea that Yocto can indeed be used to build MicroOS packages, and in that regard this was a success.
If you are interested on learning more details about the original idea, you can check the edit history of this page.
A new way
Based on the lessons learned, the new idea is based on three principles:
- Provide of a "microos" Yocto distribution
- Automatically feed the binary RPMs into the sysroot under demand
- Use the cross compiler without extracting any subpackage, using the ones already available in MicroOS
A Yocto distribution allows the management of certain global configuration shared among the current a new recipes, the control of the current version and the definition of the external compiler.
Because MicroOS is already built using OBS, we have already available all the RPM packages of the distribution. The Yocto recipes can be adapted to fetch, unpack and deploy MicroOS packages into the Yocto sysroot. Using "scripts/microos -u" we can update the "meta-microos" recipes into the last MicroOS release, that will point to the current version of package, update the dependencies, providers, licenses and checksum.
New recipes can now "depends" on those MicroOS packages directly, and Yocto will take care of moving the content into the sysroot so can be linked during the "do_compile" task.
Finally, the cross compiler is not polluting anymore the target system. In the previous approach (as done in meta-arm-toolchain) some files and libraries were re-packaged and deployed into the recipe sysroot. As commented that was the correct approach when the distributions is build from source, but with MicroOS we already have those same libraries in different RPMs packages already available. Libraries like glibc, glibc-devel, or the gcc libraries are now used under the MicroOS current version.
The toolchain is deployed as a tarball that contains the cross compiler, binaries and libraries required to compile applications for MicroOS. It is using the same compiler and libraries available for MicroOS, but depending on an older glibc version, so it can be used in different Linux distributions.
Currently, the tool chain is not truly self-contained and there is more work to be done in that regard. The existing toolchain is sufficient to have successful builds in other distributions like Debian, Ubuntu or RedHat.
The installation only requires download on the tarball and place it in the system:
mkdir -p cross-sdk && cd cross-sdk wget https://download.opensuse.org/repositories/home:/aplanas:/yocto/images/cross-sdk.x86_64.tar.xz tar -xJvf cross-sdk.x86_64.tar.xz
This version of the toolchain is under development and will change in the future, but the installation process will remain the same.
There is a version of this same toolchain deployed as a container, and can be installed with Podman:
podman pull registry.opensuse.org/home/aplanas/yocto/containerfile/opensuse/yocto-microos:latest
The container also provides the dependencies required by Yocto, so it is the easiest way to start creating new MicroOS packages. The full documentation of the container can be found in the README file in the OBS project .
The new meta-microos layer contains the definition of the MicroOS distribution in Yocto, the collection of recipes that define openSUSE MicroOS and Tumbleweed, and the configuration file for the external cross compiler.
The layer can be installed directly via git. The main branch represent the last stable version of Poky ("mickledore" at the time of writing this).
There are plenty of information about how to install Yocto . If we are using a Virtual Machine or a physical host, we will need to install some dependencies required by Yocto, like gcc, git and Python. Again refer to the project documentation  for a complete list of requirements.
If you are using the container, those dependencies are already available.
The first step should be to clone the Poky git repository:
git clone git://git.yoctoproject.org/poky -b mickledore
Poky is the reference distribution of Yocto, but also bundle all the OpenEmbedded Core recipes and layers, the relevant bbclass, the bitbake set of tools and the Yocto scripts and documentation.
Instead of working with "master", we will switch to the "mickledore" branch, that will contain the last (as the write of this guide) stable Poky release.
For this release we need to backport a commit from the "master" branch.
cd poky git cherry-pick cc2c3b1b62070db2b84d967ce20a1651fd50b7fb
It is possible that this present a conflict, very easy to resolve. The next Yocto stable release will contain this change by default.
Now we can create the build directory and the configuration files with:
This script is also setting multiple environment variables (including PATH), so we will need to source it every time that we want to work with Yocto.
The first time that this is called it will create the build directory (and place us on it), and the conf/bblayers.conf and conf/local.conf configuration files that we will need to adjust.
For conf/bblayers.conf we need to register the meta-microos and the meta-example (described later) layers, so bitbake can find them during the parsing stage. So be sure that the BBLAYERS variable is something like this:
BBLAYERS ?= " \ ... FULL-PATH/meta-microos \ FULL-PATH/meta-example \ "
For conf/local.conf we need to request the "microos" distribution and set the target as a aarch64 machine. We need to indicate the path of the external toolchain. Add those lines at the end of the file:
DISTRO = "microos" MACHINE ?= "qemuarm64" DEFAULTTUNE = "aarch64" EXTERNAL_TOOLCHAIN = "FULL-PATH/cross-sdk"
Creating a MicroOS package
The last step is to create this "meta-example" layer, that will contain something that we can compile. For the demo I prepared a bare-bones, self contained and with some adjustment to target MicroOS.
The recipe (example-c_0.1.bb) is a default one, that calls the "gcc" compiler directly and generate a binary. By default it will depends on glibc automatically, but others dependencies can be added in the recipe.
This will generate the RPM and place it in tmp/work/aarch64-poky-linux/example/0.1-r0/deploy-rpms/aarch64 inside the build directory. This package can be directly installed in our MicroOS system.
Check this repository to find other examples.
MicroOS and Tumbleweed
The "meta-microos" contains a snapshot to automatically generated recipes for all the packages of Tumbleweed and MicroOS.
We can update those recipes with:
This will update the full set of packages from "pool-tumbleweed" and the subset of those that compose MicroOS in "recipes-microos". The script will also take care of updating the MicroOS version in the distribution file, and "recipes-microos/opensuse_microos.group" file, that contains the list of Tumbleweed packages that compose MicroOS.
The recipes from MicroOS are links to the ones living in the pool directory, but the script will detect update those links when a new package is introduced or removed.
The pool of packages are not visible for Yocto by default. Yocto is not really ready to parse and analyze 50000 recipes at once. To resolve that, beside the split of "recipes-microos", we included other subsets in "recipes-devtools" and "recipes-core".
The first one is the subset of packages that do not belong to the MicroOS group, but that are required in for building new packages (like the compiler, binutils, etc). We can create our own split using the "scripts/import/ tool:
mkdir recipes-my-set ./script/import -r recipes-my-set mylib
This will create links from the pool into the new recipes directory for the requested package and all the dependencies that are missing. In case that the script find multiple providers during the dependency graph closure walk, we can disambiguate them with the "--preferred" parameter.
Yocto also collect the different licenses found during the compilation, including the ones from the MicroOS packages. If a license is not recognized, Yocto is configured by default to stop the compilation and show an error message. If we recognize the license as a valid one, we need to include it in the "license" directory of the "meta-microos" layer to continue the compilation.
Issues and future work
The current status of the project shows that we can have a good integration of MicroOS with Yocto, and that we can generate new packages with it for aarch64 using the same signed packages from the distribution.
But there are some aspects that can be improved.
The current toolchain is not fully self-contained. This should be fixed with PatchELF, to point some libraries from the system into the bundle. But also only C and C++ compilers are provided, missing some others like Fortran, Go or Rust. Other architectures like RISC-V needs to be included.
From the point of view of the Yocto integration, there are more steps that needs to be done in the current direction, like validate recipes that use autotools, provide kernel modules or the generation of a final ISO image.