Skip to content

Commit

Permalink
cmake: use GLOBAL property instead TARGET properties for scoping
Browse files Browse the repository at this point in the history
Targets are not available in script mode.
To support the Zephyr scoping feature used by snippets and yaml module
then this commit moves from using custom targets to use GLOBAL
properties for scopes.

A scope property is prefixed with `<scope>:<property>` to avoid naming
collisions.
A `scope:<scope-name>` global property is used to track created scopes.
Tracking valid scopes ensure that properties are only set on known
scopes and thus catches typos / naming errors.

Add zephyr_scope_exists() and zephyr_get_scoped() to abstract the
implementation details of the scoped property retrieval and refactor
current code to use them.

Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no>
Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
  • Loading branch information
tejlmand authored and kartben committed Dec 26, 2024
1 parent 535c40d commit 4e29a35
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 22 deletions.
66 changes: 53 additions & 13 deletions cmake/modules/extensions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -3251,8 +3251,9 @@ function(zephyr_get variable)
set(sysbuild_global_${var})
endif()

if(TARGET snippets_scope)
get_property(snippets_${var} TARGET snippets_scope PROPERTY ${var})
zephyr_scope_exists(scope_defined snippets)
if(scope_defined)
zephyr_get_scoped(snippets_${var} snippets ${var})
endif()
endforeach()

Expand Down Expand Up @@ -3317,11 +3318,54 @@ endfunction(zephyr_get variable)
# <scope>: Name of new scope.
#
function(zephyr_create_scope scope)
if(TARGET ${scope}_scope)
zephyr_scope_exists(scope_defined ${scope})
if(scope_defined)
message(FATAL_ERROR "zephyr_create_scope(${scope}) already exists.")
endif()

add_custom_target(${scope}_scope)
set_property(GLOBAL PROPERTY scope:${scope} TRUE)
endfunction()

# Usage:
# zephyr_scope_exists(<result> <scope>)
#
# Check if <scope> exists.
#
# <result>: Variable to set with result.
# TRUE if scope exists, FALSE otherwise.
# <scope> : Name of scope.
#
function(zephyr_scope_exists result scope)
get_property(scope_defined GLOBAL PROPERTY scope:${scope})
if(scope_defined)
set(${result} TRUE PARENT_SCOPE)
else()
set(${result} FALSE PARENT_SCOPE)
endif()
endfunction()

# Usage:
# zephyr_get_scoped(<output> <scope> <var>)
#
# Get the current value of <var> in a specific <scope>, as defined by a
# previous zephyr_set() call. The value will be stored in the <output> var.
#
# <output> : Variable to store the value in
# <scope> : Scope for the variable look up
# <var> : Name to look up in the specific scope
#
function(zephyr_get_scoped output scope var)
zephyr_scope_exists(scope_defined ${scope})
if(NOT scope_defined)
message(FATAL_ERROR "zephyr_get_scoped(): scope ${scope} doesn't exists.")
endif()

get_property(value GLOBAL PROPERTY ${scope}_scope:${var})
if(DEFINED value)
set(${output} "${value}" PARENT_SCOPE)
else()
unset(${output} PARENT_SCOPE)
endif()
endfunction()

# Usage:
Expand All @@ -3342,16 +3386,17 @@ function(zephyr_set variable)

zephyr_check_arguments_required_all(zephyr_set SET_VAR SCOPE)

if(NOT TARGET ${SET_VAR_SCOPE}_scope)
zephyr_scope_exists(scope_defined ${SET_VAR_SCOPE})
if(NOT scope_defined)
message(FATAL_ERROR "zephyr_set(... SCOPE ${SET_VAR_SCOPE}) doesn't exists.")
endif()

if(SET_VAR_APPEND)
set(property_args APPEND)
endif()

set_property(TARGET ${SET_VAR_SCOPE}_scope ${property_args}
PROPERTY ${variable} ${SET_VAR_UNPARSED_ARGUMENTS}
set_property(GLOBAL ${property_args} PROPERTY
${SET_VAR_SCOPE}_scope:${variable} ${SET_VAR_UNPARSED_ARGUMENTS}
)
endfunction()

Expand Down Expand Up @@ -5886,16 +5931,11 @@ if(CMAKE_SCRIPT_MODE_FILE)
# This silence the error: 'set_target_properties command is not scriptable'
endfunction()

function(zephyr_set variable)
# This silence the error: zephyr_set(... SCOPE <scope>) doesn't exists.
endfunction()

# Build info creates a custom target for handling of build info.
# build_info is not needed in script mode but still called by Zephyr CMake
# modules. Therefore disable build_info(...) in when including
# extensions.cmake in script mode.
function(build_info)
# This silence the error: 'YAML context 'build_info' does not exist.'
# 'Remember to create a YAML context'
# This silence the error: 'Unknown CMake command "yaml_context"'
endfunction()
endif()
17 changes: 9 additions & 8 deletions cmake/modules/yaml.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ function(yaml_context)
)
endif()

if(TARGET ${ARG_YAML_NAME}_scope)
zephyr_scope_exists(scope_defined ${ARG_YAML_NAME})
if(scope_defined)
list(POP_FRONT ARG_YAML_UNPARSED_ARGUMENTS out-var)
set(${out-var} TRUE PARENT_SCOPE)
else()
Expand Down Expand Up @@ -183,7 +184,7 @@ function(yaml_get out_var)
zephyr_check_arguments_required_all(${CMAKE_CURRENT_FUNCTION} ARG_YAML NAME KEY)
internal_yaml_context_required(NAME ${ARG_YAML_NAME})

get_property(json_content TARGET ${ARG_YAML_NAME}_scope PROPERTY JSON)
zephyr_get_scoped(json_content ${ARG_YAML_NAME} JSON)

# We specify error variable to avoid a fatal error.
# If key is not found, then type becomes '-NOTFOUND' and value handling is done below.
Expand Down Expand Up @@ -224,7 +225,7 @@ function(yaml_length out_var)
zephyr_check_arguments_required_all(${CMAKE_CURRENT_FUNCTION} ARG_YAML NAME KEY)
internal_yaml_context_required(NAME ${ARG_YAML_NAME})

get_property(json_content TARGET ${ARG_YAML_NAME}_scope PROPERTY JSON)
zephyr_get_scoped(json_content ${ARG_YAML_NAME} JSON)

string(JSON type ERROR_VARIABLE error TYPE "${json_content}" ${ARG_YAML_KEY})
if(type STREQUAL ARRAY)
Expand Down Expand Up @@ -262,7 +263,7 @@ function(yaml_set)
zephyr_check_arguments_exclusive(${CMAKE_CURRENT_FUNCTION} ARG_YAML VALUE LIST)
internal_yaml_context_required(NAME ${ARG_YAML_NAME})

get_property(json_content TARGET ${ARG_YAML_NAME}_scope PROPERTY JSON)
zephyr_get_scoped(json_content ${ARG_YAML_NAME} JSON)

set(yaml_key_undefined ${ARG_YAML_KEY})
foreach(k ${yaml_key_undefined})
Expand Down Expand Up @@ -335,7 +336,7 @@ function(yaml_remove)
zephyr_check_arguments_required_all(${CMAKE_CURRENT_FUNCTION} ARG_YAML NAME KEY)
internal_yaml_context_required(NAME ${ARG_YAML_NAME})

get_property(json_content TARGET ${ARG_YAML_NAME}_scope PROPERTY JSON)
zephyr_get_scoped(json_content ${ARG_YAML_NAME} JSON)
string(JSON json_content REMOVE "${json_content}" ${ARG_YAML_KEY})

zephyr_set(JSON "${json_content}" SCOPE ${ARG_YAML_NAME})
Expand All @@ -359,18 +360,18 @@ function(yaml_save)
zephyr_check_arguments_required(${CMAKE_CURRENT_FUNCTION} ARG_YAML NAME)
internal_yaml_context_required(NAME ${ARG_YAML_NAME})

get_target_property(yaml_file ${ARG_YAML_NAME}_scope FILE)
zephyr_get_scoped(yaml_file ${ARG_YAML_NAME} FILE)
if(NOT yaml_file)
zephyr_check_arguments_required(${CMAKE_CURRENT_FUNCTION} ARG_YAML FILE)
endif()

get_property(json_content TARGET ${ARG_YAML_NAME}_scope PROPERTY JSON)
zephyr_get_scoped(json_content ${ARG_YAML_NAME} JSON)
to_yaml("${json_content}" 0 yaml_out)

if(DEFINED ARG_YAML_FILE)
set(yaml_file ${ARG_YAML_FILE})
else()
get_property(yaml_file TARGET ${ARG_YAML_NAME}_scope PROPERTY FILE)
zephyr_get_scoped(yaml_file ${ARG_YAML_NAME} FILE)
endif()
if(EXISTS ${yaml_file})
FILE(RENAME ${yaml_file} ${yaml_file}.bak)
Expand Down
3 changes: 2 additions & 1 deletion tests/cmake/zephyr_get/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,8 @@ endfunction()


function(test_snippets_scope)
if(NOT TARGET snippets_scope)
zephyr_scope_exists(snippets_defined snippets)
if(NOT snippets_defined)
zephyr_create_scope(snippets)
endif()

Expand Down

0 comments on commit 4e29a35

Please sign in to comment.