1# SPDX-License-Identifier: Apache-2.0 2 3include_guard(GLOBAL) 4 5include(extensions) 6include(python) 7 8# autoconf.h is generated by Kconfig and placed in 9# <build>/zephyr/include/generated/autoconf.h. 10# A project may request a custom location by setting AUTOCONF_H explicitly before 11# calling 'find_package(Zephyr)' or loading this module. 12set_ifndef(AUTOCONF_H ${PROJECT_BINARY_DIR}/include/generated/zephyr/autoconf.h) 13# Re-configure (Re-execute all CMakeLists.txt code) when autoconf.h changes 14set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${AUTOCONF_H}) 15 16# Folders needed for conf/mconf files (kconfig has no method of redirecting all output files). 17# conf/mconf needs to be run from a different directory because of: GH-3408 18file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/kconfig/include/generated) 19file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/kconfig/include/config) 20 21set_ifndef(KCONFIG_NAMESPACE "CONFIG") 22 23set_ifndef(KCONFIG_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/Kconfig) 24set(KCONFIG_BOARD_DIR ${KCONFIG_BINARY_DIR}/boards) 25file(MAKE_DIRECTORY ${KCONFIG_BINARY_DIR}) 26 27if(HWMv1) 28 # HWMv1 only supoorts a single board dir which points directly to the board dir. 29 set(KCONFIG_BOARD_DIR ${BOARD_DIR}) 30 # Support multiple SOC_ROOT 31 file(MAKE_DIRECTORY ${KCONFIG_BINARY_DIR}/soc) 32 set(kconfig_soc_root ${SOC_ROOT}) 33 list(REMOVE_ITEM kconfig_soc_root ${ZEPHYR_BASE}) 34 set(soc_defconfig_file ${KCONFIG_BINARY_DIR}/soc/Kconfig.defconfig) 35 36 set(OPERATION WRITE) 37 foreach(root ${kconfig_soc_root}) 38 file(APPEND ${soc_defconfig_file} 39 "osource \"${root}/soc/$(ARCH)/*/Kconfig.defconfig\"\n") 40 file(${OPERATION} ${KCONFIG_BINARY_DIR}/soc/Kconfig.soc.choice 41 "osource \"${root}/soc/$(ARCH)/*/Kconfig.soc\"\n" 42 ) 43 file(${OPERATION} ${KCONFIG_BINARY_DIR}/soc/Kconfig.soc.arch 44 "osource \"${root}/soc/$(ARCH)/Kconfig\"\n" 45 "osource \"${root}/soc/$(ARCH)/*/Kconfig\"\n" 46 ) 47 set(OPERATION APPEND) 48 endforeach() 49endif() 50 51# Support multiple shields in BOARD_ROOT, remove ZEPHYR_BASE as that is always sourced. 52set(kconfig_board_root ${BOARD_ROOT}) 53list(REMOVE_ITEM kconfig_board_root ${ZEPHYR_BASE}) 54set(OPERATION WRITE) 55foreach(root ${kconfig_board_root}) 56 file(${OPERATION} ${KCONFIG_BINARY_DIR}/Kconfig.shield.defconfig 57 "osource \"${root}/boards/shields/*/Kconfig.defconfig\"\n" 58 ) 59 file(${OPERATION} ${KCONFIG_BINARY_DIR}/Kconfig.shield 60 "osource \"${root}/boards/shields/*/Kconfig.shield\"\n" 61 ) 62 set(OPERATION APPEND) 63endforeach() 64 65if(KCONFIG_ROOT) 66 # Perform any variable substitutions if they are present 67 string(CONFIGURE "${KCONFIG_ROOT}" KCONFIG_ROOT) 68 69 zephyr_file(APPLICATION_ROOT KCONFIG_ROOT) 70 # KCONFIG_ROOT has either been specified as a CMake variable or is 71 # already in the CMakeCache.txt. This has precedence. 72elseif(EXISTS ${APPLICATION_SOURCE_DIR}/Kconfig) 73 set(KCONFIG_ROOT ${APPLICATION_SOURCE_DIR}/Kconfig) 74else() 75 set(KCONFIG_ROOT ${ZEPHYR_BASE}/Kconfig) 76endif() 77 78if(NOT DEFINED BOARD_DEFCONFIG) 79 zephyr_file(CONF_FILES ${BOARD_DIRECTORIES} DEFCONFIG BOARD_DEFCONFIG) 80endif() 81 82if(DEFINED BOARD_REVISION) 83 zephyr_build_string(config_board_string 84 BOARD ${BOARD} 85 BOARD_QUALIFIERS ${BOARD_QUALIFIERS} 86 BOARD_REVISION ${BOARD_REVISION} 87 ) 88 set(board_rev_file ${config_board_string}) 89 if(EXISTS ${BOARD_DIR}/${board_rev_file}.conf) 90 message(DEPRECATION "Use of '${board_rev_file}.conf' is deprecated, please switch to '${board_rev_file}_defconfig'") 91 set_ifndef(BOARD_REVISION_CONFIG ${BOARD_DIR}/${board_rev_file}.conf) 92 endif() 93endif() 94 95set(DOTCONFIG ${PROJECT_BINARY_DIR}/.config) 96set(PARSED_KCONFIG_SOURCES_TXT ${PROJECT_BINARY_DIR}/kconfig/sources.txt) 97 98if(CONF_FILE) 99 string(CONFIGURE "${CONF_FILE}" CONF_FILE_EXPANDED) 100 string(REPLACE " " ";" CONF_FILE_AS_LIST "${CONF_FILE_EXPANDED}") 101 build_info(kconfig user-files PATH ${CONF_FILE_AS_LIST}) 102endif() 103 104if(EXTRA_CONF_FILE) 105 string(CONFIGURE "${EXTRA_CONF_FILE}" EXTRA_CONF_FILE_EXPANDED) 106 string(REPLACE " " ";" EXTRA_CONF_FILE_AS_LIST "${EXTRA_CONF_FILE_EXPANDED}") 107 build_info(kconfig extra-user-files PATH ${EXTRA_CONF_FILE_AS_LIST}) 108endif() 109 110zephyr_file(CONF_FILES ${BOARD_EXTENSION_DIRS} KCONF board_extension_conf_files SUFFIX ${FILE_SUFFIX}) 111 112# DTS_ROOT_BINDINGS is a semicolon separated list, this causes 113# problems when invoking kconfig_target since semicolon is a special 114# character in the C shell, so we make it into a question-mark 115# separated list instead. 116string(REPLACE ";" "?" DTS_ROOT_BINDINGS "${DTS_ROOT_BINDINGS}") 117 118# Export each `ZEPHYR_<module>_MODULE_DIR` to Kconfig. 119# This allows Kconfig files to refer relative from a modules root as: 120# source "$(ZEPHYR_FOO_MODULE_DIR)/Kconfig" 121foreach(module_name ${ZEPHYR_MODULE_NAMES}) 122 zephyr_string(SANITIZE TOUPPER MODULE_NAME_UPPER ${module_name}) 123 list(APPEND 124 ZEPHYR_KCONFIG_MODULES_DIR 125 "ZEPHYR_${MODULE_NAME_UPPER}_MODULE_DIR=${ZEPHYR_${MODULE_NAME_UPPER}_MODULE_DIR}" 126 ) 127 128 if(ZEPHYR_${MODULE_NAME_UPPER}_KCONFIG) 129 list(APPEND 130 ZEPHYR_KCONFIG_MODULES_DIR 131 "ZEPHYR_${MODULE_NAME_UPPER}_KCONFIG=${ZEPHYR_${MODULE_NAME_UPPER}_KCONFIG}" 132 ) 133 endif() 134endforeach() 135 136# A list of common environment settings used when invoking Kconfig during CMake 137# configure time or menuconfig and related build target. 138string(REPLACE ";" "\\\;" SHIELD_AS_LIST_ESCAPED "${SHIELD_AS_LIST}") 139# cmake commands are escaped differently 140string(REPLACE ";" "\\;" SHIELD_AS_LIST_ESCAPED_COMMAND "${SHIELD_AS_LIST}") 141 142if(TOOLCHAIN_HAS_NEWLIB) 143 set(_local_TOOLCHAIN_HAS_NEWLIB y) 144else() 145 set(_local_TOOLCHAIN_HAS_NEWLIB n) 146endif() 147 148if(TOOLCHAIN_HAS_PICOLIBC) 149 set(_local_TOOLCHAIN_HAS_PICOLIBC y) 150else() 151 set(_local_TOOLCHAIN_HAS_PICOLIBC n) 152endif() 153 154set(COMMON_KCONFIG_ENV_SETTINGS 155 PYTHON_EXECUTABLE=${PYTHON_EXECUTABLE} 156 srctree=${ZEPHYR_BASE} 157 KERNELVERSION=${KERNELVERSION} 158 APPVERSION=${APP_VERSION_STRING} 159 APP_VERSION_EXTENDED_STRING=${APP_VERSION_EXTENDED_STRING} 160 APP_VERSION_TWEAK_STRING=${APP_VERSION_TWEAK_STRING} 161 CONFIG_=${KCONFIG_NAMESPACE}_ 162 KCONFIG_CONFIG=${DOTCONFIG} 163 KCONFIG_BOARD_DIR=${KCONFIG_BOARD_DIR} 164 BOARD=${BOARD} 165 BOARD_REVISION=${BOARD_REVISION} 166 BOARD_QUALIFIERS=${BOARD_QUALIFIERS} 167 HWM_SCHEME=${HWM} 168 KCONFIG_BINARY_DIR=${KCONFIG_BINARY_DIR} 169 APPLICATION_SOURCE_DIR=${APPLICATION_SOURCE_DIR} 170 ZEPHYR_TOOLCHAIN_VARIANT=${ZEPHYR_TOOLCHAIN_VARIANT} 171 TOOLCHAIN_KCONFIG_DIR=${TOOLCHAIN_KCONFIG_DIR} 172 TOOLCHAIN_HAS_NEWLIB=${_local_TOOLCHAIN_HAS_NEWLIB} 173 TOOLCHAIN_HAS_PICOLIBC=${_local_TOOLCHAIN_HAS_PICOLIBC} 174 EDT_PICKLE=${EDT_PICKLE} 175 # Export all Zephyr modules to Kconfig 176 ${ZEPHYR_KCONFIG_MODULES_DIR} 177) 178 179if(HWMv1) 180 list(APPEND COMMON_KCONFIG_ENV_SETTINGS 181 ARCH=${ARCH} 182 ARCH_DIR=${ARCH_DIR} 183 ) 184else() 185 # For HWMv2 we should in future generate a Kconfig.arch.v2 which instead 186 # glob-sources all arch roots, but for Zephyr itself, the current approach is 187 # sufficient. 188 list(APPEND COMMON_KCONFIG_ENV_SETTINGS 189 ARCH=* 190 ARCH_DIR=${ZEPHYR_BASE}/arch 191 ) 192endif() 193 194# Allow out-of-tree users to add their own Kconfig python frontend 195# targets by appending targets to the CMake list 196# 'EXTRA_KCONFIG_TARGETS' and setting variables named 197# 'EXTRA_KCONFIG_TARGET_COMMAND_FOR_<target>' 198# 199# e.g. 200# cmake -DEXTRA_KCONFIG_TARGETS=cli 201# -DEXTRA_KCONFIG_TARGET_COMMAND_FOR_cli=cli_kconfig_frontend.py 202 203set(EXTRA_KCONFIG_TARGET_COMMAND_FOR_menuconfig 204 ${ZEPHYR_BASE}/scripts/kconfig/menuconfig.py 205 ) 206 207set(EXTRA_KCONFIG_TARGET_COMMAND_FOR_guiconfig 208 ${ZEPHYR_BASE}/scripts/kconfig/guiconfig.py 209 ) 210 211set(EXTRA_KCONFIG_TARGET_COMMAND_FOR_hardenconfig 212 ${ZEPHYR_BASE}/scripts/kconfig/hardenconfig.py 213 ) 214 215set_ifndef(KCONFIG_TARGETS menuconfig guiconfig hardenconfig) 216 217foreach(kconfig_target 218 ${KCONFIG_TARGETS} 219 ${EXTRA_KCONFIG_TARGETS} 220 ) 221 add_custom_target( 222 ${kconfig_target} 223 ${CMAKE_COMMAND} -E env 224 ZEPHYR_BASE=${ZEPHYR_BASE} 225 ${COMMON_KCONFIG_ENV_SETTINGS} 226 "SHIELD_AS_LIST=${SHIELD_AS_LIST_ESCAPED}" 227 DTS_POST_CPP=${DTS_POST_CPP} 228 DTS_ROOT_BINDINGS=${DTS_ROOT_BINDINGS} 229 ${PTY_INTERFACE} 230 ${PYTHON_EXECUTABLE} 231 ${EXTRA_KCONFIG_TARGET_COMMAND_FOR_${kconfig_target}} 232 ${KCONFIG_ROOT} 233 WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/kconfig 234 USES_TERMINAL 235 COMMAND_EXPAND_LISTS 236 ) 237endforeach() 238 239# Support assigning Kconfig symbols on the command-line with CMake 240# cache variables prefixed according to the Kconfig namespace. 241# This feature is experimental and undocumented until it has undergone more 242# user-testing. 243unset(EXTRA_KCONFIG_OPTIONS) 244if(SYSBUILD) 245 get_property(sysbuild_variable_names TARGET sysbuild_cache PROPERTY "SYSBUILD_CACHE:VARIABLES") 246 zephyr_get(SYSBUILD_MAIN_APP) 247 zephyr_get(SYSBUILD_NAME) 248 249 foreach (name ${sysbuild_variable_names}) 250 if("${name}" MATCHES "^${SYSBUILD_NAME}_${KCONFIG_NAMESPACE}_") 251 string(REGEX REPLACE "^${SYSBUILD_NAME}_" "" org_name ${name}) 252 get_property(${org_name} TARGET sysbuild_cache PROPERTY ${name}) 253 list(APPEND cache_variable_names ${org_name}) 254 elseif(SYSBUILD_MAIN_APP AND "${name}" MATCHES "^${KCONFIG_NAMESPACE}_") 255 get_property(${name} TARGET sysbuild_cache PROPERTY ${name}) 256 list(APPEND cache_variable_names ${name}) 257 endif() 258 endforeach() 259else() 260 get_cmake_property(cache_variable_names CACHE_VARIABLES) 261 list(FILTER cache_variable_names INCLUDE REGEX "^(CLI_)?${KCONFIG_NAMESPACE}_") 262 list(TRANSFORM cache_variable_names REPLACE "^CLI_" "") 263 list(REMOVE_DUPLICATES cache_variable_names) 264endif() 265 266# Sorting the variable names will make checksum calculation more stable. 267list(SORT cache_variable_names) 268foreach (name ${cache_variable_names}) 269 if(DEFINED ${name}) 270 # When a cache variable starts with the 'KCONFIG_NAMESPACE' value, it is 271 # assumed to be a Kconfig symbol assignment from the CMake command line. 272 set(EXTRA_KCONFIG_OPTIONS 273 "${EXTRA_KCONFIG_OPTIONS}\n${name}=${${name}}" 274 ) 275 set(CLI_${name} "${${name}}") 276 list(APPEND cli_config_list ${name}) 277 elseif(DEFINED CLI_${name}) 278 # An additional 'CLI_' prefix means that the value was set by the user in 279 # an earlier invocation. Append it to extra config only if no new value was 280 # assigned above. 281 set(EXTRA_KCONFIG_OPTIONS 282 "${EXTRA_KCONFIG_OPTIONS}\n${name}=${CLI_${name}}" 283 ) 284 endif() 285endforeach() 286 287if(EXTRA_KCONFIG_OPTIONS) 288 set(EXTRA_KCONFIG_OPTIONS_FILE ${PROJECT_BINARY_DIR}/misc/generated/extra_kconfig_options.conf) 289 file(WRITE 290 ${EXTRA_KCONFIG_OPTIONS_FILE} 291 ${EXTRA_KCONFIG_OPTIONS} 292 ) 293endif() 294 295# Bring in extra configuration files dropped in by the user or anyone else; 296# make sure they are set at the end so we can override any other setting 297file(GLOB config_files ${APPLICATION_BINARY_DIR}/*.conf) 298list(SORT config_files) 299set( 300 merge_config_files 301 ${BOARD_DEFCONFIG} 302 ${BOARD_REVISION_CONFIG} 303 ${board_extension_conf_files} 304 ${CONF_FILE_AS_LIST} 305 ${shield_conf_files} 306 ${EXTRA_CONF_FILE_AS_LIST} 307 ${EXTRA_KCONFIG_OPTIONS_FILE} 308 ${config_files} 309) 310 311# Create a list of absolute paths to the .config sources from 312# merge_config_files, which is a mix of absolute and relative paths. 313set(merge_config_files_with_absolute_paths "") 314foreach(f ${merge_config_files}) 315 if(IS_ABSOLUTE ${f}) 316 set(path ${f}) 317 else() 318 set(path ${APPLICATION_CONFIG_DIR}/${f}) 319 endif() 320 321 list(APPEND merge_config_files_with_absolute_paths ${path}) 322endforeach() 323set(merge_config_files ${merge_config_files_with_absolute_paths}) 324 325foreach(f ${merge_config_files}) 326 if(NOT EXISTS ${f} OR IS_DIRECTORY ${f}) 327 message(FATAL_ERROR "File not found: ${f}") 328 endif() 329endforeach() 330 331# Calculate a checksum of merge_config_files to determine if we need 332# to re-generate .config 333set(merge_config_files_checksum "") 334foreach(f ${merge_config_files}) 335 file(MD5 ${f} checksum) 336 set(merge_config_files_checksum "${merge_config_files_checksum}${checksum}") 337endforeach() 338 339# Create a new .config if it does not exists, or if the checksum of 340# the dependencies has changed 341set(merge_config_files_checksum_file ${PROJECT_BINARY_DIR}/.cmake.dotconfig.checksum) 342set(CREATE_NEW_DOTCONFIG 1) 343# Check if the checksum file exists too before trying to open it, though it 344# should under normal circumstances 345if(EXISTS ${DOTCONFIG} AND EXISTS ${merge_config_files_checksum_file}) 346 # Read out what the checksum was previously 347 file(READ 348 ${merge_config_files_checksum_file} 349 merge_config_files_checksum_prev 350 ) 351 if( 352 ${merge_config_files_checksum} STREQUAL 353 ${merge_config_files_checksum_prev} 354 ) 355 # Checksum is the same as before 356 set(CREATE_NEW_DOTCONFIG 0) 357 endif() 358endif() 359 360if(CREATE_NEW_DOTCONFIG) 361 set(input_configs_flags --handwritten-input-configs) 362 set(input_configs ${merge_config_files} ${FORCED_CONF_FILE}) 363 build_info(kconfig files PATH ${input_configs}) 364else() 365 set(input_configs ${DOTCONFIG} ${FORCED_CONF_FILE}) 366endif() 367 368if(DEFINED FORCED_CONF_FILE) 369 list(APPEND input_configs_flags --forced-input-configs) 370endif() 371 372cmake_path(GET AUTOCONF_H PARENT_PATH autoconf_h_path) 373if(NOT EXISTS ${autoconf_h_path}) 374 file(MAKE_DIRECTORY ${autoconf_h_path}) 375endif() 376 377execute_process( 378 COMMAND ${CMAKE_COMMAND} -E env 379 ${COMMON_KCONFIG_ENV_SETTINGS} 380 SHIELD_AS_LIST=${SHIELD_AS_LIST_ESCAPED_COMMAND} 381 ${PYTHON_EXECUTABLE} 382 ${ZEPHYR_BASE}/scripts/kconfig/kconfig.py 383 --zephyr-base=${ZEPHYR_BASE} 384 ${input_configs_flags} 385 ${KCONFIG_ROOT} 386 ${DOTCONFIG} 387 ${AUTOCONF_H} 388 ${PARSED_KCONFIG_SOURCES_TXT} 389 ${input_configs} 390 WORKING_DIRECTORY ${APPLICATION_SOURCE_DIR} 391 # The working directory is set to the app dir such that the user 392 # can use relative paths in CONF_FILE, e.g. CONF_FILE=nrf5.conf 393 RESULT_VARIABLE ret 394 ) 395if(NOT "${ret}" STREQUAL "0") 396 message(FATAL_ERROR "command failed with return code: ${ret}") 397endif() 398 399if(CREATE_NEW_DOTCONFIG) 400 # Write the new configuration fragment checksum. Only do this if kconfig.py 401 # succeeds, to avoid marking zephyr/.config as up-to-date when it hasn't been 402 # regenerated. 403 file(WRITE ${merge_config_files_checksum_file} 404 ${merge_config_files_checksum}) 405endif() 406 407# Read out the list of 'Kconfig' sources that were used by the engine. 408file(STRINGS ${PARSED_KCONFIG_SOURCES_TXT} PARSED_KCONFIG_SOURCES_LIST ENCODING UTF-8) 409 410# Force CMAKE configure when the Kconfig sources or configuration files changes. 411foreach(kconfig_input 412 ${merge_config_files} 413 ${DOTCONFIG} 414 ${PARSED_KCONFIG_SOURCES_LIST} 415 ) 416 set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${kconfig_input}) 417endforeach() 418 419add_custom_target(config-twister DEPENDS ${DOTCONFIG}) 420 421# Remove the CLI Kconfig symbols from the namespace and 422# CMakeCache.txt. If the symbols end up in DOTCONFIG they will be 423# re-introduced to the namespace through 'import_kconfig'. 424foreach (name ${cli_config_list}) 425 unset(${name}) 426 unset(${name} CACHE) 427endforeach() 428 429# Before importing the symbol values from DOTCONFIG, process the CLI values by 430# re-importing them from EXTRA_KCONFIG_OPTIONS_FILE. Later, we want to compare 431# the values from both files, and 'import_kconfig' will make this easier. 432if(EXTRA_KCONFIG_OPTIONS_FILE) 433 import_kconfig(${KCONFIG_NAMESPACE} ${EXTRA_KCONFIG_OPTIONS_FILE}) 434 foreach (name ${cache_variable_names}) 435 if(DEFINED ${name}) 436 set(temp_${name} "${${name}}") 437 unset(${name}) 438 endif() 439 endforeach() 440endif() 441 442# Import the .config file and make all settings available in CMake processing. 443import_kconfig(${KCONFIG_NAMESPACE} ${DOTCONFIG}) 444 445# Cache the CLI Kconfig symbols that survived through Kconfig, prefixed with CLI_. 446# Remove those who might have changed compared to earlier runs, if they no longer appears. 447foreach (name ${cache_variable_names}) 448 # Note: "${CLI_${name}}" is the verbatim value of ${name} from command-line, 449 # while "${temp_${name}}" is the same value processed by 'import_kconfig'. 450 if(((NOT DEFINED ${name}) AND (NOT DEFINED temp_${name})) OR 451 ((DEFINED ${name}) AND (DEFINED temp_${name}) AND (${name} STREQUAL temp_${name}))) 452 set(CLI_${name} ${CLI_${name}} CACHE INTERNAL "") 453 else() 454 unset(CLI_${name} CACHE) 455 endif() 456 unset(temp_${name}) 457endforeach() 458