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