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