Browse Source

sysbuild: Add support for snippets

Adds support for sysbuild loading snippets, these can be included
by using e.g.: cmake ... -DSB_SNIPPET=blah for sysbuild
directly or can be used with an application and sysbuild using
-DSNIPPET. Snippets for sysbuild can use SB_EXTRA_CONF_FILE in the
snippet file to specify an extra Kconfig fragment for sysbuild

Signed-off-by: Jamie McCrae <jamie.mccrae@nordicsemi.no>
pull/83421/head
Jamie McCrae 1 year ago committed by Benjamin Cabé
parent
commit
0711f42e3a
  1. 2
      cmake/modules/root.cmake
  2. 11
      cmake/modules/snippets.cmake
  3. 2
      scripts/schemas/snippet-schema.yml
  4. 24
      scripts/snippets.py
  5. 1
      share/sysbuild/cmake/modules/sysbuild_default.cmake
  6. 8
      share/sysbuild/cmake/modules/sysbuild_kconfig.cmake
  7. 6
      share/sysbuild/cmake/modules/sysbuild_root.cmake
  8. 16
      share/sysbuild/cmake/modules/sysbuild_snippets.cmake

2
cmake/modules/root.cmake

@ -28,6 +28,7 @@ zephyr_get(BOARD_ROOT MERGE SYSBUILD GLOBAL) @@ -28,6 +28,7 @@ zephyr_get(BOARD_ROOT MERGE SYSBUILD GLOBAL)
zephyr_get(SOC_ROOT MERGE SYSBUILD GLOBAL)
zephyr_get(ARCH_ROOT MERGE SYSBUILD GLOBAL)
zephyr_get(SCA_ROOT MERGE SYSBUILD GLOBAL)
zephyr_get(SNIPPET_ROOT MERGE SYSBUILD GLOBAL)
# Convert paths to absolute, relative from APPLICATION_SOURCE_DIR
zephyr_file(APPLICATION_ROOT MODULE_EXT_ROOT)
@ -35,6 +36,7 @@ zephyr_file(APPLICATION_ROOT BOARD_ROOT) @@ -35,6 +36,7 @@ zephyr_file(APPLICATION_ROOT BOARD_ROOT)
zephyr_file(APPLICATION_ROOT SOC_ROOT)
zephyr_file(APPLICATION_ROOT ARCH_ROOT)
zephyr_file(APPLICATION_ROOT SCA_ROOT)
zephyr_file(APPLICATION_ROOT SNIPPET_ROOT)
if(unittest IN_LIST Zephyr_FIND_COMPONENTS)
# Zephyr used in unittest mode, use dedicated unittest root.

11
cmake/modules/snippets.cmake

@ -45,19 +45,23 @@ zephyr_check_cache(SNIPPET WATCH) @@ -45,19 +45,23 @@ zephyr_check_cache(SNIPPET WATCH)
function(zephyr_process_snippets)
set(snippets_py ${ZEPHYR_BASE}/scripts/snippets.py)
set(snippets_generated ${CMAKE_BINARY_DIR}/zephyr/snippets_generated.cmake)
set_ifndef(SNIPPET_NAMESPACE SNIPPET)
set_ifndef(SNIPPET_PYTHON_EXTRA_ARGS "")
set_ifndef(SNIPPET_APP_DIR "${APPLICATION_SOURCE_DIR}")
# Set SNIPPET_AS_LIST, removing snippets_generated.cmake if we are
# running cmake again and snippets are no longer requested.
if (NOT DEFINED SNIPPET)
if(NOT DEFINED SNIPPET)
set(SNIPPET_AS_LIST "" PARENT_SCOPE)
file(REMOVE ${snippets_generated})
else()
string(REPLACE " " ";" SNIPPET_AS_LIST "${SNIPPET}")
string(REPLACE " " ";" SNIPPET_AS_LIST "${${SNIPPET_NAMESPACE}}")
set(SNIPPET_AS_LIST "${SNIPPET_AS_LIST}" PARENT_SCOPE)
endif()
# Set SNIPPET_ROOT.
list(APPEND SNIPPET_ROOT ${APPLICATION_SOURCE_DIR})
zephyr_get(SNIPPET_ROOT MERGE SYSBUILD GLOBAL)
list(APPEND SNIPPET_ROOT ${SNIPPET_APP_DIR})
list(APPEND SNIPPET_ROOT ${ZEPHYR_BASE})
unset(real_snippet_root)
foreach(snippet_dir ${SNIPPET_ROOT})
@ -85,6 +89,7 @@ function(zephyr_process_snippets) @@ -85,6 +89,7 @@ function(zephyr_process_snippets)
${snippet_root_args}
${requested_snippet_args}
--cmake-out ${snippets_generated}
${SNIPPET_PYTHON_EXTRA_ARGS}
OUTPUT_VARIABLE output
ERROR_VARIABLE output
RESULT_VARIABLE ret)

