sysbuild: support Zephyr modules
This commit extends the Zephyr module yaml scheme with additional entries for sysbuild in the build section. This allows for Zephyr modules to extend the sysbuild infrastructure by providing additional CMake and Kconfig files to be included in sysbuild. The new settings are: build: sysbuild-cmake: <path> sysbuild-kconfig: <path>/<file> sysbuild-ext: <true>|<false> sysbuild-kconfig-ext: <true>|<false> those settings follow the same pattern as the equivalent Zephyr build settings but are processed by sysbuild. Signed-off-by: Jamie McCrae <jamie.mccrae@nordicsemi.no> Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no>
This commit is contained in:
parent
631fa63610
commit
df9027a64a
|
@ -43,6 +43,9 @@ endif()
|
|||
|
||||
file(MAKE_DIRECTORY ${KCONFIG_BINARY_DIR})
|
||||
set(kconfig_modules_file ${KCONFIG_BINARY_DIR}/Kconfig.modules)
|
||||
set(kconfig_sysbuild_file ${KCONFIG_BINARY_DIR}/Kconfig.sysbuild.modules)
|
||||
set(cmake_modules_file ${CMAKE_BINARY_DIR}/zephyr_modules.txt)
|
||||
set(cmake_sysbuild_file ${CMAKE_BINARY_DIR}/sysbuild_modules.txt)
|
||||
set(zephyr_settings_file ${CMAKE_BINARY_DIR}/zephyr_settings.txt)
|
||||
|
||||
if(WEST)
|
||||
|
@ -59,7 +62,9 @@ if(WEST OR ZEPHYR_MODULES)
|
|||
${ZEPHYR_MODULES_ARG}
|
||||
${ZEPHYR_EXTRA_MODULES_ARG}
|
||||
--kconfig-out ${kconfig_modules_file}
|
||||
--cmake-out ${CMAKE_BINARY_DIR}/zephyr_modules.txt
|
||||
--cmake-out ${cmake_modules_file}
|
||||
--sysbuild-kconfig-out ${kconfig_sysbuild_file}
|
||||
--sysbuild-cmake-out ${cmake_sysbuild_file}
|
||||
--settings-out ${zephyr_settings_file}
|
||||
WORKING_DIRECTORY ${ZEPHYR_BASE}
|
||||
ERROR_VARIABLE
|
||||
|
@ -87,9 +92,9 @@ if(WEST OR ZEPHYR_MODULES)
|
|||
# Append ZEPHYR_BASE as a default ext root at lowest priority
|
||||
list(APPEND MODULE_EXT_ROOT ${ZEPHYR_BASE})
|
||||
|
||||
if(EXISTS ${CMAKE_BINARY_DIR}/zephyr_modules.txt)
|
||||
file(STRINGS ${CMAKE_BINARY_DIR}/zephyr_modules.txt zephyr_modules_txt
|
||||
ENCODING UTF-8)
|
||||
if(EXISTS ${cmake_modules_file})
|
||||
file(STRINGS ${cmake_modules_file} zephyr_modules_txt ENCODING UTF-8)
|
||||
endif()
|
||||
|
||||
set(ZEPHYR_MODULE_NAMES)
|
||||
foreach(module ${zephyr_modules_txt})
|
||||
|
@ -99,8 +104,20 @@ if(WEST OR ZEPHYR_MODULES)
|
|||
string(REGEX REPLACE "\"(.*)\":\".*\":\".*\"" "\\1" module_name ${module})
|
||||
list(APPEND ZEPHYR_MODULE_NAMES ${module_name})
|
||||
endforeach()
|
||||
|
||||
if(EXISTS ${cmake_sysbuild_file})
|
||||
file(STRINGS ${cmake_sysbuild_file} sysbuild_modules_txt ENCODING UTF-8)
|
||||
endif()
|
||||
|
||||
set(SYSBUILD_MODULE_NAMES)
|
||||
foreach(module ${sysbuild_modules_txt})
|
||||
# Match "<name>":"<path>" for each line of file, each corresponding to
|
||||
# one module. The use of quotes is required due to CMake not supporting
|
||||
# lazy regexes (it supports greedy only).
|
||||
string(REGEX REPLACE "\"(.*)\":\".*\":\".*\"" "\\1" module_name ${module})
|
||||
list(APPEND SYSBUILD_MODULE_NAMES ${module_name})
|
||||
endforeach()
|
||||
|
||||
# MODULE_EXT_ROOT is process order which means Zephyr module roots processed
|
||||
# later wins. therefore we reverse the list before processing.
|
||||
list(REVERSE MODULE_EXT_ROOT)
|
||||
|
@ -112,7 +129,6 @@ if(WEST OR ZEPHYR_MODULES)
|
|||
include(${root}/modules/modules.cmake)
|
||||
endforeach()
|
||||
|
||||
if(DEFINED zephyr_modules_txt)
|
||||
foreach(module ${zephyr_modules_txt})
|
||||
# Match "<name>":"<path>" for each line of file, each corresponding to
|
||||
# one Zephyr module. The use of quotes is required due to CMake not
|
||||
|
@ -132,11 +148,34 @@ ${MODULE_NAME_UPPER} is a restricted name for Zephyr modules as it is used for \
|
|||
\${ZEPHYR_${MODULE_NAME_UPPER}_MODULE_DIR} CMake variable.")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
foreach(module ${sysbuild_modules_txt})
|
||||
# Match "<name>":"<path>" for each line of file, each corresponding to
|
||||
# one Zephyr module. The use of quotes is required due to CMake not
|
||||
# supporting lazy regexes (it supports greedy only).
|
||||
string(CONFIGURE ${module} module)
|
||||
string(REGEX REPLACE "\"(.*)\":\".*\":\".*\"" "\\1" module_name ${module})
|
||||
string(REGEX REPLACE "\".*\":\"(.*)\":\".*\"" "\\1" module_path ${module})
|
||||
string(REGEX REPLACE "\".*\":\".*\":\"(.*)\"" "\\1" cmake_path ${module})
|
||||
|
||||
zephyr_string(SANITIZE TOUPPER MODULE_NAME_UPPER ${module_name})
|
||||
if(NOT ${MODULE_NAME_UPPER} STREQUAL CURRENT)
|
||||
set(SYSBUILD_${MODULE_NAME_UPPER}_MODULE_DIR ${module_path})
|
||||
set(SYSBUILD_${MODULE_NAME_UPPER}_CMAKE_DIR ${cmake_path})
|
||||
else()
|
||||
message(FATAL_ERROR "Found Zephyr module named: ${module_name}\n\
|
||||
${MODULE_NAME_UPPER} is a restricted name for Zephyr modules as it is used for \
|
||||
\${SYSBUILD_${MODULE_NAME_UPPER}_MODULE_DIR} CMake variable.")
|
||||
endif()
|
||||
endforeach()
|
||||
else()
|
||||
|
||||
file(WRITE ${kconfig_modules_file}
|
||||
"# No west and no Zephyr modules\n"
|
||||
)
|
||||
|
||||
file(WRITE ${kconfig_sysbuild_file}
|
||||
"# No west and no Zephyr modules\n"
|
||||
)
|
||||
|
||||
endif()
|
||||
|
|
28
modules/Kconfig.sysbuild
Normal file
28
modules/Kconfig.sysbuild
Normal file
|
@ -0,0 +1,28 @@
|
|||
# Copyright (c) 2019 Intel Corporation
|
||||
# Copyright (c) 2022 Nordic Semiconductor
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
comment "Available modules."
|
||||
|
||||
source "$(KCONFIG_BINARY_DIR)/Kconfig.sysbuild.modules"
|
||||
|
||||
comment "Unavailable modules, please install those via the project manifest."
|
||||
|
||||
# List of comments to display when Zephyr modules are not available, please
|
||||
# use the following syntax:
|
||||
# ---------------------------------------------------
|
||||
# comment "<module_name> module not available."
|
||||
# depends on !SYSBUILD_<MODULE_NAME_UPPER>_MODULE
|
||||
#
|
||||
# Remember to add the following code inside the `<module>/Kconfig file:
|
||||
# ---------------------------------------------------
|
||||
# config SYSBUILD_<MODULE_NAME_UPPER>_MODULE
|
||||
# bool
|
||||
|
||||
# This ensures that symbols are available in Kconfig for dependency checking
|
||||
# and referencing, while keeping the settings themselves unavailable when the
|
||||
# modules are not present in the workspace
|
||||
if 0
|
||||
osource "modules/*/Kconfig.sysbuild"
|
||||
endif
|
|
@ -57,6 +57,20 @@ mapping:
|
|||
required: false
|
||||
type: bool
|
||||
default: false
|
||||
sysbuild-cmake:
|
||||
required: false
|
||||
type: str
|
||||
sysbuild-kconfig:
|
||||
required: false
|
||||
type: str
|
||||
sysbuild-cmake-ext:
|
||||
required: false
|
||||
type: bool
|
||||
default: false
|
||||
sysbuild-kconfig-ext:
|
||||
required: false
|
||||
type: bool
|
||||
default: false
|
||||
depends:
|
||||
required: false
|
||||
type: seq
|
||||
|
@ -216,6 +230,40 @@ def process_cmake(module, meta):
|
|||
module_path.as_posix()))
|
||||
|
||||
|
||||
def process_sysbuildcmake(module, meta):
|
||||
section = meta.get('build', dict())
|
||||
module_path = PurePath(module)
|
||||
module_yml = module_path.joinpath('zephyr/module.yml')
|
||||
|
||||
cmake_extern = section.get('sysbuild-cmake-ext', False)
|
||||
if cmake_extern:
|
||||
return('\"{}\":\"{}\":\"{}\"\n'
|
||||
.format(meta['name'],
|
||||
module_path.as_posix(),
|
||||
"${SYSBUILD_" + meta['name-sanitized'].upper() + "_CMAKE_DIR}"))
|
||||
|
||||
cmake_setting = section.get('sysbuild-cmake', None)
|
||||
if not validate_setting(cmake_setting, module, 'CMakeLists.txt'):
|
||||
sys.exit('ERROR: "cmake" key in {} has folder value "{}" which '
|
||||
'does not contain a CMakeLists.txt file.'
|
||||
.format(module_yml.as_posix(), cmake_setting))
|
||||
|
||||
if cmake_setting is None:
|
||||
return ""
|
||||
|
||||
cmake_path = os.path.join(module, cmake_setting or 'zephyr')
|
||||
cmake_file = os.path.join(cmake_path, 'CMakeLists.txt')
|
||||
if os.path.isfile(cmake_file):
|
||||
return('\"{}\":\"{}\":\"{}\"\n'
|
||||
.format(meta['name'],
|
||||
module_path.as_posix(),
|
||||
Path(cmake_path).resolve().as_posix()))
|
||||
else:
|
||||
return('\"{}\":\"{}\":\"\"\n'
|
||||
.format(meta['name'],
|
||||
module_path.as_posix()))
|
||||
|
||||
|
||||
def process_settings(module, meta):
|
||||
section = meta.get('build', dict())
|
||||
build_settings = section.get('settings', None)
|
||||
|
@ -260,12 +308,13 @@ def process_blobs(module, meta):
|
|||
return blobs
|
||||
|
||||
|
||||
def kconfig_snippet(meta, path, kconfig_file=None, blobs=False):
|
||||
def kconfig_snippet(meta, path, kconfig_file=None, blobs=False, sysbuild=False):
|
||||
name = meta['name']
|
||||
name_sanitized = meta['name-sanitized']
|
||||
|
||||
snippet = [f'menu "{name} ({path.as_posix()})"',
|
||||
f'osource "{kconfig_file.resolve().as_posix()}"' if kconfig_file
|
||||
else f'osource "$(SYSBUILD_{name_sanitized.upper()}_KCONFIG)"' if sysbuild is True
|
||||
else f'osource "$(ZEPHYR_{name_sanitized.upper()}_KCONFIG)"',
|
||||
f'config ZEPHYR_{name_sanitized.upper()}_MODULE',
|
||||
' bool',
|
||||
|
@ -301,6 +350,30 @@ def process_kconfig(module, meta):
|
|||
return ""
|
||||
|
||||
|
||||
def process_sysbuildkconfig(module, meta):
|
||||
section = meta.get('build', dict())
|
||||
module_path = PurePath(module)
|
||||
module_yml = module_path.joinpath('zephyr/module.yml')
|
||||
kconfig_extern = section.get('sysbuild-kconfig-ext', False)
|
||||
if kconfig_extern:
|
||||
return kconfig_snippet(meta, module_path, sysbuild=True)
|
||||
|
||||
kconfig_setting = section.get('sysbuild-kconfig', None)
|
||||
if not validate_setting(kconfig_setting, module):
|
||||
sys.exit('ERROR: "kconfig" key in {} has value "{}" which does '
|
||||
'not point to a valid Kconfig file.'
|
||||
.format(module_yml, kconfig_setting))
|
||||
|
||||
if kconfig_setting is None:
|
||||
return ""
|
||||
|
||||
kconfig_file = os.path.join(module, kconfig_setting)
|
||||
if os.path.isfile(kconfig_file):
|
||||
return kconfig_snippet(meta, module_path, Path(kconfig_file))
|
||||
else:
|
||||
return ""
|
||||
|
||||
|
||||
def process_twister(module, meta):
|
||||
|
||||
out = ""
|
||||
|
@ -553,6 +626,12 @@ def main():
|
|||
parser.add_argument('--cmake-out',
|
||||
help="""File to write with resulting <name>:<path>
|
||||
values to use for including in CMake""")
|
||||
parser.add_argument('--sysbuild-kconfig-out',
|
||||
help="""File to write with resulting KConfig import
|
||||
statements.""")
|
||||
parser.add_argument('--sysbuild-cmake-out',
|
||||
help="""File to write with resulting <name>:<path>
|
||||
values to use for including in CMake""")
|
||||
parser.add_argument('--meta-out',
|
||||
help="""Write a build meta YaML file containing a list
|
||||
of Zephyr modules and west projects.
|
||||
|
@ -576,6 +655,8 @@ def main():
|
|||
|
||||
kconfig = ""
|
||||
cmake = ""
|
||||
sysbuild_kconfig = ""
|
||||
sysbuild_cmake = ""
|
||||
settings = ""
|
||||
twister = ""
|
||||
|
||||
|
@ -586,6 +667,8 @@ def main():
|
|||
for module in modules:
|
||||
kconfig += process_kconfig(module.project, module.meta)
|
||||
cmake += process_cmake(module.project, module.meta)
|
||||
sysbuild_kconfig += process_sysbuildkconfig(module.project, module.meta)
|
||||
sysbuild_cmake += process_sysbuildcmake(module.project, module.meta)
|
||||
settings += process_settings(module.project, module.meta)
|
||||
twister += process_twister(module.project, module.meta)
|
||||
|
||||
|
@ -597,6 +680,14 @@ def main():
|
|||
with open(args.cmake_out, 'w', encoding="utf-8") as fp:
|
||||
fp.write(cmake)
|
||||
|
||||
if args.sysbuild_kconfig_out:
|
||||
with open(args.sysbuild_kconfig_out, 'w', encoding="utf-8") as fp:
|
||||
fp.write(sysbuild_kconfig)
|
||||
|
||||
if args.sysbuild_cmake_out:
|
||||
with open(args.sysbuild_cmake_out, 'w', encoding="utf-8") as fp:
|
||||
fp.write(sysbuild_cmake)
|
||||
|
||||
if args.settings_out:
|
||||
with open(args.settings_out, 'w', encoding="utf-8") as fp:
|
||||
fp.write('''\
|
||||
|
|
|
@ -30,6 +30,24 @@ set(IMAGES)
|
|||
get_filename_component(APP_DIR ${APP_DIR} ABSOLUTE)
|
||||
get_filename_component(app_name ${APP_DIR} NAME)
|
||||
|
||||
# Include zephyr modules generated sysbuild CMake file.
|
||||
foreach(module_name ${SYSBUILD_MODULE_NAMES})
|
||||
# Note the second, binary_dir parameter requires the added
|
||||
# subdirectory to have its own, local cmake target(s). If not then
|
||||
# this binary_dir is created but stays empty. Object files land in
|
||||
# the main binary dir instead.
|
||||
# https://cmake.org/pipermail/cmake/2019-June/069547.html
|
||||
zephyr_string(SANITIZE TOUPPER MODULE_NAME_UPPER ${module_name})
|
||||
if(NOT ${SYSBUILD_${MODULE_NAME_UPPER}_CMAKE_DIR} STREQUAL "")
|
||||
set(SYSBUILD_CURRENT_MODULE_DIR ${SYSBUILD_${MODULE_NAME_UPPER}_MODULE_DIR})
|
||||
set(SYSBUILD_CURRENT_CMAKE_DIR ${SYSBUILD_${MODULE_NAME_UPPER}_CMAKE_DIR})
|
||||
add_subdirectory(${SYSBUILD_CURRENT_CMAKE_DIR} ${CMAKE_BINARY_DIR}/modules/${module_name})
|
||||
endif()
|
||||
endforeach()
|
||||
# Done processing modules, clear SYSBUILD_CURRENT_MODULE_DIR and SYSBUILD_CURRENT_CMAKE_DIR.
|
||||
set(SYSBUILD_CURRENT_MODULE_DIR)
|
||||
set(SYSBUILD_CURRENT_CMAKE_DIR)
|
||||
|
||||
# Propagate bootloader and signing settings from this system to the MCUboot and
|
||||
# application image build systems.
|
||||
if(SB_CONFIG_BOOTLOADER_MCUBOOT)
|
||||
|
|
|
@ -6,6 +6,12 @@ comment "Sysbuild image configuration"
|
|||
|
||||
osource "$(BOARD_DIR)/Kconfig.sysbuild"
|
||||
|
||||
menu "Modules"
|
||||
|
||||
source "modules/Kconfig.sysbuild"
|
||||
|
||||
endmenu
|
||||
|
||||
config EXPERIMENTAL
|
||||
bool
|
||||
help
|
||||
|
|
|
@ -46,7 +46,6 @@ 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")
|
||||
|
|
Loading…
Reference in a new issue