Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cmake/modules/root.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@ 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)
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.
Expand Down
11 changes: 8 additions & 3 deletions cmake/modules/snippets.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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})
Expand Down Expand Up @@ -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)
Expand Down
23 changes: 23 additions & 0 deletions doc/build/snippets/writing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ this:
EXTRA_DTC_OVERLAY_FILE: foo.overlay
EXTRA_CONF_FILE: foo.conf

In addition, snippets can also be applied to sysbuild configuration like so:

.. code-block:: yaml

name: foo
append:
SB_EXTRA_CONF_FILE: sb.conf
EXTRA_CONF_FILE: app.conf

Namespacing
***********

Expand Down Expand Up @@ -156,6 +165,20 @@ This :file:`snippet.yml` adds :file:`foo.conf` to the build:
The path to :file:`foo.conf` is relative to the directory containing
:file:`snippet.yml`.

Sysbuild ``.conf`` files
************************

This :file:`snippet.yml` adds :file:`foo.conf` to the sysbuild configuration:

.. code-block:: yaml

name: foo
append:
SB_EXTRA_CONF_FILE: foo.conf

The path to :file:`foo.conf` is relative to the directory containing
:file:`snippet.yml`.

``DTS_EXTRA_CPPFLAGS``
**********************

Expand Down
2 changes: 2 additions & 0 deletions scripts/schemas/snippet-schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
24 changes: 15 additions & 9 deletions scripts/snippets.py
Original file line number Diff line number Diff line change
Expand Up @@ -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}')
Expand All @@ -62,14 +62,18 @@ def append_value(variable, value):
_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.
Expand Down Expand Up @@ -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():
Expand All @@ -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