2
scripts/schemas/snippet-schema.yml

@ -13,6 +13,8 @@ schema;append-schema: @@ -13,6 +13,8 @@ schema;append-schema:
type: str
EXTRA_CONF_FILE:
type: str
SB_EXTRA_CONF_FILE:
type: str
DTS_EXTRA_CPPFLAGS:
type: str

24
scripts/snippets.py

@ -48,11 +48,11 @@ class Snippet: @@ -48,11 +48,11 @@ class Snippet:
appends: Appends = field(default_factory=_new_append)
board2appends: Dict[str, Appends] = field(default_factory=_new_board2appends)
def process_data(self, pathobj: Path, snippet_data: dict):
def process_data(self, pathobj: Path, snippet_data: dict, sysbuild: bool):
'''Process the data in a snippet.yml file, after it is loaded into a
python object and validated by pykwalify.'''
def append_value(variable, value):
if variable in ('EXTRA_DTC_OVERLAY_FILE', 'EXTRA_CONF_FILE'):
if variable in ('SB_EXTRA_CONF_FILE', 'EXTRA_DTC_OVERLAY_FILE', 'EXTRA_CONF_FILE'):
path = pathobj.parent / value
if not path.is_file():
_err(f'snippet file {pathobj}: {variable}: file not found: {path}')
@ -62,14 +62,18 @@ class Snippet: @@ -62,14 +62,18 @@ class Snippet:
_err(f'unknown append variable: {variable}')
for variable, value in snippet_data.get('append', {}).items():
self.appends[variable].append(append_value(variable, value))
if (sysbuild is True and variable[0:3] == 'SB_') or \
(sysbuild is False and variable[0:3] != 'SB_'):
self.appends[variable].append(append_value(variable, value))
for board, settings in snippet_data.get('boards', {}).items():
if board.startswith('/') and not board.endswith('/'):
_err(f"snippet file {pathobj}: board {board} starts with '/', so "
"it must end with '/' to use a regular expression")
for variable, value in settings.get('append', {}).items():
self.board2appends[board][variable].append(
append_value(variable, value))
if (sysbuild is True and variable[0:3] == 'SB_') or \
(sysbuild is False and variable[0:3] != 'SB_'):
self.board2appends[board][variable].append(
append_value(variable, value))
class Snippets(UserDict):
'''Type for all the information we have discovered about all snippets.
@ -212,6 +216,8 @@ def parse_args(): @@ -212,6 +216,8 @@ def parse_args():
parser.add_argument('--cmake-out', type=Path,
help='''file to write cmake output to; include()
this file after calling this script''')
parser.add_argument('--sysbuild', action="store_true",
help='''set if this is running as sysbuild''')
return parser.parse_args()
def setup_logging():
@ -234,7 +240,7 @@ def process_snippets(args: argparse.Namespace) -> Snippets: @@ -234,7 +240,7 @@ def process_snippets(args: argparse.Namespace) -> Snippets:
# Process each path in snippet_root in order, adjusting
# snippets as needed for each one.
for root in args.snippet_root:
process_snippets_in(root, snippets)
process_snippets_in(root, snippets, args.sysbuild)
return snippets
@ -250,11 +256,11 @@ def find_snippets_in_roots(requested_snippets, snippet_roots) -> Snippets: @@ -250,11 +256,11 @@ def find_snippets_in_roots(requested_snippets, snippet_roots) -> Snippets:
# Process each path in snippet_root in order, adjusting
# snippets as needed for each one.
for root in snippet_roots:
process_snippets_in(root, snippets)
process_snippets_in(root, snippets, False)
return snippets
def process_snippets_in(root_dir: Path, snippets: Snippets) -> None:
def process_snippets_in(root_dir: Path, snippets: Snippets, sysbuild: bool) -> None:
'''Process snippet.yml files in *root_dir*,
updating *snippets* as needed.'''
@ -276,7 +282,7 @@ def process_snippets_in(root_dir: Path, snippets: Snippets) -> None: @@ -276,7 +282,7 @@ def process_snippets_in(root_dir: Path, snippets: Snippets) -> None:
name = snippet_data['name']
if name not in snippets:
snippets[name] = Snippet(name=name)
snippets[name].process_data(snippet_yml, snippet_data)
snippets[name].process_data(snippet_yml, snippet_data, sysbuild)
snippets.paths.add(snippet_yml)
def load_snippet_yml(snippet_yml: Path) -> dict:

1
share/sysbuild/cmake/modules/sysbuild_default.cmake

@ -15,6 +15,7 @@ include(zephyr_module) @@ -15,6 +15,7 @@ include(zephyr_module)
include(boards)
include(shields)
include(hwm_v2)
include(sysbuild_snippets)
include(sysbuild_kconfig)
include(native_simulator_sb_extensions)
include(sysbuild_images)

8
share/sysbuild/cmake/modules/sysbuild_kconfig.cmake

@ -105,6 +105,14 @@ set(KCONFIG_NAMESPACE SB_CONFIG) @@ -105,6 +105,14 @@ set(KCONFIG_NAMESPACE SB_CONFIG)
if(EXISTS ${APP_DIR}/Kconfig.sysbuild)
set(KCONFIG_ROOT ${APP_DIR}/Kconfig.sysbuild)
endif()
# Apply any EXTRA_CONF_FILE variables from snippets
if(TARGET snippets_scope)
get_property(snippets_EXTRA_CONF_FILE TARGET snippets_scope PROPERTY SB_EXTRA_CONF_FILE)
list(APPEND EXTRA_CONF_FILE ${snippets_EXTRA_CONF_FILE})
endif()
include(${ZEPHYR_BASE}/cmake/modules/kconfig.cmake)
set(CONF_FILE)
set(EXTRA_CONF_FILE)
set(SB_EXTRA_CONF_FILE)

6
share/sysbuild/cmake/modules/sysbuild_root.cmake

@ -31,6 +31,7 @@ zephyr_get(BOARD_ROOT MERGE) @@ -31,6 +31,7 @@ zephyr_get(BOARD_ROOT MERGE)
zephyr_get(SOC_ROOT MERGE)
zephyr_get(ARCH_ROOT MERGE)
zephyr_get(SCA_ROOT MERGE)
zephyr_get(SNIPPET_ROOT MERGE)
# Convert paths to absolute, relative from APP_DIR
zephyr_file(APPLICATION_ROOT MODULE_EXT_ROOT BASE_DIR ${APP_DIR})
@ -38,6 +39,7 @@ zephyr_file(APPLICATION_ROOT BOARD_ROOT BASE_DIR ${APP_DIR}) @@ -38,6 +39,7 @@ zephyr_file(APPLICATION_ROOT BOARD_ROOT BASE_DIR ${APP_DIR})
zephyr_file(APPLICATION_ROOT SOC_ROOT BASE_DIR ${APP_DIR})
zephyr_file(APPLICATION_ROOT ARCH_ROOT BASE_DIR ${APP_DIR})
zephyr_file(APPLICATION_ROOT SCA_ROOT BASE_DIR ${APP_DIR})
zephyr_file(APPLICATION_ROOT SNIPPET_ROOT BASE_DIR ${APP_DIR})
# Sysbuild must ensure any locally defined variables in sysbuild/CMakeLists.txt
# have been added to the cache in order for the settings to propagate to images.
@ -61,3 +63,7 @@ endif() @@ -61,3 +63,7 @@ endif()
if(DEFINED SCA_ROOT)
set(SCA_ROOT ${SCA_ROOT} CACHE PATH "Sysbuild adjusted SCA_ROOT" FORCE)
endif()
if(DEFINED SNIPPET_ROOT)
set(SNIPPET_ROOT ${SNIPPET_ROOT} CACHE PATH "Sysbuild adjusted SNIPPET_ROOT" FORCE)
endif()

16
share/sysbuild/cmake/modules/sysbuild_snippets.cmake

@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
# Copyright (c) 2024 Nordic Semiconductor
#
# SPDX-License-Identifier: Apache-2.0
zephyr_get(SB_SNIPPET)
if(NOT SB_SNIPPET AND SNIPPET)
set_ifndef(SB_SNIPPET ${SNIPPET})
endif()
set(SNIPPET_NAMESPACE SB_SNIPPET)
set(SNIPPET_PYTHON_EXTRA_ARGS --sysbuild)
set(SNIPPET_APP_DIR ${APP_DIR})
include(${ZEPHYR_BASE}/cmake/modules/snippets.cmake)
set(SNIPPET_NAMESPACE)
set(SNIPPET_PYTHON_EXTRA_ARGS)
set(SNIPPET_APP_DIR)
Loading…
Cancel
Save