1# SPDX-License-Identifier: Apache-2.0 2# 3# Copyright (c) 2021, Nordic Semiconductor ASA 4 5# Validate shields and setup shields target. 6# 7# This module will validate the SHIELD argument. 8# 9# If a shield implementation is not found for one of the specified shields, an 10# error will be raised and a list of valid shields will be printed. 11# 12# Outcome: 13# The following variables will be defined when this module completes: 14# - shield_conf_files: List of shield-specific Kconfig fragments 15# - shield_dts_files : List of shield-specific devicetree files 16# - SHIELD_AS_LIST : A CMake list of shields created from the SHIELD variable. 17# - SHIELD_DIRS : A CMake list of directories which contain shield definitions 18# 19# The following targets will be defined when this CMake module completes: 20# - shields: when invoked, a list of valid shields will be printed 21# 22# If the SHIELD variable is changed after this module completes, 23# a warning will be printed. 24# 25# Optional variables: 26# - BOARD_ROOT: CMake list of board roots containing board implementations 27# 28# Variables set by this module and not mentioned above are for internal 29# use only, and may be removed, renamed, or re-purposed without prior notice. 30 31include_guard(GLOBAL) 32 33include(extensions) 34include(python) 35 36# Check that SHIELD has not changed. 37zephyr_check_cache(SHIELD WATCH) 38 39if(SHIELD) 40 message(STATUS "Shield(s): ${SHIELD}") 41endif() 42 43if(DEFINED SHIELD) 44 string(REPLACE " " ";" SHIELD_AS_LIST "${SHIELD}") 45endif() 46# SHIELD-NOTFOUND is a real CMake list, from which valid shields can be popped. 47# After processing all shields, only invalid shields will be left in this list. 48set(SHIELD-NOTFOUND ${SHIELD_AS_LIST}) 49 50# Prepare list shields command. 51# This command is used for locating the shield dir as well as printing all shields 52# in the system in the following cases: 53# - User specifies an invalid SHIELD 54# - User invokes '<build-command> shields' target 55list(TRANSFORM BOARD_ROOT PREPEND "--board-root=" OUTPUT_VARIABLE board_root_args) 56 57set(list_shields_commands 58 COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/list_shields.py 59 ${board_root_args} --json 60) 61 62# Get list of shields in JSON format 63execute_process(${list_shields_commands} 64 OUTPUT_VARIABLE shields_json 65 ERROR_VARIABLE err_shields 66 RESULT_VARIABLE ret_val 67) 68 69if(ret_val) 70 message(FATAL_ERROR "Error finding shields\nError message: ${err_shields}") 71endif() 72 73string(JSON shields_length LENGTH ${shields_json}) 74 75if(shields_length GREATER 0) 76 math(EXPR shields_length "${shields_length} - 1") 77 78 foreach(i RANGE ${shields_length}) 79 string(JSON shield GET "${shields_json}" "${i}") 80 string(JSON shield_name GET ${shield} name) 81 string(JSON shield_dir GET ${shield} dir) 82 list(APPEND SHIELD_LIST ${shield_name}) 83 set(SHIELD_DIR_${shield_name} ${shield_dir}) 84 endforeach() 85endif() 86 87# Process shields in-order 88if(DEFINED SHIELD) 89 foreach(s ${SHIELD_AS_LIST}) 90 if(NOT ${s} IN_LIST SHIELD_LIST) 91 continue() 92 endif() 93 94 list(REMOVE_ITEM SHIELD-NOTFOUND ${s}) 95 96 # Add <shield>.overlay to the shield_dts_files output variable. 97 list(APPEND 98 shield_dts_files 99 ${SHIELD_DIR_${s}}/${s}.overlay 100 ) 101 102 # Add the shield's directory to the SHIELD_DIRS output variable. 103 list(APPEND 104 SHIELD_DIRS 105 ${SHIELD_DIR_${s}} 106 ) 107 108 include(${SHIELD_DIR_${s}}/pre_dt_shield.cmake OPTIONAL) 109 110 # Search for shield/shield.conf file 111 if(EXISTS ${SHIELD_DIR_${s}}/${s}.conf) 112 list(APPEND 113 shield_conf_files 114 ${SHIELD_DIR_${s}}/${s}.conf 115 ) 116 endif() 117 118 # Add board-specific .conf and .overlay files to their 119 # respective output variables. 120 zephyr_file(CONF_FILES ${SHIELD_DIR_${s}}/boards 121 DTS shield_dts_files 122 KCONF shield_conf_files 123 ) 124 zephyr_file(CONF_FILES ${SHIELD_DIR_${s}}/boards/${s} 125 DTS shield_dts_files 126 KCONF shield_conf_files 127 ) 128 endforeach() 129endif() 130 131# Prepare shield usage command printing. 132# This command prints all shields in the system in the following cases: 133# - User specifies an invalid SHIELD 134# - User invokes '<build-command> shields' target 135list(SORT SHIELD_LIST) 136 137if(DEFINED SHIELD AND NOT (SHIELD-NOTFOUND STREQUAL "")) 138 # Convert the list to pure string with newlines for printing. 139 string(REPLACE ";" "\n" shield_string "${SHIELD_LIST}") 140 141 foreach (s ${SHIELD-NOTFOUND}) 142 message("No shield named '${s}' found") 143 endforeach() 144 message("Please choose from among the following shields:\n" 145 "${shield_string}" 146 ) 147 unset(CACHED_SHIELD CACHE) 148 message(FATAL_ERROR "Invalid SHIELD; see above.") 149endif() 150 151# Prepend each shield with COMMAND <cmake> -E echo <shield>" for printing. 152# Each shield is printed as new command because build files are not fond of newlines. 153list(TRANSFORM SHIELD_LIST PREPEND "COMMAND;${CMAKE_COMMAND};-E;echo;" 154 OUTPUT_VARIABLE shields_target_cmd 155) 156 157add_custom_target(shields ${shields_target_cmd} USES_TERMINAL) 158