Expand All @@ -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.'''

Expand All @@ -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:
Expand Down
1 change: 1 addition & 0 deletions share/sysbuild/cmake/modules/sysbuild_default.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 8 additions & 0 deletions share/sysbuild/cmake/modules/sysbuild_kconfig.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 6 additions & 0 deletions share/sysbuild/cmake/modules/sysbuild_root.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,15 @@ 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})
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.
Expand All @@ -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 changes: 16 additions & 0 deletions share/sysbuild/cmake/modules/sysbuild_snippets.cmake
Original file line number Diff line number Diff line change
@@ -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)
1 change: 1 addition & 0 deletions tests/cmake/snippets/testcase.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ common:
- qemu_cortex_m3
integration_platforms:
- native_sim
sysbuild: false

tests:
# Test the initial state with no snippets applied
Expand Down
9 changes: 9 additions & 0 deletions tests/cmake/sysbuild_snippets/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# SPDX-License-Identifier: Apache-2.0

cmake_minimum_required(VERSION 3.20.0)

find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(test_snippets)

FILE(GLOB app_sources src/*.c)
target_sources(app PRIVATE ${app_sources})
13 changes: 13 additions & 0 deletions tests/cmake/sysbuild_snippets/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright 2024 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0

menu "Zephyr"
source "Kconfig.zephyr"
endmenu

# Test values set by the snippet config overlays and tested by the test logic
config TEST_FOO_VAL
int "Test value"
default 12
help
This option's value should be overridden by sysbuild.
22 changes: 22 additions & 0 deletions tests/cmake/sysbuild_snippets/Kconfig.sysbuild
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Copyright 2024 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0

config TEST_FOO_VAL
int "Test value"
default 0
help
This option's value should be overridden by the 'foo' snippet config overlay.

config EXPECTED_SB_TEST_FOO_VAL
int "Expected sysbuild test value"
default 999999
help
Expected sysbuild value for the test.

config EXPECTED_APP_TEST_FOO_VAL
int "Expected application test value"
default 999999
help
Expected application value for the test.

source "${ZEPHYR_BASE}/share/sysbuild/Kconfig"
1 change: 1 addition & 0 deletions tests/cmake/sysbuild_snippets/prj.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CONFIG_ZTEST=y
7 changes: 7 additions & 0 deletions tests/cmake/sysbuild_snippets/src/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/

/* Empty file */
11 changes: 11 additions & 0 deletions tests/cmake/sysbuild_snippets/sysbuild/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# SPDX-License-Identifier: Apache-2.0

cmake_minimum_required(VERSION 3.20.0)

set(SNIPPET_ROOT "${CMAKE_CURRENT_SOURCE_DIR}")
set(sysbuild_snippets_SNIPPET_ROOT "${CMAKE_CURRENT_SOURCE_DIR}" CACHE INTERNAL "")
set(EXTRA_ZEPHYR_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/test_module" CACHE INTERNAL "test_module directory")

find_package(Sysbuild REQUIRED HINTS $ENV{ZEPHYR_BASE})

project(sysbuild LANGUAGES)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CONFIG_TEST_FOO_VAL=18382
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SB_CONFIG_TEST_FOO_VAL=464372
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
name: foo
append:
SB_EXTRA_CONF_FILE: sb.conf
EXTRA_CONF_FILE: app.conf
24 changes: 24 additions & 0 deletions tests/cmake/sysbuild_snippets/sysbuild/test_module/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# SPDX-License-Identifier: Apache-2.0

function(${SYSBUILD_CURRENT_MODULE_NAME}_post_cmake)
ExternalProject_Get_Property(${DEFAULT_IMAGE} BINARY_DIR)
import_kconfig(CONFIG_ ${BINARY_DIR}/zephyr/.config)

if("${SB_CONFIG_TEST_FOO_VAL}" STREQUAL "${CONFIG_TEST_FOO_VAL}")
message(FATAL_ERROR "Values match (sysbuild and app): ${SB_CONFIG_TEST_FOO_VAL} and ${CONFIG_TEST_FOO_VAL}")
else()
message(NOTICE "Values diverge (sysbuild and app)")
endif()

if("${SB_CONFIG_EXPECTED_SB_TEST_FOO_VAL}" STREQUAL "${SB_CONFIG_TEST_FOO_VAL}")
message(NOTICE "Values match (sysbuild and snippet): ${SB_CONFIG_EXPECTED_SB_TEST_FOO_VAL} and ${SB_CONFIG_TEST_FOO_VAL}")
else()
message(FATAL_ERROR "Values diverge (sysbuild and snippet): ${SB_CONFIG_EXPECTED_SB_TEST_FOO_VAL} and ${SB_CONFIG_TEST_FOO_VAL}")
endif()

if("${SB_CONFIG_EXPECTED_APP_TEST_FOO_VAL}" STREQUAL "${CONFIG_TEST_FOO_VAL}")
message(NOTICE "Values match (app and snippet): ${SB_CONFIG_EXPECTED_APP_TEST_FOO_VAL} and ${CONFIG_TEST_FOO_VAL}")
else()
message(FATAL_ERROR "Values diverge (app and snippet): ${SB_CONFIG_EXPECTED_APP_TEST_FOO_VAL} and ${CONFIG_TEST_FOO_VAL}")
endif()
endfunction()
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
build:
sysbuild-cmake: .
20 changes: 20 additions & 0 deletions tests/cmake/sysbuild_snippets/testcase.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
common:
sysbuild: true
tags: sysbuild_snippets sysbuild
platform_allow:
- native_sim
integration_platforms:
- native_sim

tests:
# Test the initial state with no snippets applied
buildsystem.sysbuild.snippets.none:
extra_args:
- SB_CONFIG_EXPECTED_SB_TEST_FOO_VAL=0
- SB_CONFIG_EXPECTED_APP_TEST_FOO_VAL=12
# Test the `foo` snippet in sysbuild
buildsystem.sysbuild.snippets.applied:
extra_args:
- SNIPPET=foo
- SB_CONFIG_EXPECTED_SB_TEST_FOO_VAL=464372
- SB_CONFIG_EXPECTED_APP_TEST_FOO_VAL=18382
Loading