kconfig: provide an option for enforcing Kconfig settings

This commit introduces an internal FORCE_CONF_FILE CMake setting which
allows higher order build systems to generate a configuration file
which will always take precedence.

This means that in case a user tries to change any setting to be
different than the defined value in the FORCE_CONF_FILE provide file(s),
then a warning will be printed and the setting will be reset to the
value given in the FORCE_CONF_FILE file.

Example of such warning:
   <path>/.config.sysbuild:1: warning: BOOTLOADER_MCUBOOT
   (defined at Kconfig.zephyr:766) set more than once.
   Old value "n", new value "y".

Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no>
This commit is contained in:
Torsten Rasmussen 2023-03-16 14:49:59 +01:00 committed by Carles Cufí
commit 5c71e68607
2 changed files with 40 additions and 6 deletions

View file

@ -306,10 +306,14 @@ if(EXISTS ${DOTCONFIG} AND EXISTS ${merge_config_files_checksum_file})
endif() endif()
if(CREATE_NEW_DOTCONFIG) if(CREATE_NEW_DOTCONFIG)
set(input_configs_are_handwritten --handwritten-input-configs) set(input_configs_flags --handwritten-input-configs)
set(input_configs ${merge_config_files}) set(input_configs ${merge_config_files} ${FORCED_CONF_FILE})
else() else()
set(input_configs ${DOTCONFIG}) set(input_configs ${DOTCONFIG} ${FORCED_CONF_FILE})
endif()
if(DEFINED FORCED_CONF_FILE)
list(APPEND input_configs_flags --forced-input-configs)
endif() endif()
cmake_path(GET AUTOCONF_H PARENT_PATH autoconf_h_path) cmake_path(GET AUTOCONF_H PARENT_PATH autoconf_h_path)
@ -324,7 +328,7 @@ execute_process(
${PYTHON_EXECUTABLE} ${PYTHON_EXECUTABLE}
${ZEPHYR_BASE}/scripts/kconfig/kconfig.py ${ZEPHYR_BASE}/scripts/kconfig/kconfig.py
--zephyr-base=${ZEPHYR_BASE} --zephyr-base=${ZEPHYR_BASE}
${input_configs_are_handwritten} ${input_configs_flags}
${KCONFIG_ROOT} ${KCONFIG_ROOT}
${DOTCONFIG} ${DOTCONFIG}
${AUTOCONF_H} ${AUTOCONF_H}

View file

@ -11,6 +11,7 @@
import argparse import argparse
import os import os
import re
import sys import sys
import textwrap import textwrap
@ -41,7 +42,16 @@ def main():
kconf.warn_assign_override = False kconf.warn_assign_override = False
kconf.warn_assign_redun = False kconf.warn_assign_redun = False
# Load configuration files if args.forced_input_configs:
# Do not warn on a redundant config.
# The reason is that a regular .config will be followed by the forced
# config which under normal circumstances should be identical to the
# configured setting.
# Only if user has modified to a value that gets overruled by the forced
# a warning shall be issued.
kconf.warn_assign_redun = False
# Load files
print(kconf.load_config(args.configs_in[0])) print(kconf.load_config(args.configs_in[0]))
for config in args.configs_in[1:]: for config in args.configs_in[1:]:
# replace=False creates a merged configuration # replace=False creates a merged configuration
@ -76,18 +86,30 @@ def main():
# fast. # fast.
kconf.write_config(os.devnull) kconf.write_config(os.devnull)
warn_only = r"warning:.*set more than once."
if kconf.warnings: if kconf.warnings:
if args.forced_input_configs:
error_out = False
else:
error_out = True
# Put a blank line between warnings to make them easier to read # Put a blank line between warnings to make them easier to read
for warning in kconf.warnings: for warning in kconf.warnings:
print("\n" + warning, file=sys.stderr) print("\n" + warning, file=sys.stderr)
if not error_out and not re.search(warn_only, warning):
# The warning is not a warn_only, fail the Kconfig.
error_out = True
# Turn all warnings into errors, so that e.g. assignments to undefined # Turn all warnings into errors, so that e.g. assignments to undefined
# Kconfig symbols become errors. # Kconfig symbols become errors.
# #
# A warning is generated by this script whenever a symbol gets a # A warning is generated by this script whenever a symbol gets a
# different value than the one it was assigned. Keep that one as just a # different value than the one it was assigned. Keep that one as just a
# warning for now. # warning for now.
err("Aborting due to Kconfig warnings") if error_out:
err("Aborting due to Kconfig warnings")
# Write the merged configuration and the C header # Write the merged configuration and the C header
print(kconf.write_config(args.config_out)) print(kconf.write_config(args.config_out))
@ -258,6 +280,14 @@ def parse_args():
"handwritten fragments and do additional checks " "handwritten fragments and do additional checks "
"on them, like no promptless symbols being " "on them, like no promptless symbols being "
"assigned") "assigned")
parser.add_argument("--forced-input-configs",
action="store_true",
help="Indicate the input configuration files are "
"followed by an forced configuration file."
"The forced configuration is used to forcefully "
"set specific configuration settings to a "
"pre-defined value and thereby remove any user "
" adjustments.")
parser.add_argument("--zephyr-base", parser.add_argument("--zephyr-base",
help="Path to current Zephyr installation") help="Path to current Zephyr installation")
parser.add_argument("kconfig_file", parser.add_argument("kconfig_file",