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