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