Sysbuild images

Sysbuild can be used to add additional images to builds, these can be added by projects or boards though at present must be Zephyr applications.

Methods of adding images

Images can be added to project or projects in various ways, multiple ways can be used simultaneously, they can be added in the following ways:

Applications

Applications can add sysbuild images using the sysbuild.cmake file in the application directory, the inclusion of images can be controlled with a Kconfig.sysbuild file in the application directory.

Boards

Boards can add sysbuild images by using the sysbuild.cmake file in the board directory, the inclusion of images can be controlled with a Kconfig.sysbuild file in the board directory.

SoCs

SoCs can add sysbuild images by using the sysbuild.cmake file in the soc directory.

Modules

Modules (External projects) can add sysbuild images with the sysbuild-cmake and sysbuild-kconfig options in a module.yml file, see Sysbuild integration for details.

Adding images

Images can be added in one of two ways:

Single unchangeable image

With this setup, the image to be added is fixed to a specific application and cannot be changed (although it cannot be changed to another image, the version of the image itself can be changed by use of a west manifest bringing in a different version of the application repo or from an alternate source, assuming that the image is in it’s own repository).

Note

This method should only be used if the image is locked to a specific interface and has no extensibility.

An example of how to create such an image, this assumes that a Zephyr application has been created:

config MY_IMAGE
        bool "Include my amazing image"
        help
          If enabled, will include my amazing image in the build which does...

Note

Remember to have source "share/sysbuild/Kconfig" in the file if this is being applied in an application Kconfig.sysbuild file.

Additional dependency ordering can be set here if needed, see Adding dependencies among Zephyr applications for details, image configuration can also be set here, see Image configuration for details.

This image can be enabled when building with west like so:

west build -b nrf52840dk/nrf52840 --sysbuild <app> -- -DSB_CONFIG_MY_IMAGE=y

Extensible changeable image

With this setup, the image to be added can be one of any number of possible applications which the user has selection over, this list of selections can also be extended downstream to add additional options for out-of-tree specific applications that are not available in upstream Zephyr. This is more complex to create but is the preferred method for adding images to upstream Zephyr.

config SUPPORT_OTHER_APP
        bool
        # Conditions can be placed here if this application type is only usable on certain platforms
        default y

config SUPPORT_OTHER_APP_MY_IMAGE
        bool
        # Conditions can be placed here if this image is only usable on certain platforms
        default y

choice OTHER_APP
        prompt "Other app image"
        # Defaults can be specified here if a default image should be loaded if e.g. it is supported
        default OTHER_APP_NONE
        depends on SUPPORT_OTHER_APP

config OTHER_APP_IMAGE_NONE
        bool "None"
        help
          Do not Include an other app image in the build.

config OTHER_APP_IMAGE_MY_IMAGE
        bool "my_image"
        depends on SUPPORT_OTHER_APP_MY_IMAGE
        help
          Include my amazing image as the other app image to use, which does...

endchoice

config OTHER_APP_IMAGE_NAME
        string
        default "my_image" if OTHER_APP_IMAGE_MY_IMAGE
        help
          Name of other app image.

config OTHER_APP_IMAGE_PATH
        string
        default "${ZEPHYR_MY_IMAGE_MODULE_DIR}/path/to/my_image" if OTHER_APP_IMAGE_MY_IMAGE
        help
          Source directory of other app image.

Note

Remember to have source "${ZEPHYR_BASE}/share/sysbuild/Kconfig" in the file if this is being applied in an application Kconfig.sysbuild file.

Additional dependency ordering can be set here if needed, see Adding dependencies among Zephyr applications for details, image configuration can also be set here, see Image configuration for details.

This secondary image can be enabled when building with west like so:

west build -b nrf52840dk/nrf52840 --sysbuild <app> -- -DSB_CONFIG_MY_IMAGE=y

This can then be extended by Modules (External projects) like so:

config SUPPORT_OTHER_APP_MY_SECOND_IMAGE
        bool
        default y

choice OTHER_APP

config OTHER_APP_IMAGE_MY_SECOND_IMAGE
        bool "my_second_image"
        depends on SUPPORT_OTHER_APP_MY_SECOND_IMAGE
        help
          Include my other amazing image as the other app image to use, which does...

endchoice

config OTHER_APP_IMAGE_NAME
        default "my_second_image" if OTHER_APP_IMAGE_MY_SECOND_IMAGE

config OTHER_APP_IMAGE_PATH
        default "${ZEPHYR_MY_SECOND_IMAGE_MODULE_DIR}/path/to/my_second_image" if OTHER_APP_IMAGE_MY_SECOND_IMAGE

As can be seen, no additional CMake changes are needed to add an alternative image as the base CMake code will add the replacement image instead of the original image, if selected.

This alternative secondary image can be enabled when building with west like so:

west build -b nrf52840dk/nrf52840 --sysbuild <app> -- -DSB_CONFIG_MY_SECOND_IMAGE=y

Image configuration

Sysbuild supports being able to set image configuration (Kconfig options) and also supports reading the output of image configuration (Kconfig) which can be used to allow an option to be added to sysbuild itself and then to configure it globally or selectively.

Setting image configuration

Kconfig

