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) 34 35# Check that SHIELD has not changed. 36zephyr_check_cache(SHIELD WATCH) 37 38if(SHIELD) 39 message(STATUS "Shield(s): ${SHIELD}") 40endif() 41 42if(DEFINED SHIELD) 43 string(REPLACE " " ";" SHIELD_AS_LIST "${SHIELD}") 44endif() 45# SHIELD-NOTFOUND is a real CMake list, from which valid shields can be popped. 46# After processing all shields, only invalid shields will be left in this list. 47set(SHIELD-NOTFOUND ${SHIELD_AS_LIST}) 48 49foreach(root ${BOARD_ROOT}) 50 set(shield_dir ${root}/boards/shields) 51 # Match the Kconfig.shield files in the shield directories to make sure we are 52 # finding shields, e.g. x_nucleo_iks01a1/Kconfig.shield 53 file(GLOB_RECURSE shields_refs_list ${shield_dir}/*/Kconfig.shield) 54 55 # The above gives a list of Kconfig.shield files, like this: 56 # 57 # x_nucleo_iks01a1/Kconfig.shield;x_nucleo_iks01a2/Kconfig.shield 58 # 59 # we construct a list of shield names by extracting the directories 60 # from each file and looking for <shield>.overlay files in there. 61 # Each overlay corresponds to a shield. We obtain the shield name by 62 # removing the .overlay extension. 63 unset(SHIELD_LIST) 64 foreach(shields_refs ${shields_refs_list}) 65 get_filename_component(shield_path ${shields_refs} DIRECTORY) 66 file(GLOB shield_overlays RELATIVE ${shield_path} ${shield_path}/*.overlay) 67 foreach(overlay ${shield_overlays}) 68 get_filename_component(shield ${overlay} NAME_WE) 69 list(APPEND SHIELD_LIST ${shield}) 70 set(SHIELD_DIR_${shield} ${shield_path}) 71 endforeach() 72 endforeach() 73 74 if(DEFINED SHIELD) 75 foreach(s ${SHIELD_AS_LIST}) 76 if(NOT ${s} IN_LIST SHIELD_LIST) 77 continue() 78 endif() 79 80 list(REMOVE_ITEM SHIELD-NOTFOUND ${s}) 81 82 # Add <shield>.overlay to the shield_dts_files output variable. 83 list(APPEND 84 shield_dts_files 85 ${SHIELD_DIR_${s}}/${s}.overlay 86 ) 87 88 # Add the shield's directory to the SHIELD_DIRS output variable. 89 list(APPEND 90 SHIELD_DIRS 91 ${SHIELD_DIR_${s}} 92 ) 93 94 # Search for shield/shield.conf file 95 if(EXISTS ${SHIELD_DIR_${s}}/${s}.conf) 96 # Add <shield>.conf to the shield_conf_files output variable. 97 list(APPEND 98 shield_conf_files 99 ${SHIELD_DIR_${s}}/${s}.conf 100 ) 101 endif() 102 103 # Add board-specific .conf and .overlay files to their 104 # respective output variables. 105 zephyr_file(CONF_FILES ${SHIELD_DIR_${s}}/boards 106 DTS shield_dts_files 107 KCONF shield_conf_files 108 ) 109 zephyr_file(CONF_FILES ${SHIELD_DIR_${s}}/boards/${s} 110 DTS shield_dts_files 111 KCONF shield_conf_files 112 ) 113 endforeach() 114 endif() 115endforeach() 116 117# Prepare shield usage command printing. 118# This command prints all shields in the system in the following cases: 119# - User specifies an invalid SHIELD 120# - User invokes '<build-command> shields' target 121list(SORT SHIELD_LIST) 122 123if(DEFINED SHIELD AND NOT (SHIELD-NOTFOUND STREQUAL "")) 124 # Convert the list to pure string with newlines for printing. 125 string(REPLACE ";" "\n" shield_string "${SHIELD_LIST}") 126 127 foreach (s ${SHIELD-NOTFOUND}) 128 message("No shield named '${s}' found") 129 endforeach() 130 message("Please choose from among the following shields:\n" 131 "${shield_string}" 132 ) 133 unset(CACHED_SHIELD CACHE) 134 message(FATAL_ERROR "Invalid SHIELD; see above.") 135endif() 136 137# Prepend each shield with COMMAND <cmake> -E echo <shield>" for printing. 138# Each shield is printed as new command because build files are not fond of newlines. 139list(TRANSFORM SHIELD_LIST PREPEND "COMMAND;${CMAKE_COMMAND};-E;echo;" 140 OUTPUT_VARIABLE shields_target_cmd 141) 142 143add_custom_target(shields ${shields_target_cmd} USES_TERMINAL) 144