Skip to content

Instantly share code, notes, and snippets.

@kergoth
Last active April 12, 2020 19:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kergoth/d2d4f7ed65561e67ef09f258ba73111d to your computer and use it in GitHub Desktop.
Save kergoth/d2d4f7ed65561e67ef09f258ba73111d to your computer and use it in GitHub Desktop.
OpenEmbedded - Metadata Structure - Distro, Machine, Image

OpenEmbedded - Metadata Structure - Distro, Machine, Image

There are 3 major orthogonal axes governing the build:

  • Distro
  • Machine
  • Image

The image solely controls what gets built, via dependency, and in general any image should work with any combination of machine and distro, within reason. When you want to add a random package to your device's image, 90% of the time it belongs in the image recipe, unless it's required to boot the board. The image sets an IMAGE_INSTALL variable, or its related incarnations, to add individual packages to the root filesystem. There also exists an "IMAGE_FEATURES" variable. This is a space separated list of words which governs how the image will be built. In some cases, they affect configuration of the filesystem, but in other cases, it merely selects a group of packages to be installed, as a convenience for the user. The only users of this variable are the image classes that underlie the image recipes.

The machine governs the hardware dependencies throughout the build. It selects what kernel version and recipe to use, what bootloader version and recipe to use (indirectly, usually through COMPATIBLE_MACHINE in the recipes), and so on. It also defines "MACHINE_FEATURES". This is a space separated list of words, used to declare the capabilities of the hardware. There is no specific list of what words are allowed here, and the recipes can look for any word there. There are, however, conventions used, and the behavior of the packagegroup-base recipe, which is a bit special.

packagegroup-base is a rather important, central task, and is included in nearly every image, as it provides a base set of functionality given your machine and distro. I'll return to packagegroup-base in a moment, after we describe the distro.

The notion of a Linux distribution in OE/Yocto context differs slightly from what a traditional Linux distro is – in particular, it generally doesn't govern what the image does (package selection). The rest of it, though, is quite similar. It governs what package management system is in use, and sets a wide variety of variables that control aspects of the build. For example, whether we support NLS, what glibc binary locales to generate, the use of optional classes to change how things build. It also defines an important variable: DISTRO_FEATURES. These are the sorts of decisions that anyone would have to make when creating a Linux distribution. "What do I want to support?"

DISTRO_FEATURES is another space separated list of words without a specific list of what can be defined. Recipes look for words here to control how they build. Another way of describing this variable is a list of things we want to support for the distribution we're producing. For example, whether we want to support "ipv6".

For example, many recipes which can have optional dependency on libx11 will control that dependency based on the inclusion of the 'x11' distro feature.

Finally, there is a variable "COMBINED_FEATURES", which has a very specific purpose. It's intended to hold words which exist in both the machine and distro features. This intersection is where hardware support (e.g. bluetooth) intersects with what the distro chooses to support. In this way, we can ensure that we support the critical pieces of hardware, while leaving certain aspects in the distro's control. For example, the hardware may have a a DAC and ADC, yet the distro might choose to not leverage that capability, and so it leaves out the 'audio' feature.

The packagegroup-base recipe is the main place where distro and machine features intersect. The common pattern is that hardware support for something results in a task being emitted for it, so that task is available to be installed. If the distro also supports that capability, then that task is automatically pulled into default images via dependency from the packagegroup-base and packagegroup-base-extended tasks. This can result in a slightly greedy dependency tree, but ensures that we have what we need to support what the distro wants to support, in any given image. For images that don't care about this, they can choose to not use the packagegroup-base tasks.

It's important to remember that distro, machine, and image are always intended to be orthogonal, and this guides a great deal of what we do. We want any combination of the 3 to work, within reason. So, if a given package is required to boot a board, then it needs to be pulled in via the machine, otherwise use of a different distro would result in non-booting images. If a given package isn't required to boot the board, then it belongs in the hands of the distro or the image, and needs to be considered on a case-by-case basis.

It's also important to remember that the features variables can be seen as statements of intent. It's up to the rest of the metadata – the recipes and classes, to implement what the distro wants, and what the hardware requires/supports. This is why there's no list of what features are "available", as the control of behavior based on these variables lies in the hands of the recipes and classes, not in the configuration metadata.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment