Supporting multiple build configurations with Yocto
- 18 May, 2025
When adding new MACHINE and DISTRO configurations to Yocto, handling build setup for all of them can become complicated. The increased complexity is especially obvious when new DISTRO configurations are introduced, since different build directories are needed in order to avoid polluting each other’s environment (like we had in the previous post on QEMU NOR SPI).
Having separate build directories also means that builds for both configurations cannot be performed at the same time
using the same bitbake instance, and products of one build cannot be easily used in another build.
Yocto has a solution for this problem: multiconfig.
Tip
Yocto does support dynamic-layers which can
help when different configurations depend on different layers. The same can be accomplished using multiconfig with
BBMASK to mask layers that should not be used for the selected configuration.
Yocto multiconfig
Yocto multiconfig provides a mechanism to specify different configurations, as if having different local.conf files,
but making builds in the same build directory. That way, the shared state cache and download directories are shared
between configurations, which saves both time during build and space on the build machine.
It is also possible to specify that multiconfigs should use different TMPDIR, which is useful when different DISTROs
are used between multiconfigs, in order to avoid polluting each other’s environment.
The multiconfig is defined in the conf/multiconfig directory of a layer or in the build directory. For each
multiconfig option an entry in the BBMULTICONFIG variable of the local.conf should exist. There is also the default
configuration, where configuration stems only from the local.conf file.
Looking to apply the multiconfig for the setup in QEMU SPI NOR post, the default configuration
will cover the regular build running from the eMMC, and a new multiconfig called recovery will be introduced to cover
the build of recovery image. Therefore, the local.conf should contain the following definition
BBMULTICONFIG = "recovery"
The value of the current multiconfig that is used for building can be fetched using BB_CURRENT_MC, so that parameter
can be used in recipes to have conditional includes. Of course, the regular ways to make disctinction between builds,
like MACHINEOVERRIDES or DISTROOVERRIDES still apply, so BB_CURRENT_MC should only be used as a supplement.
Note
The Yocto multiconfig page covers all the details on use of multiconfig with examples.
Example multiconfig
Tip
All of the changes that will be described, plus a few more which are required for this to work, are available in the
scarthgap branch of
meta-mistra and
qemu-sunxi-yocto
repositories in Github.
Continuing our example, the local.conf (from where the default configuration stems) should be configured to specify
the default DISTRO to be mistra-framebuffer and the default MACHINE cubieboard-ng.
DISTRO ?= "mistra-framebuffer"
MACHINE ?= "cubieboard-ng"
The recovery multiconfig will then change DISTRO to mistra-recovery in the conf/multiconfig/recovery.conf file in
the meta-mistra layer.
- recovery.conf
TMPDIR .= "-${BB_CURRENT_MC}"
DISTRO = "mistra-recovery"
MACHINE = "cubieboard-ng"TMPDIR .= "-${BB_CURRENT_MC}"
DISTRO = "mistra-recovery"
MACHINE = "cubieboard-ng"Since different DISTRO is used compared to the default configuration, the TMPDIR is redefined to have multiconfig
value in it, so it is different from the other configurations.
Running builds
After the multiconfig definition is in place, the build is done using bitbake. The format of the target that is built
is mc:<multiconfig>:<recipe>, where <multiconfig> is an empty string for the default configuration.
So, if we want to build the update-image for the default configuration, command would be
bitbake mc::update-image
The command for building the bootloader and mistra-swupdate-recovery for the recovery multiconfig is
bitbake mc:recovery:virtual/bootloader mc:recovery:mistra-swupdate-recovery
And the command to build all these three targets at the same time
bitbake mc::update-image mc:recovery:virtual/bootloader mc:recovery:mistra-swupdate-recovery
The output files for all the targets would be under the same build but different TMPDIR directories (tmp and
tmp-recovery).
Multiconfig task dependencies
Multiconfig also provides a way to specify dependencies between tasks in different configs using mcdepends, which
simplifies integration between different configs.
For instance, if we wanted to include the recovery fitImage in the rootfs of the regular mistra-swupdate (for instance
if we wanted to update the stored fitImage in the SPI NOR flash memory), we could add the following dependency in the
mistra-swupdate.bb
do_rootfs[mcdepends] = "mc::recovery:virtual/kernel:do_deploy"
and copy the file in the ROOTFS_POSTPROCESS_COMMAND
copy_fitimage() {
install -d ${IMAGE_DIR}/usr/share/recovery
install -m 0644 ${TMPDIR}-recovery/deploy/images/cubieboard-ng/fitImage-cubieboard-ng.bin ${IMAGE_DIR}/usr/share/recovery/fitImage
}
ROOTFS_POSTPROCESS_COMMAND += "copy_fitimage"
Things to keep in mind
Multiconfig comes with many benefits, but there are also some things to keep in mind before using them.
With more multiconfigs that are used, the preparation step, where dependencies between tasks and recipes are analyzed, takes much longer every time configuration is changed, since that same step is done for all of the defined multiconfig options, plus the default configuration.
This also means that each of the multiconfig configurations has to be valid for all recipes at the time of building.
Therefore, masking unused parts of layers using BBMASK and scoping recipes that apply to certain configurations using
COMPATIBLE_MACHINE should be done in order to streamline builds.
Summary
This was a short overview on Yocto multiconfig. Multiconfig allows creating separate build configurations and specifying dependencies between them, so they can all be built at the same time and within the same build directory, sharing same download and sstate cache, which saves both time and space.