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