Sysbuild can be used to set image configuration before the CMake configuration of images takes place. An important note about setting Kconfig options in images is that these are persistent and cannot be changed by the images. The following functions can be used to set configuration on an image:

set_config_bool(<image> CONFIG_<setting> <value>)
set_config_string(<image> CONFIG_<setting> <value>)
set_config_int(<image> CONFIG_<setting> <value>)

For example, to change the default image to output a hex file:

set_config_bool(${DEFAULT_IMAGE} CONFIG_BUILD_OUTPUT_HEX y)

These can safely be used in an application, board or SoC sysbuild.cmake file, as that file is included before the image CMake processes are invoked. When extending sysbuild using modules the pre-CMake hook should be used instead, for example:

function(${SYSBUILD_CURRENT_MODULE_NAME}_pre_cmake)
  cmake_parse_arguments(PRE_CMAKE "" "" "IMAGES" ${ARGN})

  foreach(image ${PRE_CMAKE_IMAGES})
    set_config_bool(${image} CONFIG_BUILD_OUTPUT_HEX y)
  endforeach()
endfunction()

Image configuration script

An image configuration script is a CMake file that can be used to configure an image with common configuration values, multiple can be used per image, the configuration should be transferrable to different images to correctly configure them based upon options set in sysbuild. MCUboot configuration options are configured in both the application the MCUboot image using this method which allows sysbuild to be the central location for things like the signing key which are then kept in-sync in the main application bootloader images.

Inside image configuration scripts, the ZCMAKE_APPLICATION variable is set to the name of the application being configured, the set_config_* sysbuild CMake functions can be used to set configuration and the sysbuild Kconfig can be read, for example:

if(SB_CONFIG_BOOTLOADER_MCUBOOT AND "${SB_CONFIG_SIGNATURE_TYPE}" STREQUAL "NONE")
  set_config_bool(${ZCMAKE_APPLICATION} CONFIG_MCUBOOT_GENERATE_UNSIGNED_IMAGE y)
endif()

Image configuration script (module/application)

Module/application image configuration scripts can be set from module or application code, this must be done in a sysbuild.cmake file for an application. This can be used to add an image configuration script as follows:

# This applies the image configuration script to the default image only
get_property(tmp_conf_scripts TARGET ${DEFAULT_IMAGE} PROPERTY IMAGE_CONF_SCRIPT)
list(APPEND tmp_conf_scripts "${CMAKE_SOURCE_DIR}/image_configurations/MY_CUSTOM_TYPE_image_default.cmake")
set_target_properties(${DEFAULT_IMAGE} PROPERTIES IMAGE_CONF_SCRIPT "${tmp_conf_scripts}")

Image configuration script (Zephyr-wide)

Global Zephyr provided image configuration scripts, which allow specifying the type when using ExternalZephyrProject_Add() require changes to sysbuild code in Zephyr. This should only be added to when adding a new type that any project should be able to select, generally this should only be needed for upstream Zephyr though forked versions of Zephyr might use this to add additional types without restriction.

Image configuration has an allow-list of names which must be set in the Zephyr file share/sysbuild/cmake/modules/sysbuild_extensions.cmake in the ExternalZephyrProject_Add function. After adding a new type, it can be used when adding a sysbuild image, for example:

Full file path: share/sysbuild/cmake/modules/sysbuild_extensions.cmake

# ...
# Usage:
#   ExternalZephyrProject_Add(APPLICATION <name>
#                             SOURCE_DIR <dir>
#                             [BOARD <board> [BOARD_REVISION <revision>]]
#                             [APP_TYPE <MAIN|BOOTLOADER|MY_CUSTOM_TYPE>]
#   )
# ...
# APP_TYPE <MAIN|BOOTLOADER|MY_CUSTOM_TYPE>: Application type.
#                                            MAIN indicates this application is the main application
#                                            and where user defined settings should be passed on as-is
#                                            except for multi image build flags.
#                                            For example, -DCONF_FILES=<files> will be passed on to the
#                                            MAIN_APP unmodified.
#                                            BOOTLOADER indicates this app is a bootloader
#                                            MY_CUSTOM_TYPE indicates this app is...
# ...
function(ExternalZephyrProject_Add)
  set(app_types MAIN BOOTLOADER MY_CUSTOM_TYPE)
# ...

Reading image configuration

Kconfig

Kconfig values from images can be read by sysbuild after the CMake configuration of images has taken place. This can be used to check configuration or to adjust additional sysbuild tasks depending upon configuration. The following function can be used for this purpose:

sysbuild_get(<variable> IMAGE <image> [VAR <image-variable>] KCONFIG)

This function can only be used when sysbuild is extended by a module or inside of a sysbuild/CMakeLists.txt file after find_package(Sysbuild) has been used. An example of outputting values from all images is shown:

function(${SYSBUILD_CURRENT_MODULE_NAME}_post_cmake)
  cmake_parse_arguments(POST_CMAKE "" "" "IMAGES" ${ARGN})

  foreach(image ${POST_CMAKE_IMAGES})
    # Note that the variable to read in to must not be set before using the sysbuild_get() function
    set(tmp_val)
    sysbuild_get(tmp_val IMAGE ${image} VAR CONFIG_BUILD_OUTPUT_HEX KCONFIG)
    message(STATUS "Image ${image} build hex: ${tmp_val}")
  endforeach()
endfunction()