1# SPDX-License-Identifier: Apache-2.0
2
3# Folders needed for conf/mconf files (kconfig has no method of redirecting all output files).
4# conf/mconf needs to be run from a different directory because of: GH-3408
5file(MAKE_DIRECTORY ${APPLICATION_BINARY_DIR}/kconfig/include/generated)
6file(MAKE_DIRECTORY ${APPLICATION_BINARY_DIR}/kconfig/include/config)
7
8if(KCONFIG_ROOT)
9  # KCONFIG_ROOT has either been specified as a CMake variable or is
10  # already in the CMakeCache.txt. This has precedence.
11elseif(EXISTS   ${APPLICATION_SOURCE_DIR}/Kconfig)
12  set(KCONFIG_ROOT ${APPLICATION_SOURCE_DIR}/Kconfig)
13endif()
14
15if (EXISTS ${BOARD_DIR}/${BOARD}_defconfig)
16set(BOARD_DEFCONFIG ${BOARD_DIR}/${BOARD}_defconfig)
17endif()
18
19if(EXISTS ${APPLICATION_SOURCE_DIR}/config.cmake)
20  set(DOTCONFIG_IN                ${APPLICATION_SOURCE_DIR}/config.cmake)
21else()
22  set(DOTCONFIG_IN                ${APPLICATION_SOURCE_DIR}/.config)
23endif()
24set(DOTCONFIG_OUT                ${APPLICATION_SOURCE_DIR}/.config)
25set(PARSED_KCONFIG_SOURCES_TXT ${APPLICATION_BINARY_DIR}/kconfig/sources.txt)
26
27if(CONF_FILE)
28string(REPLACE " " ";" CONF_FILE_AS_LIST "${CONF_FILE}")
29endif()
30
31if(OVERLAY_CONFIG)
32  string(REPLACE " " ";" OVERLAY_CONFIG_AS_LIST "${OVERLAY_CONFIG}")
33endif()
34
35# DTS_ROOT_BINDINGS is a semicolon separated list, this causes
36# problems when invoking kconfig_target since semicolon is a special
37# character in the C shell, so we make it into a question-mark
38# separated list instead.
39string(REPLACE ";" "?" DTS_ROOT_BINDINGS "${DTS_ROOT_BINDINGS}")
40
41set(ENV{srctree}            ${PROJECT_ROOT})
42set(ENV{KCONFIG_BASE}       ${PROJECT_ROOT})
43
44# Not used in current MCUXpresso SDK, take from zephyr cmake build system
45set(ENV{KERNELVERSION}      ${KERNELVERSION})
46
47set(ENV{KCONFIG_CONFIG}     ${DOTCONFIG_IN})
48set(ENV{PYTHON_EXECUTABLE}  ${PYTHON_EXECUTABLE})
49
50message("project root: ${PROJECT_ROOT}")
51
52# Set environment variables so that Kconfig can prune Kconfig source
53# files for other architectures
54set(ENV{BOARD_DIR} ${BOARD_DIR})
55
56# Below environment variables currently not used in MCUXpresso SDK, take from zephyr cmake build system, remain it for future use.
57set(ENV{ARCH}      ${ARCH})
58set(ENV{SOC_DIR}   ${SOC_DIR})
59set(ENV{SHIELD_AS_LIST} "${SHIELD_AS_LIST}")
60set(ENV{CMAKE_BINARY_DIR} ${CMAKE_BINARY_DIR})
61set(ENV{ARCH_DIR}   ${ARCH_DIR})
62set(ENV{DEVICETREE_CONF} ${DEVICETREE_CONF})
63set(ENV{DTS_POST_CPP} ${DTS_POST_CPP})
64set(ENV{DTS_ROOT_BINDINGS} "${DTS_ROOT_BINDINGS}")
65set(ENV{TOOLCHAIN_KCONFIG_DIR} "${TOOLCHAIN_KCONFIG_DIR}")
66
67# Allow out-of-tree users to add their own Kconfig python frontend
68# targets by appending targets to the CMake list
69# 'EXTRA_KCONFIG_TARGETS' and setting variables named
70# 'EXTRA_KCONFIG_TARGET_COMMAND_FOR_<target>'
71#
72# e.g.
73# cmake -DEXTRA_KCONFIG_TARGETS=cli
74# -DEXTRA_KCONFIG_TARGET_COMMAND_FOR_cli=cli_kconfig_frontend.py
75
76set(EXTRA_KCONFIG_TARGET_COMMAND_FOR_menuconfig
77  ${PROJECT_ROOT}/scripts/kconfig/menuconfig.py
78  )
79
80set(EXTRA_KCONFIG_TARGET_COMMAND_FOR_guiconfig
81  ${PROJECT_ROOT}/scripts/kconfig/guiconfig.py
82  )
83
84set(EXTRA_KCONFIG_TARGET_COMMAND_FOR_hardenconfig
85  ${PROJECT_ROOT}/scripts/kconfig/hardenconfig.py
86  )
87
88foreach(kconfig_target
89    menuconfig
90    guiconfig
91    hardenconfig
92    ${EXTRA_KCONFIG_TARGETS}
93    )
94  add_custom_target(
95    ${kconfig_target}
96    ${CMAKE_COMMAND} -E env
97    PYTHON_EXECUTABLE=${PYTHON_EXECUTABLE}
98    KCONFIG_BASE=${PROJECT_ROOT}
99    KCONFIG_CONFIG=${DOTCONFIG_IN}
100    ARCH=$ENV{ARCH}
101    BOARD_DIR=$ENV{BOARD_DIR}
102    SOC_DIR=$ENV{SOC_DIR}
103    SHIELD_AS_LIST=$ENV{SHIELD_AS_LIST}
104    CMAKE_BINARY_DIR=$ENV{CMAKE_BINARY_DIR}
105    TOOLCHAIN_KCONFIG_DIR=${TOOLCHAIN_KCONFIG_DIR}
106    ARCH_DIR=$ENV{ARCH_DIR}
107    DEVICETREE_CONF=${DEVICETREE_CONF}
108    DTS_POST_CPP=${DTS_POST_CPP}
109    DTS_ROOT_BINDINGS=${DTS_ROOT_BINDINGS}
110    ${PYTHON_EXECUTABLE}
111    ${PROJECT_ROOT}/scripts/kconfig/mcux.py
112    ${kconfig_target}
113    ${KCONFIG_ROOT}
114    WORKING_DIRECTORY ${APPLICATION_BINARY_DIR}/kconfig
115    USES_TERMINAL
116    )
117endforeach()
118
119# Support assigning Kconfig symbols on the command-line with CMake
120# cache variables prefixed with 'CONFIG_'. This feature is
121# experimental and undocumented until it has undergone more
122# user-testing.
123unset(EXTRA_KCONFIG_OPTIONS)
124get_cmake_property(cache_variable_names CACHE_VARIABLES)
125foreach (name ${cache_variable_names})
126  if("${name}" MATCHES "^CONFIG_")
127    # When a cache variable starts with 'CONFIG_', it is assumed to be
128    # a Kconfig symbol assignment from the CMake command line.
129    set(EXTRA_KCONFIG_OPTIONS
130      "${EXTRA_KCONFIG_OPTIONS}\n${name}=${${name}}"
131      )
132  endif()
133endforeach()
134
135if(EXTRA_KCONFIG_OPTIONS)
136  set(EXTRA_KCONFIG_OPTIONS_FILE ${APPLICATION_BINARY_DIR}/misc/generated/extra_kconfig_options.conf)
137  file(WRITE
138    ${EXTRA_KCONFIG_OPTIONS_FILE}
139    ${EXTRA_KCONFIG_OPTIONS}
140    )
141endif()
142
143# Bring in extra configuration files dropped in by the user or anyone else;
144# make sure they are set at the end so we can override any other setting
145set(config_files ${APPLICATION_SOURCE_DIR}/config.cmake)
146set(
147  merge_config_files
148  ${BOARD_DEFCONFIG}
149  ${CONF_FILE_AS_LIST}
150  ${shield_conf_files}
151  ${OVERLAY_CONFIG_AS_LIST}
152  ${EXTRA_KCONFIG_OPTIONS_FILE}
153  ${config_files}
154)
155
156# Create a list of absolute paths to the .config sources from
157# merge_config_files, which is a mix of absolute and relative paths.
158set(merge_config_files_with_absolute_paths "")
159foreach(f ${merge_config_files})
160  if(IS_ABSOLUTE ${f})
161    set(path ${f})
162  else()
163    set(path ${APPLICATION_SOURCE_DIR}/${f})
164  endif()
165
166  list(APPEND merge_config_files_with_absolute_paths ${path})
167endforeach()
168
169foreach(f ${merge_config_files_with_absolute_paths})
170  if(NOT EXISTS ${f} OR IS_DIRECTORY ${f})
171    message(FATAL_ERROR "File not found: ${f}")
172  endif()
173endforeach()
174
175# Calculate a checksum of merge_config_files to determine if we need
176# to re-generate .config
177set(merge_config_files_checksum "")
178foreach(f ${merge_config_files_with_absolute_paths})
179  file(MD5 ${f} checksum)
180  set(merge_config_files_checksum "${merge_config_files_checksum}${checksum}")
181endforeach()
182
183# Create a new .config if it does not exists, or if the checksum of
184# the dependencies has changed
185set(merge_config_files_checksum_file ${APPLICATION_BINARY_DIR}/.cmake.dotconfig.checksum)
186set(CREATE_NEW_DOTCONFIG 1)
187# Check if the checksum file exists too before trying to open it, though it
188# should under normal circumstances
189if(EXISTS ${DOTCONFIG_OUT} AND EXISTS ${merge_config_files_checksum_file})
190  # Read out what the checksum was previously
191  file(READ
192    ${merge_config_files_checksum_file}
193    merge_config_files_checksum_prev
194    )
195  if(
196      ${merge_config_files_checksum} STREQUAL
197      ${merge_config_files_checksum_prev}
198      )
199    # Checksum is the same as before
200    set(CREATE_NEW_DOTCONFIG 0)
201  endif()
202endif()
203
204if(CREATE_NEW_DOTCONFIG)
205#  set(input_configs_are_handwritten --handwritten-input-configs="")
206  set(input_configs ${merge_config_files})
207else()
208  set(input_configs ${DOTCONFIG_IN})
209endif()
210
211
212message(
213  ${PYTHON_EXECUTABLE}
214  ${PROJECT_ROOT}/scripts/kconfig/kconfig.py
215  ${input_configs_are_handwritten}
216  ${KCONFIG_ROOT}
217  ${DOTCONFIG_OUT}
218  ${AUTOCONF_H}
219  ${PARSED_KCONFIG_SOURCES_TXT}
220  ${input_configs}
221  )
222execute_process(
223  COMMAND
224  ${PYTHON_EXECUTABLE}
225  ${PROJECT_ROOT}/scripts/kconfig/kconfig.py
226  ${input_configs_are_handwritten}
227  ${KCONFIG_ROOT}
228  ${DOTCONFIG_OUT}
229  ${AUTOCONF_H}
230  ${PARSED_KCONFIG_SOURCES_TXT}
231  ${input_configs}
232  WORKING_DIRECTORY ${PROJECT_ROOT}
233  # The working directory is set to the app dir such that the user
234  # can use relative paths in CONF_FILE, e.g. CONF_FILE=nrf5.conf
235  RESULT_VARIABLE ret
236  )
237if(NOT "${ret}" STREQUAL "0")
238  message(FATAL_ERROR "command failed with return code: ${ret}")
239endif()
240
241if(CREATE_NEW_DOTCONFIG)
242  # Write the new configuration fragment checksum. Only do this if kconfig.py
243  # succeeds, to avoid marking APPLICATION_BINARY_DIR/.config as up-to-date when it hasn't been
244  # regenerated.
245  file(WRITE ${merge_config_files_checksum_file}
246             ${merge_config_files_checksum})
247endif()
248
249# Read out the list of 'Kconfig' sources that were used by the engine.
250file(STRINGS ${PARSED_KCONFIG_SOURCES_TXT} PARSED_KCONFIG_SOURCES_LIST)
251
252# Force CMAKE configure when the Kconfig sources or configuration files changes.
253foreach(kconfig_input
254    ${merge_config_files}
255    ${DOTCONFIG_IN}
256    ${PARSED_KCONFIG_SOURCES_LIST}
257    )
258  set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${kconfig_input})
259endforeach()
260
261add_custom_target(config-sanitycheck DEPENDS ${DOTCONFIG_OUT})
262
263# Remove the CLI Kconfig symbols from the namespace and
264# CMakeCache.txt. If the symbols end up in DOTCONFIG they will be
265# re-introduced to the namespace through 'import_kconfig'.
266foreach (name ${cache_variable_names})
267  if("${name}" MATCHES "^CONFIG_")
268    unset(${name})
269    unset(${name} CACHE)
270  endif()
271endforeach()
272
273# Parse the lines prefixed with CONFIG_ in the .config file from Kconfig
274import_kconfig("^CONFIG_" ${DOTCONFIG_OUT})
275
276# Re-introduce the CLI Kconfig symbols that survived
277foreach (name ${cache_variable_names})
278  if("${name}" MATCHES "^CONFIG_")
279    if(DEFINED ${name})
280      set(${name} ${${name}} CACHE STRING "")
281    endif()
282  endif()
283endforeach()
284