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