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