diff --git a/SConstruct b/SConstruct index e27a97eb40..5ae1080cff 100755 --- a/SConstruct +++ b/SConstruct @@ -260,8 +260,9 @@ Targets: ######################################################################## kconfig_actions = ( - 'menuconfig', 'defconfig', + 'menuconfig', + 'setconfig', ) Help(""" @@ -283,6 +284,15 @@ Kconfig: kernel versions will typically (but not always) apply here as well. Kconfig tools: + defconfig: + Set up a config using values specified in a defconfig file, or if no + value is given, use the default. The second argument specifies the + defconfig file. A defconfig file in the build_opts directory can be + implicitly specified in the build path via `build//` + + scons defconfig build/foo/bar build_opts/MIPS + + menuconfig: Opens the menuconfig editor which will let you view and edit config values, and view help text. menuconfig runs in text mode. @@ -290,13 +300,11 @@ Kconfig tools: scons menuconfig build/foo/bar - defconfig: - Set up a config using values specified in a defconfig file, or if no - value is given, use the default. The second argument specifies the - defconfig file. A defconfig file in the defconfig directory can be - implicitly specified in the build path via `build//` + setconfig: + Set values in an existing config directory as specified on the command + line. For example, to enable gem5's built in systemc kernel: - scons defconfig build/foo/bar build_opts/MIPS + scons setconfig build/foo/bar USE_SYSTEMC=y """, append=True) # Take a list of paths (or SCons Nodes) and return a list with all @@ -817,15 +825,18 @@ for variant_path in variant_paths: # Handle any requested kconfig action, then exit. if kconfig_action: - if kconfig_action == 'menuconfig': - kconfig.menuconfig(env, kconfig_file.abspath, config_file.abspath, - variant_path) - elif kconfig_action == 'defconfig': + if kconfig_action == 'defconfig': if len(kconfig_args) != 1: error('Usage: scons defconfig ') defconfig_path = makePathAbsolute(kconfig_args[0]) kconfig.defconfig(env, kconfig_file.abspath, defconfig_path, config_file.abspath) + elif kconfig_action == 'menuconfig': + kconfig.menuconfig(env, kconfig_file.abspath, config_file.abspath, + variant_path) + elif kconfig_action == 'setconfig': + kconfig.setconfig(env, kconfig_file.abspath, config_file.abspath, + ARGUMENTS) else: error(f'Unrecognized kconfig action {kconfig_action}') Exit(0) diff --git a/site_scons/gem5_scons/kconfig.py b/site_scons/gem5_scons/kconfig.py index d609e24875..0251fdd8ea 100644 --- a/site_scons/gem5_scons/kconfig.py +++ b/site_scons/gem5_scons/kconfig.py @@ -28,6 +28,12 @@ import os from . import error import kconfiglib +_kconfig_helpers = { + "DEFCONFIG_PY": "defconfig.py", + "MENUCONFIG_PY": "menuconfig.py", + "SETCONFIG_PY": "setconfig.py", +} + def _prep_env(env, base_kconfig, config_path=None): """ @@ -47,17 +53,31 @@ def _prep_env(env, base_kconfig, config_path=None): if config_path: kconfig_env["ENV"]["KCONFIG_CONFIG"] = config_path + kconfig_env["BASE_KCONFIG"] = base_kconfig + ext = env.Dir("#ext") kconfiglib_dir = ext.Dir("Kconfiglib") - defconfig_py = kconfiglib_dir.File("defconfig.py") - menuconfig_py = kconfiglib_dir.File("menuconfig.py") - - kconfig_env["DEFCONFIG_PY"] = defconfig_py - kconfig_env["MENUCONFIG_PY"] = menuconfig_py - kconfig_env["BASE_KCONFIG"] = base_kconfig + for key, name in _kconfig_helpers.items(): + kconfig_env[key] = kconfiglib_dir.File(name) return kconfig_env +def _process_kconfig(env, base_kconfig): + """ + Create the kconfig instance by given Scons env vars + + :param env: Scons env + :param base_kconfig: path to the Top-level Kconfig file + """ + saved_env = os.environ + try: + os.environ.update({key: str(val) for key, val in env["ENV"].items()}) + kconfig = kconfiglib.Kconfig(filename=base_kconfig) + finally: + os.environ = saved_env + return kconfig + + def defconfig(env, base_kconfig, config_in, config_out): """ Interface of handling defconfig.py of Kconfiglib @@ -86,6 +106,29 @@ def menuconfig( error("Failed to run menuconfig") +def setconfig(env, base_kconfig, config_path, assignments): + """ + Interface of handling setconfig.py of Kconfiglib + """ + kconfig_env = _prep_env(env, base_kconfig, config_path) + + kconfig = _process_kconfig(kconfig_env, base_kconfig) + sym_names = list(sym.name for sym in kconfig.unique_defined_syms) + + filtered = dict( + {key: val for key, val in assignments.items() if key in sym_names} + ) + + setconfig_cmd_parts = ['"${SETCONFIG_PY}" --kconfig "${BASE_KCONFIG}"'] + for key, val in filtered.items(): + if isinstance(val, bool): + val = "y" if val else "n" + setconfig_cmd_parts.append(f"{key}={val}") + setconfig_cmd = " ".join(setconfig_cmd_parts) + if kconfig_env.Execute(setconfig_cmd) != 0: + error("Failed to run setconfig") + + def update_env(env, base_kconfig, config_path): """ Update the Scons' env["CONF"] options from kconfig env @@ -96,12 +139,7 @@ def update_env(env, base_kconfig, config_path): """ kconfig_env = _prep_env(env, base_kconfig, config_path) - saved_env = os.environ - os.environ.update( - {key: str(val) for key, val in kconfig_env["ENV"].items()} - ) - kconfig = kconfiglib.Kconfig(filename=base_kconfig) - os.environ = saved_env + kconfig = _process_kconfig(kconfig_env, base_kconfig) kconfig.load_config(config_path) for sym in kconfig.unique_defined_syms: