1# SPDX-License-Identifier: Apache-2.0 2# 3# Copyright (c) 2021, Nordic Semiconductor ASA 4 5# Snippets support 6# 7# This module: 8# 9# - searches for snippets in zephyr and any modules 10# - validates the SNIPPET input variable, if any 11# 12# If SNIPPET contains a snippet name that is not found, an error 13# will be raised, and the list of valid snippets will be printed. 14# 15# Outcome: 16# The following variables will be defined when this module completes: 17# 18# - SNIPPET_AS_LIST: CMake list of snippet names, created from the 19# SNIPPET variable 20# - SNIPPET_ROOT: CMake list of snippet roots, deduplicated and with 21# ZEPHYR_BASE appended at the end 22# 23# The following variables may be updated when this module completes: 24# - DTC_OVERLAY_FILE 25# - OVERLAY_CONFIG 26# 27# The following targets will be defined when this CMake module completes: 28# - snippets: when invoked, a list of valid snippets will be printed 29# 30# Optional variables: 31# - SNIPPET_ROOT: input CMake list of snippet roots (directories containing 32# additional snippet implementations); this should not include ZEPHYR_BASE, 33# as that will be added by this module 34 35include_guard(GLOBAL) 36 37include(extensions) 38 39# Warn the user if SNIPPET changes later. Such changes are ignored. 40zephyr_check_cache(SNIPPET WATCH) 41 42# Putting the body into a function prevents us from polluting the 43# parent scope. We'll set our outcome variables in the parent scope of 44# the function to ensure the outcome of the module. 45function(zephyr_process_snippets) 46 set(snippets_py ${ZEPHYR_BASE}/scripts/snippets.py) 47 set(snippets_generated ${CMAKE_BINARY_DIR}/zephyr/snippets_generated.cmake) 48 set_ifndef(SNIPPET_NAMESPACE SNIPPET) 49 set_ifndef(SNIPPET_PYTHON_EXTRA_ARGS "") 50 set_ifndef(SNIPPET_APP_DIR "${APPLICATION_SOURCE_DIR}") 51 52 # Set SNIPPET_AS_LIST, removing snippets_generated.cmake if we are 53 # running cmake again and snippets are no longer requested. 54 if(NOT DEFINED SNIPPET) 55 set(SNIPPET_AS_LIST "" PARENT_SCOPE) 56 file(REMOVE ${snippets_generated}) 57 else() 58 string(REPLACE " " ";" SNIPPET_AS_LIST "${${SNIPPET_NAMESPACE}}") 59 set(SNIPPET_AS_LIST "${SNIPPET_AS_LIST}" PARENT_SCOPE) 60 endif() 61 62 # Set SNIPPET_ROOT. 63 zephyr_get(SNIPPET_ROOT MERGE SYSBUILD GLOBAL) 64 list(APPEND SNIPPET_ROOT ${SNIPPET_APP_DIR}) 65 list(APPEND SNIPPET_ROOT ${ZEPHYR_BASE}) 66 unset(real_snippet_root) 67 foreach(snippet_dir ${SNIPPET_ROOT}) 68 # The user might have put a symbolic link in here, for example. 69 file(REAL_PATH ${snippet_dir} real_snippet_dir) 70 list(APPEND real_snippet_root ${real_snippet_dir}) 71 endforeach() 72 set(SNIPPET_ROOT ${real_snippet_root}) 73 list(REMOVE_DUPLICATES SNIPPET_ROOT) 74 set(SNIPPET_ROOT "${SNIPPET_ROOT}" PARENT_SCOPE) 75 76 # Generate and include snippets_generated.cmake. 77 # The Python script is responsible for checking for unknown 78 # snippets. 79 set(snippet_root_args) 80 foreach(root IN LISTS SNIPPET_ROOT) 81 list(APPEND snippet_root_args --snippet-root "${root}") 82 endforeach() 83 set(requested_snippet_args) 84 foreach(snippet_name ${SNIPPET_AS_LIST}) 85 list(APPEND requested_snippet_args --snippet "${snippet_name}") 86 endforeach() 87 execute_process(COMMAND ${PYTHON_EXECUTABLE} 88 ${snippets_py} 89 ${snippet_root_args} 90 ${requested_snippet_args} 91 --cmake-out ${snippets_generated} 92 ${SNIPPET_PYTHON_EXTRA_ARGS} 93 OUTPUT_VARIABLE output 94 ERROR_VARIABLE output 95 RESULT_VARIABLE ret) 96 if(${ret}) 97 message(FATAL_ERROR "${output}") 98 endif() 99 include(${snippets_generated}) 100 101 # Create the 'snippets' target. Each snippet is printed in a 102 # separate command because build system files are not fond of 103 # newlines. 104 list(TRANSFORM SNIPPET_NAMES PREPEND "COMMAND;${CMAKE_COMMAND};-E;echo;" 105 OUTPUT_VARIABLE snippets_target_cmd) 106 add_custom_target(snippets ${snippets_target_cmd} USES_TERMINAL) 107 108 # If snippets were requested, print messages for each one. 109 if(SNIPPET_AS_LIST) 110 # Print the requested snippets. 111 set(snippet_names "Snippet(s):") 112 foreach(snippet IN LISTS SNIPPET_AS_LIST) 113 string(APPEND snippet_names " ${snippet}") 114 endforeach() 115 message(STATUS "${snippet_names}") 116 endif() 117 118 # Re-run cmake if any files we depend on changed. 119 set_property(DIRECTORY APPEND PROPERTY 120 CMAKE_CONFIGURE_DEPENDS 121 ${snippets_py} 122 ${SNIPPET_PATHS} # generated variable 123 ) 124endfunction() 125 126zephyr_process_snippets() 127