Yocto virtual packages diagram
Mersad Karimi Avatar

Tags:

Virtual Packages in Yocto Project / OpenEmbedded

Understanding Virtual Packages in Yocto Project / OpenEmbedded


If you are using Yocto, this post will help you learn about Virtual Packages: how they work, why they are useful, and how to create them step by step.

We assume you are already familiar with:

  • Yocto Project setup
  • Basic command of BitBake and recipe syntax

What is a Virtual Package?

Yocto virtual packages diagram

Imagine you have multiple implementations of the same functionality (for example, different kernels such as a real-time kernel, a boot-time optimized kernel, and a kernel without loadable modules). Of course, your final image will include only one kernel, but you may want to keep several implementations in your project, so you can switch between them easily whenever you like.

With Yocto’s Virtual Package mechanism, you can store multiple implementations (along with their versions). By using Virtual Package you can switch implementations by simply changing a variable.

How to Implement a Virtual Package?

The first step in the recipe is defining the PROVIDES variable.
Using PROVIDES, you indicate that the following recipe is one of the implementations of a virtual package.

# Indicate that this recipe provides a virtual/kernel
PROVIDES = "virtual/kernel"

Secondly, use the PREFERRED_PROVIDER variable to select the implementation you want.

# In conf/local.conf:
# Force using linux-rt as the provider for virtual/kernel
PREFERRED_PROVIDER_virtual/kernel = "linux-rt"

With this line, BitBake knows that whenever virtual/kernel is needed, it will build and package linux-rt first, even if other providers are available.

Another useful feature is that you can declare the virtual package as a dependency by DEPENDS += "virtual/kernel".
No matter what provider is going to be chosen for the kernel; the developer can define the kernel as a dependency of a package.

Lock a specific version with PREFERRED_VERSION (optional)

If multiple versions of the same provider exist and you want to pin one, you can use:

# Ensure linux-rt version 5.10.* is chosen (if available)
PREFERRED_VERSION_linux-rt = "5.10.%"

This tells BitBake to prefer the linux-rt provider whose version matches 5.10.*.

Example: Kernel as a Virtual Package

In this case, we have two different implementations of the kernel:

  1. linux-yocto kernel:
DESCRIPTION = "Yocto Project Linux Kernel"
PV = "6.1.0+git${SRCPV}"
PROVIDES = "virtual/kernel"
SRC_URI = "git://git.yoctoproject.org/linux-yocto.git;branch=yocto-6.1;protocol=https"
S = "${WORKDIR}/git"
  1. Real-time kernel:
DESCRIPTION = "Real-time Linux Kernel"
PV = "5.10.0+git${SRCPV}"
PROVIDES = "virtual/kernel"
SRC_URI = "git://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt.git;branch=linux-rt-5.10.y;protocol=https"
S = "${WORKDIR}/git"

As we learned, we can control the selection of implementations by:

PREFERRED_PROVIDER_virtual/kernel = "linux-rt"
# If you want a specific version of linux-rt
PREFERRED_VERSION_linux-rt = "5.10.%"

Virtual Packages in Yocto/OpenEmbedded give you a powerful abstraction layer for managing alternative implementations, whether it is different Linux kernels, bootloaders, or any component with multiple recipe options. By declaring PROVIDES="virtual/" and using PREFERRED_PROVIDER_virtual/, you can seamlessly switch providers without editing every consumer recipe. This results in a cleaner, more modular build environment where you have precise control over which provider and version BitBake builds.