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