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