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