1# SPDX-License-Identifier: Apache-2.0
2
3include_guard(GLOBAL)
4
5include(user_cache)
6
7# Dependencies on CMake modules from the CMake distribution.
8include(CheckCCompilerFlag)
9include(CheckCXXCompilerFlag)
10
11########################################################
12# Table of contents
13########################################################
14# 1. Zephyr-aware extensions
15# 1.1. zephyr_*
16# 1.2. zephyr_library_*
17# 1.2.1 zephyr_interface_library_*
18# 1.3. generate_inc_*
19# 1.4. board_*
20# 1.5. Misc.
21# 2. Kconfig-aware extensions
22# 2.1 Misc
23# 3. CMake-generic extensions
24# 3.1. *_ifdef
25# 3.2. *_ifndef
26# 3.3. *_option compiler compatibility checks
27# 3.3.1 Toolchain integration
28# 3.4. Debugging CMake
29# 3.5. File system management
30# 4. Devicetree extensions
31# 4.1 dt_*
32# 4.2. *_if_dt_node
33# 4.3  zephyr_dt_*
34# 5. Zephyr linker functions
35# 5.1. zephyr_linker*
36# 6 Function helper macros
37# 7 Linkable loadable extensions (llext)
38# 7.1 llext_* configuration functions
39# 7.2 add_llext_* build control functions
40# 7.3 llext helper functions
41# 8. Script mode handling
42
43########################################################
44# 1. Zephyr-aware extensions
45########################################################
46# 1.1. zephyr_*
47#
48# The following methods are for modifying the CMake library[0] called
49# "zephyr". zephyr is a catch-all CMake library for source files that
50# can be built purely with the include paths, defines, and other
51# compiler flags that all zephyr source files use.
52# [0] https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html
53#
54# Example usage:
55# zephyr_sources(
56#   random_esp32.c
57#   utils.c
58# )
59#
60# Is short for:
61# target_sources(zephyr PRIVATE
62#   ${CMAKE_CURRENT_SOURCE_DIR}/random_esp32.c
63#   ${CMAKE_CURRENT_SOURCE_DIR}/utils.c
64# )
65#
66# As a very high-level introduction here are two call graphs that are
67# purposely minimalistic and incomplete.
68#
69#  zephyr_library_cc_option()
70#           |
71#           v
72#  zephyr_library_compile_options()  -->  target_compile_options()
73#
74#
75#  zephyr_cc_option()           --->  target_cc_option()
76#                                          |
77#                                          v
78#  zephyr_cc_option_fallback()  --->  target_cc_option_fallback()
79#                                          |
80#                                          v
81#  zephyr_compile_options()     --->  target_compile_options()
82#
83
84
85# https://cmake.org/cmake/help/latest/command/target_sources.html
86function(zephyr_sources)
87  foreach(arg ${ARGV})
88    if(IS_DIRECTORY ${arg})
89      message(FATAL_ERROR "zephyr_sources() was called on a directory")
90    endif()
91    target_sources(zephyr PRIVATE ${arg})
92  endforeach()
93endfunction()
94
95# https://cmake.org/cmake/help/latest/command/target_include_directories.html
96function(zephyr_include_directories)
97  target_include_directories(zephyr_interface INTERFACE ${ARGV})
98endfunction()
99
100# https://cmake.org/cmake/help/latest/command/target_include_directories.html
101function(zephyr_system_include_directories)
102  target_include_directories(zephyr_interface SYSTEM INTERFACE ${ARGV})
103endfunction()
104
105# https://cmake.org/cmake/help/latest/command/target_compile_definitions.html
106function(zephyr_compile_definitions)
107  target_compile_definitions(zephyr_interface INTERFACE ${ARGV})
108endfunction()
109
110# https://cmake.org/cmake/help/latest/command/target_compile_options.html
111function(zephyr_compile_options)
112  if(ARGV0 STREQUAL "PROPERTY")
113    set(property $<TARGET_PROPERTY:compiler,${ARGV1}>)
114    set(property_defined $<BOOL:${property}>)
115    if(ARGC GREATER 3)
116      message(FATAL_ERROR "zephyr_compile_options(PROPERTY <prop> [<var>]) "
117                          "called with too many arguments."
118      )
119    elseif(ARGC EQUAL 3)
120      target_compile_options(zephyr_interface INTERFACE $<${property_defined}:${property}${ARGV2}>)
121    else()
122      target_compile_options(zephyr_interface INTERFACE ${property})
123    endif()
124  else()
125    target_compile_options(zephyr_interface INTERFACE ${ARGV})
126  endif()
127endfunction()
128
129# https://cmake.org/cmake/help/latest/command/target_link_libraries.html
130function(zephyr_link_libraries)
131  if(ARGV0 STREQUAL "PROPERTY")
132    set(property $<TARGET_PROPERTY:linker,${ARGV1}>)
133    set(property_defined $<BOOL:${property}>)
134    if(ARGC GREATER 3)
135      message(FATAL_ERROR "zephyr_link_options(PROPERTY <prop> [<val>]) "
136                          "called with too many arguments."
137      )
138    elseif(ARGC EQUAL 3)
139      target_link_libraries(zephyr_interface INTERFACE $<${property_defined}:${property}${ARGV2}>)
140    else()
141      target_link_libraries(zephyr_interface INTERFACE ${property})
142    endif()
143  else()
144    target_link_libraries(zephyr_interface INTERFACE ${ARGV})
145  endif()
146endfunction()
147
148function(zephyr_libc_link_libraries)
149  set_property(TARGET zephyr_interface APPEND PROPERTY LIBC_LINK_LIBRARIES ${ARGV})
150endfunction()
151
152# See this file section 3.1. target_cc_option
153function(zephyr_cc_option)
154  foreach(arg ${ARGV})
155    target_cc_option(zephyr_interface INTERFACE ${arg})
156  endforeach()
157endfunction()
158
159function(zephyr_cc_option_fallback option1 option2)
160    target_cc_option_fallback(zephyr_interface INTERFACE ${option1} ${option2})
161endfunction()
162
163function(zephyr_ld_options)
164    target_ld_options(zephyr_interface INTERFACE ${ARGV})
165endfunction()
166
167# Getter functions for extracting build information from
168# zephyr_interface. Returning lists, and strings is supported, as is
169# requesting specific categories of build information (defines,
170# includes, options).
171#
172# The naming convention follows:
173# zephyr_get_${build_information}_for_lang${format}(lang x [STRIP_PREFIX])
174# Where
175#  the argument 'x' is written with the result
176# and
177#  ${build_information} can be one of
178#   - include_directories           # -I directories
179#   - system_include_directories    # -isystem directories
180#   - compile_definitions           # -D'efines
181#   - compile_options               # misc. compiler flags
182# and
183#  ${format} can be
184#   - the empty string '', signifying that it should be returned as a list
185#   - _as_string signifying that it should be returned as a string
186# and
187#  ${lang} can be one of
188#   - C
189#   - CXX
190#   - ASM
191#
192# STRIP_PREFIX
193#
194# By default the result will be returned ready to be passed directly
195# to a compiler, e.g. prefixed with -D, or -I, but it is possible to
196# omit this prefix by specifying 'STRIP_PREFIX' . This option has no
197# effect for 'compile_options'.
198#
199# e.g.
200# zephyr_get_include_directories_for_lang(ASM x)
201# writes "-Isome_dir;-Isome/other/dir" to x
202
203function(zephyr_get_include_directories_for_lang_as_string lang i)
204  zephyr_get_include_directories_for_lang(${lang} list_of_flags DELIMITER " " ${ARGN})
205
206  convert_list_of_flags_to_string_of_flags(list_of_flags str_of_flags)
207
208  set(${i} ${str_of_flags} PARENT_SCOPE)
209endfunction()
210
211function(zephyr_get_system_include_directories_for_lang_as_string lang i)
212  zephyr_get_system_include_directories_for_lang(${lang} list_of_flags DELIMITER " " ${ARGN})
213
214  convert_list_of_flags_to_string_of_flags(list_of_flags str_of_flags)
215
216  set(${i} ${str_of_flags} PARENT_SCOPE)
217endfunction()
218
219function(zephyr_get_compile_definitions_for_lang_as_string lang i)
220  zephyr_get_compile_definitions_for_lang(${lang} list_of_flags DELIMITER " " ${ARGN})
221
222  convert_list_of_flags_to_string_of_flags(list_of_flags str_of_flags)
223
224  set(${i} ${str_of_flags} PARENT_SCOPE)
225endfunction()
226
227function(zephyr_get_compile_options_for_lang_as_string lang i)
228  zephyr_get_compile_options_for_lang(${lang} list_of_flags DELIMITER " ")
229
230  convert_list_of_flags_to_string_of_flags(list_of_flags str_of_flags)
231
232  set(${i} ${str_of_flags} PARENT_SCOPE)
233endfunction()
234
235function(zephyr_get_include_directories_for_lang lang i)
236  zephyr_get_parse_args(args ${ARGN})
237  get_property(flags TARGET zephyr_interface PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
238
239  process_flags(${lang} flags output_list)
240  string(REPLACE ";" "$<SEMICOLON>" genexp_output_list "${output_list}")
241
242  if(NOT ARGN)
243    set(result_output_list "-I$<JOIN:${genexp_output_list},$<SEMICOLON>-I>")
244  elseif(args_STRIP_PREFIX)
245    # The list has no prefix, so don't add it.
246    set(result_output_list ${output_list})
247  elseif(args_DELIMITER)
248    set(result_output_list "-I$<JOIN:${genexp_output_list},${args_DELIMITER}-I>")
249  endif()
250  set(${i} ${result_output_list} PARENT_SCOPE)
251endfunction()
252
253function(zephyr_get_system_include_directories_for_lang lang i)
254  zephyr_get_parse_args(args ${ARGN})
255  get_property(flags TARGET zephyr_interface PROPERTY INTERFACE_SYSTEM_INCLUDE_DIRECTORIES)
256
257  process_flags(${lang} flags output_list)
258  string(REPLACE ";" "$<SEMICOLON>" genexp_output_list "${output_list}")
259
260  set_ifndef(args_DELIMITER "$<SEMICOLON>")
261  set(result_output_list "$<$<BOOL:${genexp_output_list}>:-isystem$<JOIN:${genexp_output_list},${args_DELIMITER}-isystem>>")
262
263  set(${i} ${result_output_list} PARENT_SCOPE)
264endfunction()
265
266function(zephyr_get_compile_definitions_for_lang lang i)
267  zephyr_get_parse_args(args ${ARGN})
268  get_property(flags TARGET zephyr_interface PROPERTY INTERFACE_COMPILE_DEFINITIONS)
269
270  process_flags(${lang} flags output_list)
271  string(REPLACE ";" "$<SEMICOLON>" genexp_output_list "${output_list}")
272
273  set_ifndef(args_DELIMITER "$<SEMICOLON>")
274  set(result_output_list "-D$<JOIN:${genexp_output_list},${args_DELIMITER}-D>")
275
276  set(${i} ${result_output_list} PARENT_SCOPE)
277endfunction()
278
279function(zephyr_get_compile_options_for_lang lang i)
280  zephyr_get_parse_args(args ${ARGN})
281  get_property(flags TARGET zephyr_interface PROPERTY INTERFACE_COMPILE_OPTIONS)
282
283  process_flags(${lang} flags output_list)
284  string(REPLACE ";" "$<SEMICOLON>" genexp_output_list "${output_list}")
285
286  set_ifndef(args_DELIMITER "$<SEMICOLON>")
287  set(result_output_list "$<JOIN:${genexp_output_list},${args_DELIMITER}>")
288
289  set(${i} ${result_output_list} PARENT_SCOPE)
290endfunction()
291
292# This function writes a dict to it's output parameter
293# 'return_dict'. The dict has information about the parsed arguments,
294#
295# Usage:
296#   zephyr_get_parse_args(foo ${ARGN})
297#   print(foo_STRIP_PREFIX) # foo_STRIP_PREFIX might be set to 1
298function(zephyr_get_parse_args return_dict)
299  foreach(x ${ARGN})
300    if(DEFINED single_argument)
301      set(${single_argument} ${x} PARENT_SCOPE)
302      unset(single_argument)
303    else()
304      if(x STREQUAL STRIP_PREFIX)
305        set(${return_dict}_STRIP_PREFIX 1 PARENT_SCOPE)
306      elseif(x STREQUAL NO_SPLIT)
307        set(${return_dict}_NO_SPLIT 1 PARENT_SCOPE)
308      elseif(x STREQUAL DELIMITER)
309        set(single_argument ${return_dict}_DELIMITER)
310      endif()
311    endif()
312  endforeach()
313endfunction()
314
315function(process_flags lang input output)
316  # The flags might contains compile language generator expressions that
317  # look like this:
318  # $<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions>
319  # $<$<COMPILE_LANGUAGE:CXX>:$<OTHER_EXPRESSION>>
320  #
321  # Flags that don't specify a language like this apply to all
322  # languages.
323  #
324  # See COMPILE_LANGUAGE in
325  # https://cmake.org/cmake/help/v3.3/manual/cmake-generator-expressions.7.html
326  #
327  # To deal with this, we apply a regex to extract the flag and also
328  # to find out if the language matches.
329  #
330  # If this doesn't work out we might need to ban the use of
331  # COMPILE_LANGUAGE and instead partition C, CXX, and ASM into
332  # different libraries
333  set(languages C CXX ASM)
334
335  set(tmp_list "")
336
337  foreach(flag ${${input}})
338    set(is_compile_lang_generator_expression 0)
339    # SHELL is used to avoid de-duplication, but when process flags
340    # then this tag must be removed to return real compile/linker flags.
341    if(flag MATCHES "^SHELL:[ ]*(.*)")
342      separate_arguments(flag UNIX_COMMAND ${CMAKE_MATCH_1})
343    endif()
344
345    foreach(l ${languages})
346      if(flag MATCHES "<COMPILE_LANGUAGE:${l}>:([^>]+)>")
347        set(updated_flag ${CMAKE_MATCH_1})
348        set(is_compile_lang_generator_expression 1)
349        if(${l} STREQUAL ${lang})
350          # This test will match in case there are more generator expressions in the flag.
351          # As example: $<$<COMPILE_LANGUAGE:C>:$<OTHER_EXPRESSION>>
352          #             $<$<OTHER_EXPRESSION:$<COMPILE_LANGUAGE:C>:something>>
353          string(REGEX MATCH "(\\\$<)[^\\\$]*(\\\$<)[^\\\$]*(\\\$<)" IGNORE_RESULT ${flag})
354          if(CMAKE_MATCH_2)
355            # Nested generator expressions are used, just substitute `$<COMPILE_LANGUAGE:${l}>` to `1`
356            string(REGEX REPLACE "\\\$<COMPILE_LANGUAGE:${l}>" "1" updated_flag ${flag})
357          endif()
358          list(APPEND tmp_list ${updated_flag})
359          break()
360        endif()
361      endif()
362    endforeach()
363
364    if(NOT is_compile_lang_generator_expression)
365      # Flags may be placed inside generator expression, therefore any flag
366      # which is not already a generator expression must have commas converted.
367      if(NOT flag MATCHES "\\\$<.*>")
368        string(REPLACE "," "$<COMMA>" flag "${flag}")
369      endif()
370      list(APPEND tmp_list ${flag})
371    endif()
372  endforeach()
373
374  set(${output} ${tmp_list} PARENT_SCOPE)
375endfunction()
376
377function(convert_list_of_flags_to_string_of_flags ptr_list_of_flags string_of_flags)
378  # Convert the list to a string so we can do string replace
379  # operations on it and replace the ";" list separators with a
380  # whitespace so the flags are spaced out
381  string(REPLACE ";"  " "  locally_scoped_string_of_flags "${${ptr_list_of_flags}}")
382
383  # Set the output variable in the parent scope
384  set(${string_of_flags} ${locally_scoped_string_of_flags} PARENT_SCOPE)
385endfunction()
386
387macro(get_property_and_add_prefix result target property prefix)
388  zephyr_get_parse_args(args ${ARGN})
389
390  if(args_STRIP_PREFIX)
391    set(maybe_prefix "")
392  else()
393    set(maybe_prefix ${prefix})
394  endif()
395
396  get_property(target_property TARGET ${target} PROPERTY ${property})
397  foreach(x ${target_property})
398    list(APPEND ${result} ${maybe_prefix}${x})
399  endforeach()
400endmacro()
401
402# 1.2 zephyr_library_*
403#
404# Zephyr libraries use CMake's library concept and a set of
405# assumptions about how zephyr code is organized to cut down on
406# boilerplate code.
407#
408# A Zephyr library can be constructed by the function zephyr_library
409# or zephyr_library_named. The constructors create a CMake library
410# with a name accessible through the variable ZEPHYR_CURRENT_LIBRARY.
411#
412# The variable ZEPHYR_CURRENT_LIBRARY should seldom be needed since
413# the zephyr libraries have methods that modify the libraries. These
414# methods have the signature: zephyr_library_<target-function>
415#
416# The methods are wrappers around the CMake target_* functions. See
417# https://cmake.org/cmake/help/latest/manual/cmake-commands.7.html for
418# documentation on the underlying target_* functions.
419#
420# The methods modify the CMake target_* API to reduce boilerplate;
421#  PRIVATE is assumed
422#  The target is assumed to be ZEPHYR_CURRENT_LIBRARY
423#
424# When a flag that is given through the zephyr_* API conflicts with
425# the zephyr_library_* API then precedence will be given to the
426# zephyr_library_* API. In other words, local configuration overrides
427# global configuration.
428
429# Constructor with a directory-inferred name
430macro(zephyr_library)
431  zephyr_library_get_current_dir_lib_name(${ZEPHYR_BASE} lib_name)
432  zephyr_library_named(${lib_name})
433endmacro()
434
435# Determines what the current directory's lib name would be according to the
436# provided base and writes it to the argument "lib_name"
437macro(zephyr_library_get_current_dir_lib_name base lib_name)
438  # Remove the prefix (/home/sebo/zephyr/driver/serial/CMakeLists.txt => driver/serial/CMakeLists.txt)
439  file(RELATIVE_PATH name ${base} ${CMAKE_CURRENT_LIST_FILE})
440
441  # Remove the filename (driver/serial/CMakeLists.txt => driver/serial)
442  get_filename_component(name ${name} DIRECTORY)
443
444  # Replace / with __ (driver/serial => driver__serial)
445  string(REGEX REPLACE "/" "__" name ${name})
446
447  # Replace : with __ (C:/zephyrproject => C____zephyrproject)
448  string(REGEX REPLACE ":" "__" name ${name})
449
450  set(${lib_name} ${name})
451endmacro()
452
453# Constructor with an explicitly given name.
454macro(zephyr_library_named name)
455  # This is a macro because we need add_library() to be executed
456  # within the scope of the caller.
457  set(ZEPHYR_CURRENT_LIBRARY ${name})
458  add_library(${name} STATIC "")
459
460  zephyr_append_cmake_library(${name})
461
462  target_link_libraries(${name} PUBLIC zephyr_interface)
463endmacro()
464
465# Provides amend functionality to a Zephyr library for out-of-tree usage.
466#
467# When called from a Zephyr module, the corresponding zephyr library defined
468# within Zephyr will be looked up.
469#
470# Note, in order to ensure correct library when amending, the folder structure in the
471# Zephyr module must resemble the structure used in Zephyr, as example:
472#
473# Example: to amend the zephyr library created in
474# ZEPHYR_BASE/drivers/entropy/CMakeLists.txt
475# add the following file:
476# ZEPHYR_MODULE/drivers/entropy/CMakeLists.txt
477# with content:
478# zephyr_library_amend()
479# zephyr_library_sources(...)
480#
481# It is also possible to use generator expression when amending to Zephyr
482# libraries.
483#
484# For example, in case it is required to expose the Zephyr library's folder as
485# include path then the following is possible:
486# zephyr_library_amend()
487# zephyr_library_include_directories($<TARGET_PROPERTY:SOURCE_DIR>)
488#
489# See the CMake documentation for more target properties or generator
490# expressions.
491#
492macro(zephyr_library_amend)
493  # This is a macro because we need to ensure the ZEPHYR_CURRENT_LIBRARY and
494  # following zephyr_library_* calls are executed within the scope of the
495  # caller.
496  if(NOT ZEPHYR_CURRENT_MODULE_DIR)
497    message(FATAL_ERROR "Function only available for Zephyr modules.")
498  endif()
499
500  zephyr_library_get_current_dir_lib_name(${ZEPHYR_CURRENT_MODULE_DIR} lib_name)
501
502  set(ZEPHYR_CURRENT_LIBRARY ${lib_name})
503endmacro()
504
505function(zephyr_link_interface interface)
506  target_link_libraries(${interface} INTERFACE zephyr_interface)
507endfunction()
508
509#
510# zephyr_library versions of normal CMake target_<func> functions
511# Note, paths passed to this function must be relative in order
512# to support the library relocation feature of zephyr_code_relocate
513#
514function(zephyr_library_sources source)
515  target_sources(${ZEPHYR_CURRENT_LIBRARY} PRIVATE ${source} ${ARGN})
516endfunction()
517
518function(zephyr_library_include_directories)
519  target_include_directories(${ZEPHYR_CURRENT_LIBRARY} PRIVATE ${ARGN})
520endfunction()
521
522function(zephyr_library_link_libraries item)
523  target_link_libraries(${ZEPHYR_CURRENT_LIBRARY} PUBLIC ${item} ${ARGN})
524endfunction()
525
526function(zephyr_library_compile_definitions item)
527  target_compile_definitions(${ZEPHYR_CURRENT_LIBRARY} PRIVATE ${item} ${ARGN})
528endfunction()
529
530function(zephyr_library_compile_options item)
531  # The compiler is relied upon for sane behaviour when flags are in
532  # conflict. Compilers generally give precedence to flags given late
533  # on the command line. So to ensure that zephyr_library_* flags are
534  # placed late on the command line we create a dummy interface
535  # library and link with it to obtain the flags.
536  #
537  # Linking with a dummy interface library will place flags later on
538  # the command line than the flags from zephyr_interface because
539  # zephyr_interface will be the first interface library that flags
540  # are taken from.
541
542  string(MD5 uniqueness "${ARGV}")
543  set(lib_name options_interface_lib_${uniqueness})
544
545  if (NOT TARGET ${lib_name})
546    # Create the unique target only if it doesn't exist.
547    add_library(           ${lib_name} INTERFACE)
548    target_compile_options(${lib_name} INTERFACE ${item} ${ARGN})
549  endif()
550
551  target_link_libraries(${ZEPHYR_CURRENT_LIBRARY} PRIVATE ${lib_name})
552endfunction()
553
554function(zephyr_library_cc_option)
555  foreach(option ${ARGV})
556    string(MAKE_C_IDENTIFIER check${option} check)
557    zephyr_check_compiler_flag(C ${option} ${check})
558
559    if(${${check}})
560      zephyr_library_compile_options(${option})
561    endif()
562  endforeach()
563endfunction()
564
565function(zephyr_library_add_dependencies)
566  add_dependencies(${ZEPHYR_CURRENT_LIBRARY} ${ARGN})
567endfunction()
568
569# Add the existing CMake library 'library' to the global list of
570# Zephyr CMake libraries. This is done automatically by the
571# constructor but must be called explicitly on CMake libraries that do
572# not use a zephyr library constructor.
573function(zephyr_append_cmake_library library)
574  if(TARGET zephyr_prebuilt)
575    message(WARNING
576      "zephyr_library() or zephyr_library_named() called in Zephyr CMake "
577      "application mode. `${library}` will not be treated as a Zephyr library."
578      "To create a Zephyr library in Zephyr CMake kernel mode consider "
579      "creating a Zephyr module. See more here: "
580      "https://docs.zephyrproject.org/latest/guides/modules.html"
581    )
582  endif()
583  set_property(GLOBAL APPEND PROPERTY ZEPHYR_LIBS ${library})
584endfunction()
585
586# Add the imported library 'library_name', located at 'library_path' to the
587# global list of Zephyr CMake libraries.
588function(zephyr_library_import library_name library_path)
589  add_library(${library_name} STATIC IMPORTED GLOBAL)
590  set_target_properties(${library_name}
591    PROPERTIES IMPORTED_LOCATION
592    ${library_path}
593    )
594  zephyr_append_cmake_library(${library_name})
595endfunction()
596
597# Place the current zephyr library in the application memory partition.
598#
599# The partition argument is the name of the partition where the library shall
600# be placed.
601#
602# Note: Ensure the given partition has been defined using
603#       K_APPMEM_PARTITION_DEFINE in source code.
604function(zephyr_library_app_memory partition)
605  set_property(TARGET zephyr_property_target
606               APPEND PROPERTY COMPILE_OPTIONS
607               "-l" $<TARGET_FILE_NAME:${ZEPHYR_CURRENT_LIBRARY}> "${partition}")
608endfunction()
609
610# Configure a Zephyr library specific property.
611#
612# Usage:
613#   zephyr_library_property(<property> <value>)
614#
615# Current Zephyr library specific properties that are supported:
616# ALLOW_EMPTY <TRUE:FALSE>: Allow a Zephyr library to be empty.
617#                           An empty Zephyr library will generate a CMake
618#                           configure time warning unless `ALLOW_EMPTY` is TRUE.
619function(zephyr_library_property)
620  set(single_args "ALLOW_EMPTY")
621  cmake_parse_arguments(LIB_PROP "" "${single_args}" "" ${ARGN})
622
623  if(LIB_PROP_UNPARSED_ARGUMENTS)
624      message(FATAL_ERROR "zephyr_library_property(${ARGV0} ...) given unknown arguments: ${FILE_UNPARSED_ARGUMENTS}")
625  endif()
626
627  foreach(arg ${single_args})
628    if(DEFINED LIB_PROP_${arg})
629      set_property(TARGET ${ZEPHYR_CURRENT_LIBRARY} PROPERTY ${arg} ${LIB_PROP_${arg}})
630    endif()
631  endforeach()
632endfunction()
633
634# 1.2.1 zephyr_interface_library_*
635#
636# A Zephyr interface library is a thin wrapper over a CMake INTERFACE
637# library. The most important responsibility of this abstraction is to
638# ensure that when a user KConfig-enables a library then the header
639# files of this library will be accessible to the 'app' library.
640#
641# This is done because when a user uses Kconfig to enable a library he
642# expects to be able to include its header files and call its
643# functions out-of-the box.
644#
645# A Zephyr interface library should be used when there exists some
646# build information (include directories, defines, compiler flags,
647# etc.) that should be applied to a set of Zephyr libraries and 'app'
648# might be one of these libraries.
649#
650# Zephyr libraries must explicitly call
651# zephyr_library_link_libraries(<interface_library>) to use this build
652# information. 'app' is treated as a special case for usability
653# reasons; a Kconfig option (CONFIG_APP_LINK_WITH_<interface_library>)
654# should exist for each interface_library and will determine if 'app'
655# links with the interface_library.
656#
657# This API has a constructor like the zephyr_library API has, but it
658# does not have wrappers over the other cmake target functions.
659macro(zephyr_interface_library_named name)
660  add_library(${name} INTERFACE)
661  set_property(GLOBAL APPEND PROPERTY ZEPHYR_INTERFACE_LIBS ${name})
662endmacro()
663
664# 1.3 generate_inc_*
665
666# These functions are useful if there is a need to generate a file
667# that can be included into the application at build time. The file
668# can also be compressed automatically when embedding it.
669#
670# See tests/application_development/gen_inc_file for an example of
671# usage.
672function(generate_inc_file
673    source_file    # The source file to be converted to hex
674    generated_file # The generated file
675    )
676  add_custom_command(
677    OUTPUT ${generated_file}
678    COMMAND
679    ${PYTHON_EXECUTABLE}
680    ${ZEPHYR_BASE}/scripts/build/file2hex.py
681    ${ARGN} # Extra arguments are passed to file2hex.py
682    --file ${source_file}
683    > ${generated_file} # Does pipe redirection work on Windows?
684    DEPENDS ${source_file}
685    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
686    )
687endfunction()
688
689function(generate_inc_file_for_gen_target
690    target          # The cmake target that depends on the generated file
691    source_file     # The source file to be converted to hex
692    generated_file  # The generated file
693    gen_target      # The generated file target we depend on
694                    # Any additional arguments are passed on to file2hex.py
695    )
696  generate_inc_file(${source_file} ${generated_file} ${ARGN})
697
698  # Ensure 'generated_file' is generated before 'target' by creating a
699  # dependency between the two targets
700
701  add_dependencies(${target} ${gen_target})
702endfunction()
703
704function(generate_inc_file_for_target
705    target          # The cmake target that depends on the generated file
706    source_file     # The source file to be converted to hex
707    generated_file  # The generated file
708                    # Any additional arguments are passed on to file2hex.py
709    )
710  # Ensure 'generated_file' is generated before 'target' by creating a
711  # 'custom_target' for it and setting up a dependency between the two
712  # targets
713
714  # But first create a unique name for the custom target
715  generate_unique_target_name_from_filename(${generated_file} generated_target_name)
716
717  add_custom_target(${generated_target_name} DEPENDS ${generated_file})
718  generate_inc_file_for_gen_target(${target} ${source_file} ${generated_file} ${generated_target_name} ${ARGN})
719endfunction()
720
721# 1.4. board_*
722#
723# This section is for extensions related to Zephyr board handling.
724#
725# Zephyr board extensions current contains:
726# - Board runners
727# - Board revision
728
729# Zephyr board runners:
730#   Zephyr board runner extension functions control Zephyr's board runners
731#   from the build system. The Zephyr build system has targets for
732#   flashing and debugging supported boards. These are wrappers around a
733#   "runner" Python subpackage that is part of Zephyr's "west" tool.
734#
735# This section provides glue between CMake and the Python code that
736# manages the runners.
737
738set(TYPES "FLASH" "DEBUG" "SIM" "ROBOT")
739function(_board_check_runner_type type) # private helper
740  if (NOT "${type}" IN_LIST TYPES)
741    message(FATAL_ERROR "invalid type ${type}; should be one of: ${TYPES}")
742  endif()
743endfunction()
744
745# This function sets the runner for the board unconditionally.  It's
746# meant to be used from application CMakeLists.txt files.
747#
748# NOTE: Usually board_set_xxx_ifnset() is best in board.cmake files.
749#       This lets the user set the runner at cmake time, or in their
750#       own application's CMakeLists.txt.
751#
752# Usage:
753#   board_set_runner(FLASH pyocd)
754#
755# This would set the board's flash runner to "pyocd".
756#
757# In general, "type" is FLASH, DEBUG, SIM or ROBOT and "runner" is
758# the name of a runner.
759function(board_set_runner type runner)
760  _board_check_runner_type(${type})
761  if (DEFINED BOARD_${type}_RUNNER)
762    message(STATUS "overriding ${type} runner ${BOARD_${type}_RUNNER}; it's now ${runner}")
763  endif()
764  set(BOARD_${type}_RUNNER ${runner} PARENT_SCOPE)
765endfunction()
766
767# This macro is like board_set_runner(), but will only make a change
768# if that runner is currently not set.
769#
770# See also board_set_flasher_ifnset() and board_set_debugger_ifnset().
771macro(board_set_runner_ifnset type runner)
772  _board_check_runner_type(${type})
773  # This is a macro because set_ifndef() works at parent scope.
774  # If this were a function, that would be this function's scope,
775  # which wouldn't work.
776  set_ifndef(BOARD_${type}_RUNNER ${runner})
777endmacro()
778
779# A convenience macro for board_set_runner(FLASH ${runner}).
780macro(board_set_flasher runner)
781  board_set_runner(FLASH ${runner})
782endmacro()
783
784# A convenience macro for board_set_runner(DEBUG ${runner}).
785macro(board_set_debugger runner)
786  board_set_runner(DEBUG ${runner})
787endmacro()
788
789# A convenience macro for board_set_runner_ifnset(FLASH ${runner}).
790macro(board_set_flasher_ifnset runner)
791  board_set_runner_ifnset(FLASH ${runner})
792endmacro()
793
794# A convenience macro for board_set_runner_ifnset(DEBUG ${runner}).
795macro(board_set_debugger_ifnset runner)
796  board_set_runner_ifnset(DEBUG ${runner})
797endmacro()
798
799# A convenience macro for board_set_runner_ifnset(ROBOT ${runner}).
800macro(board_set_robot_runner_ifnset runner)
801  board_set_runner_ifnset(ROBOT ${runner})
802endmacro()
803
804# A convenience macro for board_set_runner_ifnset(SIM ${runner}).
805macro(board_set_sim_runner_ifnset runner)
806  board_set_runner_ifnset(SIM ${runner})
807endmacro()
808
809# This function is intended for board.cmake files and application
810# CMakeLists.txt files.
811#
812# Usage from board.cmake files:
813#   board_runner_args(runner "--some-arg=val1" "--another-arg=val2")
814#
815# The build system will then ensure the command line used to
816# create the runner contains:
817#   --some-arg=val1 --another-arg=val2
818#
819# Within application CMakeLists.txt files, ensure that all calls to
820# board_runner_args() are part of a macro named app_set_runner_args(),
821# like this, which is defined before calling 'find_package(Zephyr)':
822#   macro(app_set_runner_args)
823#     board_runner_args(runner "--some-app-setting=value")
824#   endmacro()
825#
826# The build system tests for the existence of the macro and will
827# invoke it at the appropriate time if it is defined.
828#
829# Any explicitly provided settings given by this function override
830# defaults provided by the build system.
831function(board_runner_args runner)
832  string(MAKE_C_IDENTIFIER ${runner} runner_id)
833  # Note the "_EXPLICIT_" here, and see below.
834  set_property(GLOBAL APPEND PROPERTY BOARD_RUNNER_ARGS_EXPLICIT_${runner_id} ${ARGN})
835endfunction()
836
837# This function is intended for internal use by
838# boards/common/runner.board.cmake files.
839#
840# Basic usage:
841#   board_finalize_runner_args(runner)
842#
843# This ensures the build system captures all arguments added in any
844# board_runner_args() calls, and otherwise finishes registering a
845# runner for use.
846#
847# Extended usage:
848#   board_runner_args(runner "--some-arg=default-value")
849#
850# This provides common or default values for arguments. These are
851# placed before board_runner_args() calls, so they generally take
852# precedence, except for arguments which can be given multiple times
853# (use these with caution).
854function(board_finalize_runner_args runner)
855  # If the application provided a macro to add additional runner
856  # arguments, handle them.
857  if(COMMAND app_set_runner_args)
858    app_set_runner_args()
859  endif()
860
861  # Retrieve the list of explicitly set arguments.
862  string(MAKE_C_IDENTIFIER ${runner} runner_id)
863  get_property(explicit GLOBAL PROPERTY "BOARD_RUNNER_ARGS_EXPLICIT_${runner_id}")
864
865  # Note no _EXPLICIT_ here. This property contains the final list.
866  set_property(GLOBAL APPEND PROPERTY BOARD_RUNNER_ARGS_${runner_id}
867    # Default arguments from the common runner file come first.
868    ${ARGN}
869    # Arguments explicitly given with board_runner_args() come
870    # next, so they take precedence over the common runner file.
871    ${explicit}
872    # Arguments given via the CMake cache come last of all. Users
873    # can provide variables in this way from the CMake command line.
874    ${BOARD_RUNNER_ARGS_${runner_id}}
875    )
876
877  # Add the finalized runner to the global property list.
878  set_property(GLOBAL APPEND PROPERTY ZEPHYR_RUNNERS ${runner})
879endfunction()
880
881function(board_set_rimage_target target)
882  set(RIMAGE_TARGET ${target} CACHE STRING "rimage target")
883  zephyr_check_cache(RIMAGE_TARGET)
884endfunction()
885
886function(board_emu_args emu)
887  string(MAKE_C_IDENTIFIER ${emu} emu_id)
888  # Note the "_EXPLICIT_" here, and see below.
889  set_property(GLOBAL APPEND PROPERTY BOARD_EMU_ARGS_EXPLICIT_${emu_id} ${ARGN})
890endfunction()
891
892function(board_finalize_emu_args emu)
893  # If the application provided a macro to add additional emu
894  # arguments, handle them.
895  if(COMMAND app_set_emu_args)
896    app_set_emu_args()
897  endif()
898
899  # Retrieve the list of explicitly set arguments.
900  string(MAKE_C_IDENTIFIER ${emu} emu_id)
901  get_property(explicit GLOBAL PROPERTY "BOARD_EMU_ARGS_EXPLICIT_${emu_id}")
902
903  # Note no _EXPLICIT_ here. This property contains the final list.
904  set_property(GLOBAL APPEND PROPERTY BOARD_EMU_ARGS_${emu_id}
905    # Default arguments from the common emu file come first.
906    ${ARGN}
907    # Arguments explicitly given with board_emu_args() come
908    # next, so they take precedence over the common emu file.
909    ${explicit}
910    # Arguments given via the CMake cache come last of all. Users
911    # can provide variables in this way from the CMake command line.
912    ${BOARD_EMU_ARGS_${emu_id}}
913    )
914
915  # Add the finalized emu to the global property list.
916  set_property(GLOBAL APPEND PROPERTY ZEPHYR_EMUS ${emu})
917endfunction()
918
919# Zephyr board revision:
920#
921# This section provides a function for revision checking.
922
923# Usage:
924#   board_check_revision(FORMAT <LETTER | NUMBER | MAJOR.MINOR.PATCH>
925#                        [EXACT]
926#                        [DEFAULT_REVISION <revision>]
927#                        [HIGHEST_REVISION <revision>]
928#   )
929#
930# Zephyr board extension function.
931#
932# This function can be used in `boards/<board>/revision.cmake` to check a user
933# requested revision against available board revisions.
934#
935# The function will check the revision from `-DBOARD=<board>@<revision>` that
936# is provided by the user according to the arguments.
937# When `EXACT` is not specified, this function will set the Zephyr build system
938# variable `ACTIVE_BOARD_REVISION` with the selected revision.
939#
940# FORMAT <LETTER | NUMBER | MAJOR.MINOR.PATCH>: Specify the revision format.
941#         LETTER:             Revision format is a single letter from A - Z.
942#         NUMBER:             Revision format is a single integer number.
943#         MAJOR.MINOR.PATCH:  Revision format is three numbers, separated by `.`,
944#                             `x.y.z`. Trailing zeroes may be omitted on the
945#                             command line, which means:
946#                             1.0.0 == 1.0 == 1
947#
948# OPTIONAL: Revision specifier is optional. If revision is not provided the base
949#           board will be used. If both `EXACT` and `OPTIONAL` are given, then
950#           specifying the revision is optional, but if it is given then the
951#           `EXACT` requirements apply. Mutually exclusive with `DEFAULT_REVISION`.
952#
953# EXACT: Revision is required to be an exact match. As example, available revisions are:
954#        0.1.0 and 0.3.0, and user provides 0.2.0, then an error is reported
955#        when `EXACT` is given.
956#        If `EXACT` is not provided, then closest lower revision will be selected
957#        as the active revision, which in the example will be `0.1.0`.
958#
959# DEFAULT_REVISION: Provides a default revision to use when user has not selected
960#                   a revision number. If no default revision is provided then
961#                   user will be printed with an error if no revision is given
962#                   on the command line.
963#
964# HIGHEST_REVISION: Allows to specify highest valid revision for a board.
965#                   This can be used to ensure that a newer board cannot be used
966#                   with an older Zephyr. As example, if current board supports
967#                   revisions 0.x.0-0.99.99 and 1.0.0-1.99.99, and it is expected
968#                   that current board implementation will not work with board
969#                   revision 2.0.0, then HIGHEST_REVISION can be set to 1.99.99,
970#                   and user will be printed with an error if using
971#                   `<board>@2.0.0` or higher.
972#                   This field is not needed when `EXACT` is used.
973#
974# VALID_REVISIONS:  A list of valid revisions for this board.
975#                   If this argument is not provided, then each Kconfig fragment
976#                   of the form ``<board>_<revision>.conf`` in the board folder
977#                   will be used as a valid revision for the board.
978#
979function(board_check_revision)
980  set(options OPTIONAL EXACT)
981  set(single_args FORMAT DEFAULT_REVISION HIGHEST_REVISION)
982  set(multi_args  VALID_REVISIONS)
983  cmake_parse_arguments(BOARD_REV "${options}" "${single_args}" "${multi_args}" ${ARGN})
984
985  string(TOUPPER ${BOARD_REV_FORMAT} BOARD_REV_FORMAT)
986
987  if(DEFINED BOARD_REV_DEFAULT_REVISION AND BOARD_REV_OPTIONAL)
988    message(FATAL_ERROR "Arguments BOARD_REVISION and OPTIONAL are mutually exclusive")
989  endif()
990
991  if(NOT DEFINED BOARD_REVISION)
992    if(BOARD_REV_OPTIONAL)
993      return()
994    elseif(DEFINED BOARD_REV_DEFAULT_REVISION)
995      set(BOARD_REVISION ${BOARD_REV_DEFAULT_REVISION})
996      set(BOARD_REVISION ${BOARD_REVISION} PARENT_SCOPE)
997    else()
998      message(FATAL_ERROR "No board revision specified, Board: `${BOARD}` \
999              requires a revision. Please use: `-DBOARD=${BOARD}@<revision>`")
1000    endif()
1001  endif()
1002
1003  if(DEFINED BOARD_REV_HIGHEST_REVISION)
1004    if(((BOARD_REV_FORMAT STREQUAL LETTER) AND
1005        (BOARD_REVISION STRGREATER BOARD_REV_HIGHEST_REVISION)) OR
1006       ((BOARD_REV_FORMAT STREQUAL NUMBER) AND
1007       (BOARD_REVISION GREATER BOARD_REV_HIGHEST_REVISION)) OR
1008       ((BOARD_REV_FORMAT MATCHES "^MAJOR\.MINOR\.PATCH$") AND
1009        (BOARD_REVISION VERSION_GREATER BOARD_REV_HIGHEST_REVISION))
1010    )
1011      message(FATAL_ERROR "Board revision `${BOARD_REVISION}` greater than \
1012              highest supported revision `${BOARD_REV_HIGHEST_REVISION}`. \
1013              Please specify a valid board revision.")
1014    endif()
1015  endif()
1016
1017  if(BOARD_REV_FORMAT STREQUAL LETTER)
1018    set(revision_regex "([A-Z])")
1019  elseif(BOARD_REV_FORMAT STREQUAL NUMBER)
1020    set(revision_regex "([0-9]+)")
1021  elseif(BOARD_REV_FORMAT MATCHES "^MAJOR\.MINOR\.PATCH$")
1022    set(revision_regex "((0|[1-9][0-9]*)(\.[0-9]+)(\.[0-9]+))")
1023    # We allow loose <board>@<revision> typing on command line.
1024    # so append missing zeroes.
1025    if(BOARD_REVISION MATCHES "((0|[1-9][0-9]*)(\.[0-9]+)?(\.[0-9]+)?)")
1026      if(NOT CMAKE_MATCH_3)
1027        set(BOARD_REVISION ${BOARD_REVISION}.0)
1028        set(BOARD_REVISION ${BOARD_REVISION} PARENT_SCOPE)
1029      endif()
1030      if(NOT CMAKE_MATCH_4)
1031        set(BOARD_REVISION ${BOARD_REVISION}.0)
1032        set(BOARD_REVISION ${BOARD_REVISION} PARENT_SCOPE)
1033      endif()
1034    endif()
1035  else()
1036    message(FATAL_ERROR "Invalid format specified for \
1037    `board_check_revision(FORMAT <LETTER | NUMBER | MAJOR.MINOR.PATCH>)`")
1038  endif()
1039
1040  if(NOT (BOARD_REVISION MATCHES "^${revision_regex}$"))
1041    message(FATAL_ERROR "Invalid revision format used for `${BOARD_REVISION}`. \
1042            Board `${BOARD}` uses revision format: ${BOARD_REV_FORMAT}.")
1043  endif()
1044
1045  if(NOT DEFINED BOARD_REV_VALID_REVISIONS)
1046    file(GLOB revision_candidates LIST_DIRECTORIES false RELATIVE ${BOARD_DIR}
1047         ${BOARD_DIR}/${BOARD}_*.conf
1048    )
1049    string(REPLACE "." "_" underscore_revision_regex ${revision_regex})
1050    set(file_revision_regex "${BOARD}_${underscore_revision_regex}.conf")
1051    foreach(candidate ${revision_candidates})
1052      if(${candidate} MATCHES "${file_revision_regex}")
1053        string(REPLACE "_" "." FOUND_BOARD_REVISION ${CMAKE_MATCH_1})
1054        list(APPEND BOARD_REV_VALID_REVISIONS ${FOUND_BOARD_REVISION})
1055      endif()
1056    endforeach()
1057  endif()
1058
1059  if(${BOARD_REVISION} IN_LIST BOARD_REV_VALID_REVISIONS)
1060    # Found exact match.
1061    return()
1062  endif()
1063
1064  if(NOT BOARD_REV_EXACT)
1065    foreach(TEST_REVISION ${BOARD_REV_VALID_REVISIONS})
1066      if((BOARD_REV_FORMAT MATCHES "^MAJOR\.MINOR\.PATCH$") AND
1067         (${BOARD_REVISION} VERSION_GREATER_EQUAL ${TEST_REVISION}) AND
1068         (${TEST_REVISION} VERSION_GREATER_EQUAL "${ACTIVE_BOARD_REVISION}")
1069      )
1070        set(ACTIVE_BOARD_REVISION ${TEST_REVISION})
1071      elseif((BOARD_REV_FORMAT STREQUAL LETTER) AND
1072             (${BOARD_REVISION} STRGREATER ${TEST_REVISION}) AND
1073             (${TEST_REVISION} STRGREATER "${ACTIVE_BOARD_REVISION}")
1074      )
1075        set(ACTIVE_BOARD_REVISION ${TEST_REVISION})
1076      elseif((BOARD_REV_FORMAT STREQUAL NUMBER) AND
1077             (${BOARD_REVISION} GREATER ${TEST_REVISION}) AND
1078             (${TEST_REVISION} GREATER "${ACTIVE_BOARD_REVISION}")
1079      )
1080        set(ACTIVE_BOARD_REVISION ${TEST_REVISION})
1081      endif()
1082    endforeach()
1083  endif()
1084
1085  if(BOARD_REV_EXACT OR NOT DEFINED ACTIVE_BOARD_REVISION)
1086    message(FATAL_ERROR "Board revision `${BOARD_REVISION}` for board \
1087            `${BOARD}` not found. Please specify a valid board revision.")
1088  endif()
1089
1090  set(ACTIVE_BOARD_REVISION ${ACTIVE_BOARD_REVISION} PARENT_SCOPE)
1091endfunction()
1092
1093# 1.5. Misc.
1094
1095# zephyr_check_compiler_flag is a part of Zephyr's toolchain
1096# infrastructure. It should be used when testing toolchain
1097# capabilities and it should normally be used in place of the
1098# functions:
1099#
1100# check_compiler_flag
1101# check_c_compiler_flag
1102# check_cxx_compiler_flag
1103#
1104# See check_compiler_flag() for API documentation as it has the same
1105# API.
1106#
1107# It is implemented as a wrapper on top of check_compiler_flag, which
1108# again wraps the CMake-builtin's check_c_compiler_flag and
1109# check_cxx_compiler_flag.
1110#
1111# It takes time to check for compatibility of flags against toolchains
1112# so we cache the capability test results in USER_CACHE_DIR (This
1113# caching comes in addition to the caching that CMake does in the
1114# build folder's CMakeCache.txt)
1115function(zephyr_check_compiler_flag lang option check)
1116  # Check if the option is covered by any hardcoded check before doing
1117  # an automated test.
1118  zephyr_check_compiler_flag_hardcoded(${lang} "${option}" _${check} exists)
1119  if(exists)
1120    set(${check} ${_${check}} PARENT_SCOPE)
1121    return()
1122  endif()
1123
1124  # Locate the cache directory
1125  set_ifndef(
1126    ZEPHYR_TOOLCHAIN_CAPABILITY_CACHE_DIR
1127    ${USER_CACHE_DIR}/ToolchainCapabilityDatabase
1128    )
1129
1130  # The toolchain capability database/cache is maintained as a
1131  # directory of files. The filenames in the directory are keys, and
1132  # the file contents are the values in this key-value store.
1133
1134  # We need to create a unique key wrt. testing the toolchain
1135  # capability. This key must include everything that can affect the
1136  # toolchain test.
1137  #
1138  # Also, to fit the key into a filename we calculate the MD5 sum of
1139  # the key.
1140
1141  # The 'cacheformat' must be bumped if a bug in the caching mechanism
1142  # is detected and all old keys must be invalidated.
1143  set(cacheformat 3)
1144
1145  set(key_string "")
1146  set(key_string "${key_string}${cacheformat}_")
1147  set(key_string "${key_string}${TOOLCHAIN_SIGNATURE}_")
1148  set(key_string "${key_string}${lang}_")
1149  set(key_string "${key_string}${option}_")
1150  set(key_string "${key_string}${CMAKE_REQUIRED_FLAGS}_")
1151
1152  string(MD5 key "${key_string}")
1153
1154  # Check the cache
1155  set(key_path ${ZEPHYR_TOOLCHAIN_CAPABILITY_CACHE_DIR}/${key})
1156  if(EXISTS ${key_path})
1157    file(READ
1158    ${key_path}   # File to be read
1159    key_value     # Output variable
1160    LIMIT 1       # Read at most 1 byte ('0' or '1')
1161    )
1162
1163    set(${check} ${key_value} PARENT_SCOPE)
1164    return()
1165  endif()
1166
1167  # Flags that start with -Wno-<warning> can not be tested by
1168  # check_compiler_flag, they will always pass, but -W<warning> can be
1169  # tested, so to test -Wno-<warning> flags we test -W<warning>
1170  # instead.
1171  if("${option}" MATCHES "-Wno-(.*)")
1172    string(REPLACE "-Wno-" "-W" possibly_translated_option "${option}")
1173  else()
1174    set(possibly_translated_option ${option})
1175  endif()
1176
1177  check_compiler_flag(${lang} "${possibly_translated_option}" inner_check)
1178
1179  set(${check} ${inner_check} PARENT_SCOPE)
1180
1181  # Populate the cache
1182  if(NOT (EXISTS ${key_path}))
1183
1184    # This is racy. As often with race conditions, this one can easily be
1185    # made worse and demonstrated with a simple delay:
1186    #    execute_process(COMMAND "sleep" "5")
1187    # Delete the cache, add the sleep above and run twister with a
1188    # large number of JOBS. Once it's done look at the log.txt file
1189    # below and you will see that concurrent cmake processes created the
1190    # same files multiple times.
1191
1192    # While there are a number of reasons why this race seems both very
1193    # unlikely and harmless, let's play it safe anyway and write to a
1194    # private, temporary file first. All modern filesystems seem to
1195    # support at least one atomic rename API and cmake's file(RENAME
1196    # ...) officially leverages that.
1197    string(RANDOM LENGTH 8 tempsuffix)
1198
1199    file(
1200      WRITE
1201      "${key_path}_tmp_${tempsuffix}"
1202      ${inner_check}
1203      )
1204    file(
1205      RENAME
1206      "${key_path}_tmp_${tempsuffix}" "${key_path}"
1207      )
1208
1209    # Populate a metadata file (only intended for trouble shooting)
1210    # with information about the hash, the toolchain capability
1211    # result, and the toolchain test.
1212    file(
1213      APPEND
1214      ${ZEPHYR_TOOLCHAIN_CAPABILITY_CACHE_DIR}/log.txt
1215      "${inner_check} ${key} ${key_string}\n"
1216      )
1217  endif()
1218endfunction()
1219
1220function(zephyr_check_compiler_flag_hardcoded lang option check exists)
1221  # Various flags that are not supported for CXX may not be testable
1222  # because they would produce a warning instead of an error during
1223  # the test.  Exclude them by toolchain-specific blocklist.
1224  if((${lang} STREQUAL CXX) AND ("${option}" IN_LIST CXX_EXCLUDED_OPTIONS))
1225    set(${check} 0 PARENT_SCOPE)
1226    set(${exists} 1 PARENT_SCOPE)
1227  else()
1228    # There does not exist a hardcoded check for this option.
1229    set(${exists} 0 PARENT_SCOPE)
1230  endif()
1231endfunction(zephyr_check_compiler_flag_hardcoded)
1232
1233# zephyr_linker_sources(<location> [SORT_KEY <sort_key>] <files>)
1234#
1235# <files> is one or more .ld formatted files whose contents will be
1236#    copied/included verbatim into the given <location> in the global linker.ld.
1237#    Preprocessor directives work inside <files>. Relative paths are resolved
1238#    relative to the calling file, like zephyr_sources().
1239#    Subsequent calls to zephyr_linker_sources with the same file(s) will remove
1240#    these from the original location. Only the last call is considered.
1241# <location> is one of
1242#    NOINIT        Inside the noinit output section.
1243#    RWDATA        Inside the data output section.
1244#    RODATA        Inside the rodata output section.
1245#    ROM_START     Inside the first output section of the image. This option is
1246#                  currently only available on ARM Cortex-M, ARM Cortex-R,
1247#                  x86, ARC, openisa_rv32m1, and RISC-V.
1248#    ROM_SECTIONS  Inside the ROMABLE_REGION GROUP, not initialized.
1249#    RAM_SECTIONS  Inside the RAMABLE_REGION GROUP, not initialized.
1250#    DATA_SECTIONS Inside the RAMABLE_REGION GROUP, initialized.
1251#    RAMFUNC_SECTION Inside the RAMFUNC RAMABLE_REGION GROUP, not initialized.
1252#    NOCACHE_SECTION Inside the NOCACHE section
1253#    ITCM_SECTION  Inside the itcm section.
1254#    DTCM_SECTION  Inside the dtcm data section.
1255#    SECTIONS      Near the end of the file. Don't use this when linking into
1256#                  RAMABLE_REGION, use RAM_SECTIONS instead.
1257#    PINNED_RODATA Similar to RODATA but pinned in memory.
1258#    PINNED_RAM_SECTIONS
1259#                  Similar to RAM_SECTIONS but pinned in memory.
1260#    PINNED_DATA_SECTIONS
1261#                  Similar to DATA_SECTIONS but pinned in memory.
1262# <sort_key> is an optional key to sort by inside of each location. The key must
1263#    be alphanumeric, and the keys are sorted alphabetically. If no key is
1264#    given, the key 'default' is used. Keys are case-sensitive.
1265#
1266# Use NOINIT, RWDATA, and RODATA unless they don't work for your use case.
1267#
1268# When placing into NOINIT, RWDATA, RODATA, ROM_START, RAMFUNC_SECTION,
1269# NOCACHE_SECTION, DTCM_SECTION or ITCM_SECTION the contents of the files will
1270# be placed inside an output section, so assume the section definition is
1271# already present, e.g.:
1272#    _mysection_start = .;
1273#    KEEP(*(.mysection));
1274#    _mysection_end = .;
1275#    _mysection_size = ABSOLUTE(_mysection_end - _mysection_start);
1276#
1277# When placing into SECTIONS, ROM_SECTIONS, RAM_SECTIONS or DATA_SECTIONS, the
1278# files must instead define their own output sections to achieve the same thing:
1279#    SECTION_PROLOGUE(.mysection,,)
1280#    {
1281#        _mysection_start = .;
1282#        KEEP(*(.mysection))
1283#        _mysection_end = .;
1284#    } GROUP_LINK_IN(ROMABLE_REGION)
1285#    _mysection_size = _mysection_end - _mysection_start;
1286#
1287# Note about the above examples: If the first example was used with RODATA, and
1288# the second with SECTIONS, the two examples do the same thing from a user
1289# perspective.
1290#
1291# Friendly reminder: Beware of the different ways the location counter ('.')
1292# behaves inside vs. outside section definitions.
1293function(zephyr_linker_sources location)
1294  # Set up the paths to the destination files. These files are #included inside
1295  # the global linker.ld.
1296  set(snippet_base       "${__build_dir}/include/generated")
1297  set(sections_path      "${snippet_base}/snippets-sections.ld")
1298  set(rom_sections_path  "${snippet_base}/snippets-rom-sections.ld")
1299  set(ram_sections_path  "${snippet_base}/snippets-ram-sections.ld")
1300  set(data_sections_path "${snippet_base}/snippets-data-sections.ld")
1301  set(rom_start_path     "${snippet_base}/snippets-rom-start.ld")
1302  set(noinit_path        "${snippet_base}/snippets-noinit.ld")
1303  set(rwdata_path        "${snippet_base}/snippets-rwdata.ld")
1304  set(rodata_path        "${snippet_base}/snippets-rodata.ld")
1305  set(ramfunc_path       "${snippet_base}/snippets-ramfunc-section.ld")
1306  set(nocache_path       "${snippet_base}/snippets-nocache-section.ld")
1307  set(itcm_path          "${snippet_base}/snippets-itcm-section.ld")
1308  set(dtcm_path          "${snippet_base}/snippets-dtcm-section.ld")
1309
1310  set(pinned_ram_sections_path  "${snippet_base}/snippets-pinned-ram-sections.ld")
1311  set(pinned_data_sections_path "${snippet_base}/snippets-pinned-data-sections.ld")
1312  set(pinned_rodata_path        "${snippet_base}/snippets-pinned-rodata.ld")
1313
1314  # Clear destination files if this is the first time the function is called.
1315  get_property(cleared GLOBAL PROPERTY snippet_files_cleared)
1316  if (NOT DEFINED cleared)
1317    file(WRITE ${sections_path} "")
1318    file(WRITE ${rom_sections_path} "")
1319    file(WRITE ${ram_sections_path} "")
1320    file(WRITE ${data_sections_path} "")
1321    file(WRITE ${rom_start_path} "")
1322    file(WRITE ${noinit_path} "")
1323    file(WRITE ${rwdata_path} "")
1324    file(WRITE ${rodata_path} "")
1325    file(WRITE ${ramfunc_path} "")
1326    file(WRITE ${nocache_path} "")
1327    file(WRITE ${itcm_path} "")
1328    file(WRITE ${dtcm_path} "")
1329    file(WRITE ${pinned_ram_sections_path} "")
1330    file(WRITE ${pinned_data_sections_path} "")
1331    file(WRITE ${pinned_rodata_path} "")
1332    set_property(GLOBAL PROPERTY snippet_files_cleared true)
1333  endif()
1334
1335  # Choose destination file, based on the <location> argument.
1336  if ("${location}" STREQUAL "SECTIONS")
1337    set(snippet_path "${sections_path}")
1338  elseif("${location}" STREQUAL "ROM_SECTIONS")
1339    set(snippet_path "${rom_sections_path}")
1340  elseif("${location}" STREQUAL "RAM_SECTIONS")
1341    set(snippet_path "${ram_sections_path}")
1342  elseif("${location}" STREQUAL "DATA_SECTIONS")
1343    set(snippet_path "${data_sections_path}")
1344  elseif("${location}" STREQUAL "ROM_START")
1345    set(snippet_path "${rom_start_path}")
1346  elseif("${location}" STREQUAL "NOINIT")
1347    set(snippet_path "${noinit_path}")
1348  elseif("${location}" STREQUAL "RWDATA")
1349    set(snippet_path "${rwdata_path}")
1350  elseif("${location}" STREQUAL "RODATA")
1351    set(snippet_path "${rodata_path}")
1352  elseif("${location}" STREQUAL "RAMFUNC_SECTION")
1353    set(snippet_path "${ramfunc_path}")
1354  elseif("${location}" STREQUAL "NOCACHE_SECTION")
1355    set(snippet_path "${nocache_path}")
1356  elseif("${location}" STREQUAL "ITCM_SECTION")
1357    dt_has_chosen(HAS_ITCM PROPERTY "zephyr,itcm")
1358    if(NOT HAS_ITCM)
1359      message(FATAL_ERROR "Trying to link snippet into itcm but no itcm available. "
1360              "Add `zephyr,itcm` to the device tree if supported on your device or choose another "
1361              "location.")
1362    endif()
1363    set(snippet_path "${itcm_path}")
1364  elseif("${location}" STREQUAL "DTCM_SECTION")
1365    dt_has_chosen(HAS_DTCM PROPERTY "zephyr,dtcm")
1366    if(NOT HAS_DTCM)
1367      message(FATAL_ERROR "Trying to link snippet into dtcm but no dtcm available. "
1368              "Add `zephyr,dtcm` to the device tree if supported on your device or choose another "
1369              "location.")
1370    endif()
1371    set(snippet_path "${dtcm_path}")
1372  elseif("${location}" STREQUAL "PINNED_RAM_SECTIONS")
1373    set(snippet_path "${pinned_ram_sections_path}")
1374  elseif("${location}" STREQUAL "PINNED_DATA_SECTIONS")
1375    set(snippet_path "${pinned_data_sections_path}")
1376  elseif("${location}" STREQUAL "PINNED_RODATA")
1377    set(snippet_path "${pinned_rodata_path}")
1378  else()
1379    message(fatal_error "Must choose valid location for linker snippet.")
1380  endif()
1381
1382  cmake_parse_arguments(L "" "SORT_KEY" "" ${ARGN})
1383  set(SORT_KEY default)
1384  if(DEFINED L_SORT_KEY)
1385    set(SORT_KEY ${L_SORT_KEY})
1386  endif()
1387
1388  foreach(file IN ITEMS ${L_UNPARSED_ARGUMENTS})
1389    # Resolve path.
1390    if(IS_ABSOLUTE ${file})
1391      set(path ${file})
1392    else()
1393      set(path ${CMAKE_CURRENT_SOURCE_DIR}/${file})
1394    endif()
1395
1396    if(IS_DIRECTORY ${path})
1397      message(FATAL_ERROR "zephyr_linker_sources() was called on a directory")
1398    endif()
1399
1400    # Find the relative path to the linker file from the include folder.
1401    file(RELATIVE_PATH relpath ${ZEPHYR_BASE}/include ${path})
1402
1403    # Create strings to be written into the file
1404    set (include_str "/* Sort key: \"${SORT_KEY}\" */#include \"${relpath}\"")
1405
1406    # Remove line from other snippet file, if already used
1407    get_property(old_path GLOBAL PROPERTY "snippet_files_used_${relpath}")
1408    if (DEFINED old_path)
1409      file(STRINGS ${old_path} lines)
1410      list(FILTER lines EXCLUDE REGEX ${relpath})
1411      string(REPLACE ";" "\n;" lines "${lines}") # Add newline to each line.
1412      file(WRITE ${old_path} ${lines} "\n")
1413    endif()
1414    set_property(GLOBAL PROPERTY "snippet_files_used_${relpath}" ${snippet_path})
1415
1416    # Add new line to existing lines, sort them, and write them back.
1417    file(STRINGS ${snippet_path} lines) # Get current lines (without newlines).
1418    list(APPEND lines ${include_str})
1419    list(SORT lines)
1420    string(REPLACE ";" "\n;" lines "${lines}") # Add newline to each line.
1421    file(WRITE ${snippet_path} ${lines} "\n")
1422  endforeach()
1423endfunction(zephyr_linker_sources)
1424
1425# Helper macro for conditionally calling zephyr_code_relocate() when a
1426# specific Kconfig symbol is enabled. See zephyr_code_relocate() description
1427# for supported arguments.
1428macro(zephyr_code_relocate_ifdef feature_toggle)
1429  if(${${feature_toggle}})
1430    zephyr_code_relocate(${ARGN})
1431  endif()
1432endmacro()
1433
1434# Helper function for CONFIG_CODE_DATA_RELOCATION
1435# This function may either be invoked with a list of files, or a library
1436# name to relocate.
1437#
1438# The FILES directive will relocate a list of files (wildcards supported)
1439# This directive will relocate file1. and file2.c to SRAM:
1440# zephyr_code_relocate(FILES file1.c file2.c LOCATION SRAM)
1441# Note, files can also be passed as a comma separated list to support using
1442# cmake generator arguments
1443#
1444# The LIBRARY directive will relocate a library
1445# This directive will relocate the target my_lib to SRAM:
1446# zephyr_code_relocate(LIBRARY my_lib SRAM)
1447#
1448# The following optional arguments are supported:
1449# - NOCOPY: this flag indicates that the file data does not need to be copied
1450#   at boot time (For example, for flash XIP).
1451# - NOKEEP: suppress the generation of KEEP() statements in the linker script,
1452#   to allow any unused code in the given files/library to be discarded.
1453# - PHDR [program_header]: add program header. Used on Xtensa platforms.
1454function(zephyr_code_relocate)
1455  set(options NOCOPY NOKEEP)
1456  set(single_args LIBRARY LOCATION PHDR FILTER)
1457  set(multi_args FILES)
1458  cmake_parse_arguments(CODE_REL "${options}" "${single_args}"
1459    "${multi_args}" ${ARGN})
1460  # Argument validation
1461  if(CODE_REL_UNPARSED_ARGUMENTS)
1462    message(FATAL_ERROR "zephyr_code_relocate(${ARGV0} ...) "
1463      "given unknown arguments: ${CODE_REL_UNPARSED_ARGUMENTS}")
1464  endif()
1465  if((NOT CODE_REL_FILES) AND (NOT CODE_REL_LIBRARY))
1466    message(FATAL_ERROR
1467      "zephyr_code_relocate() requires either FILES or LIBRARY be provided")
1468  endif()
1469  if(CODE_REL_FILES AND CODE_REL_LIBRARY)
1470    message(FATAL_ERROR "zephyr_code_relocate() only accepts "
1471      "one argument between FILES and LIBRARY")
1472  endif()
1473  if(NOT CODE_REL_LOCATION)
1474    message(FATAL_ERROR "zephyr_code_relocate() requires a LOCATION argument")
1475  endif()
1476  if(CODE_REL_LIBRARY)
1477    # Use cmake generator expression to convert library to file list,
1478    # supporting relative and absolute paths
1479    set(genex_src_dir "$<TARGET_PROPERTY:${CODE_REL_LIBRARY},SOURCE_DIR>")
1480    set(genex_src_list "$<TARGET_PROPERTY:${CODE_REL_LIBRARY},SOURCES>")
1481
1482    if(CMAKE_HOST_WIN32)
1483      # Note that this assumes windows absolute filenames start with a letter and colon, this does
1484      # not support \\x network paths and is untested under the likes of msys2/cygwin
1485      set(src_list_abs "$<FILTER:${genex_src_list},INCLUDE,^[A-Za-z]\:>")
1486      set(src_list_rel "$<FILTER:${genex_src_list},EXCLUDE,^[A-Za-z]\:>")
1487    else()
1488      set(src_list_abs "$<FILTER:${genex_src_list},INCLUDE,^/>")
1489      set(src_list_rel "$<FILTER:${genex_src_list},EXCLUDE,^/>")
1490    endif()
1491
1492    set(src_list "${genex_src_dir}/$<JOIN:${src_list_rel},$<SEMICOLON>${genex_src_dir}/>")
1493    set(nonempty_src_list "$<$<BOOL:${src_list_rel}>:${src_list}>")
1494    set(sep_list "$<$<AND:$<BOOL:${src_list_abs}>,$<BOOL:${src_list_rel}>>:$<SEMICOLON>>")
1495    set(file_list "${src_list_abs}${sep_list}${nonempty_src_list}")
1496  else()
1497    # Check if CODE_REL_FILES is a generator expression, if so leave it
1498    # untouched.
1499    string(GENEX_STRIP "${CODE_REL_FILES}" no_genex)
1500    if(CODE_REL_FILES STREQUAL no_genex)
1501      # no generator expression in CODE_REL_FILES, check if list of files
1502      # is absolute
1503      foreach(file ${CODE_REL_FILES})
1504        if(NOT IS_ABSOLUTE ${file})
1505          set(file ${CMAKE_CURRENT_SOURCE_DIR}/${file})
1506        endif()
1507        list(APPEND file_list ${file})
1508      endforeach()
1509    else()
1510      # Generator expression is present in file list. Leave the list untouched.
1511      set(file_list ${CODE_REL_FILES})
1512    endif()
1513  endif()
1514  if(NOT CODE_REL_NOCOPY)
1515    set(flag_list COPY)
1516  else()
1517    set(flag_list NOCOPY)
1518  endif()
1519  if(CODE_REL_NOKEEP)
1520    list(APPEND flag_list NOKEEP)
1521  endif()
1522  if(CODE_REL_PHDR)
1523    set(CODE_REL_LOCATION "${CODE_REL_LOCATION}\ :${CODE_REL_PHDR}")
1524  endif()
1525  # Each code relocation directive is placed on an independent line, instead of
1526  # using set_property(APPEND) to produce a ";"-separated CMake list. This way,
1527  # each directive can embed multiple CMake lists, representing flags and files,
1528  # the latter of which can come from generator expressions.
1529  get_property(code_rel_str TARGET code_data_relocation_target
1530    PROPERTY INTERFACE_SOURCES)
1531  set_property(TARGET code_data_relocation_target
1532    PROPERTY INTERFACE_SOURCES
1533    "${code_rel_str}\n${CODE_REL_LOCATION}:${flag_list}:${file_list},${CODE_REL_FILTER}")
1534endfunction()
1535
1536# Usage:
1537#   check_dtc_flag("-Wtest" DTC_WARN_TEST)
1538#
1539# Writes 1 to the output variable 'ok' if
1540# the flag is supported, otherwise writes 0.
1541#
1542# using
1543function(check_dtc_flag flag ok)
1544  execute_process(
1545    COMMAND
1546    ${DTC} ${flag} -v
1547    ERROR_QUIET
1548    OUTPUT_QUIET
1549    RESULT_VARIABLE dtc_check_ret
1550  )
1551  if (dtc_check_ret EQUAL 0)
1552    set(${ok} 1 PARENT_SCOPE)
1553  else()
1554    set(${ok} 0 PARENT_SCOPE)
1555  endif()
1556endfunction()
1557
1558# Function to round number to next power of two.
1559#
1560# Usage:
1561#   pow2round(<variable>)
1562#
1563# Example:
1564# set(test 2)
1565# pow2round(test)
1566# # test is still 2
1567#
1568# set(test 5)
1569# pow2round(test)
1570# # test is now 8
1571#
1572# Arguments:
1573# n   = Variable containing the number to round
1574function(pow2round n)
1575  math(EXPR x "${${n}} & (${${n}} - 1)")
1576  if(${x} EQUAL 0)
1577    return()
1578  endif()
1579
1580  math(EXPR ${n} "${${n}} | (${${n}} >> 1)")
1581  math(EXPR ${n} "${${n}} | (${${n}} >> 2)")
1582  math(EXPR ${n} "${${n}} | (${${n}} >> 4)")
1583  math(EXPR ${n} "${${n}} | (${${n}} >> 8)")
1584  math(EXPR ${n} "${${n}} | (${${n}} >> 16)")
1585  math(EXPR ${n} "${${n}} | (${${n}} >> 32)")
1586  math(EXPR ${n} "${${n}} + 1")
1587  set(${n} ${${n}} PARENT_SCOPE)
1588endfunction()
1589
1590# Function to create a build string based on BOARD, BOARD_REVISION, and
1591# BOARD_QUALIFIER.
1592#
1593# This is a common function to ensure that build strings are always created
1594# in a uniform way.
1595# A single string is returned containing the full build string constructed from
1596# all arguments.
1597#
1598# When MERGE is supplied a list of build strings will be returned with the full
1599# build string as first item in the list.
1600# The full order of build strings returned in the list will be:
1601# - Normalized board target build string, this includes qualifiers and revision
1602# - Build string with board variants removed in addition
1603# - Build string with cpuset removed in addition
1604# - Build string with soc removed in addition
1605#
1606# If REVISION is supplied or obtained as system wide setting a build string
1607# with the sanitized revision string will be added in addition to the
1608# non-revisioned entry for each entry.
1609#
1610# Usage:
1611#   zephyr_build_string(<out-variable>
1612#                       BOARD <board>
1613#                       [SHORT <out-variable>]
1614#                       [BOARD_QUALIFIERS <qualifiers>]
1615#                       [BOARD_REVISION <revision>]
1616#                       [MERGE [REVERSE]]
1617#   )
1618#   zephyr_build_string(<out-variable>
1619#                       BOARD_QUALIFIERS <qualifiers>
1620#                       [MERGE [REVERSE]]
1621#   )
1622#
1623# <out-variable>:            Output variable where the build string will be returned.
1624# SHORT <out-variable>:      Output variable where the shortened build string will be returned.
1625# BOARD <board>:             Board name to use when creating the build string.
1626# BOARD_REVISION <revision>: Board revision to use when creating the build string.
1627# MERGE:                     Return a list of build strings instead of a single build string.
1628# REVERSE:                   Reverse the list before returning it.
1629#
1630# Examples
1631# calling
1632#   zephyr_build_string(build_string BOARD alpha)
1633# will return the string `alpha` in `build_string` parameter.
1634#
1635# calling
1636#   zephyr_build_string(build_string BOARD alpha BOARD_REVISION 1.0.0)
1637# will return the string `alpha_1_0_0` in `build_string` parameter.
1638#
1639# calling
1640#   zephyr_build_string(build_string BOARD alpha BOARD_QUALIFIERS /soc/bar)
1641# will return the string `alpha_soc_bar` in `build_string` parameter.
1642#
1643# calling
1644#   zephyr_build_string(build_string BOARD alpha BOARD_REVISION 1.0.0 BOARD_QUALIFIERS /soc/bar MERGE)
1645# will return a list of the following strings
1646# `alpha_soc_bar_1_0_0;alpha_soc_bar` in `build_string` parameter.
1647#
1648# calling
1649#   zephyr_build_string(build_string SHORT short_build_string BOARD alpha BOARD_REVISION 1.0.0 BOARD_QUALIFIERS /soc/bar MERGE)
1650# will return two lists of the following strings
1651# `alpha_soc_bar_1_0_0;alpha_soc_bar` in `build_string` parameter.
1652# `alpha_bar_1_0_0;alpha_bar` in `short_build_string` parameter.
1653#
1654# calling
1655#   zephyr_build_string(build_string BOARD_QUALIFIERS /soc/bar/foo)
1656# will return the string `soc_bar_foo` in `build_string` parameter.
1657#
1658function(zephyr_build_string outvar)
1659  set(options MERGE REVERSE)
1660  set(single_args BOARD BOARD_QUALIFIERS BOARD_REVISION SHORT)
1661
1662  cmake_parse_arguments(BUILD_STR "${options}" "${single_args}" "" ${ARGN})
1663  if(BUILD_STR_UNPARSED_ARGUMENTS)
1664    message(FATAL_ERROR
1665      "zephyr_build_string(${ARGV0} <val> ...) given unknown arguments:"
1666      " ${BUILD_STR_UNPARSED_ARGUMENTS}"
1667    )
1668  endif()
1669
1670  if(DEFINED BUILD_STR_BOARD_REVISION AND NOT BUILD_STR_BOARD)
1671    message(FATAL_ERROR
1672      "zephyr_build_string(${ARGV0} <list> BOARD_REVISION ${BUILD_STR_BOARD_REVISION} ...)"
1673      " given without BOARD argument, please specify BOARD"
1674    )
1675  endif()
1676
1677  if(DEFINED BUILD_STR_BOARD_REVISION AND NOT DEFINED BUILD_STR_BOARD)
1678    message(FATAL_ERROR
1679      "zephyr_build_string(${ARGV0} <list> BOARD_REVISION ${BUILD_STR_BOARD_REVISION} ...)"
1680      " given without BOARD argument, these must be used together"
1681    )
1682  endif()
1683
1684  if(DEFINED BUILD_STR_SHORT AND NOT DEFINED BUILD_STR_BOARD)
1685    message(FATAL_ERROR
1686      "zephyr_build_string(${ARGV0} <list> SHORT ${BUILD_STR_SHORT} ...)"
1687      " given without BOARD argument, these must be used together"
1688    )
1689  endif()
1690
1691  string(REPLACE "/" ";" str_segment_list "${BUILD_STR_BOARD_QUALIFIERS}")
1692  string(REPLACE "." "_" revision_string "${BUILD_STR_BOARD_REVISION}")
1693
1694  string(JOIN "_" ${outvar} ${BUILD_STR_BOARD} ${str_segment_list} ${revision_string})
1695
1696  if(BUILD_STR_MERGE)
1697    string(JOIN "_" variant_string ${BUILD_STR_BOARD} ${str_segment_list})
1698
1699    if(NOT "${variant_string}" IN_LIST ${outvar})
1700      list(APPEND ${outvar} "${variant_string}")
1701    endif()
1702  endif()
1703
1704  if(BUILD_STR_REVERSE)
1705    list(REVERSE ${outvar})
1706  endif()
1707  list(REMOVE_DUPLICATES ${outvar})
1708
1709  if(BUILD_STR_SHORT AND BUILD_STR_BOARD_QUALIFIERS)
1710    string(REGEX REPLACE "^/[^/]*(.*)" "\\1" shortened_qualifiers "${BOARD_QUALIFIERS}")
1711    string(REPLACE "/" ";" str_short_segment_list "${shortened_qualifiers}")
1712    string(JOIN "_" ${BUILD_STR_SHORT}
1713           ${BUILD_STR_BOARD} ${str_short_segment_list} ${revision_string}
1714    )
1715    if(BUILD_STR_MERGE)
1716      string(JOIN "_" variant_string ${BUILD_STR_BOARD} ${str_short_segment_list})
1717
1718      if(NOT "${variant_string}" IN_LIST ${BUILD_STR_SHORT})
1719        list(APPEND ${BUILD_STR_SHORT} "${variant_string}")
1720      endif()
1721    endif()
1722
1723    if(BUILD_STR_REVERSE)
1724      list(REVERSE ${BUILD_STR_SHORT})
1725    endif()
1726    list(REMOVE_DUPLICATES ${BUILD_STR_SHORT})
1727    set(${BUILD_STR_SHORT} ${${BUILD_STR_SHORT}} PARENT_SCOPE)
1728  endif()
1729
1730  # This updates the provided outvar in parent scope (callers scope)
1731  set(${outvar} ${${outvar}} PARENT_SCOPE)
1732endfunction()
1733
1734# Function to add one or more directories to the include list passed to the syscall generator.
1735function(zephyr_syscall_include_directories)
1736  foreach(one_dir ${ARGV})
1737    if(EXISTS ${one_dir})
1738      set(include_dir ${one_dir})
1739    elseif(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${one_dir})
1740      set(include_dir ${CMAKE_CURRENT_SOURCE_DIR}/${one_dir})
1741    else()
1742      message(FATAL_ERROR "Syscall include directory not found: ${one_dir}")
1743    endif()
1744
1745    target_include_directories(
1746      syscalls_interface INTERFACE
1747      ${include_dir}
1748    )
1749    add_dependencies(
1750      syscalls_interface
1751      ${include_dir}
1752    )
1753
1754    unset(include_dir)
1755  endforeach()
1756endfunction()
1757
1758# Function to add header file(s) to the list to be passed to syscall generator.
1759function(zephyr_syscall_header)
1760  foreach(one_file ${ARGV})
1761    if(EXISTS ${one_file})
1762      set(header_file ${one_file})
1763    elseif(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${one_file})
1764      set(header_file ${CMAKE_CURRENT_SOURCE_DIR}/${one_file})
1765    else()
1766      message(FATAL_ERROR "Syscall header file not found: ${one_file}")
1767    endif()
1768
1769    target_sources(
1770      syscalls_interface INTERFACE
1771      ${header_file}
1772    )
1773    add_dependencies(
1774      syscalls_interface
1775      ${header_file}
1776    )
1777
1778    unset(header_file)
1779  endforeach()
1780endfunction()
1781
1782# Function to add header file(s) to the list to be passed to syscall generator
1783# if condition is true.
1784function(zephyr_syscall_header_ifdef feature_toggle)
1785  if(${${feature_toggle}})
1786    zephyr_syscall_header(${ARGN})
1787  endif()
1788endfunction()
1789
1790# Verify blobs fetched using west. If the sha256 checksum isn't valid, a warning/
1791# fatal error message is printed (depends on REQUIRED flag).
1792#
1793# Usage:
1794#   zephyr_blobs_verify(<MODULE module|FILES file [files...]> [REQUIRED])
1795#
1796# Example:
1797# zephyr_blobs_verify(MODULE my_module REQUIRED) # verify all blobs in my_module and fail on error
1798# zephyr_blobs_verify(FILES img/file.bin)        # verify a single file and print on error
1799function(zephyr_blobs_verify)
1800  cmake_parse_arguments(BLOBS_VERIFY "REQUIRED" "MODULE" "FILES" ${ARGN})
1801
1802  if((DEFINED BLOBS_VERIFY_MODULE) EQUAL (DEFINED BLOBS_VERIFY_FILES))
1803    message(FATAL_ERROR "Either MODULE or FILES required when calling ${CMAKE_CURRENT_FUNCTION}")
1804  endif()
1805
1806  if(NOT WEST)
1807    return()
1808  endif()
1809
1810  execute_process(
1811    COMMAND ${WEST} blobs list ${BLOBS_VERIFY_MODULE} --format "{status} {abspath}"
1812    OUTPUT_VARIABLE BLOBS_LIST_OUTPUT
1813    OUTPUT_STRIP_TRAILING_WHITESPACE
1814    COMMAND_ERROR_IS_FATAL ANY
1815  )
1816
1817  if(${BLOBS_VERIFY_REQUIRED})
1818    set(msg_lvl FATAL_ERROR)
1819  else()
1820    set(msg_lvl WARNING)
1821  endif()
1822
1823  string(REPLACE "\n" ";" BLOBS_LIST ${BLOBS_LIST_OUTPUT})
1824
1825  if(DEFINED BLOBS_VERIFY_FILES)
1826    foreach(file ${BLOBS_VERIFY_FILES})
1827      # Resolve path.
1828      if(IS_ABSOLUTE ${file})
1829        file(REAL_PATH "${file}" real_path)
1830      else()
1831        file(REAL_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${file}" real_path)
1832      endif()
1833      file(TO_NATIVE_PATH ${real_path} path)
1834
1835      message(VERBOSE "Verifying blob \"${path}\"")
1836
1837      if(NOT EXISTS "${path}")
1838        message(${msg_lvl} "Blob for path \"${path}\" missing. Update with: west blobs fetch")
1839      elseif(NOT "A ${path}" IN_LIST BLOBS_LIST)
1840        # Each path that has a correct sha256 is prefixed with an A
1841        message(${msg_lvl} "Blob for path \"${path}\" isn't valid. Update with: west blobs fetch")
1842      endif()
1843    endforeach()
1844  else()
1845    foreach(blob ${BLOBS_LIST})
1846      separate_arguments(blob)
1847      list(GET blob 0 status)
1848      list(GET blob 1 path)
1849
1850      message(VERBOSE "Verifying blob \"${path}\"")
1851
1852      if(NOT EXISTS "${path}")
1853        message(${msg_lvl} "Blob for path \"${path}\" missing. Update with: west blobs fetch ${BLOBS_VERIFY_MODULE}")
1854      elseif(NOT "${status}" STREQUAL "A")
1855        message(${msg_lvl} "Blob for path \"${path}\" isn't valid. Update with: west blobs fetch ${BLOBS_VERIFY_MODULE}")
1856      endif()
1857    endforeach()
1858  endif()
1859endfunction()
1860
1861########################################################
1862# 2. Kconfig-aware extensions
1863########################################################
1864#
1865# Kconfig is a configuration language developed for the Linux
1866# kernel. The below functions integrate CMake with Kconfig.
1867#
1868
1869# 2.1 Misc
1870#
1871# import_kconfig(<prefix> <kconfig_fragment> [<keys>] [TARGET <target>])
1872#
1873# Parse a KConfig fragment (typically with extension .config) and
1874# introduce all the symbols that are prefixed with 'prefix' into the
1875# CMake namespace. List all created variable names in the 'keys'
1876# output variable if present.
1877#
1878# <prefix>          : symbol prefix of settings in the Kconfig fragment.
1879# <kconfig_fragment>: absolute path to the config fragment file.
1880# <keys>            : output variable which will be populated with variable
1881#                     names loaded from the kconfig fragment.
1882# TARGET <target>   : set all symbols on <target> instead of adding them to the
1883#                     CMake namespace.
1884function(import_kconfig prefix kconfig_fragment)
1885  cmake_parse_arguments(IMPORT_KCONFIG "" "TARGET" "" ${ARGN})
1886  file(
1887    STRINGS
1888    ${kconfig_fragment}
1889    DOT_CONFIG_LIST
1890    ENCODING "UTF-8"
1891  )
1892
1893  foreach (LINE ${DOT_CONFIG_LIST})
1894    if("${LINE}" MATCHES "^(${prefix}[^=]+)=([ymn]|.+$)")
1895      # Matched a normal value assignment, like: CONFIG_NET_BUF=y
1896      # Note: if the value starts with 'y', 'm', or 'n', then we assume it's a
1897      # bool or tristate (we don't know the type from <kconfig_fragment> alone)
1898      # and we only match the first character. This is to align with Kconfiglib.
1899      set(CONF_VARIABLE_NAME "${CMAKE_MATCH_1}")
1900      set(CONF_VARIABLE_VALUE "${CMAKE_MATCH_2}")
1901    elseif("${LINE}" MATCHES "^# (${prefix}[^ ]+) is not set")
1902      # Matched something like: # CONFIG_FOO is not set
1903      # This is interpreted as: CONFIG_FOO=n
1904      set(CONF_VARIABLE_NAME "${CMAKE_MATCH_1}")
1905      set(CONF_VARIABLE_VALUE "n")
1906    else()
1907      # Ignore this line.
1908      # Note: we also ignore assignments which don't have the desired <prefix>.
1909      continue()
1910    endif()
1911
1912    # If the provided value is n, then the corresponding CMake variable or
1913    # target property will be unset.
1914    if("${CONF_VARIABLE_VALUE}" STREQUAL "n")
1915      if(DEFINED IMPORT_KCONFIG_TARGET)
1916        set_property(TARGET ${IMPORT_KCONFIG_TARGET} PROPERTY "${CONF_VARIABLE_NAME}")
1917      else()
1918        unset("${CONF_VARIABLE_NAME}" PARENT_SCOPE)
1919      endif()
1920      list(REMOVE_ITEM keys "${CONF_VARIABLE_NAME}")
1921      continue()
1922    endif()
1923
1924    # Otherwise, the variable/property will be set to the provided value.
1925    # For string values, we also remove the surrounding quotation marks.
1926    if("${CONF_VARIABLE_VALUE}" MATCHES "^\"(.*)\"$")
1927      set(CONF_VARIABLE_VALUE ${CMAKE_MATCH_1})
1928    endif()
1929
1930    if(DEFINED IMPORT_KCONFIG_TARGET)
1931      set_property(TARGET ${IMPORT_KCONFIG_TARGET} PROPERTY "${CONF_VARIABLE_NAME}" "${CONF_VARIABLE_VALUE}")
1932    else()
1933      set("${CONF_VARIABLE_NAME}" "${CONF_VARIABLE_VALUE}" PARENT_SCOPE)
1934    endif()
1935    list(APPEND keys "${CONF_VARIABLE_NAME}")
1936  endforeach()
1937
1938  if(DEFINED IMPORT_KCONFIG_TARGET)
1939    set_property(TARGET ${IMPORT_KCONFIG_TARGET} PROPERTY "kconfigs" "${keys}")
1940  endif()
1941
1942  list(LENGTH IMPORT_KCONFIG_UNPARSED_ARGUMENTS unparsed_length)
1943  if(unparsed_length GREATER 0)
1944    if(unparsed_length GREATER 1)
1945    # Two mandatory arguments and one optional, anything after that is an error.
1946      list(GET IMPORT_KCONFIG_UNPARSED_ARGUMENTS 1 first_invalid)
1947      message(FATAL_ERROR "Unexpected argument after '<keys>': import_kconfig(... ${first_invalid})")
1948    endif()
1949    set(${IMPORT_KCONFIG_UNPARSED_ARGUMENTS} "${keys}" PARENT_SCOPE)
1950  endif()
1951endfunction()
1952
1953########################################################
1954# 3. CMake-generic extensions
1955########################################################
1956#
1957# These functions extend the CMake API in a way that is not particular
1958# to Zephyr. Primarily they work around limitations in the CMake
1959# language to allow cleaner build scripts.
1960
1961# 3.1. *_ifdef
1962#
1963# Functions for conditionally executing CMake functions with oneliners
1964# e.g.
1965#
1966# if(CONFIG_FFT)
1967#   zephyr_library_source(
1968#     fft_32.c
1969#     fft_utils.c
1970#     )
1971# endif()
1972#
1973# Becomes
1974#
1975# zephyr_source_ifdef(
1976#   CONFIG_FFT
1977#   fft_32.c
1978#   fft_utils.c
1979#   )
1980#
1981# More Generally
1982# "<function-name>_ifdef(CONDITION args)"
1983# Becomes
1984# """
1985# if(CONDITION)
1986#   <function-name>(args)
1987# endif()
1988# """
1989#
1990# ifdef functions are added on an as-need basis. See
1991# https://cmake.org/cmake/help/latest/manual/cmake-commands.7.html for
1992# a list of available functions.
1993function(add_subdirectory_ifdef feature_toggle source_dir)
1994  if(${${feature_toggle}})
1995    add_subdirectory(${source_dir} ${ARGN})
1996  endif()
1997endfunction()
1998
1999function(target_sources_ifdef feature_toggle target scope item)
2000  if(${${feature_toggle}})
2001    target_sources(${target} ${scope} ${item} ${ARGN})
2002  endif()
2003endfunction()
2004
2005function(target_compile_definitions_ifdef feature_toggle target scope item)
2006  if(${${feature_toggle}})
2007    target_compile_definitions(${target} ${scope} ${item} ${ARGN})
2008  endif()
2009endfunction()
2010
2011function(target_include_directories_ifdef feature_toggle target scope item)
2012  if(${${feature_toggle}})
2013    target_include_directories(${target} ${scope} ${item} ${ARGN})
2014  endif()
2015endfunction()
2016
2017function(target_link_libraries_ifdef feature_toggle target item)
2018  if(${${feature_toggle}})
2019    target_link_libraries(${target} ${item} ${ARGN})
2020  endif()
2021endfunction()
2022
2023function(add_compile_option_ifdef feature_toggle option)
2024  if(${${feature_toggle}})
2025    add_compile_options(${option})
2026  endif()
2027endfunction()
2028
2029function(target_compile_option_ifdef feature_toggle target scope option)
2030  if(${feature_toggle})
2031    target_compile_options(${target} ${scope} ${option})
2032  endif()
2033endfunction()
2034
2035function(target_cc_option_ifdef feature_toggle target scope option)
2036  if(${feature_toggle})
2037    target_cc_option(${target} ${scope} ${option})
2038  endif()
2039endfunction()
2040
2041function(zephyr_library_sources_ifdef feature_toggle source)
2042  if(${${feature_toggle}})
2043    zephyr_library_sources(${source} ${ARGN})
2044  endif()
2045endfunction()
2046
2047function(zephyr_sources_ifdef feature_toggle)
2048  if(${${feature_toggle}})
2049    zephyr_sources(${ARGN})
2050  endif()
2051endfunction()
2052
2053function(zephyr_cc_option_ifdef feature_toggle)
2054  if(${${feature_toggle}})
2055    zephyr_cc_option(${ARGN})
2056  endif()
2057endfunction()
2058
2059function(zephyr_ld_option_ifdef feature_toggle)
2060  if(${${feature_toggle}})
2061    zephyr_ld_options(${ARGN})
2062  endif()
2063endfunction()
2064
2065function(zephyr_link_libraries_ifdef feature_toggle)
2066  if(${${feature_toggle}})
2067    zephyr_link_libraries(${ARGN})
2068  endif()
2069endfunction()
2070
2071function(zephyr_compile_options_ifdef feature_toggle)
2072  if(${${feature_toggle}})
2073    zephyr_compile_options(${ARGN})
2074  endif()
2075endfunction()
2076
2077function(zephyr_compile_definitions_ifdef feature_toggle)
2078  if(${${feature_toggle}})
2079    zephyr_compile_definitions(${ARGN})
2080  endif()
2081endfunction()
2082
2083function(zephyr_include_directories_ifdef feature_toggle)
2084  if(${${feature_toggle}})
2085    zephyr_include_directories(${ARGN})
2086  endif()
2087endfunction()
2088
2089function(zephyr_library_compile_definitions_ifdef feature_toggle item)
2090  if(${${feature_toggle}})
2091    zephyr_library_compile_definitions(${item} ${ARGN})
2092  endif()
2093endfunction()
2094
2095function(zephyr_library_include_directories_ifdef feature_toggle)
2096  if(${${feature_toggle}})
2097    zephyr_library_include_directories(${ARGN})
2098  endif()
2099endfunction()
2100
2101function(zephyr_library_compile_options_ifdef feature_toggle item)
2102  if(${${feature_toggle}})
2103    zephyr_library_compile_options(${item} ${ARGN})
2104  endif()
2105endfunction()
2106
2107function(zephyr_link_interface_ifdef feature_toggle interface)
2108  if(${${feature_toggle}})
2109    target_link_libraries(${interface} INTERFACE zephyr_interface)
2110  endif()
2111endfunction()
2112
2113function(zephyr_library_link_libraries_ifdef feature_toggle item)
2114  if(${${feature_toggle}})
2115     zephyr_library_link_libraries(${item})
2116  endif()
2117endfunction()
2118
2119function(zephyr_linker_sources_ifdef feature_toggle)
2120  if(${${feature_toggle}})
2121    zephyr_linker_sources(${ARGN})
2122  endif()
2123endfunction()
2124
2125function(zephyr_library_add_dependencies_ifdef feature_toggle)
2126  if(${${feature_toggle}})
2127    zephyr_library_add_dependencies(${ARGN})
2128  endif()
2129endfunction()
2130
2131macro(list_append_ifdef feature_toggle list)
2132  if(${${feature_toggle}})
2133    list(APPEND ${list} ${ARGN})
2134  endif()
2135endmacro()
2136
2137# 3.2. *_ifndef
2138# See 3.1 *_ifdef
2139function(set_ifndef variable value)
2140  if(NOT ${variable})
2141    set(${variable} ${value} ${ARGN} PARENT_SCOPE)
2142  endif()
2143endfunction()
2144
2145function(add_subdirectory_ifndef feature_toggle source_dir)
2146  if(NOT ${feature_toggle})
2147    add_subdirectory(${source_dir} ${ARGN})
2148  endif()
2149endfunction()
2150
2151function(target_sources_ifndef feature_toggle target scope item)
2152  if(NOT ${feature_toggle})
2153    target_sources(${target} ${scope} ${item} ${ARGN})
2154  endif()
2155endfunction()
2156
2157function(target_compile_definitions_ifndef feature_toggle target scope item)
2158  if(NOT ${feature_toggle})
2159    target_compile_definitions(${target} ${scope} ${item} ${ARGN})
2160  endif()
2161endfunction()
2162
2163function(target_include_directories_ifndef feature_toggle target scope item)
2164  if(NOT ${feature_toggle})
2165    target_include_directories(${target} ${scope} ${item} ${ARGN})
2166  endif()
2167endfunction()
2168
2169function(target_link_libraries_ifndef feature_toggle target item)
2170  if(NOT ${feature_toggle})
2171    target_link_libraries(${target} ${item} ${ARGN})
2172  endif()
2173endfunction()
2174
2175function(add_compile_option_ifndef feature_toggle option)
2176  if(NOT ${feature_toggle})
2177    add_compile_options(${option})
2178  endif()
2179endfunction()
2180
2181function(target_compile_option_ifndef feature_toggle target scope option)
2182  if(NOT ${feature_toggle})
2183    target_compile_options(${target} ${scope} ${option})
2184  endif()
2185endfunction()
2186
2187function(target_cc_option_ifndef feature_toggle target scope option)
2188  if(NOT ${feature_toggle})
2189    target_cc_option(${target} ${scope} ${option})
2190  endif()
2191endfunction()
2192
2193function(zephyr_library_sources_ifndef feature_toggle source)
2194  if(NOT ${feature_toggle})
2195    zephyr_library_sources(${source} ${ARGN})
2196  endif()
2197endfunction()
2198
2199function(zephyr_sources_ifndef feature_toggle)
2200   if(NOT ${feature_toggle})
2201    zephyr_sources(${ARGN})
2202  endif()
2203endfunction()
2204
2205function(zephyr_cc_option_ifndef feature_toggle)
2206  if(NOT ${feature_toggle})
2207    zephyr_cc_option(${ARGN})
2208  endif()
2209endfunction()
2210
2211function(zephyr_ld_option_ifndef feature_toggle)
2212  if(NOT ${feature_toggle})
2213    zephyr_ld_options(${ARGN})
2214  endif()
2215endfunction()
2216
2217function(zephyr_link_libraries_ifndef feature_toggle)
2218  if(NOT ${feature_toggle})
2219    zephyr_link_libraries(${ARGN})
2220  endif()
2221endfunction()
2222
2223function(zephyr_compile_options_ifndef feature_toggle)
2224  if(NOT ${feature_toggle})
2225    zephyr_compile_options(${ARGN})
2226  endif()
2227endfunction()
2228
2229function(zephyr_compile_definitions_ifndef feature_toggle)
2230  if(NOT ${feature_toggle})
2231    zephyr_compile_definitions(${ARGN})
2232  endif()
2233endfunction()
2234
2235function(zephyr_include_directories_ifndef feature_toggle)
2236  if(NOT ${feature_toggle})
2237    zephyr_include_directories(${ARGN})
2238  endif()
2239endfunction()
2240
2241function(zephyr_library_compile_definitions_ifndef feature_toggle item)
2242  if(NOT ${feature_toggle})
2243    zephyr_library_compile_definitions(${item} ${ARGN})
2244  endif()
2245endfunction()
2246
2247function(zephyr_library_include_directories_ifndef feature_toggle)
2248  if(NOT ${feature_toggle})
2249    zephyr_library_include_directories(${ARGN})
2250  endif()
2251endfunction()
2252
2253function(zephyr_library_compile_options_ifndef feature_toggle item)
2254  if(NOT ${feature_toggle})
2255    zephyr_library_compile_options(${item} ${ARGN})
2256  endif()
2257endfunction()
2258
2259function(zephyr_link_interface_ifndef feature_toggle interface)
2260  if(NOT ${feature_toggle})
2261    target_link_libraries(${interface} INTERFACE zephyr_interface)
2262  endif()
2263endfunction()
2264
2265function(zephyr_library_link_libraries_ifndef feature_toggle item)
2266  if(NOT ${feature_toggle})
2267     zephyr_library_link_libraries(${item})
2268  endif()
2269endfunction()
2270
2271function(zephyr_linker_sources_ifndef feature_toggle)
2272  if(NOT ${feature_toggle})
2273    zephyr_linker_sources(${ARGN})
2274  endif()
2275endfunction()
2276
2277function(zephyr_library_add_dependencies_ifndef feature_toggle)
2278  if(NOT ${feature_toggle})
2279    zephyr_library_add_dependencies(${ARGN})
2280  endif()
2281endfunction()
2282
2283macro(list_append_ifndef feature_toggle list)
2284  if(NOT ${feature_toggle})
2285    list(APPEND ${list} ${ARGN})
2286  endif()
2287endmacro()
2288
2289# 3.3. *_option Compiler-compatibility checks
2290#
2291# Utility functions for silently omitting compiler flags when the
2292# compiler lacks support. *_cc_option was ported from KBuild, see
2293# cc-option in
2294# https://www.kernel.org/doc/Documentation/kbuild/makefiles.txt
2295
2296# Writes 1 to the output variable 'ok' for the language 'lang' if
2297# the flag is supported, otherwise writes 0.
2298#
2299# lang must be C or CXX
2300#
2301# TODO: Support ASM
2302#
2303# Usage:
2304#
2305# check_compiler_flag(C "-Wall" my_check)
2306# print(my_check) # my_check is now 1
2307function(check_compiler_flag lang option ok)
2308  if(NOT DEFINED CMAKE_REQUIRED_QUIET)
2309    set(CMAKE_REQUIRED_QUIET 1)
2310  endif()
2311
2312  string(MAKE_C_IDENTIFIER
2313    "check${option}_${lang}_${CMAKE_REQUIRED_FLAGS}"
2314    ${ok}
2315    )
2316
2317  if(${lang} STREQUAL C)
2318    check_c_compiler_flag("${option}" ${${ok}})
2319  else()
2320    check_cxx_compiler_flag("${option}" ${${ok}})
2321  endif()
2322
2323  if(${${${ok}}})
2324    set(ret 1)
2325  else()
2326    set(ret 0)
2327  endif()
2328
2329  set(${ok} ${ret} PARENT_SCOPE)
2330endfunction()
2331
2332function(target_cc_option target scope option)
2333  target_cc_option_fallback(${target} ${scope} ${option} "")
2334endfunction()
2335
2336# Support an optional second option for when the first option is not
2337# supported.
2338function(target_cc_option_fallback target scope option1 option2)
2339  if(CONFIG_CPP)
2340    foreach(lang C CXX)
2341      # For now, we assume that all flags that apply to C/CXX also
2342      # apply to ASM.
2343      zephyr_check_compiler_flag(${lang} ${option1} check)
2344      if(${check})
2345        target_compile_options(${target} ${scope}
2346          $<$<COMPILE_LANGUAGE:${lang}>:${option1}>
2347          $<$<COMPILE_LANGUAGE:ASM>:${option1}>
2348          )
2349      elseif(option2)
2350        target_compile_options(${target} ${scope}
2351          $<$<COMPILE_LANGUAGE:${lang}>:${option2}>
2352          $<$<COMPILE_LANGUAGE:ASM>:${option2}>
2353          )
2354      endif()
2355    endforeach()
2356  else()
2357    zephyr_check_compiler_flag(C ${option1} check)
2358    if(${check})
2359      target_compile_options(${target} ${scope} ${option1})
2360    elseif(option2)
2361      target_compile_options(${target} ${scope} ${option2})
2362    endif()
2363  endif()
2364endfunction()
2365
2366function(target_ld_options target scope)
2367  zephyr_get_parse_args(args ${ARGN})
2368  list(REMOVE_ITEM ARGN NO_SPLIT)
2369
2370  foreach(option ${ARGN})
2371    if(args_NO_SPLIT)
2372      set(option ${ARGN})
2373    endif()
2374    string(JOIN "" check_identifier "check" ${option})
2375    string(MAKE_C_IDENTIFIER ${check_identifier} check)
2376
2377    set(SAVED_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
2378    string(JOIN " " CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS} ${option})
2379    zephyr_check_compiler_flag(C "" ${check})
2380    set(CMAKE_REQUIRED_FLAGS ${SAVED_CMAKE_REQUIRED_FLAGS})
2381
2382    target_link_libraries_ifdef(${check} ${target} ${scope} ${option})
2383
2384    if(args_NO_SPLIT)
2385      break()
2386    endif()
2387  endforeach()
2388endfunction()
2389
2390# 3.3.1 Toolchain integration
2391#
2392# 'toolchain_parse_make_rule' is a function that parses the output of
2393# 'gcc -M'.
2394#
2395# The argument 'input_file' is in input parameter with the path to the
2396# file with the dependency information.
2397#
2398# The argument 'include_files' is an output parameter with the result
2399# of parsing the include files.
2400function(toolchain_parse_make_rule input_file include_files)
2401  file(STRINGS ${input_file} input)
2402
2403  # The file is formatted like this:
2404  # empty_file.o: misc/empty_file.c \
2405  # nrf52840dk_nrf52840/nrf52840dk_nrf52840.dts \
2406  # nrf52840_qiaa.dtsi
2407
2408  # The dep file will contain `\` for line continuation.
2409  # This results in `\;` which is then treated a the char `;` instead of
2410  # the element separator, so let's get the pure `;` back.
2411  string(REPLACE "\;" ";" input_as_list ${input})
2412
2413  # The file might also contain multiple files on one line if one or both of
2414  # the file paths are short, split these up into multiple elements using regex
2415  string(REGEX REPLACE "([^ ])[ ]([^ ])" "\\1;\\2" input_as_list "${input_as_list}")
2416
2417  # Pop the first item containing "empty_file.o:"
2418  list(POP_FRONT input_as_list first_input_line)
2419
2420  # Remove whitespace before and after filename and convert to CMake path.
2421  foreach(file ${input_as_list})
2422    string(STRIP "${file}" file)
2423    file(TO_CMAKE_PATH "${file}" file)
2424    list(APPEND result "${file}")
2425  endforeach()
2426
2427  set(${include_files} ${result} PARENT_SCOPE)
2428endfunction()
2429
2430# 'set_linker_property' is a function that sets the property for the linker
2431# property target used for toolchain abstraction.
2432#
2433# This function is similar in nature to the CMake set_property function, but
2434# with some additional extension flags for improved behavioral control.
2435#
2436# NO_CREATE: Flag to indicate that the property should only be set if not already
2437#            defined with a value.
2438# APPEND: Flag indicated that the property should be appended to the existing
2439#         value list for the property.
2440# TARGET: Name of target on which to add the property (default: linker)
2441# PROPERTY: Name of property with the value(s) following immediately after
2442#           property name
2443function(set_linker_property)
2444  set(options APPEND NO_CREATE)
2445  set(single_args TARGET)
2446  set(multi_args  PROPERTY)
2447  cmake_parse_arguments(LINKER_PROPERTY "${options}" "${single_args}" "${multi_args}" ${ARGN})
2448
2449  if(LINKER_PROPERTY_APPEND)
2450   set(APPEND "APPEND")
2451  endif()
2452
2453  if(NOT DEFINED LINKER_PROPERTY_TARGET)
2454   set(LINKER_PROPERTY_TARGET "linker")
2455  endif()
2456
2457  if(LINKER_PROPERTY_NO_CREATE)
2458    list(GET LINKER_PROPERTY_PROPERTY 0 property_name)
2459    get_target_property(var ${LINKER_PROPERTY_TARGET} ${property_name})
2460    if(NOT "${var}" STREQUAL "var-NOTFOUND")
2461      return()
2462    endif()
2463  endif()
2464  set_property(TARGET ${LINKER_PROPERTY_TARGET} ${APPEND} PROPERTY ${LINKER_PROPERTY_PROPERTY})
2465endfunction()
2466
2467# 'check_set_linker_property' is a function that check the provided linker
2468# flag and only set the linker property if the check succeeds
2469#
2470# This function is similar in nature to the CMake set_property function, but
2471# with the extension that it will check that the linker supports the flag before
2472# setting the property.
2473#
2474# APPEND: Flag indicated that the property should be appended to the existing
2475#         value list for the property.
2476# TARGET: Name of target on which to add the property (default: linker)
2477# PROPERTY: Name of property with the value(s) following immediately after
2478#           property name
2479function(check_set_linker_property)
2480  set(options APPEND)
2481  set(single_args TARGET)
2482  set(multi_args  PROPERTY)
2483  cmake_parse_arguments(LINKER_PROPERTY "${options}" "${single_args}" "${multi_args}" ${ARGN})
2484
2485  if(LINKER_PROPERTY_APPEND)
2486   set(APPEND "APPEND")
2487  endif()
2488
2489  if(NOT DEFINED LINKER_PROPERTY_TARGET)
2490   set(LINKER_PROPERTY_TARGET "linker")
2491  endif()
2492
2493  list(GET LINKER_PROPERTY_PROPERTY 0 property)
2494  list(REMOVE_AT LINKER_PROPERTY_PROPERTY 0)
2495
2496  foreach(option ${LINKER_PROPERTY_PROPERTY})
2497    string(MAKE_C_IDENTIFIER check${option} check)
2498
2499    set(SAVED_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
2500    set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${option}")
2501    zephyr_check_compiler_flag(C "" ${check})
2502    set(CMAKE_REQUIRED_FLAGS ${SAVED_CMAKE_REQUIRED_FLAGS})
2503
2504    if(${${check}})
2505      set_property(TARGET ${LINKER_PROPERTY_TARGET} ${APPEND} PROPERTY ${property} ${option})
2506      set(APPEND "APPEND")
2507    endif()
2508  endforeach()
2509endfunction()
2510
2511# 'set_compiler_property' is a function that sets the property for the C and
2512# C++ property targets used for toolchain abstraction.
2513#
2514# This function is similar in nature to the CMake set_property function, but
2515# with the extension that it will set the property on both the compile and
2516# compiler-cpp targets.
2517#
2518# APPEND: Flag indicated that the property should be appended to the existing
2519#         value list for the property.
2520# PROPERTY: Name of property with the value(s) following immediately after
2521#           property name
2522function(set_compiler_property)
2523  set(options APPEND)
2524  set(multi_args  PROPERTY)
2525  cmake_parse_arguments(COMPILER_PROPERTY "${options}" "${single_args}" "${multi_args}" ${ARGN})
2526  if(COMPILER_PROPERTY_APPEND)
2527   set(APPEND "APPEND")
2528   set(APPEND-CPP "APPEND")
2529  endif()
2530
2531  set_property(TARGET compiler ${APPEND} PROPERTY ${COMPILER_PROPERTY_PROPERTY})
2532  set_property(TARGET compiler-cpp ${APPEND} PROPERTY ${COMPILER_PROPERTY_PROPERTY})
2533endfunction()
2534
2535# 'check_set_compiler_property' is a function that check the provided compiler
2536# flag and only set the compiler or compiler-cpp property if the check succeeds
2537#
2538# This function is similar in nature to the CMake set_property function, but
2539# with the extension that it will check that the compiler supports the flag
2540# before setting the property on compiler or compiler-cpp targets.
2541#
2542# To test flags together, such as '-Wformat -Wformat-security', an option group
2543# can be specified by using shell-like quoting along with a 'SHELL:' prefix.
2544# The 'SHELL:' prefix will be dropped before testing, so that
2545# '"SHELL:-Wformat -Wformat-security"' becomes '-Wformat -Wformat-security' for
2546# testing.
2547#
2548# APPEND: Flag indicated that the property should be appended to the existing
2549#         value list for the property.
2550# PROPERTY: Name of property with the value(s) following immediately after
2551#           property name
2552function(check_set_compiler_property)
2553  set(options APPEND)
2554  set(multi_args  PROPERTY)
2555  cmake_parse_arguments(COMPILER_PROPERTY "${options}" "${single_args}" "${multi_args}" ${ARGN})
2556  if(COMPILER_PROPERTY_APPEND)
2557   set(APPEND "APPEND")
2558   set(APPEND-CPP "APPEND")
2559  endif()
2560
2561  list(GET COMPILER_PROPERTY_PROPERTY 0 property)
2562  list(REMOVE_AT COMPILER_PROPERTY_PROPERTY 0)
2563
2564  foreach(option ${COMPILER_PROPERTY_PROPERTY})
2565    if(${option} MATCHES "^SHELL:")
2566      string(REGEX REPLACE "^SHELL:" "" option ${option})
2567      separate_arguments(option UNIX_COMMAND ${option})
2568    endif()
2569
2570    if(CONFIG_CPP)
2571      zephyr_check_compiler_flag(CXX "${option}" check)
2572
2573      if(${check})
2574        set_property(TARGET compiler-cpp ${APPEND-CPP} PROPERTY ${property} ${option})
2575        set(APPEND-CPP "APPEND")
2576      endif()
2577    endif()
2578
2579    zephyr_check_compiler_flag(C "${option}" check)
2580
2581    if(${check})
2582      set_property(TARGET compiler ${APPEND} PROPERTY ${property} ${option})
2583      set(APPEND "APPEND")
2584    endif()
2585  endforeach()
2586endfunction()
2587
2588
2589# 3.4. Debugging CMake
2590
2591# Usage:
2592#   print(BOARD)
2593#
2594# will print: "BOARD: nrf52dk"
2595function(print arg)
2596  message(STATUS "${arg}: ${${arg}}")
2597endfunction()
2598
2599# Usage:
2600#   assert(ZEPHYR_TOOLCHAIN_VARIANT "ZEPHYR_TOOLCHAIN_VARIANT not set.")
2601#
2602# will cause a FATAL_ERROR and print an error message if the first
2603# expression is false
2604macro(assert test comment)
2605  if(NOT ${test})
2606    message(FATAL_ERROR "Assertion failed: ${comment}")
2607  endif()
2608endmacro()
2609
2610# Usage:
2611#   assert_not(OBSOLETE_VAR "OBSOLETE_VAR has been removed; use NEW_VAR instead")
2612#
2613# will cause a FATAL_ERROR and print an error message if the first
2614# expression is true
2615macro(assert_not test comment)
2616  if(${test})
2617    message(FATAL_ERROR "Assertion failed: ${comment}")
2618  endif()
2619endmacro()
2620
2621# Usage:
2622#   assert_exists(CMAKE_READELF)
2623#
2624# will cause a FATAL_ERROR if there is no file or directory behind the
2625# variable
2626macro(assert_exists var)
2627  if(NOT EXISTS ${${var}})
2628    message(FATAL_ERROR "No such file or directory: ${var}: '${${var}}'")
2629  endif()
2630endmacro()
2631
2632# 3.5. File system management
2633function(generate_unique_target_name_from_filename filename target_name)
2634  get_filename_component(basename ${filename} NAME)
2635  string(REPLACE "." "_" x ${basename})
2636  string(REPLACE "@" "_" x ${x})
2637
2638  string(MD5 unique_chars ${filename})
2639
2640  set(${target_name} gen_${x}_${unique_chars} PARENT_SCOPE)
2641endfunction()
2642
2643# Usage:
2644#   zephyr_file(<mode> <arg> ...)
2645#
2646# Zephyr file function extension.
2647# This function currently supports the following <modes>
2648#
2649# APPLICATION_ROOT <path>: Check all paths in provided variable, and convert
2650#                          those paths that are defined with `-D<path>=<val>`
2651#                          to absolute path, relative from `APPLICATION_SOURCE_DIR`
2652#                          Issue an error for any relative path not specified
2653#                          by user with `-D<path>`
2654#                          BASE_DIR <base-dir>: convert paths relative to <base-dir>
2655#                                               instead of `APPLICATION_SOURCE_DIR`
2656#
2657# returns an updated list of absolute paths
2658#
2659# Usage:
2660#   zephyr_file(CONF_FILES <paths> [DTS <list>] [KCONF <list>]
2661#               [BOARD <board> [BOARD_REVISION <revision>] | NAMES <name> ...]
2662#               [SUFFIX <suffix>] [REQUIRED]
2663#   )
2664#
2665# CONF_FILES <paths>: Find all configuration files in the list of paths and
2666#                     return them in a list. If paths is empty then no configuration
2667#                     files are returned. Configuration files will be:
2668#                     - DTS:       Overlay files (.overlay)
2669#                     - Kconfig:   Config fragments (.conf)
2670#                     - defconfig: defconfig files (_defconfig)
2671#                     The conf file search will return existing configuration
2672#                     files for the current board.
2673#                     CONF_FILES takes the following additional arguments:
2674#                     BOARD <board>:             Find configuration files for specified board.
2675#                     BOARD_REVISION <revision>: Find configuration files for specified board
2676#                                                revision. Requires BOARD to be specified.
2677#
2678#                                                If no board is given the current BOARD and
2679#                                                BOARD_REVISION will be used, unless NAMES are
2680#                                                specified.
2681#
2682#                     NAMES <name1> [name2] ...  List of file names to look for and instead of
2683#                                                creating file names based on board settings.
2684#                                                Only the first match found in <paths> will be
2685#                                                returned in the <list>
2686#                     DTS <list>:    List to append DTS overlay files in <path> to
2687#                     KCONF <list>:  List to append Kconfig fragment files in <path> to
2688#                     DEFCONF <list>: List to append _defconfig files in <path> to
2689#                     SUFFIX <name>: Suffix name to check for instead of the default name
2690#                                    but with a fallback to the default name if not found.
2691#                                    For example:
2692#                                    SUFFIX fish, will look for <file>_fish.conf and use
2693#                                    if found but will use <file>.conf if not found
2694#                     REQUIRED:      Option to indicate that the <list> specified by DTS or KCONF
2695#                                    must contain at least one element, else an error will be raised.
2696#
2697function(zephyr_file)
2698  set(file_options APPLICATION_ROOT CONF_FILES)
2699  if((ARGC EQUAL 0) OR (NOT (ARGV0 IN_LIST file_options)))
2700    message(FATAL_ERROR "No <mode> given to `zephyr_file(<mode> <args>...)` function,\n \
2701Please provide one of following: APPLICATION_ROOT, CONF_FILES")
2702  endif()
2703
2704  if(${ARGV0} STREQUAL APPLICATION_ROOT)
2705    set(single_args APPLICATION_ROOT BASE_DIR)
2706  elseif(${ARGV0} STREQUAL CONF_FILES)
2707    set(options QUALIFIERS REQUIRED)
2708    set(single_args BOARD BOARD_REVISION BOARD_QUALIFIERS DTS KCONF DEFCONFIG SUFFIX)
2709    set(multi_args CONF_FILES NAMES)
2710  endif()
2711
2712  cmake_parse_arguments(ZFILE "${options}" "${single_args}" "${multi_args}" ${ARGN})
2713  if(ZFILE_UNPARSED_ARGUMENTS)
2714      message(FATAL_ERROR "zephyr_file(${ARGV0} <val> ...) given unknown arguments: ${ZFILE_UNPARSED_ARGUMENTS}")
2715  endif()
2716
2717  if(ZFILE_APPLICATION_ROOT)
2718    if(NOT DEFINED ZFILE_BASE_DIR)
2719      set(ZFILE_BASE_DIR ${APPLICATION_SOURCE_DIR})
2720    endif()
2721
2722    # Note: user can do: `-D<var>=<relative-path>` and app can at same
2723    # time specify `list(APPEND <var> <abs-path>)`
2724    # Thus need to check and update only CACHED variables (-D<var>).
2725    set(CACHED_PATH $CACHE{${ZFILE_APPLICATION_ROOT}})
2726    foreach(path ${CACHED_PATH})
2727      # The cached variable is relative path, i.e. provided by `-D<var>` or
2728      # `set(<var> CACHE)`, so let's update current scope variable to absolute
2729      # path from  `APPLICATION_SOURCE_DIR`.
2730      if(NOT IS_ABSOLUTE ${path})
2731        list(FIND ${ZFILE_APPLICATION_ROOT} ${path} index)
2732        cmake_path(ABSOLUTE_PATH path BASE_DIRECTORY ${ZFILE_BASE_DIR} NORMALIZE)
2733        if(NOT ${index} LESS 0)
2734          list(REMOVE_AT ${ZFILE_APPLICATION_ROOT} ${index})
2735          list(INSERT ${ZFILE_APPLICATION_ROOT} ${index} ${path})
2736        endif()
2737      endif()
2738    endforeach()
2739
2740    # Now all cached relative paths has been updated.
2741    # Let's check if anyone uses relative path as scoped variable, and fail
2742    foreach(path ${${ZFILE_APPLICATION_ROOT}})
2743      if(NOT IS_ABSOLUTE ${path})
2744        message(FATAL_ERROR
2745"Relative path encountered in scoped variable: ${ZFILE_APPLICATION_ROOT}, value=${path}\n \
2746Please adjust any `set(${ZFILE_APPLICATION_ROOT} ${path})` or `list(APPEND ${ZFILE_APPLICATION_ROOT} ${path})`\n \
2747to absolute path using `\${CMAKE_CURRENT_SOURCE_DIR}/${path}` or similar. \n \
2748Relative paths are only allowed with `-D${ARGV1}=<path>`")
2749      endif()
2750    endforeach()
2751
2752    list(REMOVE_DUPLICATES ${ZFILE_APPLICATION_ROOT})
2753    # This updates the provided argument in parent scope (callers scope)
2754    set(${ZFILE_APPLICATION_ROOT} ${${ZFILE_APPLICATION_ROOT}} PARENT_SCOPE)
2755  endif()
2756
2757  if(ZFILE_CONF_FILES)
2758    if(DEFINED ZFILE_BOARD_REVISION AND NOT ZFILE_BOARD)
2759        message(FATAL_ERROR
2760          "zephyr_file(${ARGV0} <path> BOARD_REVISION ${ZFILE_BOARD_REVISION} ...)"
2761          " given without BOARD argument, please specify BOARD"
2762        )
2763    endif()
2764
2765    if(NOT DEFINED ZFILE_BOARD)
2766      # Defaulting to system wide settings when BOARD is not given as argument
2767      set(ZFILE_BOARD ${BOARD})
2768      if(DEFINED BOARD_REVISION)
2769        set(ZFILE_BOARD_REVISION ${BOARD_REVISION})
2770      endif()
2771
2772      if(DEFINED BOARD_QUALIFIERS)
2773        set(ZFILE_BOARD_QUALIFIERS ${BOARD_QUALIFIERS})
2774      endif()
2775    endif()
2776
2777    if(ZFILE_NAMES)
2778      set(dts_filename_list ${ZFILE_NAMES})
2779      set(kconf_filename_list ${ZFILE_NAMES})
2780    else()
2781      if(NOT ZFILE_QUALIFIERS)
2782        zephyr_build_string(filename_list
2783                            SHORT shortened_filename_list
2784                            BOARD ${ZFILE_BOARD}
2785                            BOARD_REVISION ${ZFILE_BOARD_REVISION}
2786                            BOARD_QUALIFIERS ${ZFILE_BOARD_QUALIFIERS}
2787                            MERGE REVERSE
2788        )
2789      else()
2790        zephyr_build_string(filename_list
2791                            BOARD_QUALIFIERS ${ZFILE_BOARD_QUALIFIERS}
2792                            MERGE REVERSE
2793        )
2794      endif()
2795
2796      set(dts_filename_list ${filename_list})
2797      set(dts_shortened_filename_list ${shortened_filename_list})
2798      list(TRANSFORM dts_filename_list APPEND ".overlay")
2799      list(TRANSFORM dts_shortened_filename_list APPEND ".overlay")
2800
2801      set(kconf_filename_list ${filename_list})
2802      set(kconf_shortened_filename_list ${shortened_filename_list})
2803      list(TRANSFORM kconf_filename_list APPEND ".conf")
2804      list(TRANSFORM kconf_shortened_filename_list APPEND ".conf")
2805    endif()
2806
2807    if(ZFILE_DTS)
2808      foreach(path ${ZFILE_CONF_FILES})
2809        foreach(filename IN ZIP_LISTS dts_filename_list dts_shortened_filename_list)
2810          foreach(i RANGE 1)
2811            if(NOT IS_ABSOLUTE filename_${i} AND DEFINED filename_${i})
2812              set(test_file_${i} ${path}/${filename_${i}})
2813            else()
2814              set(test_file_${i} ${filename_${i}})
2815            endif()
2816            zephyr_file_suffix(test_file_${i} SUFFIX ${ZFILE_SUFFIX})
2817
2818            if(NOT EXISTS ${test_file_${i}})
2819              set(test_file_${i})
2820            endif()
2821          endforeach()
2822
2823          if(test_file_0 OR test_file_1)
2824            list(APPEND found_dts_files ${test_file_0})
2825            list(APPEND found_dts_files ${test_file_1})
2826
2827            if(ZFILE_NAMES)
2828              break()
2829            endif()
2830          endif()
2831
2832          if(test_file_1 AND NOT BOARD_${ZFILE_BOARD}_SINGLE_SOC)
2833            message(FATAL_ERROR "Board ${ZFILE_BOARD} defines multiple SoCs.\nShortened file name "
2834                    "(${filename_1}) not allowed, use '<board>_<soc>.overlay' naming"
2835            )
2836          endif()
2837
2838          if(test_file_0 AND test_file_1)
2839            message(FATAL_ERROR "Conflicting file names discovered. Cannot use both ${filename_0} "
2840                    "and ${filename_1}. Please choose one naming style, "
2841                    "${filename_0} is recommended."
2842            )
2843          endif()
2844        endforeach()
2845      endforeach()
2846
2847      list(APPEND ${ZFILE_DTS} ${found_dts_files})
2848
2849      # This updates the provided list in parent scope (callers scope)
2850      set(${ZFILE_DTS} ${${ZFILE_DTS}} PARENT_SCOPE)
2851    endif()
2852
2853    if(ZFILE_KCONF)
2854      set(found_conf_files)
2855      foreach(path ${ZFILE_CONF_FILES})
2856        foreach(filename IN ZIP_LISTS kconf_filename_list kconf_shortened_filename_list)
2857          foreach(i RANGE 1)
2858            if(NOT IS_ABSOLUTE filename_${i} AND DEFINED filename_${i})
2859              set(test_file_${i} ${path}/${filename_${i}})
2860            else()
2861              set(test_file_${i} ${filename_${i}})
2862            endif()
2863            zephyr_file_suffix(test_file_${i} SUFFIX ${ZFILE_SUFFIX})
2864
2865            if(NOT EXISTS ${test_file_${i}})
2866              set(test_file_${i})
2867            endif()
2868          endforeach()
2869
2870          if(test_file_0 OR test_file_1)
2871            list(APPEND found_conf_files ${test_file_0})
2872            list(APPEND found_conf_files ${test_file_1})
2873
2874            if(ZFILE_NAMES)
2875              break()
2876            endif()
2877          endif()
2878
2879          if(test_file_1 AND NOT BOARD_${ZFILE_BOARD}_SINGLE_SOC)
2880            message(FATAL_ERROR "Board ${ZFILE_BOARD} defines multiple SoCs.\nShortened file name "
2881                    "(${filename_1}) not allowed, use '<board>_<soc>.conf' naming"
2882            )
2883          endif()
2884
2885          if(test_file_0 AND test_file_1)
2886            message(FATAL_ERROR "Conflicting file names discovered. Cannot use both ${filename_0} "
2887                    "and ${filename_1}. Please choose one naming style, "
2888                    "${filename_0} is recommended."
2889            )
2890          endif()
2891        endforeach()
2892      endforeach()
2893
2894      list(APPEND ${ZFILE_KCONF} ${found_conf_files})
2895
2896      # This updates the provided list in parent scope (callers scope)
2897      set(${ZFILE_KCONF} ${${ZFILE_KCONF}} PARENT_SCOPE)
2898
2899      if(NOT ${ZFILE_KCONF})
2900        set(not_found ${kconf_filename_list})
2901      endif()
2902    endif()
2903
2904    if(ZFILE_REQUIRED AND DEFINED not_found)
2905      message(FATAL_ERROR
2906              "No ${not_found} file(s) was found in the ${ZFILE_CONF_FILES} folder(s), "
2907              "please read the Zephyr documentation on application development."
2908      )
2909    endif()
2910
2911    if(ZFILE_DEFCONFIG)
2912      set(found_defconf_files)
2913      foreach(path ${ZFILE_CONF_FILES})
2914        foreach(filename IN ZIP_LISTS filename_list shortened_filename_list)
2915          foreach(i RANGE 1)
2916            set(test_file_${i} ${path}/${filename_${i}}_defconfig)
2917
2918            if(EXISTS ${test_file_${i}})
2919              list(APPEND found_defconf_files ${test_file_${i}})
2920            else()
2921              set(test_file_${i})
2922            endif()
2923          endforeach()
2924
2925          if(test_file_1 AND NOT BOARD_${ZFILE_BOARD}_SINGLE_SOC)
2926            message(FATAL_ERROR "Board ${ZFILE_BOARD} defines multiple SoCs.\nShortened file name "
2927                    "(${filename_1}_defconfig) not allowed, use '<board>_<soc>_defconfig' naming"
2928            )
2929          endif()
2930
2931          if(test_file_0 AND test_file_1)
2932            message(FATAL_ERROR "Conflicting file names discovered. Cannot use both "
2933                    "${filename_0}_defconfig and ${filename_1}_defconfig. Please choose one "
2934                    "naming style, ${filename_0}_defconfig is recommended."
2935            )
2936          endif()
2937        endforeach()
2938      endforeach()
2939      list(APPEND ${ZFILE_DEFCONFIG} ${found_defconf_files})
2940
2941      # This updates the provided list in parent scope (callers scope)
2942      set(${ZFILE_DEFCONFIG} ${${ZFILE_DEFCONFIG}} PARENT_SCOPE)
2943    endif()
2944  endif()
2945endfunction()
2946
2947# Usage:
2948#   zephyr_file_copy(<oldname> <newname> [ONLY_IF_DIFFERENT])
2949#
2950# Zephyr file copy extension.
2951# This function is similar to CMake function
2952# 'file(COPY_FILE <oldname> <newname> [ONLY_IF_DIFFERENT])'
2953# introduced with CMake 3.21.
2954#
2955# Because the minimal required CMake version with Zephyr is 3.20, this function
2956# is not guaranteed to be available.
2957#
2958# When using CMake version 3.21 or newer 'zephyr_file_copy()' simply calls
2959# 'file(COPY_FILE...)' directly.
2960# When using CMake version 3.20, the implementation will execute using CMake
2961# for running command line tool in a subprocess for identical functionality.
2962function(zephyr_file_copy oldname newname)
2963  set(options ONLY_IF_DIFFERENT)
2964  cmake_parse_arguments(ZEPHYR_FILE_COPY "${options}" "" "" ${ARGN})
2965
2966  if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.21.0)
2967    if(ZEPHYR_FILE_COPY_ONLY_IF_DIFFERENT)
2968      set(copy_file_options ONLY_IF_DIFFERENT)
2969    endif()
2970    file(COPY_FILE ${oldname} ${newname} ${copy_file_options})
2971  else()
2972    if(ZEPHYR_FILE_COPY_ONLY_IF_DIFFERENT)
2973      set(copy_file_command copy_if_different)
2974    else()
2975      set(copy_file_command copy)
2976    endif()
2977    execute_process(
2978      COMMAND ${CMAKE_COMMAND} -E ${copy_file_command} ${oldname} ${newname}
2979    )
2980  endif()
2981endfunction()
2982
2983# Usage:
2984#   zephyr_file_suffix(<filename> SUFFIX <suffix>)
2985#
2986# Zephyr file add suffix extension.
2987# This function will check the provied filename or list of filenames to see if they have a
2988# `_<suffix>` extension to them and if so, updates the supplied variable/list with the new
2989# path/paths.
2990#
2991# <filename>: Variable (singlular or list) of absolute path filename(s) which should be checked
2992#             and updated if there is a filename which has the <suffix> present.
2993# <suffix>: The suffix to test for and append to the end of the provided filename.
2994#
2995# Returns an updated variable of absolute path(s)
2996#
2997function(zephyr_file_suffix filename)
2998  set(single_args SUFFIX)
2999  cmake_parse_arguments(SFILE "" "${single_args}" "" ${ARGN})
3000
3001  if(NOT DEFINED SFILE_SUFFIX OR NOT DEFINED ${filename})
3002    # If the file suffix variable is not known then there is nothing to do, return early
3003    return()
3004  endif()
3005
3006  set(tmp_new_list)
3007
3008  foreach(file ${${filename}})
3009    if("${file}" STREQUAL "")
3010      # Skip checking empty variables
3011      continue()
3012    endif()
3013
3014    # Search for the full stop so we know where to add the file suffix before the file extension
3015    cmake_path(GET file EXTENSION file_ext)
3016    cmake_path(REMOVE_EXTENSION file OUTPUT_VARIABLE new_filename)
3017    cmake_path(APPEND_STRING new_filename "_${SFILE_SUFFIX}${file_ext}")
3018
3019    # Use the filename with the suffix if it exists, if not then fall back to the default
3020    if(EXISTS "${new_filename}")
3021      list(APPEND tmp_new_list ${new_filename})
3022    else()
3023      list(APPEND tmp_new_list ${file})
3024    endif()
3025  endforeach()
3026
3027  # Update supplied variable if it differs
3028  if(NOT "${${filename}}" STREQUAL "${tmp_new_list}")
3029    set(${filename} "${tmp_new_list}" PARENT_SCOPE)
3030  endif()
3031endfunction()
3032
3033# Usage:
3034#   zephyr_string(<mode> <out-var> <input> ...)
3035#
3036# Zephyr string function extension.
3037# This function extends the CMake string function by providing additional
3038# manipulation arguments to CMake string.
3039#
3040# ESCAPE:   Ensure that any single '\', except '\"', in the input string is
3041#           escaped with the escape char '\'. For example the string 'foo\bar'
3042#           will be escaped so that it becomes 'foo\\bar'.
3043#           Backslashes which are already escaped will not be escaped further,
3044#           for example 'foo\\bar' will not be modified.
3045#           This is useful for handling of windows path separator in strings or
3046#           when strings contains newline escapes such as '\n' and this can
3047#           cause issues when writing to a file where a '\n' is desired in the
3048#           string instead of a newline.
3049#
3050# SANITIZE: Ensure that the output string does not contain any special
3051#           characters. Special characters, such as -, +, =, $, etc. are
3052#           converted to underscores '_'.
3053#
3054# SANITIZE TOUPPER: Ensure that the output string does not contain any special
3055#                   characters. Special characters, such as -, +, =, $, etc. are
3056#                   converted to underscores '_'.
3057#                   The sanitized string will be returned in UPPER case.
3058#
3059# returns the updated string
3060function(zephyr_string)
3061  set(options SANITIZE TOUPPER ESCAPE)
3062  cmake_parse_arguments(ZEPHYR_STRING "${options}" "" "" ${ARGN})
3063
3064  zephyr_check_flags_exclusive(${CMAKE_CURRENT_FUNCTION} ZEPHYR_STRING SANITIZE ESCAPE)
3065
3066  if (NOT ZEPHYR_STRING_UNPARSED_ARGUMENTS)
3067    message(FATAL_ERROR "Function zephyr_string() called without a return variable")
3068  endif()
3069
3070  list(GET ZEPHYR_STRING_UNPARSED_ARGUMENTS 0 return_arg)
3071  list(REMOVE_AT ZEPHYR_STRING_UNPARSED_ARGUMENTS 0)
3072
3073  list(JOIN ZEPHYR_STRING_UNPARSED_ARGUMENTS "" work_string)
3074
3075  if(ZEPHYR_STRING_SANITIZE)
3076    string(REGEX REPLACE "[^a-zA-Z0-9_]" "_" work_string ${work_string})
3077  endif()
3078
3079  if(ZEPHYR_STRING_TOUPPER)
3080    string(TOUPPER ${work_string} work_string)
3081  endif()
3082
3083  if(ZEPHYR_STRING_ESCAPE)
3084    # If a single '\' is discovered, such as 'foo\bar', then it must be escaped like: 'foo\\bar'
3085    # \\1 and \\2 are keeping the match patterns, the \\\\ --> \\ meaning an escaped '\',
3086    # which then becomes a single '\' in the final string.
3087    string(REGEX REPLACE "([^\\][\\])([^\\\"])" "\\1\\\\\\2" work_string "${ZEPHYR_STRING_UNPARSED_ARGUMENTS}")
3088  endif()
3089
3090  set(${return_arg} ${work_string} PARENT_SCOPE)
3091endfunction()
3092
3093# Usage:
3094#    zephyr_list(TRANSFORM <list> <ACTION>
3095#                [OUTPUT_VARIABLE <output variable])
3096#
3097# Example:
3098#
3099#    zephyr_list(TRANSFORM my_input_var NORMALIZE_PATHS
3100#                OUTPUT_VARIABLE my_input_as_list)
3101#
3102# Like CMake's list(TRANSFORM ...). This is intended as a placeholder
3103# for storing current and future Zephyr-related extensions for list
3104# processing.
3105#
3106# <ACTION>: This currently must be NORMALIZE_PATHS. This action
3107#           converts the argument list <list> to a ;-list with
3108#           CMake path names, after passing its contents through
3109#           a configure_file() transformation. The input list
3110#           may be whitespace- or semicolon-separated.
3111#
3112# OUTPUT_VARIABLE: the result is normally stored in place, but
3113#                  an alternative variable to store the result
3114#                  can be provided with this.
3115function(zephyr_list transform list_var action)
3116  # Parse arguments.
3117  if(NOT "${transform}" STREQUAL "TRANSFORM")
3118    message(FATAL_ERROR "the first argument must be TRANSFORM")
3119  endif()
3120  if(NOT "${action}" STREQUAL "NORMALIZE_PATHS")
3121    message(FATAL_ERROR "the third argument must be NORMALIZE_PATHS")
3122  endif()
3123  set(single_args OUTPUT_VARIABLE)
3124  cmake_parse_arguments(ZEPHYR_LIST "" "${single_args}" "" ${ARGN})
3125  if(DEFINED ZEPHYR_LIST_OUTPUT_VARIABLE)
3126    set(out_var ${ZEPHYR_LIST_OUTPUT_VARIABLE})
3127  else()
3128    set(out_var ${list_var})
3129  endif()
3130  set(input ${${list_var}})
3131
3132  # Perform the transformation.
3133  set(ret)
3134  string(CONFIGURE "${input}" input_expanded)
3135  string(REPLACE " " ";" input_raw_list "${input_expanded}")
3136  foreach(file ${input_raw_list})
3137    file(TO_CMAKE_PATH "${file}" cmake_path_file)
3138    list(APPEND ret ${cmake_path_file})
3139  endforeach()
3140
3141  set(${out_var} ${ret} PARENT_SCOPE)
3142endfunction()
3143
3144# Usage:
3145#   zephyr_var_name(<variable> <scope> <out>)
3146#
3147# Internal function for construction of scoped variable name expansion string.
3148# Examples:
3149#   reading a current scope FOO variable is identical to expand ${FOO}.
3150#   reading a cache scope FOO variable is identical to expand $CACHE{FOO}.
3151#
3152# this functions will return the var name in out var for the scope if it is
3153# defined, else it will set the outvar to undefined.
3154function(zephyr_var_name variable scope out)
3155  if(scope STREQUAL "ENV" OR scope STREQUAL "CACHE")
3156    if(DEFINED ${scope}{${variable}})
3157      set(${out} "$${scope}{${variable}}" PARENT_SCOPE)
3158    else()
3159      set(${out} PARENT_SCOPE)
3160    endif()
3161  else()
3162    if(DEFINED ${scope}_${variable})
3163      set(${out} "${${scope}_${variable}}" PARENT_SCOPE)
3164    else()
3165      set(${out} PARENT_SCOPE)
3166    endif()
3167  endif()
3168endfunction()
3169
3170# Usage:
3171#   zephyr_get(<variable> [MERGE [REVERSE]] [SYSBUILD [LOCAL|GLOBAL]] [VAR <var1> ...])
3172#
3173# Return the value of <variable> as local scoped variable of same name. If MERGE
3174# is supplied, will return a list of found items. If REVERSE is supplied
3175# together with MERGE, the order of the list will be reversed before being
3176# returned. Reverse will happen before the list is returned and hence it will
3177# not change the order of precedence in which the list itself is constructed.
3178#
3179# VAR can be used either to store the result in a variable with a different
3180# name, or to look for values from multiple variables.
3181# zephyr_get(FOO VAR FOO_A FOO_B)
3182# zephyr_get(FOO MERGE VAR FOO_A FOO_B)
3183#
3184# zephyr_get() is a common function to provide a uniform way of supporting
3185# build settings that can be set from sysbuild, CMakeLists.txt, CMake cache, or
3186# in environment.
3187#
3188# The order of precedence for variables defined in multiple scopes:
3189# - Sysbuild defined when sysbuild is used.
3190#   Sysbuild variables can be defined as global or local to specific image.
3191#   Examples:
3192#   - BOARD is considered a global sysbuild cache variable
3193#   - blinky_BOARD is considered a local sysbuild cache variable only for the
3194#     blinky image.
3195#   If no sysbuild scope is specified, GLOBAL is assumed.
3196#   If using MERGE then SYSBUILD GLOBAL will get both the local and global
3197#   sysbuild scope variables (in that order, if both exist).
3198# - CMake cache, set by `-D<var>=<value>` or `set(<var> <val> CACHE ...)
3199# - Environment
3200# - Locally in CMakeLists.txt before 'find_package(Zephyr)'
3201#
3202# For example, if ZEPHYR_TOOLCHAIN_VARIANT is set in environment but locally
3203# overridden by setting ZEPHYR_TOOLCHAIN_VARIANT directly in the CMake cache
3204# using `-DZEPHYR_TOOLCHAIN_VARIANT=<val>`, then the value from the cache is
3205# returned.
3206function(zephyr_get variable)
3207  cmake_parse_arguments(GET_VAR "MERGE;REVERSE" "SYSBUILD" "VAR" ${ARGN})
3208
3209  if(DEFINED GET_VAR_SYSBUILD)
3210    if(NOT ("${GET_VAR_SYSBUILD}" STREQUAL "GLOBAL" OR
3211            "${GET_VAR_SYSBUILD}" STREQUAL "LOCAL")
3212    )
3213      message(FATAL_ERROR "zephyr_get(... SYSBUILD) requires GLOBAL or LOCAL.")
3214    endif()
3215  else()
3216    set(GET_VAR_SYSBUILD "GLOBAL")
3217  endif()
3218
3219  if(GET_VAR_REVERSE AND NOT GET_VAR_MERGE)
3220    message(FATAL_ERROR "zephyr_get(... REVERSE) missing a required argument: MERGE")
3221  endif()
3222
3223  if(NOT DEFINED GET_VAR_VAR)
3224    set(GET_VAR_VAR ${variable})
3225  endif()
3226
3227  # Keep current scope variables in internal variables.
3228  # This is needed to properly handle cases where we want to check value against
3229  # environment value or when appending with the MERGE operation.
3230  foreach(var ${GET_VAR_VAR})
3231    set(current_${var} ${${var}})
3232    set(${var})
3233
3234    if(SYSBUILD)
3235      get_property(sysbuild_name TARGET sysbuild_cache PROPERTY SYSBUILD_NAME)
3236      get_property(sysbuild_main_app TARGET sysbuild_cache PROPERTY SYSBUILD_MAIN_APP)
3237      get_property(sysbuild_local_${var} TARGET sysbuild_cache PROPERTY ${sysbuild_name}_${var})
3238      get_property(sysbuild_global_${var} TARGET sysbuild_cache PROPERTY ${var})
3239      if(NOT DEFINED sysbuild_local_${var} AND sysbuild_main_app)
3240        set(sysbuild_local_${var} ${sysbuild_global_${var}})
3241      endif()
3242      if(NOT "${GET_VAR_SYSBUILD}" STREQUAL "GLOBAL")
3243        set(sysbuild_global_${var})
3244      endif()
3245    else()
3246      set(sysbuild_local_${var})
3247      set(sysbuild_global_${var})
3248    endif()
3249
3250    zephyr_scope_exists(scope_defined snippets)
3251    if(scope_defined)
3252      zephyr_get_scoped(snippets_${var} snippets ${var})
3253    endif()
3254  endforeach()
3255
3256  set(${variable} "")
3257  set(scopes "sysbuild_local;sysbuild_global;CACHE;snippets;ENV;current")
3258  if(GET_VAR_REVERSE)
3259    list(REVERSE scopes)
3260  endif()
3261  foreach(scope IN LISTS scopes)
3262    foreach(var ${GET_VAR_VAR})
3263      zephyr_var_name("${var}" "${scope}" expansion_var)
3264      if(DEFINED expansion_var)
3265        string(CONFIGURE "${expansion_var}" scope_value)
3266        if(GET_VAR_MERGE)
3267          list(APPEND ${variable} ${scope_value})
3268        else()
3269          set(${variable} ${scope_value} PARENT_SCOPE)
3270
3271          if("${scope}" STREQUAL "ENV")
3272            # Set the environment variable in CMake cache, so that a build
3273            # invocation triggering a CMake rerun doesn't rely on the
3274            # environment variable still being available / have identical value.
3275            set(${var} $ENV{${var}} CACHE INTERNAL "Cached environment variable ${var}")
3276          endif()
3277
3278          if("${scope}" STREQUAL "ENV" AND DEFINED current_${var}
3279             AND NOT "${current_${var}}" STREQUAL "$ENV{${var}}"
3280          )
3281            # Variable exists as current scoped variable, defined in a CMakeLists.txt
3282            # file, however it is also set in environment.
3283            # This might be a surprise to the user, so warn about it.
3284            message(WARNING "environment variable '${var}' is hiding local "
3285                            "variable of same name.\n"
3286                            "Environment value (in use): $ENV{${var}}\n"
3287                            "Current scope value (hidden): ${current_${var}}\n"
3288            )
3289          endif()
3290
3291          return()
3292        endif()
3293      endif()
3294    endforeach()
3295  endforeach()
3296
3297  if(GET_VAR_MERGE)
3298    if(GET_VAR_REVERSE)
3299      list(REVERSE ${variable})
3300      list(REMOVE_DUPLICATES ${variable})
3301      list(REVERSE ${variable})
3302    else()
3303      list(REMOVE_DUPLICATES ${variable})
3304    endif()
3305    set(${variable} ${${variable}} PARENT_SCOPE)
3306  endif()
3307endfunction(zephyr_get variable)
3308
3309# Usage:
3310#   zephyr_create_scope(<scope>)
3311#
3312# Create a new scope for creation of scoped variables.
3313#
3314# <scope>: Name of new scope.
3315#
3316function(zephyr_create_scope scope)
3317  zephyr_scope_exists(scope_defined ${scope})
3318  if(scope_defined)
3319    message(FATAL_ERROR "zephyr_create_scope(${scope}) already exists.")
3320  endif()
3321
3322  set_property(GLOBAL PROPERTY scope:${scope} TRUE)
3323endfunction()
3324
3325# Usage:
3326#   zephyr_scope_exists(<result> <scope>)
3327#
3328# Check if <scope> exists.
3329#
3330# <result>: Variable to set with result.
3331#           TRUE if scope exists, FALSE otherwise.
3332# <scope> : Name of scope.
3333#
3334function(zephyr_scope_exists result scope)
3335  get_property(scope_defined GLOBAL PROPERTY scope:${scope})
3336  if(scope_defined)
3337    set(${result} TRUE PARENT_SCOPE)
3338  else()
3339    set(${result} FALSE PARENT_SCOPE)
3340  endif()
3341endfunction()
3342
3343# Usage:
3344#   zephyr_get_scoped(<output> <scope> <var>)
3345#
3346# Get the current value of <var> in a specific <scope>, as defined by a
3347# previous zephyr_set() call. The value will be stored in the <output> var.
3348#
3349# <output> : Variable to store the value in
3350# <scope>  : Scope for the variable look up
3351# <var>    : Name to look up in the specific scope
3352#
3353function(zephyr_get_scoped output scope var)
3354  zephyr_scope_exists(scope_defined ${scope})
3355  if(NOT scope_defined)
3356    message(FATAL_ERROR "zephyr_get_scoped(): scope ${scope} doesn't exists.")
3357  endif()
3358
3359  get_property(value GLOBAL PROPERTY ${scope}_scope:${var})
3360  if(DEFINED value)
3361    set(${output} "${value}" PARENT_SCOPE)
3362  else()
3363    unset(${output} PARENT_SCOPE)
3364  endif()
3365endfunction()
3366
3367# Usage:
3368#   zephyr_set(<variable> <value> SCOPE <scope> [APPEND])
3369#
3370# Zephyr extension of CMake set which allows a variable to be set in a specific
3371# scope. The scope is used on later zephyr_get() invocation for precedence
3372# handling when a variable it set in multiple scopes.
3373#
3374# <variable>   : Name of variable
3375# <value>      : Value of variable, multiple values will create a list.
3376#                The SCOPE argument identifies the end of value list.
3377# SCOPE <scope>: Name of scope for the variable
3378# APPEND       : Append values to the already existing variable in <scope>
3379#
3380function(zephyr_set variable)
3381  cmake_parse_arguments(SET_VAR "APPEND" "SCOPE" "" ${ARGN})
3382
3383  zephyr_check_arguments_required_all(zephyr_set SET_VAR SCOPE)
3384
3385  zephyr_scope_exists(scope_defined ${SET_VAR_SCOPE})
3386  if(NOT scope_defined)
3387    message(FATAL_ERROR "zephyr_set(... SCOPE ${SET_VAR_SCOPE}) doesn't exists.")
3388  endif()
3389
3390  if(SET_VAR_APPEND)
3391    set(property_args APPEND)
3392  endif()
3393
3394  set_property(GLOBAL ${property_args} PROPERTY
3395               ${SET_VAR_SCOPE}_scope:${variable} ${SET_VAR_UNPARSED_ARGUMENTS}
3396  )
3397endfunction()
3398
3399# Usage:
3400#   zephyr_check_cache(<variable> [REQUIRED])
3401#
3402# Check the current CMake cache for <variable> and warn the user if the value
3403# is being modified.
3404#
3405# This can be used to ensure the user does not accidentally try to change
3406# Zephyr build variables, such as:
3407# - BOARD
3408# - SHIELD
3409#
3410# variable: Name of <variable> to check and set, for example BOARD.
3411# REQUIRED: Optional flag. If specified, then an unset <variable> will be
3412#           treated as an error.
3413# WATCH: Optional flag. If specified, watch the variable and print a warning if
3414#        the variable is later being changed.
3415#
3416# Details:
3417#   <variable> can be set by 3 sources.
3418#   - Using CMake argument, -D<variable>
3419#   - Using an environment variable
3420#   - In the project CMakeLists.txt before `find_package(Zephyr)`.
3421#
3422#   CLI has the highest precedence, then comes environment variables,
3423#   and then finally CMakeLists.txt.
3424#
3425#   The value defined on the first CMake invocation will be stored in the CMake
3426#   cache as CACHED_<variable>. This allows the Zephyr build system to detect
3427#   when a user reconfigures a sticky variable.
3428#
3429#   A user can ignore all the precedence rules if the same source is always used
3430#   E.g. always specifies -D<variable>= on the command line,
3431#   always has an environment <variable> set, or always has a set(<variable> foo)
3432#   line in his CMakeLists.txt and avoids mixing sources.
3433#
3434#   The selected <variable> can be accessed through the variable '<variable>' in
3435#   following Zephyr CMake code.
3436#
3437#   If the user tries to change <variable> to a new value, then a warning will
3438#   be printed, and the previously cached value (CACHED_<variable>) will be
3439#   used, as it has precedence.
3440#
3441#   Together with the warning, user is informed that in order to change
3442#   <variable> the build directory must be cleaned.
3443#
3444function(zephyr_check_cache variable)
3445  cmake_parse_arguments(CACHE_VAR "REQUIRED;WATCH" "" "" ${ARGN})
3446  string(TOLOWER ${variable} variable_text)
3447  string(REPLACE "_" " " variable_text ${variable_text})
3448
3449  get_property(cached_value CACHE ${variable} PROPERTY VALUE)
3450
3451  # If the build has already been configured in an earlier CMake invocation,
3452  # then CACHED_${variable} is set. The CACHED_${variable} setting takes
3453  # precedence over any user or CMakeLists.txt input.
3454  # If we detect that user tries to change the setting, then print a warning
3455  # that a pristine build is needed.
3456
3457  # If user uses -D<variable>=<new_value>, then cli_argument will hold the new
3458  # value, otherwise cli_argument will hold the existing (old) value.
3459  set(cli_argument ${cached_value})
3460  if(cli_argument STREQUAL CACHED_${variable})
3461    # The is no changes to the <variable> value.
3462    unset(cli_argument)
3463  endif()
3464
3465  set(app_cmake_lists ${${variable}})
3466  if(cached_value STREQUAL ${variable})
3467    # The app build scripts did not set a default, The variable we are
3468    # reading is the cached value from the CLI
3469    unset(app_cmake_lists)
3470  endif()
3471
3472  if(DEFINED CACHED_${variable})
3473    # Warn the user if it looks like he is trying to change the variable
3474    # without cleaning first
3475    if(cli_argument)
3476      if(NOT ((CACHED_${variable} STREQUAL cli_argument) OR (${variable}_DEPRECATED STREQUAL cli_argument)))
3477        message(WARNING "The build directory must be cleaned pristinely when "
3478                        "changing ${variable_text},\n"
3479                        "Current value=\"${CACHED_${variable}}\", "
3480                        "Ignored value=\"${cli_argument}\"")
3481      endif()
3482    endif()
3483
3484    if(CACHED_${variable})
3485      set(${variable} ${CACHED_${variable}} PARENT_SCOPE)
3486      set(${variable} ${CACHED_${variable}})
3487      # This resets the user provided value with previous (working) value.
3488      set(${variable} ${CACHED_${variable}} CACHE STRING "Selected ${variable_text}" FORCE)
3489    else()
3490      unset(${variable} PARENT_SCOPE)
3491      unset(${variable} CACHE)
3492    endif()
3493  else()
3494    zephyr_get(${variable})
3495  endif()
3496
3497  if(${CACHE_VAR_REQUIRED} AND NOT DEFINED ${variable})
3498    message(FATAL_ERROR "${variable} is not being defined on the CMake command-line,"
3499                        " in the environment or by the app."
3500    )
3501  endif()
3502
3503  if(DEFINED ${variable})
3504    # Store the specified variable in parent scope and the cache
3505    set(${variable} ${${variable}} PARENT_SCOPE)
3506    set(${variable} ${${variable}} CACHE STRING "Selected ${variable_text}")
3507  endif()
3508  set(CACHED_${variable} ${${variable}} CACHE STRING "Selected ${variable_text}")
3509
3510  if(CACHE_VAR_WATCH)
3511    # The variable is now set to its final value.
3512    zephyr_boilerplate_watch(${variable})
3513  endif()
3514endfunction(zephyr_check_cache variable)
3515
3516
3517# Usage:
3518#   zephyr_boilerplate_watch(SOME_BOILERPLATE_VAR)
3519#
3520# Inform the build system that SOME_BOILERPLATE_VAR, a variable
3521# handled in the Zephyr package's boilerplate code, is now fixed and
3522# should no longer be changed.
3523#
3524# This function uses variable_watch() to print a noisy warning
3525# if the variable is set after it returns.
3526function(zephyr_boilerplate_watch variable)
3527  variable_watch(${variable} zephyr_variable_set_too_late)
3528endfunction()
3529
3530function(zephyr_variable_set_too_late variable access value current_list_file)
3531  if (access STREQUAL "MODIFIED_ACCESS")
3532    message(WARNING
3533"
3534   **********************************************************************
3535   *
3536   *                    WARNING
3537   *
3538   * CMake variable ${variable} set to \"${value}\" in:
3539   *     ${current_list_file}
3540   *
3541   * This is too late to make changes! The change was ignored.
3542   *
3543   * Hint: ${variable} must be set before calling find_package(Zephyr ...).
3544   *
3545   **********************************************************************
3546")
3547  endif()
3548endfunction()
3549
3550# Usage:
3551#   zephyr_get_targets(<directory> <types> <targets>)
3552#
3553# Get build targets for a given directory and sub-directories.
3554#
3555# This functions will traverse the build tree, starting from <directory>.
3556# It will read the `BUILDSYSTEM_TARGETS` for each directory in the build tree
3557# and return the build types matching the <types> list.
3558# Example of types: OBJECT_LIBRARY, STATIC_LIBRARY, INTERFACE_LIBRARY, UTILITY.
3559#
3560# returns a list of targets in <targets> matching the required <types>.
3561function(zephyr_get_targets directory types targets)
3562    get_property(sub_directories DIRECTORY ${directory} PROPERTY SUBDIRECTORIES)
3563    get_property(dir_targets DIRECTORY ${directory} PROPERTY BUILDSYSTEM_TARGETS)
3564    foreach(dir_target ${dir_targets})
3565      get_property(target_type TARGET ${dir_target} PROPERTY TYPE)
3566      if(${target_type} IN_LIST types)
3567        list(APPEND ${targets} ${dir_target})
3568      endif()
3569    endforeach()
3570
3571    foreach(directory ${sub_directories})
3572        zephyr_get_targets(${directory} "${types}" ${targets})
3573    endforeach()
3574    set(${targets} ${${targets}} PARENT_SCOPE)
3575endfunction()
3576
3577# Usage:
3578#   test_sysbuild([REQUIRED])
3579#
3580# Test that current sample is invoked through sysbuild.
3581#
3582# This function tests that current CMake configure was invoked through sysbuild.
3583# If CMake configure was not invoked through sysbuild, then a warning is printed
3584# to the user. The warning can be upgraded to an error by setting `REQUIRED` as
3585# argument the `test_sysbuild()`.
3586#
3587# This function allows samples that are multi-image samples by nature to ensure
3588# all samples are correctly built together.
3589function(test_sysbuild)
3590  cmake_parse_arguments(TEST_SYSBUILD "REQUIRED" "" "" ${ARGN})
3591
3592  if(TEST_SYSBUILD_REQUIRED)
3593    set(message_mode FATAL_ERROR)
3594  else()
3595    set(message_mode WARNING)
3596  endif()
3597
3598  if(NOT SYSBUILD)
3599    message(${message_mode}
3600            "Project '${PROJECT_NAME}' is designed for sysbuild.\n"
3601            "For correct user-experiences, please build '${PROJECT_NAME}' "
3602            "using sysbuild."
3603    )
3604  endif()
3605endfunction()
3606
3607# Usage:
3608#   target_byproducts(TARGET <target> BYPRODUCTS <file> [<file>...])
3609#
3610# Specify additional BYPRODUCTS that this target produces.
3611#
3612# This function allows the build system to specify additional byproducts to
3613# target created with `add_executable()`. When linking an executable the linker
3614# may produce additional files, like map files. Those files are not known to the
3615# build system. This function makes it possible to describe such additional
3616# byproducts in an easy manner.
3617function(target_byproducts)
3618  cmake_parse_arguments(TB "" "TARGET" "BYPRODUCTS" ${ARGN})
3619
3620  if(NOT DEFINED TB_TARGET)
3621    message(FATAL_ERROR "target_byproducts() missing parameter: TARGET <target>")
3622  endif()
3623
3624  add_custom_command(TARGET ${TB_TARGET}
3625                     POST_BUILD COMMAND ${CMAKE_COMMAND} -E true
3626                     BYPRODUCTS ${TB_BYPRODUCTS}
3627                     COMMENT "Logical command for additional byproducts on target: ${TB_TARGET}"
3628  )
3629endfunction()
3630
3631# Usage:
3632#   topological_sort(TARGETS <target> [<target> ...]
3633#                    PROPERTY_NAME <property>
3634#                    RESULT <out-variable>)
3635#
3636# This function performs topological sorting of CMake targets using a specific
3637# <property>, which dictates target dependencies. A fatal error occurs if the
3638# provided dependencies cannot be met, e.g., if they contain cycles.
3639#
3640# TARGETS:       List of target names.
3641# PROPERTY_NAME: Name of the target property to be used when sorting. For every
3642#                target listed in TARGETS, this property must contain a list
3643#                (possibly empty) of other targets, which this target depends on
3644#                for a particular purpose. The property must not contain any
3645#                target which is not also found in TARGETS.
3646# RESULT:        Output variable, where the topologically sorted list of target
3647#                names will be returned.
3648#
3649function(topological_sort)
3650  cmake_parse_arguments(TS "" "RESULT;PROPERTY_NAME" "TARGETS" ${ARGN})
3651
3652  set(dep_targets)
3653  set(start_targets)
3654  set(sorted_targets)
3655
3656  foreach(target ${TS_TARGETS})
3657    get_target_property(${target}_dependencies ${target} ${TS_PROPERTY_NAME})
3658
3659    if(${target}_dependencies)
3660      list(APPEND dep_targets ${target})
3661    else()
3662      list(APPEND start_targets ${target})
3663    endif()
3664  endforeach()
3665
3666  while(TRUE)
3667    list(POP_FRONT start_targets node)
3668    list(APPEND sorted_targets ${node})
3669    set(to_remove)
3670    foreach(target ${dep_targets})
3671      if("${node}" IN_LIST ${target}_dependencies)
3672        list(REMOVE_ITEM ${target}_dependencies ${node})
3673        if(NOT ${target}_dependencies)
3674          list(APPEND start_targets ${target})
3675          list(APPEND to_remove ${target})
3676        endif()
3677      endif()
3678    endforeach()
3679
3680    foreach(target ${to_remove})
3681      list(REMOVE_ITEM dep_targets ${target})
3682    endforeach()
3683    if(NOT start_targets)
3684      break()
3685    endif()
3686  endwhile()
3687
3688  if(dep_targets)
3689    foreach(target ${dep_targets})
3690      get_target_property(deps ${target} ${TS_PROPERTY_NAME})
3691      list(JOIN deps " " deps)
3692      list(APPEND dep_string "${target} depends on: ${deps}")
3693    endforeach()
3694    list(JOIN dep_string "\n" dep_string)
3695    message(FATAL_ERROR "Unmet or cyclic dependencies:\n${dep_string}")
3696  endif()
3697
3698  set(${TS_RESULT} "${sorted_targets}" PARENT_SCOPE)
3699endfunction()
3700
3701# Usage:
3702#   build_info(<tag>... VALUE <value>...)
3703#   build_info(<tag>... PATH  <path>...)
3704#
3705# This function populates the build_info.yml info file with exchangable build
3706# information related to the current build.
3707#
3708# Example:
3709#   build_info(devicetree files VALUE file1.dts file2.dts file3.dts)
3710# Will update the 'devicetree files' key in the build info yaml with the list
3711# of files, file1.dts file2.dts file3.dts.
3712#
3713#   build_info(vendor-specific foo VALUE bar)
3714# Will place the vendor specific key 'foo' with value 'bar' in the vendor specific section
3715# of the build info file.
3716#
3717# <tag>...: One of the pre-defined valid CMake keys supported by build info or vendor-specific.
3718#           See 'scripts/schemas/build-schema.yml' CMake section for valid tags.
3719# VALUE <value>... : value(s) to place in the build_info.yml file.
3720# PATH  <path>... : path(s) to place in the build_info.yml file. All paths are converted to CMake
3721#                   style. If no conversion is required, for example when paths are already
3722#                   guaranteed to be CMake style, then VALUE can also be used.
3723function(build_info)
3724  set(convert_path FALSE)
3725  set(arg_list ${ARGV})
3726  list(FIND arg_list VALUE index)
3727  if(index EQUAL -1)
3728    list(FIND arg_list PATH index)
3729    set(convert_path TRUE)
3730  endif()
3731
3732  if(index EQUAL -1)
3733    message(FATAL_ERROR "${CMAKE_CURRENT_FUNCTION}(...) missing a required argument: VALUE or PATH")
3734  endif()
3735
3736  string(GENEX_STRIP "${arg_list}" arg_list_no_genexes)
3737  if (NOT "${arg_list}" STREQUAL "${arg_list_no_genexes}")
3738    if (convert_path)
3739      message(FATAL_ERROR "build_info: generator expressions unsupported on PATH entries")
3740    endif()
3741    set(genex_flag GENEX)
3742  endif()
3743
3744  yaml_context(EXISTS NAME build_info result)
3745  if(NOT result)
3746    yaml_load(FILE ${ZEPHYR_BASE}/scripts/schemas/build-schema.yml NAME build_info_schema)
3747    if(EXISTS ${CMAKE_BINARY_DIR}/build_info.yml)
3748      yaml_load(FILE ${CMAKE_BINARY_DIR}/build_info.yml NAME build_info)
3749    else()
3750      yaml_create(FILE ${CMAKE_BINARY_DIR}/build_info.yml NAME build_info)
3751    endif()
3752    yaml_set(NAME build_info KEY version VALUE "0.1.0")
3753  endif()
3754
3755  list(SUBLIST arg_list 0 ${index} keys)
3756  list(SUBLIST arg_list ${index} -1 values)
3757  list(POP_FRONT values)
3758
3759  if(convert_path)
3760    set(converted_values)
3761    foreach(val ${values})
3762      cmake_path(SET cmake_path "${val}")
3763      list(APPEND converted_values "${cmake_path}")
3764    endforeach()
3765    set(values "${converted_values}")
3766  endif()
3767
3768  if(ARGV0 STREQUAL "vendor-specific")
3769    set(type VALUE)
3770  else()
3771    set(schema_check ${keys})
3772    list(TRANSFORM schema_check PREPEND "mapping;")
3773    yaml_get(check NAME build_info_schema KEY mapping cmake ${schema_check})
3774    if(check MATCHES ".*-NOTFOUND")
3775      message(FATAL_ERROR "${CMAKE_CURRENT_FUNCTION}(...) called with invalid tag: ${keys}")
3776    endif()
3777
3778    yaml_get(type NAME build_info_schema KEY mapping cmake ${schema_check} type)
3779    if(type MATCHES "seq|sequence")
3780      set(type LIST)
3781    else()
3782      set(type VALUE)
3783    endif()
3784  endif()
3785
3786  yaml_set(NAME build_info KEY cmake ${keys} ${type} "${values}" ${genex_flag})
3787endfunction()
3788
3789########################################################
3790# 4. Devicetree extensions
3791########################################################
3792# 4.1. dt_*
3793#
3794# The following methods are for retrieving devicetree information in CMake.
3795#
3796# Notes:
3797#
3798# - In CMake, we refer to the nodes using the node's path, therefore
3799#   there is no dt_path(...) function for obtaining a node identifier
3800#   like there is in the C devicetree.h API.
3801#
3802# - As another difference from the C API, you can generally use an
3803#   alias at the beginning of a path interchangeably with the full
3804#   path to the aliased node in these functions. The usage comments
3805#   will make this clear in each case.
3806
3807# Usage:
3808#   dt_nodelabel(<var> NODELABEL <label>)
3809#
3810# Function for retrieving the node path for the node having nodelabel
3811# <label>.
3812#
3813# Example devicetree fragment:
3814#
3815#   / {
3816#           soc {
3817#                   nvic: interrupt-controller@e000e100  { ... };
3818#           };
3819#   };
3820#
3821# Example usage:
3822#
3823#   # Sets 'nvic_path' to "/soc/interrupt-controller@e000e100"
3824#   dt_nodelabel(nvic_path NODELABEL "nvic")
3825#
3826# The node's path will be returned in the <var> parameter.
3827# <var> will be undefined if node does not exist.
3828#
3829# <var>              : Return variable where the node path will be stored
3830# NODELABEL <label>  : Node label
3831# REQUIRED           : Generate a fatal error if the node-label is not found
3832function(dt_nodelabel var)
3833  set(options "REQUIRED")
3834  set(req_single_args "NODELABEL")
3835  cmake_parse_arguments(DT_LABEL "${options}" "${req_single_args}" "" ${ARGN})
3836
3837  if(${ARGV0} IN_LIST req_single_args)
3838    message(FATAL_ERROR "dt_nodelabel(${ARGV0} ...) missing return parameter.")
3839  endif()
3840
3841  foreach(arg ${req_single_args})
3842    if(NOT DEFINED DT_LABEL_${arg})
3843      message(FATAL_ERROR "dt_nodelabel(${ARGV0} ...) "
3844                          "missing required argument: ${arg}"
3845      )
3846    endif()
3847  endforeach()
3848
3849  get_target_property(${var} devicetree_target "DT_NODELABEL|${DT_LABEL_NODELABEL}")
3850  if(${${var}} STREQUAL ${var}-NOTFOUND)
3851    if(DT_LABEL_REQUIRED)
3852      message(FATAL_ERROR "required nodelabel not found: ${DT_LABEL_NODELABEL}")
3853    endif()
3854    set(${var})
3855  endif()
3856
3857  set(${var} ${${var}} PARENT_SCOPE)
3858endfunction()
3859
3860# Usage:
3861#   dt_alias(<var> PROPERTY <prop>)
3862#
3863# Get a node path for an /aliases node property.
3864#
3865# Example usage:
3866#
3867#   # The full path to the 'led0' alias is returned in 'path'.
3868#   dt_alias(path PROPERTY "led0")
3869#
3870#   # The variable 'path' will be left undefined for a nonexistent
3871#   # alias "does-not-exist".
3872#   dt_alias(path PROPERTY "does-not-exist")
3873#
3874# The node's path will be returned in the <var> parameter. The
3875# variable will be left undefined if the alias does not exist.
3876#
3877# <var>           : Return variable where the node path will be stored
3878# PROPERTY <prop> : The alias to check
3879# REQUIRED        : Generate a fatal error if the alias is not found
3880function(dt_alias var)
3881  set(options "REQUIRED")
3882  set(req_single_args "PROPERTY")
3883  cmake_parse_arguments(DT_ALIAS "${options}" "${req_single_args}" "" ${ARGN})
3884
3885  if(${ARGV0} IN_LIST req_single_args)
3886    message(FATAL_ERROR "dt_alias(${ARGV0} ...) missing return parameter.")
3887  endif()
3888
3889  foreach(arg ${req_single_args})
3890    if(NOT DEFINED DT_ALIAS_${arg})
3891      message(FATAL_ERROR "dt_alias(${ARGV0} ...) "
3892                          "missing required argument: ${arg}"
3893      )
3894    endif()
3895  endforeach()
3896
3897  get_target_property(${var} devicetree_target "DT_ALIAS|${DT_ALIAS_PROPERTY}")
3898  if(${${var}} STREQUAL ${var}-NOTFOUND)
3899    if(DT_ALIAS_REQUIRED)
3900      message(FATAL_ERROR "required alias not found: ${DT_ALIAS_PROPERTY}")
3901    endif()
3902    set(${var})
3903  endif()
3904
3905  set(${var} ${${var}} PARENT_SCOPE)
3906endfunction()
3907
3908# Usage:
3909#   dt_node_exists(<var> PATH <path>)
3910#
3911# Tests whether a node with path <path> exists in the devicetree.
3912#
3913# The <path> value may be any of these:
3914#
3915# - absolute path to a node, like '/foo/bar'
3916# - a node alias, like 'my-alias'
3917# - a node alias followed by a path to a child node, like 'my-alias/child-node'
3918#
3919# The result of the check, either TRUE or FALSE, will be returned in
3920# the <var> parameter.
3921#
3922# <var>       : Return variable where the check result will be returned
3923# PATH <path> : Node path
3924function(dt_node_exists var)
3925  set(req_single_args "PATH")
3926  cmake_parse_arguments(DT_NODE "" "${req_single_args}" "" ${ARGN})
3927
3928  if(${ARGV0} IN_LIST req_single_args)
3929    message(FATAL_ERROR "dt_node_exists(${ARGV0} ...) missing return parameter.")
3930  endif()
3931
3932  foreach(arg ${req_single_args})
3933    if(NOT DEFINED DT_NODE_${arg})
3934      message(FATAL_ERROR "dt_node_exists(${ARGV0} ...) "
3935                          "missing required argument: ${arg}"
3936      )
3937    endif()
3938  endforeach()
3939
3940  dt_path_internal(canonical "${DT_NODE_PATH}")
3941  if (DEFINED canonical)
3942    set(${var} TRUE PARENT_SCOPE)
3943  else()
3944    set(${var} FALSE PARENT_SCOPE)
3945  endif()
3946endfunction()
3947
3948# Usage:
3949#   dt_node_has_status(<var> PATH <path> STATUS <status>)
3950#
3951# Tests whether <path> refers to a node which:
3952# - exists in the devicetree, and
3953# - has a status property matching the <status> argument
3954#   (a missing status or an “ok” status is treated as if it
3955#    were “okay” instead)
3956#
3957# The <path> value may be any of these:
3958#
3959# - absolute path to a node, like '/foo/bar'
3960# - a node alias, like 'my-alias'
3961# - a node alias followed by a path to a child node, like 'my-alias/child-node'
3962#
3963# The result of the check, either TRUE or FALSE, will be returned in
3964# the <var> parameter.
3965#
3966# <var>           : Return variable where the check result will be returned
3967# PATH <path>     : Node path
3968# STATUS <status> : Status to check
3969function(dt_node_has_status var)
3970  set(req_single_args "PATH;STATUS")
3971  cmake_parse_arguments(DT_NODE "" "${req_single_args}" "" ${ARGN})
3972
3973  if(${ARGV0} IN_LIST req_single_args)
3974    message(FATAL_ERROR "dt_node_has_status(${ARGV0} ...) missing return parameter.")
3975  endif()
3976
3977  foreach(arg ${req_single_args})
3978    if(NOT DEFINED DT_NODE_${arg})
3979      message(FATAL_ERROR "dt_node_has_status(${ARGV0} ...) "
3980                          "missing required argument: ${arg}"
3981      )
3982    endif()
3983  endforeach()
3984
3985  dt_path_internal(canonical ${DT_NODE_PATH})
3986  if(NOT DEFINED canonical)
3987    set(${var} FALSE PARENT_SCOPE)
3988    return()
3989  endif()
3990
3991  dt_prop(status PATH ${canonical} PROPERTY status)
3992
3993  if(NOT DEFINED status OR status STREQUAL "ok")
3994    set(status "okay")
3995  endif()
3996
3997  if(status STREQUAL "${DT_NODE_STATUS}")
3998    set(${var} TRUE PARENT_SCOPE)
3999  else()
4000    set(${var} FALSE PARENT_SCOPE)
4001  endif()
4002endfunction()
4003
4004# Usage:
4005#
4006#   dt_prop(<var> PATH <path> PROPERTY <prop> [INDEX <idx>])
4007#
4008# Get a devicetree property value. The value will be returned in the
4009# <var> parameter.
4010#
4011# The <path> value may be any of these:
4012#
4013# - absolute path to a node, like '/foo/bar'
4014# - a node alias, like 'my-alias'
4015# - a node alias followed by a path to a child node, like 'my-alias/child-node'
4016#
4017# This function currently only supports properties with the following
4018# devicetree binding types: string, int, boolean, array, uint8-array,
4019# string-array, path.
4020#
4021# For array valued properties (including uint8-array and
4022# string-array), the entire array is returned as a CMake list unless
4023# INDEX is given. If INDEX is given, just the array element at index
4024# <idx> is returned.
4025#
4026# The property value will be returned in the <var> parameter if the
4027# node exists and has a property <prop> with one of the above types.
4028# <var> will be undefined otherwise.
4029#
4030# To test if the property is defined before using it, use DEFINED on
4031# the return <var>, like this:
4032#
4033#   dt_prop(reserved_ranges PATH "/soc/gpio@deadbeef" PROPERTY "gpio-reserved-ranges")
4034#   if(DEFINED reserved_ranges)
4035#     # Node exists and has the "gpio-reserved-ranges" property.
4036#   endif()
4037#
4038# To distinguish a missing node from a missing property, combine
4039# dt_prop() and dt_node_exists(), like this:
4040#
4041#   dt_node_exists(node_exists PATH "/soc/gpio@deadbeef")
4042#   dt_prop(reserved_ranges    PATH "/soc/gpio@deadbeef" PROPERTY "gpio-reserved-ranges")
4043#   if(DEFINED reserved_ranges)
4044#     # Node "/soc/gpio@deadbeef" exists and has the "gpio-reserved-ranges" property
4045#   elseif(node_exists)
4046#     # Node exists, but doesn't have the property, or the property has an unsupported type.
4047#   endif()
4048#
4049# <var>          : Return variable where the property value will be stored
4050# PATH <path>    : Node path
4051# PROPERTY <prop>: Property for which a value should be returned, as it
4052#                  appears in the DTS source
4053# INDEX <idx>    : Optional index when retrieving a value in an array property
4054# REQUIRED       : Generate a fatal error if the property is not found
4055function(dt_prop var)
4056  set(options "REQUIRED")
4057  set(req_single_args "PATH;PROPERTY")
4058  set(single_args "INDEX")
4059  cmake_parse_arguments(DT_PROP "${options}" "${req_single_args};${single_args}" "" ${ARGN})
4060
4061  if(${ARGV0} IN_LIST req_single_args)
4062    message(FATAL_ERROR "dt_prop(${ARGV0} ...) missing return parameter.")
4063  endif()
4064
4065  foreach(arg ${req_single_args})
4066    if(NOT DEFINED DT_PROP_${arg})
4067      message(FATAL_ERROR "dt_prop(${ARGV0} ...) "
4068                          "missing required argument: ${arg}"
4069      )
4070    endif()
4071  endforeach()
4072
4073  dt_path_internal(canonical "${DT_PROP_PATH}")
4074  get_property(exists TARGET devicetree_target
4075      PROPERTY "DT_PROP|${canonical}|${DT_PROP_PROPERTY}"
4076      SET
4077  )
4078
4079  if(NOT exists)
4080    set(${var} PARENT_SCOPE)
4081    if(DT_PROP_REQUIRED)
4082      message(FATAL_ERROR "required property not found: ${canonical}/${DT_PROP_PROPERTY}")
4083    endif()
4084    return()
4085  endif()
4086
4087  get_target_property(val devicetree_target
4088      "DT_PROP|${canonical}|${DT_PROP_PROPERTY}"
4089  )
4090
4091  if(DEFINED DT_PROP_INDEX)
4092    list(GET val ${DT_PROP_INDEX} element)
4093    set(${var} "${element}" PARENT_SCOPE)
4094  else()
4095    set(${var} "${val}" PARENT_SCOPE)
4096  endif()
4097endfunction()
4098
4099# Usage:
4100#
4101#   dt_comp_path(<var> COMPATIBLE <compatible> [INDEX <idx>])
4102#
4103# Get a list of paths for the nodes with the given compatible. The value will
4104# be returned in the <var> parameter.
4105# <var> will be undefined if no such compatible exists.
4106#
4107# For details and considerations about the format of <path> and the returned
4108# parameter refer to dt_prop().
4109#
4110# <var>                  : Return variable where the property value will be stored
4111# COMPATIBLE <compatible>: Compatible for which the list of paths should be
4112#                          returned, as it appears in the DTS source
4113# INDEX <idx>            : Optional index when retrieving a value in an array property
4114
4115function(dt_comp_path var)
4116  set(req_single_args "COMPATIBLE")
4117  set(single_args "INDEX")
4118  cmake_parse_arguments(DT_COMP "" "${req_single_args};${single_args}" "" ${ARGN})
4119
4120  if(${ARGV0} IN_LIST req_single_args)
4121    message(FATAL_ERROR "dt_comp_path(${ARGV0} ...) missing return parameter.")
4122  endif()
4123
4124  foreach(arg ${req_single_args})
4125    if(NOT DEFINED DT_COMP_${arg})
4126      message(FATAL_ERROR "dt_comp_path(${ARGV0} ...) "
4127                          "missing required argument: ${arg}"
4128      )
4129    endif()
4130  endforeach()
4131
4132  get_property(exists TARGET devicetree_target
4133      PROPERTY "DT_COMP|${DT_COMP_COMPATIBLE}"
4134      SET
4135  )
4136
4137  if(NOT exists)
4138    set(${var} PARENT_SCOPE)
4139    return()
4140  endif()
4141
4142  get_target_property(val devicetree_target
4143      "DT_COMP|${DT_COMP_COMPATIBLE}"
4144  )
4145
4146  if(DEFINED DT_COMP_INDEX)
4147    list(GET val ${DT_COMP_INDEX} element)
4148    set(${var} "${element}" PARENT_SCOPE)
4149  else()
4150    set(${var} "${val}" PARENT_SCOPE)
4151  endif()
4152endfunction()
4153
4154# Usage:
4155#   dt_num_regs(<var> PATH <path>)
4156#
4157# Get the number of register blocks in the node's reg property;
4158# this may be zero.
4159#
4160# The value will be returned in the <var> parameter.
4161#
4162# The <path> value may be any of these:
4163#
4164# - absolute path to a node, like '/foo/bar'
4165# - a node alias, like 'my-alias'
4166# - a node alias followed by a path to a child node, like 'my-alias/child-node'
4167#
4168# <var>          : Return variable where the property value will be stored
4169# PATH <path>    : Node path
4170function(dt_num_regs var)
4171  set(req_single_args "PATH")
4172  cmake_parse_arguments(DT_REG "" "${req_single_args}" "" ${ARGN})
4173
4174  if(${ARGV0} IN_LIST req_single_args)
4175    message(FATAL_ERROR "dt_num_regs(${ARGV0} ...) missing return parameter.")
4176  endif()
4177
4178  foreach(arg ${req_single_args})
4179    if(NOT DEFINED DT_REG_${arg})
4180      message(FATAL_ERROR "dt_num_regs(${ARGV0} ...) "
4181                          "missing required argument: ${arg}"
4182      )
4183    endif()
4184  endforeach()
4185
4186  dt_path_internal(canonical "${DT_REG_PATH}")
4187  get_target_property(${var} devicetree_target "DT_REG|${canonical}|NUM")
4188
4189  set(${var} ${${var}} PARENT_SCOPE)
4190endfunction()
4191
4192# Usage:
4193#   dt_reg_addr(<var> PATH <path> [INDEX <idx>] [NAME <name>])
4194#
4195# Get the base address of the register block at index <idx>, or with
4196# name <name>. If <idx> and <name> are both omitted, the value at
4197# index 0 will be returned. Do not give both <idx> and <name>.
4198#
4199# The value will be returned in the <var> parameter.
4200#
4201# The <path> value may be any of these:
4202#
4203# - absolute path to a node, like '/foo/bar'
4204# - a node alias, like 'my-alias'
4205# - a node alias followed by a path to a child node, like 'my-alias/child-node'
4206#
4207# Results can be:
4208# - The base address of the register block
4209# - <var> will be undefined if node does not exists or does not have a register
4210#   block at the requested index or with the requested name
4211#
4212# <var>          : Return variable where the address value will be stored
4213# PATH <path>    : Node path
4214# INDEX <idx>    : Register block index number
4215# NAME <name>    : Register block name
4216function(dt_reg_addr var)
4217  set(req_single_args "PATH")
4218  set(single_args "INDEX;NAME")
4219  cmake_parse_arguments(DT_REG "" "${req_single_args};${single_args}" "" ${ARGN})
4220
4221  if(${ARGV0} IN_LIST req_single_args)
4222    message(FATAL_ERROR "dt_reg_addr(${ARGV0} ...) missing return parameter.")
4223  endif()
4224
4225  foreach(arg ${req_single_args})
4226    if(NOT DEFINED DT_REG_${arg})
4227      message(FATAL_ERROR "dt_reg_addr(${ARGV0} ...) "
4228                          "missing required argument: ${arg}"
4229      )
4230    endif()
4231  endforeach()
4232
4233  if(DEFINED DT_REG_INDEX AND DEFINED DT_REG_NAME)
4234    message(FATAL_ERROR "dt_reg_addr(${ARGV0} ...) given both INDEX and NAME")
4235  elseif(NOT DEFINED DT_REG_INDEX AND NOT DEFINED DT_REG_NAME)
4236    set(DT_REG_INDEX 0)
4237  elseif(DEFINED DT_REG_NAME)
4238    dt_reg_index_private(DT_REG_INDEX "${DT_REG_PATH}" "${DT_REG_NAME}")
4239    if(DT_REG_INDEX EQUAL "-1")
4240      set(${var} PARENT_SCOPE)
4241      return()
4242    endif()
4243  endif()
4244
4245  dt_path_internal(canonical "${DT_REG_PATH}")
4246  get_target_property(${var}_list devicetree_target "DT_REG|${canonical}|ADDR")
4247
4248  list(GET ${var}_list ${DT_REG_INDEX} ${var})
4249
4250  if("${var}" STREQUAL NONE)
4251    set(${var})
4252  endif()
4253
4254  set(${var} ${${var}} PARENT_SCOPE)
4255endfunction()
4256
4257# Usage:
4258#   dt_reg_size(<var> PATH <path> [INDEX <idx>] [NAME <name>])
4259#
4260# Get the size of the register block at index <idx>, or with
4261# name <name>. If <idx> and <name> are both omitted, the value at
4262# index 0 will be returned. Do not give both <idx> and <name>.
4263#
4264# The value will be returned in the <value> parameter.
4265#
4266# The <path> value may be any of these:
4267#
4268# - absolute path to a node, like '/foo/bar'
4269# - a node alias, like 'my-alias'
4270# - a node alias followed by a path to a child node, like 'my-alias/child-node'
4271#
4272# <var>          : Return variable where the size value will be stored
4273# PATH <path>    : Node path
4274# INDEX <idx>    : Register block index number
4275# NAME <name>    : Register block name
4276function(dt_reg_size var)
4277  set(req_single_args "PATH")
4278  set(single_args "INDEX;NAME")
4279  cmake_parse_arguments(DT_REG "" "${req_single_args};${single_args}" "" ${ARGN})
4280
4281  if(${ARGV0} IN_LIST req_single_args)
4282    message(FATAL_ERROR "dt_reg_size(${ARGV0} ...) missing return parameter.")
4283  endif()
4284
4285  foreach(arg ${req_single_args})
4286    if(NOT DEFINED DT_REG_${arg})
4287      message(FATAL_ERROR "dt_reg_size(${ARGV0} ...) "
4288                          "missing required argument: ${arg}"
4289      )
4290    endif()
4291  endforeach()
4292
4293  if(DEFINED DT_REG_INDEX AND DEFINED DT_REG_NAME)
4294    message(FATAL_ERROR "dt_reg_size(${ARGV0} ...) given both INDEX and NAME")
4295  elseif(NOT DEFINED DT_REG_INDEX AND NOT DEFINED DT_REG_NAME)
4296    set(DT_REG_INDEX 0)
4297  elseif(DEFINED DT_REG_NAME)
4298    dt_reg_index_private(DT_REG_INDEX "${DT_REG_PATH}" "${DT_REG_NAME}")
4299    if(DT_REG_INDEX EQUAL "-1")
4300      set(${var} PARENT_SCOPE)
4301      return()
4302    endif()
4303  endif()
4304
4305  dt_path_internal(canonical "${DT_REG_PATH}")
4306  get_target_property(${var}_list devicetree_target "DT_REG|${canonical}|SIZE")
4307
4308  list(GET ${var}_list ${DT_REG_INDEX} ${var})
4309
4310  if("${var}" STREQUAL NONE)
4311    set(${var})
4312  endif()
4313
4314  set(${var} ${${var}} PARENT_SCOPE)
4315endfunction()
4316
4317# Internal helper for dt_reg_addr/dt_reg_size; not meant to be used directly
4318function(dt_reg_index_private var path name)
4319  dt_prop(reg_names PATH "${path}" PROPERTY "reg-names")
4320  if(NOT DEFINED reg_names)
4321    set(index "-1")
4322  else()
4323    list(FIND reg_names "${name}" index)
4324  endif()
4325  set(${var} "${index}" PARENT_SCOPE)
4326endfunction()
4327
4328# Usage:
4329#   dt_has_chosen(<var> PROPERTY <prop>)
4330#
4331# Test if the devicetree's /chosen node has a given property
4332# <prop> which contains the path to a node.
4333#
4334# Example devicetree fragment:
4335#
4336#       chosen {
4337#               foo = &bar;
4338#       };
4339#
4340# Example usage:
4341#
4342#       # Sets 'result' to TRUE
4343#       dt_has_chosen(result PROPERTY "foo")
4344#
4345#       # Sets 'result' to FALSE
4346#       dt_has_chosen(result PROPERTY "baz")
4347#
4348# The result of the check, either TRUE or FALSE, will be stored in the
4349# <var> parameter.
4350#
4351# <var>           : Return variable
4352# PROPERTY <prop> : Chosen property
4353function(dt_has_chosen var)
4354  set(req_single_args "PROPERTY")
4355  cmake_parse_arguments(DT_CHOSEN "" "${req_single_args}" "" ${ARGN})
4356
4357  if(${ARGV0} IN_LIST req_single_args)
4358    message(FATAL_ERROR "dt_has_chosen(${ARGV0} ...) missing return parameter.")
4359  endif()
4360
4361  foreach(arg ${req_single_args})
4362    if(NOT DEFINED DT_CHOSEN_${arg})
4363      message(FATAL_ERROR "dt_has_chosen(${ARGV0} ...) "
4364                          "missing required argument: ${arg}"
4365      )
4366    endif()
4367  endforeach()
4368
4369  get_target_property(exists devicetree_target "DT_CHOSEN|${DT_CHOSEN_PROPERTY}")
4370
4371  if(${exists} STREQUAL exists-NOTFOUND)
4372    set(${var} FALSE PARENT_SCOPE)
4373  else()
4374    set(${var} TRUE PARENT_SCOPE)
4375  endif()
4376endfunction()
4377
4378# Usage:
4379#   dt_chosen(<var> PROPERTY <prop>)
4380#
4381# Get a node path for a /chosen node property.
4382#
4383# The node's path will be returned in the <var> parameter. The
4384# variable will be left undefined if the chosen node does not exist.
4385#
4386# <var>           : Return variable where the node path will be stored
4387# PROPERTY <prop> : Chosen property
4388function(dt_chosen var)
4389  set(req_single_args "PROPERTY")
4390  cmake_parse_arguments(DT_CHOSEN "" "${req_single_args}" "" ${ARGN})
4391
4392  if(${ARGV0} IN_LIST req_single_args)
4393    message(FATAL_ERROR "dt_chosen(${ARGV0} ...) missing return parameter.")
4394  endif()
4395
4396  foreach(arg ${req_single_args})
4397    if(NOT DEFINED DT_CHOSEN_${arg})
4398      message(FATAL_ERROR "dt_chosen(${ARGV0} ...) "
4399                          "missing required argument: ${arg}"
4400      )
4401    endif()
4402  endforeach()
4403
4404  get_target_property(${var} devicetree_target "DT_CHOSEN|${DT_CHOSEN_PROPERTY}")
4405
4406  if(${${var}} STREQUAL ${var}-NOTFOUND)
4407    set(${var} PARENT_SCOPE)
4408  else()
4409    set(${var} ${${var}} PARENT_SCOPE)
4410  endif()
4411endfunction()
4412
4413# Internal helper. Canonicalizes a path 'path' into the output
4414# variable 'var'. This resolves aliases, if any. Child nodes may be
4415# accessed via alias as well. 'var' is left undefined if the path does
4416# not refer to an existing node.
4417#
4418# Example devicetree:
4419#
4420#   / {
4421#           foo {
4422#                   my-label: bar {
4423#                           baz {};
4424#                   };
4425#           };
4426#           aliases {
4427#                   my-alias = &my-label;
4428#           };
4429#   };
4430#
4431# Example usage:
4432#
4433#   dt_path_internal(ret "/foo/bar")     # sets ret to "/foo/bar"
4434#   dt_path_internal(ret "my-alias")     # sets ret to "/foo/bar"
4435#   dt_path_internal(ret "my-alias/baz") # sets ret to "/foo/bar/baz"
4436#   dt_path_internal(ret "/blub")        # ret is undefined
4437function(dt_path_internal var path)
4438  string(FIND "${path}" "/" slash_index)
4439
4440  if("${slash_index}" EQUAL 0)
4441    # If the string starts with a slash, it should be an existing
4442    # canonical path.
4443    dt_path_internal_exists(check "${path}")
4444    if (check)
4445      set(${var} "${path}" PARENT_SCOPE)
4446      return()
4447    endif()
4448  else()
4449    # Otherwise, try to expand a leading alias.
4450    string(SUBSTRING "${path}" 0 "${slash_index}" alias_name)
4451    dt_alias(alias_path PROPERTY "${alias_name}")
4452
4453    # If there is a leading alias, append the rest of the string
4454    # onto it and see if that's an existing node.
4455    if (DEFINED alias_path)
4456      set(rest)
4457      if (NOT "${slash_index}" EQUAL -1)
4458        string(SUBSTRING "${path}" "${slash_index}" -1 rest)
4459      endif()
4460      dt_path_internal_exists(expanded_path_exists "${alias_path}${rest}")
4461      if (expanded_path_exists)
4462        set(${var} "${alias_path}${rest}" PARENT_SCOPE)
4463        return()
4464      endif()
4465    endif()
4466  endif()
4467
4468  # Failed search; ensure return variable is undefined.
4469  set(${var} PARENT_SCOPE)
4470endfunction()
4471
4472# Internal helper. Set 'var' to TRUE if a canonical path 'path' refers
4473# to an existing node. Set it to FALSE otherwise. See
4474# dt_path_internal for a definition and examples of 'canonical' paths.
4475function(dt_path_internal_exists var path)
4476  get_target_property(path_prop devicetree_target "DT_NODE|${path}")
4477  if (path_prop)
4478    set(${var} TRUE PARENT_SCOPE)
4479  else()
4480    set(${var} FALSE PARENT_SCOPE)
4481  endif()
4482endfunction()
4483
4484# 4.2. *_if_dt_node
4485#
4486# This section is similar to the extensions named *_ifdef, except
4487# actions are performed if the devicetree contains some node.
4488# *_if_dt_node functions may be added as needed, or if they are likely
4489# to be useful for user applications.
4490
4491# Add item(s) to a target's SOURCES list if a devicetree node exists.
4492#
4493# Example usage:
4494#
4495#   # If the devicetree alias "led0" refers to a node, this
4496#   # adds "blink_led.c" to the sources list for the "app" target.
4497#   target_sources_if_dt_node("led0" app PRIVATE blink_led.c)
4498#
4499#   # If the devicetree path "/soc/serial@4000" is a node, this
4500#   # adds "uart.c" to the sources list for the "lib" target,
4501#   target_sources_if_dt_node("/soc/serial@4000" lib PRIVATE uart.c)
4502#
4503# <path>    : Path to devicetree node to check
4504# <target>  : Build system target whose sources to add to
4505# <scope>   : Scope to add items to
4506# <item>    : Item (or items) to add to the target
4507function(target_sources_if_dt_node path target scope item)
4508  dt_node_exists(check PATH "${path}")
4509  if(${check})
4510    target_sources(${target} ${scope} ${item} ${ARGN})
4511  endif()
4512endfunction()
4513
4514########################################################
4515# 4.3 zephyr_dt_*
4516#
4517# The following methods are common code for dealing
4518# with devicetree related files in CMake.
4519#
4520# Note that functions related to accessing the
4521# *contents* of the devicetree belong in section 4.1.
4522# This section is just for DT file processing at
4523# configuration time.
4524########################################################
4525
4526# Usage:
4527#   zephyr_dt_preprocess(CPP <path> [<argument...>]
4528#                        SOURCE_FILES <file...>
4529#                        OUT_FILE <file>
4530#                        [DEPS_FILE <file>]
4531#                        [EXTRA_CPPFLAGS <flag...>]
4532#                        [INCLUDE_DIRECTORIES <dir...>]
4533#                        [WORKING_DIRECTORY <dir>]
4534#
4535# Preprocess one or more devicetree source files. The preprocessor
4536# symbol __DTS__ will be defined. If the preprocessor command fails, a
4537# fatal error occurs.
4538#
4539# Mandatory arguments:
4540#
4541# CPP <path> [<argument...>]: path to C preprocessor, followed by any
4542#                             additional arguments
4543#
4544# SOURCE_FILES <file...>: The source files to run the preprocessor on.
4545#                         These will, in effect, be concatenated in order
4546#                         and used as the preprocessor input.
4547#
4548# OUT_FILE <file>: Where to store the preprocessor output.
4549#
4550# Optional arguments:
4551#
4552# DEPS_FILE <file>: If set, generate a dependency file here.
4553#
4554# EXTRA_CPPFLAGS <flag...>: Additional flags to pass the preprocessor.
4555#
4556# INCLUDE_DIRECTORIES <dir...>: Additional #include file directories.
4557#
4558# WORKING_DIRECTORY <dir>: where to run the preprocessor.
4559function(zephyr_dt_preprocess)
4560  set(req_single_args "OUT_FILE")
4561  set(single_args "DEPS_FILE;WORKING_DIRECTORY")
4562  set(req_multi_args "CPP;SOURCE_FILES")
4563  set(multi_args "EXTRA_CPPFLAGS;INCLUDE_DIRECTORIES")
4564  cmake_parse_arguments(DT_PREPROCESS "" "${req_single_args};${single_args}" "${req_multi_args};${multi_args}" ${ARGN})
4565
4566  foreach(arg ${req_single_args} ${req_multi_args})
4567    if(NOT DEFINED DT_PREPROCESS_${arg})
4568      message(FATAL_ERROR "dt_preprocess() missing required argument: ${arg}")
4569    endif()
4570  endforeach()
4571
4572  set(include_opts)
4573  foreach(dir ${DT_PREPROCESS_INCLUDE_DIRECTORIES})
4574    list(APPEND include_opts -isystem ${dir})
4575  endforeach()
4576
4577  set(source_opts)
4578  foreach(file ${DT_PREPROCESS_SOURCE_FILES})
4579    list(APPEND source_opts -include ${file})
4580  endforeach()
4581
4582  set(deps_opts)
4583  if(DEFINED DT_PREPROCESS_DEPS_FILE)
4584    list(APPEND deps_opts -MD -MF ${DT_PREPROCESS_DEPS_FILE})
4585  endif()
4586
4587  set(workdir_opts)
4588  if(DEFINED DT_PREPROCESS_WORKING_DIRECTORY)
4589    list(APPEND workdir_opts WORKING_DIRECTORY ${DT_PREPROCESS_WORKING_DIRECTORY})
4590  endif()
4591
4592  # We are leaving linemarker directives enabled on purpose. This tells
4593  # dtlib where each line actually came from, which improves error
4594  # reporting.
4595  set(preprocess_cmd ${DT_PREPROCESS_CPP}
4596    -x assembler-with-cpp
4597    -nostdinc
4598    ${include_opts}
4599    ${source_opts}
4600    ${NOSYSDEF_CFLAG}
4601    -D__DTS__
4602    ${DT_PREPROCESS_EXTRA_CPPFLAGS}
4603    -E   # Stop after preprocessing
4604    ${deps_opts}
4605    -o ${DT_PREPROCESS_OUT_FILE}
4606    ${ZEPHYR_BASE}/misc/empty_file.c
4607    ${workdir_opts})
4608
4609  execute_process(COMMAND ${preprocess_cmd} RESULT_VARIABLE ret)
4610  if(NOT "${ret}" STREQUAL "0")
4611    message(FATAL_ERROR "failed to preprocess devicetree files (error code ${ret}): ${DT_PREPROCESS_SOURCE_FILES}")
4612  endif()
4613endfunction()
4614
4615########################################################
4616# 5. Zephyr linker functions
4617########################################################
4618# 5.1. zephyr_linker*
4619#
4620# The following methods are for defining linker structure using CMake functions.
4621#
4622# This allows Zephyr developers to define linker sections and their content and
4623# have this configuration rendered into an appropriate linker script based on
4624# the toolchain in use.
4625# For example:
4626# ld linker scripts with GNU ld
4627# ARM scatter files with ARM linker.
4628#
4629# Example usage:
4630# zephyr_linker_section(
4631#   NAME my_data
4632#   VMA  RAM
4633#   LMA  FLASH
4634# )
4635#
4636# and to configure special input sections for the section
4637# zephyr_linker_section_configure(
4638#   SECTION my_data
4639#   INPUT   "my_custom_data"
4640#   KEEP
4641# )
4642
4643
4644# Usage:
4645#   zephyr_linker([FORMAT <format>]
4646#     [ENTRY <entry symbol>]
4647#   )
4648#
4649# Zephyr linker general settings.
4650# This function specifies general settings for the linker script to be generated.
4651#
4652# FORMAT <format>:            The output format of the linked executable.
4653# ENTRY <entry symbolformat>: The code entry symbol.
4654#
4655function(zephyr_linker)
4656  set(single_args "ENTRY;FORMAT")
4657  cmake_parse_arguments(LINKER "" "${single_args}" "" ${ARGN})
4658
4659  if(LINKER_UNPARSED_ARGUMENTS)
4660    message(FATAL_ERROR "zephyr_linker(${ARGV0} ...) given unknown "
4661                        "arguments: ${LINKER_UNPARSED_ARGUMENTS}"
4662    )
4663  endif()
4664
4665  if(DEFINED LINKER_FORMAT)
4666    get_property(format_defined TARGET linker PROPERTY FORMAT SET)
4667    if(format_defined)
4668      message(FATAL_ERROR "zephyr_linker(FORMAT ...) already configured.")
4669    else()
4670      set_property(TARGET linker PROPERTY FORMAT ${LINKER_FORMAT})
4671    endif()
4672  endif()
4673
4674  if(DEFINED LINKER_ENTRY)
4675    get_property(entry_defined TARGET linker PROPERTY ENTRY SET)
4676    if(entry_defined)
4677      message(FATAL_ERROR "zephyr_linker(ENTRY ...) already configured.")
4678    else()
4679      set_property(TARGET linker PROPERTY ENTRY ${LINKER_ENTRY})
4680    endif()
4681  endif()
4682endfunction()
4683
4684# Usage:
4685#   zephyr_linker_memory(NAME <name> START <address> SIZE <size> [FLAGS <flags>])
4686#
4687# Zephyr linker memory.
4688# This function specifies a memory region for the platform in use.
4689#
4690# Note:
4691#   This function should generally be called with values obtained from
4692#   devicetree or Kconfig.
4693#
4694# NAME <name>    : Name of the memory region, for example FLASH.
4695# START <address>: Start address of the memory region.
4696#                  Start address can be given as decimal or hex value.
4697# SIZE <size>    : Size of the memory region.
4698#                  Size can be given as decimal value, hex value, or decimal with postfix k or m.
4699#                  All the following are valid values:
4700#                    1048576, 0x10000, 1024k, 1024K, 1m, and 1M.
4701# FLAGS <flags>  : Flags describing properties of the memory region.
4702#                  r: Read-only region
4703#                  w: Read-write region
4704#                  x: Executable region
4705#                  a: Allocatable region
4706#                  i: Initialized region
4707#                  l: Same as ‘i’
4708#                  !: Invert the sense of any of the attributes that follow
4709#                  The flags may be combined like: rx, rx!w.
4710function(zephyr_linker_memory)
4711  set(req_single_args "NAME;SIZE;START")
4712  set(single_args "FLAGS")
4713  cmake_parse_arguments(MEMORY "" "${req_single_args};${single_args}" "" ${ARGN})
4714
4715  if(MEMORY_UNPARSED_ARGUMENTS)
4716    message(FATAL_ERROR "zephyr_linker_memory(${ARGV0} ...) given unknown "
4717                        "arguments: ${MEMORY_UNPARSED_ARGUMENTS}"
4718    )
4719  endif()
4720
4721  foreach(arg ${req_single_args})
4722    if(NOT DEFINED MEMORY_${arg})
4723      message(FATAL_ERROR "zephyr_linker_memory(${ARGV0} ...) missing required "
4724                          "argument: ${arg}"
4725      )
4726    endif()
4727  endforeach()
4728
4729  set(MEMORY)
4730  zephyr_linker_arg_val_list(MEMORY "${req_single_args}")
4731  zephyr_linker_arg_val_list(MEMORY "${single_args}")
4732
4733  string(REPLACE ";" "\;" MEMORY "${MEMORY}")
4734  set_property(TARGET linker
4735               APPEND PROPERTY MEMORY_REGIONS "{${MEMORY}}"
4736  )
4737endfunction()
4738
4739# Usage:
4740#   zephyr_linker_memory_ifdef(<setting> NAME <name> START <address> SIZE <size> [FLAGS <flags>])
4741#
4742# Will create memory region if <setting> is enabled.
4743#
4744# <setting>: Setting to check for True value before invoking
4745#            zephyr_linker_memory()
4746#
4747# See zephyr_linker_memory() description for other supported arguments.
4748#
4749macro(zephyr_linker_memory_ifdef feature_toggle)
4750  if(${${feature_toggle}})
4751    zephyr_linker_memory(${ARGN})
4752  endif()
4753endmacro()
4754
4755# Usage:
4756#   zephyr_linker_dts_section(PATH <path>)
4757#
4758# Zephyr linker devicetree memory section from path.
4759#
4760# This function specifies an output section for the platform in use based on its
4761# devicetree configuration.
4762#
4763# The section will only be defined if the devicetree exists and has status okay.
4764#
4765# PATH <path>      : Devicetree node path.
4766#
4767function(zephyr_linker_dts_section)
4768  set(single_args "PATH")
4769  cmake_parse_arguments(DTS_SECTION "" "${single_args}" "" ${ARGN})
4770
4771  if(DTS_SECTION_UNPARSED_ARGUMENTS)
4772    message(FATAL_ERROR "zephyr_linker_dts_section(${ARGV0} ...) given unknown "
4773            "arguments: ${DTS_SECTION_UNPARSED_ARGUMENTS}"
4774    )
4775  endif()
4776
4777  if(NOT DEFINED DTS_SECTION_PATH)
4778    message(FATAL_ERROR "zephyr_linker_dts_section(${ARGV0} ...) missing "
4779                        "required argument: PATH"
4780    )
4781  endif()
4782
4783  dt_node_has_status(okay PATH ${DTS_SECTION_PATH} STATUS okay)
4784  if(NOT ${okay})
4785    return()
4786  endif()
4787
4788  dt_prop(name PATH ${DTS_SECTION_PATH} PROPERTY "zephyr,memory-region")
4789  if(NOT DEFINED name)
4790    message(FATAL_ERROR "zephyr_linker_dts_section(${ARGV0} ...) missing "
4791                        "\"zephyr,memory-region\" property"
4792    )
4793  endif()
4794  zephyr_string(SANITIZE name ${name})
4795
4796  dt_reg_addr(addr PATH ${DTS_SECTION_PATH})
4797
4798  zephyr_linker_section(NAME ${name} ADDRESS ${addr} VMA ${name} TYPE NOLOAD)
4799
4800endfunction()
4801
4802# Usage:
4803#   zephyr_linker_dts_memory(PATH <path>)
4804#   zephyr_linker_dts_memory(NODELABEL <nodelabel>)
4805#   zephyr_linker_dts_memory(CHOSEN <prop>)
4806#
4807# Zephyr linker devicetree memory.
4808# This function specifies a memory region for the platform in use based on its
4809# devicetree configuration.
4810#
4811# The memory will only be defined if the devicetree node or a devicetree node
4812# matching the nodelabel exists and has status okay.
4813#
4814# Only one of PATH, NODELABEL, and CHOSEN parameters may be given.
4815#
4816# PATH <path>      : Devicetree node identifier.
4817# NODELABEL <label>: Node label
4818# CHOSEN <prop>    : Chosen property, add memory section described by the
4819#                    /chosen property if it exists.
4820#
4821function(zephyr_linker_dts_memory)
4822  set(single_args "CHOSEN;PATH;NODELABEL")
4823  cmake_parse_arguments(DTS_MEMORY "" "${single_args}" "" ${ARGN})
4824
4825  if(DTS_MEMORY_UNPARSED_ARGUMENTS)
4826    message(FATAL_ERROR "zephyr_linker_dts_memory(${ARGV0} ...) given unknown "
4827                        "arguments: ${DTS_MEMORY_UNPARSED_ARGUMENTS}"
4828    )
4829  endif()
4830
4831  if((DEFINED DTS_MEMORY_PATH AND (DEFINED DTS_MEMORY_NODELABEL OR DEFINED DTS_MEMORY_CHOSEN))
4832     OR (DEFINED DTS_MEMORY_NODELABEL AND DEFINED DTS_MEMORY_CHOSEN))
4833    message(FATAL_ERROR "zephyr_linker_dts_memory(${ARGV0} ...), only one of "
4834                        "PATH, NODELABEL, and CHOSEN is allowed."
4835    )
4836  endif()
4837
4838  if(DEFINED DTS_MEMORY_NODELABEL)
4839    dt_nodelabel(DTS_MEMORY_PATH NODELABEL ${DTS_MEMORY_NODELABEL})
4840  endif()
4841
4842  if(DEFINED DTS_MEMORY_CHOSEN)
4843    dt_chosen(DTS_MEMORY_PATH PROPERTY ${DTS_MEMORY_CHOSEN})
4844  endif()
4845
4846  if(NOT DEFINED DTS_MEMORY_PATH)
4847    return()
4848  endif()
4849
4850  dt_node_has_status(okay PATH ${DTS_MEMORY_PATH} STATUS okay)
4851  if(NOT ${okay})
4852    return()
4853  endif()
4854
4855  dt_reg_addr(addr PATH ${DTS_MEMORY_PATH})
4856  dt_reg_size(size PATH ${DTS_MEMORY_PATH})
4857  dt_prop(name PATH ${DTS_MEMORY_PATH} PROPERTY "zephyr,memory-region")
4858  if(NOT DEFINED name)
4859    message(FATAL_ERROR "zephyr_linker_dts_memory(${ARGV0} ...) missing "
4860                        "\"zephyr,memory-region\" property"
4861    )
4862  endif()
4863  zephyr_string(SANITIZE name ${name})
4864
4865  dt_prop(flags PATH ${DTS_MEMORY_PATH} PROPERTY "zephyr,memory-region-flags")
4866  if(NOT DEFINED flags)
4867    zephyr_linker_memory(
4868      NAME  ${name}
4869      START ${addr}
4870      SIZE  ${size}
4871      FLAGS "rw"
4872    )
4873  elseif("${flags}" STREQUAL "")
4874    zephyr_linker_memory(
4875      NAME  ${name}
4876      START ${addr}
4877      SIZE  ${size}
4878    )
4879  else()
4880    zephyr_linker_memory(
4881      NAME  ${name}
4882      START ${addr}
4883      SIZE  ${size}
4884      FLAGS ${flags}
4885    )
4886  endif()
4887endfunction()
4888
4889# Usage:
4890#   zephyr_linker_group(NAME <name> [VMA <region|group>] [LMA <region|group>] [SYMBOL <SECTION>])
4891#   zephyr_linker_group(NAME <name> GROUP <group> [SYMBOL <SECTION>])
4892#
4893# Zephyr linker group.
4894# This function specifies a group inside a memory region or another group.
4895#
4896# The group ensures that all section inside the group are located together inside
4897# the specified group.
4898#
4899# This also allows for section placement inside a given group without the section
4900# itself needing the precise knowledge regarding the exact memory region this
4901# section will be placed in, as that will be determined by the group setup.
4902#
4903# Each group will define the following linker symbols:
4904# __<name>_start      : Start address of the group
4905# __<name>_end        : End address of the group
4906# __<name>_size       : Size of the group
4907#
4908# Note: <name> will be converted to lower casing for linker symbols definitions.
4909#
4910# NAME <name>         : Name of the group.
4911# VMA <region|group>  : VMA Memory region or group to be used for this group.
4912#                       If a group is used then the VMA region of that group will be used.
4913# LMA <region|group>  : Memory region or group to be used for this group.
4914# GROUP <group>       : Place the new group inside the existing group <group>
4915# SYMBOL <SECTION>    : Specify that start symbol of the region should be identical
4916#                       to the start address of the first section in the group.
4917#
4918# Note: VMA and LMA are mutual exclusive with GROUP
4919#
4920# Example:
4921#   zephyr_linker_memory(NAME memA START ... SIZE ... FLAGS ...)
4922#   zephyr_linker_group(NAME groupA LMA memA)
4923#   zephyr_linker_group(NAME groupB LMA groupA)
4924#
4925# will create two groups in same memory region as groupB will inherit the LMA
4926# from groupA:
4927#
4928# +-----------------+
4929# | memory region A |
4930# |                 |
4931# | +-------------+ |
4932# | | groupA      | |
4933# | +-------------+ |
4934# |                 |
4935# | +-------------+ |
4936# | | groupB      | |
4937# | +-------------+ |
4938# |                 |
4939# +-----------------+
4940#
4941# whereas
4942#   zephyr_linker_memory(NAME memA START ... SIZE ... FLAGS ...)
4943#   zephyr_linker_group(NAME groupA LMA memA)
4944#   zephyr_linker_group(NAME groupB GROUP groupA)
4945#
4946# will create groupB inside groupA:
4947#
4948# +---------------------+
4949# | memory region A     |
4950# |                     |
4951# | +-----------------+ |
4952# | | groupA          | |
4953# | |                 | |
4954# | | +-------------+ | |
4955# | | | groupB      | | |
4956# | | +-------------+ | |
4957# | |                 | |
4958# | +-----------------+ |
4959# |                     |
4960# +---------------------+
4961function(zephyr_linker_group)
4962  set(single_args "NAME;GROUP;LMA;SYMBOL;VMA")
4963  set(symbol_values SECTION)
4964  cmake_parse_arguments(GROUP "" "${single_args}" "" ${ARGN})
4965
4966  if(GROUP_UNPARSED_ARGUMENTS)
4967    message(FATAL_ERROR "zephyr_linker_group(${ARGV0} ...) given unknown "
4968                        "arguments: ${GROUP_UNPARSED_ARGUMENTS}"
4969    )
4970  endif()
4971
4972  if(DEFINED GROUP_GROUP AND (DEFINED GROUP_VMA OR DEFINED GROUP_LMA))
4973    message(FATAL_ERROR "zephyr_linker_group(GROUP ...) cannot be used with "
4974                        "VMA or LMA"
4975    )
4976  endif()
4977
4978  if(DEFINED GROUP_SYMBOL)
4979    if(NOT ${GROUP_SYMBOL} IN_LIST symbol_values)
4980      message(FATAL_ERROR "zephyr_linker_group(SYMBOL ...) given unknown value")
4981    endif()
4982  endif()
4983
4984  set(GROUP)
4985  zephyr_linker_arg_val_list(GROUP "${single_args}")
4986
4987  string(REPLACE ";" "\;" GROUP "${GROUP}")
4988  set_property(TARGET linker
4989               APPEND PROPERTY GROUPS "{${GROUP}}"
4990  )
4991endfunction()
4992
4993# Usage:
4994#   zephyr_linker_section(NAME <name> [GROUP <group>]
4995#                         [VMA <region|group>] [LMA <region|group>]
4996#                         [ADDRESS <address>] [ALIGN <alignment>]
4997#                         [SUBALIGN <alignment>] [FLAGS <flags>]
4998#                         [HIDDEN] [NOINPUT] [NOINIT]
4999#                         [PASS [NOT] <name>]
5000#   )
5001#
5002# Zephyr linker output section.
5003# This function specifies an output section for the linker.
5004#
5005# When using zephyr_linker_section(NAME <name>) an output section with <name>
5006# will be configured. This section will default include input sections of the
5007# same name, unless NOINPUT is specified.
5008# This means the section named `foo` will default include the sections matching
5009# `foo` and `foo.*`
5010# Each output section will define the following linker symbols:
5011# __<name>_start      : Start address of the section
5012# __<name>_end        : End address of the section
5013# __<name>_size       : Size of the section
5014# __<name>_load_start : Load address of the section, if VMA = LMA then this
5015#                       value will be identical to `__<name>_start`
5016#
5017# The location of the output section can be controlled using LMA, VMA, and
5018# address parameters
5019#
5020# NAME <name>         : Name of the output section.
5021# VMA <region|group>  : VMA Memory region or group where code / data is located runtime (VMA)
5022#                       If <group> is used here it means the section will use the
5023#                       same VMA memory region as <group> but will not be placed
5024#                       inside the group itself, see also GROUP argument.
5025# KVMA <region|group> : Kernel VMA Memory region or group where code / data is located runtime (VMA)
5026#                       When MMU is active and Kernel VM base and offset is different
5027#                       from SRAM base and offset, then the region defined by KVMA will
5028#                       be used as VMA.
5029#                       If <group> is used here it means the section will use the
5030#                       same VMA memory region as <group> but will not be placed
5031#                       inside the group itself, see also GROUP argument.
5032# LMA <region|group>  : Memory region or group where code / data is loaded (LMA)
5033#                       If VMA is different from LMA, the code / data will be loaded
5034#                       from LMA into VMA at bootup, this is usually the case for
5035#                       global or static variables that are loaded in rom and copied
5036#                       to ram at boot time.
5037#                       If <group> is used here it means the section will use the
5038#                       same LMA memory region as <group> but will not be placed
5039#                       inside the group itself, see also GROUP argument.
5040# GROUP <group>       : Place this section inside the group <group>
5041# ADDRESS <address>   : Specific address to use for this section.
5042# ALIGN_WITH_INPUT    : The alignment difference between VMA and LMA is kept
5043#                       intact for this section.
5044# ALIGN <alignment>   : Align the execution address with alignment.
5045# SUBALIGN <alignment>: Align input sections with alignment value.
5046# ENDALIGN <alignment>: Align the end so that next output section will start aligned.
5047#                       This only has effect on Scatter scripts.
5048#  Note: Regarding all alignment attributes. Not all linkers may handle alignment
5049#        in identical way. For example the Scatter file will align both load and
5050#        execution address (LMA and VMA) to be aligned when given the ALIGN attribute.
5051# NOINPUT             : No default input sections will be defined, to setup input
5052#                       sections for section <name>, the corresponding
5053#                       `zephyr_linker_section_configure()` must be used.
5054# PASS [NOT] <name>   : Linker pass iteration where this section should be active.
5055#                       Default a section will be present during all linker passes
5056#                       but in cases a section shall only be present at a specific
5057#                       pass, this argument can be used. For example to only have
5058#                       this section present on the `TEST` linker pass, use `PASS TEST`.
5059#                       It is possible to negate <name>, such as `PASS NOT <name>`.
5060#                       For example, `PASS NOT TEST` means the call is effective
5061#                       on all but the `TEST` linker pass iteration.
5062#
5063# Note: VMA and LMA are mutual exclusive with GROUP
5064#
5065function(zephyr_linker_section)
5066  set(options     "ALIGN_WITH_INPUT;HIDDEN;NOINIT;NOINPUT")
5067  set(single_args "ADDRESS;ALIGN;ENDALIGN;GROUP;KVMA;LMA;NAME;SUBALIGN;TYPE;VMA")
5068  set(multi_args  "PASS")
5069  cmake_parse_arguments(SECTION "${options}" "${single_args}" "${multi_args}" ${ARGN})
5070
5071  if(SECTION_UNPARSED_ARGUMENTS)
5072    message(WARNING "zephyr_linker_section(${ARGV0} ...) given unknown "
5073                    "arguments: ${SECTION_UNPARSED_ARGUMENTS}"
5074    )
5075  endif()
5076
5077  if(DEFINED SECTION_GROUP AND (DEFINED SECTION_VMA OR DEFINED SECTION_LMA))
5078    message(FATAL_ERROR "zephyr_linker_section(GROUP ...) cannot be used with "
5079                        "VMA or LMA"
5080    )
5081  endif()
5082
5083  if(DEFINED SECTION_KVMA)
5084    # If KVMA is set and the Kernel virtual memory settings reqs are met, we
5085    # substitute the VMA setting with the specified KVMA value.
5086    if(CONFIG_MMU)
5087      math(EXPR KERNEL_MEM_VM_OFFSET
5088           "(${CONFIG_KERNEL_VM_BASE} + ${CONFIG_KERNEL_VM_OFFSET})\
5089            - (${CONFIG_SRAM_BASE_ADDRESS} + ${CONFIG_SRAM_OFFSET})"
5090      )
5091
5092      if(NOT (${KERNEL_MEM_VM_OFFSET} EQUAL 0))
5093        set(SECTION_VMA ${SECTION_KVMA})
5094        set(SECTION_KVMA)
5095      endif()
5096    endif()
5097  endif()
5098
5099  if(DEFINED SECTION_PASS)
5100    list(LENGTH SECTION_PASS pass_length)
5101    if(${pass_length} GREATER 1)
5102      list(GET SECTION_PASS 0 pass_elem_0)
5103      if((NOT (${pass_elem_0} STREQUAL "NOT")) OR (${pass_length} GREATER 2))
5104        message(FATAL_ERROR "zephyr_linker_section(PASS takes maximum "
5105          "a single argument of the form: '<pass name>' or 'NOT <pass_name>'.")
5106      endif()
5107    endif()
5108  endif()
5109
5110  set(SECTION)
5111  zephyr_linker_arg_val_list(SECTION "${single_args}")
5112  zephyr_linker_arg_val_list(SECTION "${options}")
5113  zephyr_linker_arg_val_list(SECTION "${multi_args}")
5114
5115  string(REPLACE ";" "\;" SECTION "${SECTION}")
5116  set_property(TARGET linker
5117               APPEND PROPERTY SECTIONS "{${SECTION}}"
5118  )
5119endfunction()
5120
5121# Usage:
5122#   zephyr_linker_section_ifdef(<setting>
5123#                               NAME <name> [VMA <region>] [LMA <region>]
5124#                               [ADDRESS <address>] [ALIGN <alignment>]
5125#                               [SUBALIGN <alignment>] [FLAGS <flags>]
5126#                               [HIDDEN] [NOINPUT] [NOINIT]
5127#                               [PASS <no> [<no>...]
5128#   )
5129#
5130# Will create an output section if <setting> is enabled.
5131#
5132# <setting>: Setting to check for True value before invoking
5133#            zephyr_linker_section()
5134#
5135# See zephyr_linker_section() description for other supported arguments.
5136#
5137macro(zephyr_linker_section_ifdef feature_toggle)
5138  if(${${feature_toggle}})
5139    zephyr_linker_section(${ARGN})
5140  endif()
5141endmacro()
5142
5143# Usage:
5144#   zephyr_iterable_section(NAME <name> [GROUP <group>]
5145#                           [VMA <region|group>] [LMA <region|group>]
5146#                           [ALIGN_WITH_INPUT] [SUBALIGN <alignment>]
5147#   )
5148#
5149#
5150# Define an output section which will set up an iterable area
5151# of equally-sized data structures. For use with STRUCT_SECTION_ITERABLE.
5152# Input sections will be sorted by name in lexicographical order.
5153#
5154# Each list for an input section will define the following linker symbols:
5155# _<name>_list_start: Start of the iterable list
5156# _<name>_list_end  : End of the iterable list
5157#
5158# The output section will be named `<name>_area` and define the following linker
5159# symbols:
5160# __<name>_area_start      : Start address of the section
5161# __<name>_area_end        : End address of the section
5162# __<name>_area_size       : Size of the section
5163# __<name>_area_load_start : Load address of the section, if VMA = LMA then this
5164#                            value will be identical to `__<name>_area_start`
5165#
5166# NAME <name>         : Name of the struct type, the output section be named
5167#                       accordingly as: <name>_area.
5168# VMA <region|group>  : VMA Memory region where code / data is located runtime (VMA)
5169# LMA <region|group>  : Memory region where code / data is loaded (LMA)
5170#                       If VMA is different from LMA, the code / data will be loaded
5171#                       from LMA into VMA at bootup, this is usually the case for
5172#                       global or static variables that are loaded in rom and copied
5173#                       to ram at boot time.
5174# GROUP <group>       : Place this section inside the group <group>
5175# ADDRESS <address>   : Specific address to use for this section.
5176# ALIGN_WITH_INPUT    : The alignment difference between VMA and LMA is kept
5177#                       intact for this section.
5178# NUMERIC             : Use numeric sorting.
5179# SUBALIGN <alignment>: Force input alignment with size <alignment>
5180#  Note: Regarding all alignment attributes. Not all linkers may handle alignment
5181#        in identical way. For example the Scatter file will align both load and
5182#        execution address (LMA and VMA) to be aligned when given the ALIGN attribute.
5183#/
5184function(zephyr_iterable_section)
5185  # ToDo - Should we use ROM, RAM, etc as arguments ?
5186  set(options     "ALIGN_WITH_INPUT;NUMERIC")
5187  set(single_args "GROUP;LMA;NAME;SUBALIGN;VMA")
5188  set(multi_args  "")
5189  set(align_input)
5190  cmake_parse_arguments(SECTION "${options}" "${single_args}" "${multi_args}" ${ARGN})
5191
5192  if(NOT DEFINED SECTION_NAME)
5193    message(FATAL_ERROR "zephyr_iterable_section(${ARGV0} ...) missing "
5194                        "required argument: NAME"
5195    )
5196  endif()
5197
5198  if(NOT DEFINED SECTION_SUBALIGN)
5199    message(FATAL_ERROR "zephyr_iterable_section(${ARGV0} ...) missing "
5200                        "required argument: SUBALIGN"
5201    )
5202  endif()
5203
5204  if(SECTION_ALIGN_WITH_INPUT)
5205    set(align_input ALIGN_WITH_INPUT)
5206  endif()
5207
5208  if(SECTION_NUMERIC)
5209    set(INPUT "._${SECTION_NAME}.static.*_?_*;"
5210              "._${SECTION_NAME}.static.*_??_*;"
5211              "._${SECTION_NAME}.static.*_???_*;"
5212              "._${SECTION_NAME}.static.*_????_*;"
5213              "._${SECTION_NAME}.static.*_?????_*")
5214  else()
5215    set(INPUT "._${SECTION_NAME}.static.*")
5216  endif()
5217
5218  zephyr_linker_section(
5219    NAME ${SECTION_NAME}_area
5220    GROUP "${SECTION_GROUP}"
5221    VMA "${SECTION_VMA}" LMA "${SECTION_LMA}"
5222    NOINPUT ${align_input} SUBALIGN ${SECTION_SUBALIGN}
5223  )
5224  zephyr_linker_section_configure(
5225    SECTION ${SECTION_NAME}_area
5226    INPUT "${INPUT}"
5227    SYMBOLS _${SECTION_NAME}_list_start _${SECTION_NAME}_list_end
5228    KEEP SORT NAME
5229  )
5230endfunction()
5231
5232# Usage:
5233#   zephyr_linker_section_obj_level(SECTION <section> LEVEL <level>)
5234#
5235# generate a symbol to mark the start of the objects array for
5236# the specified object and level, then link all of those objects
5237# (sorted by priority). Ensure the objects aren't discarded if there is
5238# no direct reference to them.
5239#
5240# This is useful content such as struct devices.
5241#
5242# For example: zephyr_linker_section_obj_level(SECTION init LEVEL PRE_KERNEL_1)
5243# will create an input section matching `.z_init_PRE_KERNEL_1?_` and
5244# `.z_init_PRE_KERNEL_1??_`.
5245#
5246# SECTION <section>: Section in which the objects shall be placed
5247# LEVEL <level>    : Priority level, all input sections matching the level
5248#                    will be sorted.
5249#
5250function(zephyr_linker_section_obj_level)
5251  set(single_args "SECTION;LEVEL")
5252  cmake_parse_arguments(OBJ "" "${single_args}" "" ${ARGN})
5253
5254  if(NOT DEFINED OBJ_SECTION)
5255    message(FATAL_ERROR "zephyr_linker_section_obj_level(${ARGV0} ...) "
5256                        "missing required argument: SECTION"
5257    )
5258  endif()
5259
5260  if(NOT DEFINED OBJ_LEVEL)
5261    message(FATAL_ERROR "zephyr_linker_section_obj_level(${ARGV0} ...) "
5262                        "missing required argument: LEVEL"
5263    )
5264  endif()
5265
5266  zephyr_linker_section_configure(
5267    SECTION ${OBJ_SECTION}
5268    INPUT ".z_${OBJ_SECTION}_${OBJ_LEVEL}?_*"
5269    SYMBOLS __${OBJ_SECTION}_${OBJ_LEVEL}_start
5270    KEEP SORT NAME
5271  )
5272  zephyr_linker_section_configure(
5273    SECTION ${OBJ_SECTION}
5274    INPUT ".z_${OBJ_SECTION}_${OBJ_LEVEL}??_*"
5275    KEEP SORT NAME
5276  )
5277endfunction()
5278
5279# Usage:
5280#   zephyr_linker_section_configure(SECTION <section> [ALIGN <alignment>]
5281#                                   [PASS [NOT] <name>] [PRIO <no>] [SORT <sort>]
5282#                                   [ANY] [FIRST] [KEEP]
5283#   )
5284#
5285# Configure an output section with additional input sections.
5286# An output section can be configured with additional input sections besides its
5287# default section.
5288# For example, to add the input section `foo` to the output section bar, with KEEP
5289# attribute, call:
5290#   zephyr_linker_section_configure(SECTION bar INPUT foo KEEP)
5291#
5292# ALIGN <alignment>   : Will align the input section placement inside the load
5293#                       region with <alignment>
5294# FIRST               : The first input section in the list should be marked as
5295#                       first section in output.
5296# SORT <NAME>         : Sort the input sections according to <type>.
5297#                       Currently only `NAME` is supported.
5298# KEEP                : Do not eliminate input section during linking
5299# PRIO                : The priority of the input section. Per default, input
5300#                       sections order is not guaranteed by all linkers, but
5301#                       using priority Zephyr CMake linker will create sections
5302#                       such that order can be guaranteed. All unprioritized
5303#                       sections will internally be given a CMake process order
5304#                       priority counting from 100, so first unprioritized section
5305#                       is handled internal prio 100, next 101, and so on.
5306#                       To ensure a specific input section come before those,
5307#                       you may use `PRIO 50`, `PRIO 20` and so on.
5308#                       To ensure an input section is at the end, it is advised
5309#                       to use `PRIO 200` and above.
5310# PASS [NOT] <name>   : The call should only be considered for linker pass where
5311#                       <name> is defined. It is possible to negate <name>, such
5312#                       as `PASS NOT <name>.
5313#                       For example, `PASS TEST` means the call is only effective
5314#                       on the `TEST` linker pass iteration. `PASS NOT TEST` on
5315#                       all iterations the are not `TEST`.
5316# FLAGS <flags>       : Special section flags such as "+RO", +XO, "+ZI".
5317# ANY                 : ANY section flag in scatter file.
5318#                       The FLAGS and ANY arguments only has effect for scatter files.
5319#
5320function(zephyr_linker_section_configure)
5321  set(options     "ANY;FIRST;KEEP")
5322  set(single_args "ALIGN;OFFSET;PRIO;SECTION;SORT")
5323  set(multi_args  "FLAGS;INPUT;PASS;SYMBOLS")
5324  cmake_parse_arguments(SECTION "${options}" "${single_args}" "${multi_args}" ${ARGN})
5325
5326  if(SECTION_UNPARSED_ARGUMENTS)
5327    message(FATAL_ERROR "zephyr_linker_section_configure(${ARGV0} ...) given unknown arguments: ${SECTION_UNPARSED_ARGUMENTS}")
5328  endif()
5329
5330  if(DEFINED SECTION_SYMBOLS)
5331    list(LENGTH SECTION_SYMBOLS symbols_count)
5332    if(${symbols_count} GREATER 2)
5333      message(FATAL_ERROR "zephyr_linker_section_configure(SYMBOLS [start_sym [end_sym]]) takes maximum two symbol names (start and end).")
5334
5335    endif()
5336  endif()
5337
5338  if(DEFINED SECTION_PASS)
5339    list(LENGTH SECTION_PASS pass_length)
5340    if(${pass_length} GREATER 1)
5341      list(GET SECTION_PASS 0 pass_elem_0)
5342      if((NOT (${pass_elem_0} STREQUAL "NOT")) OR (${pass_length} GREATER 2))
5343        message(FATAL_ERROR "zephyr_linker_section_configure(PASS takes maximum "
5344          "a single argument of the form: '<pass name>' or 'NOT <pass_name>'.")
5345      endif()
5346    endif()
5347  endif()
5348
5349  set(SECTION)
5350  zephyr_linker_arg_val_list(SECTION "${single_args}")
5351  zephyr_linker_arg_val_list(SECTION "${options}")
5352  zephyr_linker_arg_val_list(SECTION "${multi_args}")
5353
5354  string(REPLACE ";" "\;" SECTION "${SECTION}")
5355  set_property(TARGET linker
5356               APPEND PROPERTY SECTION_SETTINGS "{${SECTION}}"
5357  )
5358endfunction()
5359
5360# Usage:
5361#   zephyr_linker_symbol(SYMBOL <name> EXPR <expr>)
5362#
5363# Add additional user defined symbol to the generated linker script.
5364#
5365# SYMBOL <name>: Symbol name to be available.
5366# EXPR <expr>  : Expression that defines the symbol. Due to linker limitations
5367#                all expressions should only contain simple math, such as
5368#                `+, -, *` and similar. The expression will go directly into the
5369#                linker, and all `@<symbol>@` will be replaced with the referred
5370#                symbol.
5371#
5372# Example:
5373#   To create a new symbol `bar` pointing to the start VMA address of section
5374#   `foo` + 1024, one can write:
5375#     zephyr_linker_symbol(SYMBOL bar EXPR "(@foo@ + 1024)")
5376#
5377function(zephyr_linker_symbol)
5378  set(single_args "EXPR;SYMBOL")
5379  cmake_parse_arguments(SYMBOL "" "${single_args}" "" ${ARGN})
5380
5381  if(SECTION_UNPARSED_ARGUMENTS)
5382    message(WARNING "zephyr_linker_symbol(${ARGV0} ...) given unknown "
5383                    "arguments: ${SECTION_UNPARSED_ARGUMENTS}"
5384    )
5385  endif()
5386
5387  set(SYMBOL)
5388  zephyr_linker_arg_val_list(SYMBOL "${single_args}")
5389
5390  string(REPLACE ";" "\;" SYMBOL "${SYMBOL}")
5391  set_property(TARGET linker
5392               APPEND PROPERTY SYMBOLS "{${SYMBOL}}"
5393  )
5394endfunction()
5395
5396# Internal helper macro for zephyr_linker*() functions.
5397# The macro will create a list of argument-value pairs for defined arguments
5398# that can be passed on to linker script generators and processed as a CMake
5399# function call using cmake_parse_arguments.
5400#
5401# For example, having the following argument and value:
5402# FOO: bar
5403# BAZ: <undefined>
5404# QUX: option set
5405#
5406# will create a list as: "FOO;bar;QUX;TRUE" which can then be parsed as argument
5407# list later.
5408macro(zephyr_linker_arg_val_list list arguments)
5409  foreach(arg ${arguments})
5410    if(DEFINED ${list}_${arg})
5411      list(APPEND ${list} ${arg} "${${list}_${arg}}")
5412    endif()
5413  endforeach()
5414endmacro()
5415
5416########################################################
5417# 6. Function helper macros
5418########################################################
5419#
5420# Set of CMake macros to facilitate argument processing when defining functions.
5421#
5422
5423#
5424# Helper macro for verifying that at least one of the required arguments has
5425# been provided by the caller.
5426#
5427# A FATAL_ERROR will be raised if not one of the required arguments has been
5428# passed by the caller.
5429#
5430# Usage:
5431#   zephyr_check_arguments_required(<function_name> <prefix> <arg1> [<arg2> ...])
5432#
5433macro(zephyr_check_arguments_required function prefix)
5434  set(check_defined DEFINED)
5435  zephyr_check_flags_required(${function} ${prefix} ${ARGN})
5436  set(check_defined)
5437endmacro()
5438
5439#
5440# Helper macro for verifying that at least one of the required arguments has
5441# been provided by the caller. Arguments with empty values are allowed.
5442#
5443# A FATAL_ERROR will be raised if not one of the required arguments has been
5444# passed by the caller.
5445#
5446# Usage:
5447#   zephyr_check_arguments_required_allow_empty(<function_name> <prefix> <arg1> [<arg2> ...])
5448#
5449macro(zephyr_check_arguments_required_allow_empty function prefix)
5450  set(check_defined DEFINED)
5451  set(allow_empty TRUE)
5452  zephyr_check_flags_required(${function} ${prefix} ${ARGN})
5453  set(allow_empty)
5454  set(check_defined)
5455endmacro()
5456
5457#
5458# Helper macro for verifying that at least one of the required flags has
5459# been provided by the caller.
5460#
5461# A FATAL_ERROR will be raised if not one of the required arguments has been
5462# passed by the caller.
5463#
5464# Usage:
5465#   zephyr_check_flags_required(<function_name> <prefix> <flag1> [<flag2> ...])
5466#
5467macro(zephyr_check_flags_required function prefix)
5468  set(required_found FALSE)
5469  foreach(required ${ARGN})
5470    if(${check_defined} ${prefix}_${required})
5471      set(required_found TRUE)
5472    elseif("${allow_empty}" AND ${required} IN_LIST ${prefix}_KEYWORDS_MISSING_VALUES)
5473      set(required_found TRUE)
5474    endif()
5475  endforeach()
5476
5477  if(NOT required_found)
5478    message(FATAL_ERROR "${function}(...) missing a required argument: ${ARGN}")
5479  endif()
5480endmacro()
5481
5482#
5483# Helper macro for verifying that all the required arguments have been
5484# provided by the caller.
5485#
5486# A FATAL_ERROR will be raised if one of the required arguments is missing.
5487#
5488# Usage:
5489#   zephyr_check_arguments_required_all(<function_name> <prefix> <arg1> [<arg2> ...])
5490#
5491macro(zephyr_check_arguments_required_all function prefix)
5492  foreach(required ${ARGN})
5493    if(NOT DEFINED ${prefix}_${required})
5494      message(FATAL_ERROR "${function}(...) missing a required argument: ${required}")
5495    endif()
5496  endforeach()
5497endmacro()
5498
5499#
5500# Helper macro for verifying that none of the mutual exclusive arguments are
5501# provided together.
5502#
5503# A FATAL_ERROR will be raised if any of the arguments are given together.
5504#
5505# Usage:
5506#   zephyr_check_arguments_exclusive(<function_name> <prefix> <arg1> <arg2> [<arg3> ...])
5507#
5508macro(zephyr_check_arguments_exclusive function prefix)
5509  set(check_defined DEFINED)
5510  zephyr_check_flags_exclusive(${function} ${prefix} ${ARGN})
5511  set(check_defined)
5512endmacro()
5513
5514#
5515# Helper macro for verifying that none of the mutual exclusive flags are
5516# provided together.
5517#
5518# A FATAL_ERROR will be raised if any of the flags are given together.
5519#
5520# Usage:
5521#   zephyr_check_flags_exclusive(<function_name> <prefix> <flag1> <flag2> [<flag3> ...])
5522#
5523macro(zephyr_check_flags_exclusive function prefix)
5524  set(args_defined)
5525  foreach(arg ${ARGN})
5526    if(${check_defined} ${prefix}_${arg})
5527      list(APPEND args_defined ${arg})
5528    endif()
5529  endforeach()
5530  list(LENGTH args_defined exclusive_length)
5531  if(exclusive_length GREATER 1)
5532    list(POP_FRONT args_defined argument)
5533    message(FATAL_ERROR "${function}(${argument} ...) cannot be used with "
5534        "argument: ${args_defined}"
5535      )
5536  endif()
5537endmacro()
5538
5539########################################################
5540# 7. Linkable loadable extensions (llext)
5541########################################################
5542#
5543# These functions simplify the creation and management of linkable
5544# loadable extensions (llexts).
5545#
5546
5547# 7.1 Configuration functions
5548#
5549# The following functions simplify access to the compilation/link stage
5550# properties of an llext using the same API of the target_* functions.
5551#
5552
5553function(llext_compile_definitions target_name)
5554  target_compile_definitions(${target_name}_llext_lib PRIVATE ${ARGN})
5555endfunction()
5556
5557function(llext_compile_features target_name)
5558  target_compile_features(${target_name}_llext_lib PRIVATE ${ARGN})
5559endfunction()
5560
5561function(llext_compile_options target_name)
5562  target_compile_options(${target_name}_llext_lib PRIVATE ${ARGN})
5563endfunction()
5564
5565function(llext_include_directories target_name)
5566  target_include_directories(${target_name}_llext_lib PRIVATE ${ARGN})
5567endfunction()
5568
5569function(llext_link_options target_name)
5570  target_link_options(${target_name}_llext_lib PRIVATE ${ARGN})
5571endfunction()
5572
5573# 7.2 Build control functions
5574#
5575# The following functions add targets and subcommands to the build system
5576# to compile and link an llext.
5577#
5578
5579# Usage:
5580#   add_llext_target(<target_name>
5581#                    OUTPUT  <output_file>
5582#                    SOURCES <source_files>
5583#   )
5584#
5585# Add a custom target that compiles a set of source files to a .llext file.
5586#
5587# Output and source files must be specified using the OUTPUT and SOURCES
5588# arguments. Only one source file is supported when LLEXT_TYPE_ELF_OBJECT is
5589# selected, since there is no linking step in that case.
5590#
5591# The llext code will be compiled with mostly the same C compiler flags used
5592# in the Zephyr build, but with some important modifications. The list of
5593# flags to remove and flags to append is controlled respectively by the
5594# LLEXT_REMOVE_FLAGS and LLEXT_APPEND_FLAGS global variables.
5595#
5596# The following custom properties of <target_name> are defined and can be
5597# retrieved using the get_target_property() function:
5598#
5599# - lib_target  Target name for the source compilation and/or link step.
5600# - lib_output  The binary file resulting from compilation and/or
5601#               linking steps.
5602# - pkg_input   The file to be used as input for the packaging step.
5603# - pkg_output  The final .llext file.
5604#
5605# Example usage:
5606#   add_llext_target(hello_world
5607#     OUTPUT  ${PROJECT_BINARY_DIR}/hello_world.llext
5608#     SOURCES ${PROJECT_SOURCE_DIR}/src/llext/hello_world.c
5609#   )
5610# will compile the source file src/llext/hello_world.c to a file
5611# named "${PROJECT_BINARY_DIR}/hello_world.llext".
5612#
5613function(add_llext_target target_name)
5614  set(single_args OUTPUT)
5615  set(multi_args SOURCES)
5616  cmake_parse_arguments(PARSE_ARGV 1 LLEXT "${options}" "${single_args}" "${multi_args}")
5617
5618  # Check that the llext subsystem is enabled for this build
5619  if (NOT CONFIG_LLEXT)
5620    message(FATAL_ERROR "add_llext_target: CONFIG_LLEXT must be enabled")
5621  endif()
5622
5623  # Source and output files must be provided
5624  zephyr_check_arguments_required_all("add_llext_target" LLEXT OUTPUT SOURCES)
5625
5626  list(LENGTH LLEXT_SOURCES source_count)
5627  if(CONFIG_LLEXT_TYPE_ELF_OBJECT AND NOT (source_count EQUAL 1))
5628    message(FATAL_ERROR "add_llext_target: only one source file is supported "
5629                        "for ELF object file builds")
5630  endif()
5631
5632  set(llext_pkg_output ${LLEXT_OUTPUT})
5633  set(source_files ${LLEXT_SOURCES})
5634
5635  set(zephyr_flags
5636      "$<TARGET_PROPERTY:zephyr_interface,INTERFACE_COMPILE_OPTIONS>"
5637  )
5638  llext_filter_zephyr_flags(LLEXT_REMOVE_FLAGS ${zephyr_flags}
5639      zephyr_filtered_flags)
5640
5641  # Compile the source file using current Zephyr settings but a different
5642  # set of flags to obtain the desired llext object type.
5643  set(llext_lib_target ${target_name}_llext_lib)
5644  if(CONFIG_LLEXT_TYPE_ELF_OBJECT)
5645
5646    # Create an object library to compile the source file
5647    add_library(${llext_lib_target} EXCLUDE_FROM_ALL OBJECT ${source_files})
5648    set(llext_lib_output $<TARGET_OBJECTS:${llext_lib_target}>)
5649
5650  elseif(CONFIG_LLEXT_TYPE_ELF_RELOCATABLE)
5651
5652    # CMake does not directly support a "RELOCATABLE" library target.
5653    # The "SHARED" target would be similar, but that unavoidably adds
5654    # a "-shared" flag to the linker command line which does firmly
5655    # conflict with "-r".
5656    # A workaround is to use an executable target and make the linker
5657    # output a relocatable file. The output file suffix is changed so
5658    # the result looks like the object file it actually is.
5659    add_executable(${llext_lib_target} EXCLUDE_FROM_ALL ${source_files})
5660    target_link_options(${llext_lib_target} PRIVATE
5661      $<TARGET_PROPERTY:linker,partial_linking>)
5662    set_target_properties(${llext_lib_target} PROPERTIES
5663      RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/llext
5664      SUFFIX ${CMAKE_C_OUTPUT_EXTENSION})
5665    set(llext_lib_output $<TARGET_FILE:${llext_lib_target}>)
5666
5667    # Add the llext flags to the linking step as well
5668    target_link_options(${llext_lib_target} PRIVATE
5669      ${LLEXT_APPEND_FLAGS}
5670    )
5671
5672  elseif(CONFIG_LLEXT_TYPE_ELF_SHAREDLIB)
5673
5674    # Create a shared library
5675    add_library(${llext_lib_target} EXCLUDE_FROM_ALL SHARED ${source_files})
5676    set_target_properties(${llext_lib_target} PROPERTIES
5677      LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/llext
5678    )
5679    set(llext_lib_output $<TARGET_FILE:${llext_lib_target}>)
5680
5681    # Add the llext flags to the linking step as well
5682    target_link_options(${llext_lib_target} PRIVATE
5683      ${LLEXT_APPEND_FLAGS}
5684    )
5685
5686  endif()
5687
5688  target_compile_definitions(${llext_lib_target} PRIVATE
5689    $<TARGET_PROPERTY:zephyr_interface,INTERFACE_COMPILE_DEFINITIONS>
5690    LL_EXTENSION_BUILD
5691  )
5692  target_compile_options(${llext_lib_target} PRIVATE
5693    ${zephyr_filtered_flags}
5694    ${LLEXT_APPEND_FLAGS}
5695  )
5696  target_include_directories(${llext_lib_target} PRIVATE
5697    $<TARGET_PROPERTY:zephyr_interface,INTERFACE_INCLUDE_DIRECTORIES>
5698  )
5699  target_include_directories(${llext_lib_target} SYSTEM PUBLIC
5700    $<TARGET_PROPERTY:zephyr_interface,INTERFACE_SYSTEM_INCLUDE_DIRECTORIES>
5701  )
5702  add_dependencies(${llext_lib_target}
5703    zephyr_interface
5704    zephyr_generated_headers
5705  )
5706
5707  # Make sure the intermediate output directory exists.
5708  file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/llext)
5709
5710  # Set up an intermediate processing step between compilation and packaging
5711  # to be used to support POST_BUILD commands on targets that do not use a
5712  # dynamic library.
5713  set(llext_proc_target ${target_name}_llext_proc)
5714  set(llext_pkg_input ${PROJECT_BINARY_DIR}/llext/${target_name}_debug.elf)
5715  add_custom_target(${llext_proc_target} DEPENDS ${llext_pkg_input})
5716  set_property(TARGET ${llext_proc_target} PROPERTY has_post_build_cmds 0)
5717
5718  # By default this target must copy the `lib_output` binary file to the
5719  # expected `pkg_input` location. If actual POST_BUILD commands are defined,
5720  # they will take care of this and the default copy is replaced by a no-op.
5721  set(has_post_build_cmds "$<TARGET_PROPERTY:${llext_proc_target},has_post_build_cmds>")
5722  set(noop_cmd ${CMAKE_COMMAND} -E true)
5723  set(copy_cmd ${CMAKE_COMMAND} -E copy ${llext_lib_output} ${llext_pkg_input})
5724  add_custom_command(
5725    OUTPUT ${llext_pkg_input}
5726    COMMAND "$<IF:${has_post_build_cmds},${noop_cmd},${copy_cmd}>"
5727    DEPENDS ${llext_lib_target} ${llext_lib_output}
5728    COMMAND_EXPAND_LISTS
5729  )
5730
5731  # LLEXT ELF processing for importing via SLID
5732  #
5733  # This command must be executed as last step of the packaging process,
5734  # to ensure that the ELF processed for binary generation contains SLIDs.
5735  # If executed too early, it is possible that some tools executed to modify
5736  # the ELF file (e.g., strip) undo the work performed here.
5737  if (CONFIG_LLEXT_EXPORT_BUILTINS_BY_SLID)
5738    set(slid_inject_cmd
5739      ${PYTHON_EXECUTABLE}
5740      ${ZEPHYR_BASE}/scripts/build/llext_inject_slids.py
5741      --elf-file ${llext_pkg_output}
5742    )
5743  else()
5744    set(slid_inject_cmd ${CMAKE_COMMAND} -E true)
5745  endif()
5746
5747  # Remove sections that are unused by the llext loader
5748  add_custom_command(
5749    OUTPUT ${llext_pkg_output}
5750    COMMAND $<TARGET_PROPERTY:bintools,elfconvert_command>
5751            $<TARGET_PROPERTY:bintools,elfconvert_flag>
5752            $<TARGET_PROPERTY:bintools,elfconvert_flag_strip_unneeded>
5753            $<TARGET_PROPERTY:bintools,elfconvert_flag_section_remove>.xt.*
5754            $<TARGET_PROPERTY:bintools,elfconvert_flag_infile>${llext_pkg_input}
5755            $<TARGET_PROPERTY:bintools,elfconvert_flag_outfile>${llext_pkg_output}
5756            $<TARGET_PROPERTY:bintools,elfconvert_flag_final>
5757    COMMAND ${slid_inject_cmd}
5758    DEPENDS ${llext_proc_target} ${llext_pkg_input}
5759  )
5760
5761  # Add user-visible target and dependency, and fill in properties
5762  get_filename_component(output_name ${llext_pkg_output} NAME)
5763  add_custom_target(${target_name}
5764    COMMENT "Generating ${output_name}"
5765    DEPENDS ${llext_pkg_output}
5766  )
5767  set_target_properties(${target_name} PROPERTIES
5768    lib_target ${llext_lib_target}
5769    lib_output ${llext_lib_output}
5770    pkg_input  ${llext_pkg_input}
5771    pkg_output ${llext_pkg_output}
5772  )
5773endfunction()
5774
5775# Usage:
5776#   add_llext_command(
5777#     TARGET <target_name>
5778#     PRE_BUILD | POST_BUILD | POST_PKG
5779#     COMMAND <command> [...]
5780#   )
5781#
5782# Add a custom command to an llext target that will be executed during
5783# the build. The command will be executed at the specified build step and
5784# can refer to <target>'s properties for build-specific details.
5785#
5786# The different build steps are:
5787# - PRE_BUILD:  Before the llext code is linked, if the architecture uses
5788#               dynamic libraries. This step can access `lib_target` and
5789#               its own properties.
5790# - POST_BUILD: After the llext code is built, but before packaging
5791#               it in an .llext file. This step is expected to create a
5792#               `pkg_input` file by reading the contents of `lib_output`.
5793# - POST_PKG:   After the .llext file has been created. This can operate on
5794#               the final llext file `pkg_output`.
5795#
5796# Anything else after COMMAND will be passed to add_custom_command() as-is
5797# (including multiple commands and other options).
5798function(add_llext_command)
5799  set(options     PRE_BUILD POST_BUILD POST_PKG)
5800  set(single_args TARGET)
5801  # COMMAND and other options are passed to add_custom_command() as-is
5802
5803  cmake_parse_arguments(PARSE_ARGV 0 LLEXT "${options}" "${single_args}" "${multi_args}")
5804  zephyr_check_arguments_required_all("add_llext_command" LLEXT TARGET)
5805
5806  # Check the target exists and refers to an llext target
5807  set(target_name ${LLEXT_TARGET})
5808  set(llext_lib_target  ${target_name}_llext_lib)
5809  set(llext_proc_target ${target_name}_llext_proc)
5810  if(NOT TARGET ${llext_lib_target})
5811    message(FATAL_ERROR "add_llext_command: not an llext target: ${target_name}")
5812  endif()
5813
5814  # ARM uses an object file representation so there is no link step.
5815  if(CONFIG_ARM AND LLEXT_PRE_BUILD)
5816    message(FATAL_ERROR
5817            "add_llext_command: PRE_BUILD not supported on this arch")
5818  endif()
5819
5820  # Determine the build step and the target to attach the command to
5821  # based on the provided options
5822  if(LLEXT_PRE_BUILD)
5823    # > before the object files are linked:
5824    #   - execute user command(s) before the lib target's link step.
5825    set(cmd_target ${llext_lib_target})
5826    set(build_step PRE_LINK)
5827  elseif(LLEXT_POST_BUILD)
5828    # > after linking, but before llext packaging:
5829    #   - stop default file copy to prevent user files from being clobbered;
5830    #   - execute user command(s) after the (now empty) `llext_proc_target`.
5831    set_property(TARGET ${llext_proc_target} PROPERTY has_post_build_cmds 1)
5832    set(cmd_target ${llext_proc_target})
5833    set(build_step POST_BUILD)
5834  elseif(LLEXT_POST_PKG)
5835    # > after the final llext binary is ready:
5836    #   - execute user command(s) after the main target is done.
5837    set(cmd_target ${target_name})
5838    set(build_step POST_BUILD)
5839  else()
5840    message(FATAL_ERROR "add_llext_command: build step must be provided")
5841  endif()
5842
5843  # Check that the first unparsed argument is the word COMMAND
5844  list(GET LLEXT_UNPARSED_ARGUMENTS 0 command_str)
5845  if(NOT command_str STREQUAL "COMMAND")
5846    message(FATAL_ERROR "add_llext_command: COMMAND argument must be provided")
5847  endif()
5848
5849  # Add the actual command(s) to the target
5850  add_custom_command(
5851    TARGET ${cmd_target} ${build_step}
5852    ${LLEXT_UNPARSED_ARGUMENTS}
5853    COMMAND_EXPAND_LISTS
5854  )
5855endfunction()
5856
5857# 7.3 llext helper functions
5858
5859# Usage:
5860#   llext_filter_zephyr_flags(<filter> <flags> <outvar>)
5861#
5862# Filter out flags from a list of flags. The filter is a list of regular
5863# expressions that will be used to exclude flags from the input list.
5864#
5865# The resulting generator expression will be stored in the variable <outvar>.
5866#
5867# Example:
5868#   llext_filter_zephyr_flags(LLEXT_REMOVE_FLAGS zephyr_flags zephyr_filtered_flags)
5869#
5870function(llext_filter_zephyr_flags filter flags outvar)
5871  list(TRANSFORM ${filter}
5872       REPLACE "(.+)" "^\\1$"
5873       OUTPUT_VARIABLE llext_remove_flags_regexp
5874  )
5875  list(JOIN llext_remove_flags_regexp "|" llext_remove_flags_regexp)
5876  if ("${llext_remove_flags_regexp}" STREQUAL "")
5877    # an empty regexp would match anything, we actually need the opposite
5878    # so set it to match empty strings
5879    set(llext_remove_flags_regexp "^$")
5880  endif()
5881
5882  set(zephyr_filtered_flags
5883      "$<FILTER:${flags},EXCLUDE,${llext_remove_flags_regexp}>"
5884  )
5885
5886  set(${outvar} ${zephyr_filtered_flags} PARENT_SCOPE)
5887endfunction()
5888
5889########################################################
5890# 8. Script mode handling
5891########################################################
5892#
5893# Certain features are not available when CMake is used in script mode.
5894# For example custom targets, and thus features related to custom targets, such
5895# as target properties are not available in script mode.
5896#
5897# This section defines behavior for functions whose default implementation does
5898# not work correctly in script mode.
5899#
5900# The script mode function can be a simple stub or a more complex solution
5901# depending on the exact use of the function in script mode.
5902#
5903# Current Zephyr CMake scripts which includes `extensions.cmake` in script mode
5904# are: package_helper.cmake, verify-toolchain.cmake, llext-edk.cmake
5905#
5906
5907if(CMAKE_SCRIPT_MODE_FILE)
5908  # add_custom_target and set_target_properties are not supported in script mode.
5909  # However, Zephyr CMake functions like `zephyr_get()`, `zephyr_create_scope()`,
5910  # llext functions creates or relies on custom CMake targets.
5911  function(add_custom_target)
5912    # This silence the error: 'add_custom_target command is not scriptable'
5913  endfunction()
5914
5915  function(set_target_properties)
5916    # This silence the error: 'set_target_properties command is not scriptable'
5917  endfunction()
5918
5919  # Build info creates a custom target for handling of build info.
5920  # build_info is not needed in script mode but still called by Zephyr CMake
5921  # modules. Therefore disable build_info(...) in when including
5922  # extensions.cmake in script mode.
5923  function(build_info)
5924    # This silence the error: 'Unknown CMake command "yaml_context"'
5925  endfunction()
5926endif()
5927