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