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