1# SPDX-License-Identifier: Apache-2.0
2
3function(runners_yaml_append content)
4  # Append ${content}\n to a target property which is later evaluated as a
5  # generator expression when writing the flash runner yaml file.
6  # We define this function here to have access to the `flash` target.
7
8  set_property(
9    TARGET         runners_yaml_props_target
10    APPEND_STRING
11    PROPERTY       yaml_contents
12    "${content}\n"
13    )
14endfunction()
15
16function(get_runners_prop prop out_var default_value)
17  # Get property 'prop' from runners_yaml_props_target, storing its
18  # value in 'out_var'. If the property is not found (value is
19  # ...-NOTFOUND), 'out_var' is set to 'default_value'.
20
21  get_target_property(out runners_yaml_props_target "${prop}")
22
23  if("${out}" STREQUAL "out-NOTFOUND")
24    set("${out_var}" "${default_value}" PARENT_SCOPE)
25  else()
26    set("${out_var}" "${out}" PARENT_SCOPE)
27  endif()
28endfunction()
29
30function(runners_yaml_append_config)
31  # Append the common configuration values to the relevant property target.
32
33  runners_yaml_append("\n# Common runner configuration values.")
34  runners_yaml_append("config:")
35  runners_yaml_append("  board_dir: ${BOARD_DIR}")
36  get_runners_prop(elf_file elf "${KERNEL_ELF_NAME}")
37  runners_yaml_append("  # Build outputs:")
38  runners_yaml_append("  elf_file: ${elf}")
39  if(CONFIG_BUILD_OUTPUT_EXE)
40    get_runners_prop(exe_file exe "${KERNEL_EXE_NAME}")
41  else()
42    get_runners_prop(exe_file exe "")
43  endif()
44  if(exe)
45    runners_yaml_append("  exe_file: ${exe}")
46  endif()
47  if(CONFIG_BUILD_OUTPUT_HEX)
48    get_runners_prop(hex_file hex "${KERNEL_HEX_NAME}")
49  else()
50    get_runners_prop(hex_file hex "")
51  endif()
52  if(hex)
53    runners_yaml_append("  hex_file: ${hex}")
54  endif()
55  if(CONFIG_BUILD_OUTPUT_BIN)
56    get_runners_prop(bin_file bin "${KERNEL_BIN_NAME}")
57    runners_yaml_append("  bin_file: ${bin}")
58  endif()
59  if(CONFIG_BUILD_OUTPUT_UF2)
60    get_runners_prop(uf2_file uf2 "${KERNEL_UF2_NAME}")
61    runners_yaml_append("  uf2_file: ${uf2}")
62  endif()
63
64  if(CMAKE_GDB OR OPENOCD OR OPENOCD_DEFAULT_PATH)
65    runners_yaml_append("  # Host tools:")
66  endif()
67  if(CMAKE_GDB)
68    runners_yaml_append("  gdb: ${CMAKE_GDB}")
69  endif()
70  if(OPENOCD)
71    runners_yaml_append("  openocd: ${OPENOCD}")
72    runners_yaml_append("  openocd_search:")
73    if(OPENOCD_DEFAULT_PATH)
74      runners_yaml_append("    - ${OPENOCD_DEFAULT_PATH}")
75    endif()
76  endif()
77  runners_yaml_append("")
78endfunction()
79
80# Save runner state in a YAML file, and put that YAML file's location
81# in the cache.
82function(create_runners_yaml)
83  set(runners ${ARGV})
84
85  set(runners_yaml "${PROJECT_BINARY_DIR}/runners.yaml")
86
87  runners_yaml_append("# Available runners configured by board.cmake.\nrunners:")
88  foreach(runner ${runners})
89    runners_yaml_append("- ${runner}")
90  endforeach()
91
92  if(DEFINED BOARD_FLASH_RUNNER)
93    runners_yaml_append("\n# Default flash runner if --runner is not given.")
94    runners_yaml_append("flash-runner: ${BOARD_FLASH_RUNNER}")
95  endif()
96  if(DEFINED BOARD_DEBUG_RUNNER)
97    runners_yaml_append("\n# Default debug runner if --runner is not given.")
98    runners_yaml_append("debug-runner: ${BOARD_DEBUG_RUNNER}")
99  endif()
100
101  # Sets up common runner configuration values.
102  runners_yaml_append_config()
103
104  # Get runner-specific arguments set in the board files.
105  runners_yaml_append("# Runner specific arguments")
106  runners_yaml_append("args:")
107  foreach(runner ${runners})
108    string(MAKE_C_IDENTIFIER ${runner} runner_id)
109    runners_yaml_append("  ${runner}:")
110    get_property(args GLOBAL PROPERTY "BOARD_RUNNER_ARGS_${runner_id}")
111    if(args)
112      # Usually, the runner has arguments. Append them to runners.yaml,
113      # one per line.
114      foreach(arg ${args})
115        runners_yaml_append("    - ${arg}")
116      endforeach()
117    else()
118      # If the runner doesn't need any arguments, just use an empty list.
119      runners_yaml_append("    []\n")
120    endif()
121  endforeach()
122
123  # Write the final contents and set its location in the cache.
124  file(GENERATE OUTPUT "${runners_yaml}" CONTENT
125    $<TARGET_PROPERTY:runners_yaml_props_target,yaml_contents>)
126  set(ZEPHYR_RUNNERS_YAML "${runners_yaml}" CACHE INTERNAL
127    "a configuration file for the runners Python package")
128endfunction()
129
130get_property(RUNNERS GLOBAL PROPERTY ZEPHYR_RUNNERS)
131
132# Persist the runner-related state.
133#
134# Available runners and their arguments are configured in board.cmake
135# files.
136#
137# Everything is marked with FORCE so that re-running CMake updates the
138# configuration if the board files change.
139if(RUNNERS)
140  create_runners_yaml(${RUNNERS})
141endif()
142
143zephyr_get(WEST_DIR)
144if(WEST_DIR)
145  set(WEST "PYTHONPATH=${WEST_DIR}/src" "${PYTHON_EXECUTABLE};${WEST_DIR}/src/west/app/main.py;--zephyr-base=${ZEPHYR_BASE} ")
146endif()
147
148# Generate the flash, debug, debugserver, attach targets within the build
149# system itself.
150foreach(target flash debug debugserver attach)
151  if(target STREQUAL flash)
152    set(comment "Flashing ${BOARD}")
153  elseif(target STREQUAL debug)
154    set(comment "Debugging ${BOARD}")
155  elseif(target STREQUAL debugserver)
156    set(comment "Debugging ${BOARD}")
157    if(SUPPORTED_EMU_PLATFORMS)
158      # cmake/qemu/CMakeLists.txt will add a debugserver target for
159      # emulation platforms, so we don't add one here
160      continue()
161    endif()
162  elseif(target STREQUAL attach)
163    set(comment "Debugging ${BOARD}")
164  endif()
165  string(TOUPPER ${target} TARGET_UPPER)
166
167  list(APPEND RUNNERS_DEPS ${logical_target_for_zephyr_elf})
168
169  # Enable verbose output, if requested.
170  if(CMAKE_VERBOSE_MAKEFILE)
171    set(RUNNER_VERBOSE "--verbose")
172  else()
173    set(RUNNER_VERBOSE)
174  endif()
175
176  if(WEST)
177    add_custom_target(${target}
178      # This script will print an error message and fail if <target> has added
179      # dependencies. This is done using dedicated CMake script, as
180      # `cmake -E {true|false}` is not available until CMake 3.16.
181      COMMAND ${CMAKE_COMMAND}
182        -DTARGET=${target}
183        -DDEPENDENCIES="$<TARGET_PROPERTY:${target},MANUALLY_ADDED_DEPENDENCIES>"
184        -P ${CMAKE_CURRENT_LIST_DIR}/check_runner_dependencies.cmake
185      COMMAND
186        ${CMAKE_COMMAND} -E env
187        ${WEST}
188        ${RUNNER_VERBOSE}
189        ${target}
190      WORKING_DIRECTORY
191        ${APPLICATION_BINARY_DIR}
192      COMMENT
193        ${comment}
194      USES_TERMINAL
195    )
196  else()
197    add_custom_target(${target}
198      COMMAND ${CMAKE_COMMAND} -E echo \"West was not found in path. To support
199          '${CMAKE_MAKE_PROGRAM} ${target}', please create a west workspace.\"
200      USES_TERMINAL
201      )
202  endif(WEST)
203endforeach()
204