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