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