cmake: initial sysbuild / multi image support
This is the initial commit with system build, sysbuild. Using CMake as infrastructure together with the Zephyr sysbuild allows us to support a convenient way of building a sample and allow for extra images to be built as part of a larger system. It uses Kconfig for configuration of image builds. This allows for future extension with additional build images. Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no>
This commit is contained in:
parent
542aad5ac3
commit
9d6cc39d6f
5 changed files with 324 additions and 0 deletions
|
@ -725,6 +725,7 @@ scripts/build/gen_image_info.py @tejlmand
|
|||
/scripts/build/uf2conv.py @petejohanson
|
||||
/scripts/build/user_wordsize.py @cfriedt
|
||||
/scripts/valgrind.supp @aescolar @daor-oti
|
||||
/share/sysbuild/ @tejlmand
|
||||
/share/zephyr-package/ @tejlmand
|
||||
/share/zephyrunittest-package/ @tejlmand
|
||||
/subsys/bluetooth/ @alwa-nordic @jhedberg @Vudentz
|
||||
|
|
42
share/sysbuild/CMakeLists.txt
Normal file
42
share/sysbuild/CMakeLists.txt
Normal file
|
@ -0,0 +1,42 @@
|
|||
# Copyright (c) 2021 Nordic Semiconductor
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
if(NOT DEFINED APP_DIR)
|
||||
message(FATAL_ERROR "No main application specified")
|
||||
endif()
|
||||
|
||||
# This will update the APP_DIR cache variable to PATH type and apply a comment.
|
||||
# If APP_DIR is a relative path, then CMake will adjust to absolute path based
|
||||
# on current working dir.
|
||||
set(APP_DIR ${APP_DIR} CACHE PATH "Main Application Source Directory")
|
||||
|
||||
# Add sysbuild/cmake/modules to CMAKE_MODULE_PATH which allows us to integrate
|
||||
# sysbuild CMake modules with general Zephyr CMake modules.
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake/modules)
|
||||
# List of Zephyr and sysbuild CMake modules we need for sysbuild.
|
||||
# Note: sysbuild_kconfig will internally load kconfig CMake module.
|
||||
set(zephyr_modules extensions sysbuild_extensions python west root zephyr_module boards shields sysbuild_kconfig)
|
||||
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE} COMPONENTS ${zephyr_modules})
|
||||
|
||||
project(sysbuild LANGUAGES)
|
||||
|
||||
# Global list of images enabled in this multi image build system.
|
||||
set(IMAGES)
|
||||
|
||||
get_filename_component(APP_DIR ${APP_DIR} ABSOLUTE)
|
||||
get_filename_component(app_name ${APP_DIR} NAME)
|
||||
|
||||
# This adds the primary application to the build.
|
||||
ExternalZephyrProject_Add(
|
||||
APPLICATION ${app_name}
|
||||
SOURCE_DIR ${APP_DIR}
|
||||
MAIN_APP
|
||||
)
|
||||
|
||||
# This allows for board and app specific images to be included.
|
||||
include(${BOARD_DIR}/sysbuild.cmake OPTIONAL)
|
||||
include(${APP_DIR}/sysbuild.cmake OPTIONAL)
|
34
share/sysbuild/Kconfig
Normal file
34
share/sysbuild/Kconfig
Normal file
|
@ -0,0 +1,34 @@
|
|||
# Copyright (c) 2021 Nordic Semiconductor
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
comment "Sysbuild image configuration"
|
||||
|
||||
osource "$(BOARD_DIR)/Kconfig.sysbuild"
|
||||
|
||||
config EXPERIMENTAL
|
||||
bool
|
||||
help
|
||||
Symbol that must be selected by a feature if it is considered to be
|
||||
at an experimental implementation stage.
|
||||
|
||||
config WARN_EXPERIMENTAL
|
||||
bool
|
||||
prompt "Warn on experimental usage"
|
||||
help
|
||||
Print a warning when the Kconfig tree is parsed if any experimental
|
||||
features are enabled.
|
||||
|
||||
config DEPRECATED
|
||||
bool
|
||||
help
|
||||
Symbol that must be selected by a feature or module if it is
|
||||
considered to be deprecated.
|
||||
|
||||
config WARN_DEPRECATED
|
||||
bool
|
||||
default y
|
||||
prompt "Warn on deprecated usage"
|
||||
help
|
||||
Print a warning when the Kconfig tree is parsed if any deprecated
|
||||
features are enabled.
|
187
share/sysbuild/cmake/modules/sysbuild_extensions.cmake
Normal file
187
share/sysbuild/cmake/modules/sysbuild_extensions.cmake
Normal file
|
@ -0,0 +1,187 @@
|
|||
# Copyright (c) 2021 Nordic Semiconductor
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# Usage:
|
||||
# ExternalZephyrProject_Add(APPLICATION <name>
|
||||
# SOURCE_DIR <dir>
|
||||
# [BOARD <board>]
|
||||
# [MAIN_APP]
|
||||
# )
|
||||
#
|
||||
# This function includes a Zephyr based build system into the multiimage
|
||||
# build system
|
||||
#
|
||||
# APPLICATION: <name>: Name of the application, name will also be used for build
|
||||
# folder of the application
|
||||
# SOURCE_DIR <dir>: Source directory of the application
|
||||
# BOARD <board>: Use <board> for application build instead user defined BOARD.
|
||||
# MAIN_APP: Flag indicating 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.
|
||||
#
|
||||
function(ExternalZephyrProject_Add)
|
||||
cmake_parse_arguments(ZBUILD "MAIN_APP" "APPLICATION;BOARD;SOURCE_DIR" "" ${ARGN})
|
||||
|
||||
if(ZBUILD_UNPARSED_ARGUMENTS)
|
||||
message(FATAL_ERROR
|
||||
"ExternalZephyrProject_Add(${ARGV0} <val> ...) given unknown arguments:"
|
||||
" ${ZBUILD_UNPARSED_ARGUMENTS}"
|
||||
)
|
||||
endif()
|
||||
|
||||
set(sysbuild_vars
|
||||
"APP_DIR"
|
||||
"SB_CONF_FILE"
|
||||
)
|
||||
|
||||
# General variables that should be propagated to all Zephyr builds, for example:
|
||||
# - ZEPHYR_MODULES / ZEPHYR_EXTRA_MODULES
|
||||
# - ZEPHYR_TOOLCHAIN_VARIANT
|
||||
# - *_TOOLCHAIN_PATH
|
||||
# - *_ROOT
|
||||
# etc.
|
||||
# Note: setting vars on a single image can be done by using
|
||||
# `<image>_CONF_FILE`, like `mcuboot_CONF_FILE`
|
||||
set(
|
||||
shared_image_variables_list
|
||||
CMAKE_BUILD_TYPE
|
||||
CMAKE_VERBOSE_MAKEFILE
|
||||
BOARD
|
||||
ZEPHYR_MODULES
|
||||
ZEPHYR_EXTRA_MODULES
|
||||
ZEPHYR_TOOLCHAIN_VARIANT
|
||||
EXTRA_KCONFIG_TARGETS
|
||||
)
|
||||
|
||||
set(shared_image_variables_regex
|
||||
"^[^_]*_TOOLCHAIN_PATH|^[^_]*_ROOT"
|
||||
)
|
||||
|
||||
set(app_cache_file ${CMAKE_BINARY_DIR}/CMake${ZBUILD_APPLICATION}PreloadCache.txt)
|
||||
|
||||
if(EXISTS ${app_cache_file})
|
||||
file(STRINGS ${app_cache_file} app_cache_strings)
|
||||
set(app_cache_strings_current ${app_cache_strings})
|
||||
endif()
|
||||
|
||||
get_cmake_property(variables_cached CACHE_VARIABLES)
|
||||
foreach(var_name ${variables_cached})
|
||||
# Any var of the form `<app>_<var>` should be propagated.
|
||||
# For example mcuboot_<VAR>=<val> ==> -D<VAR>=<val> for mcuboot build.
|
||||
if("${var_name}" MATCHES "^${ZBUILD_APPLICATION}_.*")
|
||||
list(APPEND application_vars ${var_name})
|
||||
continue()
|
||||
endif()
|
||||
|
||||
# This means there is a match to another image than current one, ignore.
|
||||
if("${var_name}" MATCHES "^.*_CONFIG_.*")
|
||||
continue()
|
||||
endif()
|
||||
|
||||
# sysbuild reserved namespace.
|
||||
if(var_name IN_LIST sysbuild_vars OR "${var_name}" MATCHES "^SB_CONFIG_.*")
|
||||
continue()
|
||||
endif()
|
||||
|
||||
if("${var_name}" MATCHES "^CONFIG_.*")
|
||||
if(ZBUILD_MAIN_APP)
|
||||
list(APPEND application_vars ${var_name})
|
||||
endif()
|
||||
continue()
|
||||
endif()
|
||||
|
||||
if(var_name IN_LIST shared_image_variables_list)
|
||||
list(APPEND application_vars ${var_name})
|
||||
continue()
|
||||
endif()
|
||||
|
||||
if("${var_name}" MATCHES "${shared_image_variables_regex}")
|
||||
list(APPEND application_vars ${var_name})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
foreach(app_var_name ${application_vars})
|
||||
string(REGEX REPLACE "^${ZBUILD_APPLICATION}_" "" var_name "${app_var_name}")
|
||||
get_property(var_type CACHE ${app_var_name} PROPERTY TYPE)
|
||||
set(new_cache_entry "${var_name}:${var_type}=${${app_var_name}}")
|
||||
if(NOT new_cache_entry IN_LIST app_cache_strings)
|
||||
# This entry does not exists, let's see if it has been updated.
|
||||
foreach(entry ${app_cache_strings})
|
||||
if("${entry}" MATCHES "^${var_name}:.*")
|
||||
list(REMOVE_ITEM app_cache_strings "${entry}")
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
list(APPEND app_cache_strings "${var_name}:${var_type}=${${app_var_name}}")
|
||||
list(APPEND app_cache_entries "-D${var_name}:${var_type}=${${app_var_name}}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(NOT "${app_cache_strings_current}" STREQUAL "${app_cache_strings}")
|
||||
string(REPLACE ";" "\n" app_cache_strings "${app_cache_strings}")
|
||||
file(WRITE ${app_cache_file} ${app_cache_strings})
|
||||
endif()
|
||||
|
||||
if(DEFINED ZBUILD_BOARD)
|
||||
list(APPEND app_cache_entries "-DBOARD=${ZBUILD_BOARD}")
|
||||
elseif(NOT ZBUILD_MAIN_APP)
|
||||
list(APPEND app_cache_entries "-DBOARD=${BOARD}")
|
||||
endif()
|
||||
|
||||
set(image_banner "* Running CMake for ${ZBUILD_APPLICATION} *")
|
||||
string(LENGTH "${image_banner}" image_banner_width)
|
||||
string(REPEAT "*" ${image_banner_width} image_banner_header)
|
||||
message(STATUS "\n ${image_banner_header}\n"
|
||||
" ${image_banner}\n"
|
||||
" ${image_banner_header}\n"
|
||||
)
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-G${CMAKE_GENERATOR}
|
||||
${app_cache_entries}
|
||||
-B${CMAKE_BINARY_DIR}/${ZBUILD_APPLICATION}
|
||||
-S${ZBUILD_SOURCE_DIR}
|
||||
RESULT_VARIABLE return_val
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
)
|
||||
|
||||
if(return_val)
|
||||
message(FATAL_ERROR
|
||||
"CMake configure failed for Zephyr project: ${ZBUILD_APPLICATION}\n"
|
||||
"Location: ${ZBUILD_SOURCE_DIR}"
|
||||
)
|
||||
endif()
|
||||
|
||||
foreach(kconfig_target
|
||||
menuconfig
|
||||
hardenconfig
|
||||
guiconfig
|
||||
${EXTRA_KCONFIG_TARGETS}
|
||||
)
|
||||
|
||||
if(NOT ZBUILD_MAIN_APP)
|
||||
set(image_prefix "${ZBUILD_APPLICATION}_")
|
||||
endif()
|
||||
|
||||
add_custom_target(${image_prefix}${kconfig_target}
|
||||
${CMAKE_MAKE_PROGRAM} ${kconfig_target}
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/${ZBUILD_APPLICATION}
|
||||
USES_TERMINAL
|
||||
)
|
||||
endforeach()
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(
|
||||
${ZBUILD_APPLICATION}
|
||||
SOURCE_DIR ${ZBUILD_SOURCE_DIR}
|
||||
BINARY_DIR ${CMAKE_BINARY_DIR}/${ZBUILD_APPLICATION}
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ${CMAKE_COMMAND} --build .
|
||||
INSTALL_COMMAND ""
|
||||
BUILD_ALWAYS True
|
||||
USES_TERMINAL_BUILD True
|
||||
)
|
||||
endfunction()
|
60
share/sysbuild/cmake/modules/sysbuild_kconfig.cmake
Normal file
60
share/sysbuild/cmake/modules/sysbuild_kconfig.cmake
Normal file
|
@ -0,0 +1,60 @@
|
|||
# Copyright (c) 2021 Nordic Semiconductor
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
set(EXTRA_KCONFIG_TARGET_COMMAND_FOR_sysbuild_menuconfig
|
||||
${ZEPHYR_BASE}/scripts/kconfig/menuconfig.py
|
||||
)
|
||||
|
||||
set(EXTRA_KCONFIG_TARGET_COMMAND_FOR_sysbuild_guiconfig
|
||||
${ZEPHYR_BASE}/scripts/kconfig/guiconfig.py
|
||||
)
|
||||
|
||||
set(KCONFIG_TARGETS sysbuild_menuconfig sysbuild_guiconfig)
|
||||
list(TRANSFORM EXTRA_KCONFIG_TARGETS PREPEND "sysbuild_")
|
||||
|
||||
if(DEFINED SB_CONF_FILE)
|
||||
# SB_CONF_FILE already set so nothing to do.
|
||||
elseif(DEFINED ENV{SB_CONF_FILE})
|
||||
set(SB_CONF_FILE $ENV{SB_CONF_FILE})
|
||||
elseif(EXISTS ${APP_DIR}/sysbuild.conf)
|
||||
set(SB_CONF_FILE ${APP_DIR}/sysbuild.conf)
|
||||
else()
|
||||
# Because SYSBuild is opt-in feature, then it is permitted to not have a
|
||||
# SYSBuild dedicated configuration file.
|
||||
endif()
|
||||
|
||||
if(DEFINED SB_CONF_FILE AND NOT IS_ABSOLUTE SB_CONF_FILE)
|
||||
cmake_path(ABSOLUTE_PATH SB_CONF_FILE BASE_DIRECTORY ${APP_DIR} OUTPUT_VARIABLE SB_CONF_FILE)
|
||||
endif()
|
||||
|
||||
if(DEFINED SB_CONF_FILE AND NOT DEFINED CACHE{SB_CONF_FILE})
|
||||
# We only want to set this in cache it has been defined and is not already there.
|
||||
set(SB_CONF_FILE ${SB_CONF_FILE} CACHE STRING "If desired, you can build the application with \
|
||||
SYSbuild configuration settings specified in an alternate .conf file using this parameter. \
|
||||
These settings will override the settings in the application’s SYSBuild config file or its \
|
||||
default .conf file. Multiple files may be listed, e.g. SB_CONF_FILE=\"sys1.conf sys2.conf\"")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED SB_CONF_FILE)
|
||||
# If there is no SB_CONF_FILE, then use empty.conf to make kconfiglib happy.
|
||||
# Not adding it to CMake cache ensures that a later created sysbuild.conf
|
||||
# will be automatically detected.
|
||||
set(SB_CONF_FILE ${CMAKE_CURRENT_BINARY_DIR}/empty.conf)
|
||||
endif()
|
||||
|
||||
# Empty files to make kconfig.py happy.
|
||||
file(TOUCH ${CMAKE_CURRENT_BINARY_DIR}/empty.conf)
|
||||
set(APPLICATION_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set(KCONFIG_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set(AUTOCONF_H ${CMAKE_CURRENT_BINARY_DIR}/autoconf.h)
|
||||
set(CONF_FILE ${SB_CONF_FILE})
|
||||
set(BOARD_DEFCONFIG "${CMAKE_CURRENT_BINARY_DIR}/empty.conf")
|
||||
list(APPEND ZEPHYR_KCONFIG_MODULES_DIR BOARD=${BOARD})
|
||||
set(KCONFIG_NAMESPACE SB_CONFIG)
|
||||
|
||||
if(EXISTS ${APP_DIR}/Kconfig.sysbuild)
|
||||
set(KCONFIG_ROOT ${APP_DIR}/Kconfig.sysbuild)
|
||||
endif()
|
||||
include(${ZEPHYR_BASE}/cmake/modules/kconfig.cmake)
|
||||
set(CONF_FILE)
|
Loading…
Add table
Add a link
Reference in a new issue