From 23ee93ea768e4faffb4ae88db6c07d2b9b9267d1 Mon Sep 17 00:00:00 2001 From: Roland Dobai Date: Thu, 14 Mar 2019 09:54:04 +0100 Subject: [PATCH] Rename deprecated Kconfig options in a backward compatible way --- Kconfig | 6 +- components/esptool_py/Makefile.projbuild | 4 +- examples/system/gcov/Makefile | 2 +- examples/system/gcov/README.md | 4 +- make/common.mk | 4 +- make/project.mk | 18 +-- make/project_config.mk | 33 +++- sdkconfig.rename | 7 + tools/ci/test_build_system.sh | 29 ++++ tools/ci/test_build_system_cmake.sh | 29 ++++ tools/cmake/kconfig.cmake | 8 +- tools/kconfig_new/confgen.py | 196 +++++++++++++++++++++-- tools/kconfig_new/confserver.py | 16 +- tools/ldgen/samples/sdkconfig | 6 +- 14 files changed, 314 insertions(+), 48 deletions(-) create mode 100644 sdkconfig.rename diff --git a/Kconfig b/Kconfig index a6aaa022c1..874bb6e9a6 100644 --- a/Kconfig +++ b/Kconfig @@ -25,14 +25,14 @@ mainmenu "Espressif IoT Development Framework Configuration" menu "SDK tool configuration" - config TOOLPREFIX + config SDK_TOOLPREFIX string "Compiler toolchain path/prefix" default "xtensa-esp32-elf-" help The prefix/path that is used to call the toolchain. The default setting assumes a crosstool-ng gcc setup that is in your PATH. - config PYTHON + config SDK_PYTHON string "Python 2 interpreter" depends on !IDF_CMAKE default "python" @@ -43,7 +43,7 @@ mainmenu "Espressif IoT Development Framework Configuration" (Note: This option is used with the GNU Make build system only, not idf.py or CMake-based builds.) - config MAKE_WARN_UNDEFINED_VARIABLES + config SDK_MAKE_WARN_UNDEFINED_VARIABLES bool "'make' warns on undefined variables" default "y" help diff --git a/components/esptool_py/Makefile.projbuild b/components/esptool_py/Makefile.projbuild index 092ac0e021..9cbab03831 100644 --- a/components/esptool_py/Makefile.projbuild +++ b/components/esptool_py/Makefile.projbuild @@ -8,7 +8,7 @@ ESPFLASHSIZE ?= $(CONFIG_ESPTOOLPY_FLASHSIZE) CONFIG_ESPTOOLPY_COMPRESSED ?= -PYTHON ?= $(call dequote,$(CONFIG_PYTHON)) +PYTHON ?= $(call dequote,$(CONFIG_SDK_PYTHON)) # two commands that can be used from other components # to invoke esptool.py (with or without serial port args) @@ -99,7 +99,7 @@ simple_monitor: $(call prereq_if_explicit,%flash) | check_python_dependencies PRINT_FILTER ?= -MONITOR_OPTS := --baud $(MONITORBAUD) --port $(ESPPORT) --toolchain-prefix $(CONFIG_TOOLPREFIX) --make "$(MAKE)" --print_filter "$(PRINT_FILTER)" +MONITOR_OPTS := --baud $(MONITORBAUD) --port $(ESPPORT) --toolchain-prefix $(CONFIG_SDK_TOOLPREFIX) --make "$(MAKE)" --print_filter "$(PRINT_FILTER)" monitor: $(call prereq_if_explicit,%flash) | check_python_dependencies $(summary) MONITOR diff --git a/examples/system/gcov/Makefile b/examples/system/gcov/Makefile index f31bb6a574..145ada5f3f 100644 --- a/examples/system/gcov/Makefile +++ b/examples/system/gcov/Makefile @@ -7,7 +7,7 @@ PROJECT_NAME := gcov_example include $(IDF_PATH)/make/project.mk -GCOV := $(call dequote,$(CONFIG_TOOLPREFIX))gcov +GCOV := $(call dequote,$(CONFIG_SDK_TOOLPREFIX))gcov REPORT_DIR := $(BUILD_DIR_BASE)/coverage_report lcov-report: diff --git a/examples/system/gcov/README.md b/examples/system/gcov/README.md index d1c7126b1d..941ae68c48 100644 --- a/examples/system/gcov/README.md +++ b/examples/system/gcov/README.md @@ -109,7 +109,7 @@ There are several ways to process collected data. Two of the most common are: Add the following lines to you project's `Makefile` after the line including `project.mk`: ``` -GCOV := $(call dequote,$(CONFIG_TOOLPREFIX))gcov +GCOV := $(call dequote,$(CONFIG_SDK_TOOLPREFIX))gcov REPORT_DIR := $(BUILD_DIR_BASE)/coverage_report lcov-report: @@ -160,4 +160,4 @@ Overall coverage rate: ``` NOTE: Since `lcov` tool is not part of GCC bundle it can happen that format of GCOV binary data has been changed and your local version of `lcov` fails to understand it. -So it always better to use the latest `lcov` version from [LCOV repo](https://github.com/linux-test-project/lcov). \ No newline at end of file +So it always better to use the latest `lcov` version from [LCOV repo](https://github.com/linux-test-project/lcov). diff --git a/make/common.mk b/make/common.mk index 468bf2c688..6280ca4a87 100644 --- a/make/common.mk +++ b/make/common.mk @@ -2,7 +2,7 @@ # and component makefiles (component_wrapper.mk) # -PYTHON=$(call dequote,$(CONFIG_PYTHON)) +PYTHON=$(call dequote,$(CONFIG_SDK_PYTHON)) # Include project config makefile, if it exists. # @@ -34,7 +34,7 @@ details := @true MAKEFLAGS += --silent endif # $(V)==1 -ifdef CONFIG_MAKE_WARN_UNDEFINED_VARIABLES +ifdef CONFIG_SDK_MAKE_WARN_UNDEFINED_VARIABLES MAKEFLAGS += --warn-undefined-variables endif diff --git a/make/project.mk b/make/project.mk index 034ad2a15e..2f1def70d2 100644 --- a/make/project.mk +++ b/make/project.mk @@ -471,13 +471,13 @@ export CFLAGS CPPFLAGS CXXFLAGS ARFLAGS # Set target compiler. Defaults to whatever the user has # configured as prefix + ye olde gcc commands -CC := $(call dequote,$(CONFIG_TOOLPREFIX))gcc -CXX := $(call dequote,$(CONFIG_TOOLPREFIX))c++ -LD := $(call dequote,$(CONFIG_TOOLPREFIX))ld -AR := $(call dequote,$(CONFIG_TOOLPREFIX))ar -OBJCOPY := $(call dequote,$(CONFIG_TOOLPREFIX))objcopy -OBJDUMP := $(call dequote,$(CONFIG_TOOLPREFIX))objdump -SIZE := $(call dequote,$(CONFIG_TOOLPREFIX))size +CC := $(call dequote,$(CONFIG_SDK_TOOLPREFIX))gcc +CXX := $(call dequote,$(CONFIG_SDK_TOOLPREFIX))c++ +LD := $(call dequote,$(CONFIG_SDK_TOOLPREFIX))ld +AR := $(call dequote,$(CONFIG_SDK_TOOLPREFIX))ar +OBJCOPY := $(call dequote,$(CONFIG_SDK_TOOLPREFIX))objcopy +OBJDUMP := $(call dequote,$(CONFIG_SDK_TOOLPREFIX))objdump +SIZE := $(call dequote,$(CONFIG_SDK_TOOLPREFIX))size export CC CXX LD AR OBJCOPY OBJDUMP SIZE COMPILER_VERSION_STR := $(shell $(CC) -dumpversion) @@ -665,7 +665,7 @@ print_flash_cmd: partition_table_get_info blank_ota_data # The output normally looks as follows # xtensa-esp32-elf-gcc (crosstool-NG crosstool-ng-1.22.0-80-g6c4433a) 5.2.0 # The part in brackets is extracted into TOOLCHAIN_COMMIT_DESC variable -ifdef CONFIG_TOOLPREFIX +ifdef CONFIG_SDK_TOOLPREFIX ifndef MAKE_RESTARTS TOOLCHAIN_HEADER := $(shell $(CC) --version | head -1) @@ -704,7 +704,7 @@ $(info WARNING: Failed to find Xtensa toolchain, may need to alter PATH or set o endif # TOOLCHAIN_COMMIT_DESC endif #MAKE_RESTARTS -endif #CONFIG_TOOLPREFIX +endif #CONFIG_SDK_TOOLPREFIX ##################################################################### endif #CONFIG_IDF_TARGET diff --git a/make/project_config.mk b/make/project_config.mk index 79a6efd01a..4ec591c6af 100644 --- a/make/project_config.mk +++ b/make/project_config.mk @@ -42,8 +42,24 @@ $(SDKCONFIG): defconfig endif endif +# macro for running confgen.py +define RunConfGen + mkdir -p $(BUILD_DIR_BASE)/include/config + $(PYTHON) $(IDF_PATH)/tools/kconfig_new/confgen.py \ + --kconfig $(IDF_PATH)/Kconfig \ + --config $(SDKCONFIG) \ + --env "COMPONENT_KCONFIGS=$(strip $(COMPONENT_KCONFIGS))" \ + --env "COMPONENT_KCONFIGS_PROJBUILD=$(strip $(COMPONENT_KCONFIGS_PROJBUILD))" \ + --env "IDF_CMAKE=n" \ + --output config ${SDKCONFIG} \ + --output makefile $(SDKCONFIG_MAKEFILE) \ + --output header $(BUILD_DIR_BASE)/include/sdkconfig.h +endef + # macro for the commands to run kconfig tools conf-idf or mconf-idf. # $1 is the name (& args) of the conf tool to run +# Note: Currently only mconf-idf is used for compatibility with the CMake build system. The header file used is also +# the same. define RunConf mkdir -p $(BUILD_DIR_BASE)/include/config cd $(BUILD_DIR_BASE); KCONFIG_AUTOHEADER=$(abspath $(BUILD_DIR_BASE)/include/sdkconfig.h) \ @@ -65,7 +81,7 @@ ifndef MAKE_RESTARTS # depend on any prerequisite that may cause a make restart as part of # the prerequisite's own recipe. -menuconfig: $(KCONFIG_TOOL_DIR)/mconf-idf +menuconfig: $(KCONFIG_TOOL_DIR)/mconf-idf | check_python_dependencies $(summary) MENUCONFIG ifdef BATCH_BUILD @echo "Can't run interactive configuration inside non-interactive build process." @@ -74,25 +90,26 @@ ifdef BATCH_BUILD @echo "See esp-idf documentation for more details." @exit 1 else + $(call RunConfGen) + # RunConfGen before mconf-idf ensures that deprecated options won't be ignored (they've got renamed) $(call RunConf,mconf-idf) + # RunConfGen after mconf-idf ensures that deprecated options are appended to $(SDKCONFIG) for backward compatibility + $(call RunConfGen) endif # defconfig creates a default config, based on SDKCONFIG_DEFAULTS if present -defconfig: $(KCONFIG_TOOL_DIR)/conf-idf +defconfig: | check_python_dependencies $(summary) DEFCONFIG ifneq ("$(wildcard $(SDKCONFIG_DEFAULTS))","") cat $(SDKCONFIG_DEFAULTS) >> $(SDKCONFIG) # append defaults to sdkconfig, will override existing values endif - $(call RunConf,conf-idf --olddefconfig) + $(call RunConfGen) # if neither defconfig or menuconfig are requested, use the GENCONFIG rule to # ensure generated config files are up to date -$(SDKCONFIG_MAKEFILE) $(BUILD_DIR_BASE)/include/sdkconfig.h: $(KCONFIG_TOOL_DIR)/conf-idf $(SDKCONFIG) $(COMPONENT_KCONFIGS) $(COMPONENT_KCONFIGS_PROJBUILD) | $(call prereq_if_explicit,defconfig) $(call prereq_if_explicit,menuconfig) +$(SDKCONFIG_MAKEFILE) $(BUILD_DIR_BASE)/include/sdkconfig.h: $(SDKCONFIG) $(COMPONENT_KCONFIGS) $(COMPONENT_KCONFIGS_PROJBUILD) | check_python_dependencies $(call prereq_if_explicit,defconfig) $(call prereq_if_explicit,menuconfig) $(summary) GENCONFIG -ifdef BATCH_BUILD # can't prompt for new config values like on terminal - $(call RunConf,conf-idf --olddefconfig) -endif - $(call RunConf,conf-idf --silentoldconfig) + $(call RunConfGen) touch $(SDKCONFIG_MAKEFILE) $(BUILD_DIR_BASE)/include/sdkconfig.h # ensure newer than sdkconfig else # "$(MAKE_RESTARTS)" != "" diff --git a/sdkconfig.rename b/sdkconfig.rename new file mode 100644 index 0000000000..c2f45861c6 --- /dev/null +++ b/sdkconfig.rename @@ -0,0 +1,7 @@ +# sdkconfig replacement configurations for deprecated options formatted as +# CONFIG_DEPRECATED_OPTION CONFIG_NEW_OPTION + +# SDK tool configuration +CONFIG_TOOLPREFIX CONFIG_SDK_TOOLPREFIX +CONFIG_PYTHON CONFIG_SDK_PYTHON +CONFIG_MAKE_WARN_UNDEFINED_VARIABLES CONFIG_SDK_MAKE_WARN_UNDEFINED_VARIABLES diff --git a/tools/ci/test_build_system.sh b/tools/ci/test_build_system.sh index 8153e7e5b2..9ffea7042c 100755 --- a/tools/ci/test_build_system.sh +++ b/tools/ci/test_build_system.sh @@ -310,6 +310,35 @@ function run_tests() rm -rf esp32 rm -rf mycomponents + print_status "Handling deprecated Kconfig options" + make clean > /dev/null; + rm -f sdkconfig.defaults; + rm -f sdkconfig; + echo "" > ${IDF_PATH}/sdkconfig.rename; + make defconfig > /dev/null; + echo "CONFIG_TEST_OLD_OPTION=y" >> sdkconfig; + echo "CONFIG_TEST_OLD_OPTION CONFIG_TEST_NEW_OPTION" >> ${IDF_PATH}/sdkconfig.rename; + echo -e "\n\ +menu \"test\"\n\ + config TEST_NEW_OPTION\n\ + bool \"test\"\n\ + default \"n\"\n\ + help\n\ + TEST_NEW_OPTION description\n\ +endmenu\n" >> ${IDF_PATH}/Kconfig; + make defconfig > /dev/null; + grep "CONFIG_TEST_OLD_OPTION=y" sdkconfig || failure "CONFIG_TEST_OLD_OPTION should be in sdkconfig for backward compatibility" + grep "CONFIG_TEST_NEW_OPTION=y" sdkconfig || failure "CONFIG_TEST_NEW_OPTION should be now in sdkconfig" + grep "#define CONFIG_TEST_NEW_OPTION 1" build/include/sdkconfig.h || failure "sdkconfig.h should contain the new macro" + grep "#define CONFIG_TEST_OLD_OPTION CONFIG_TEST_NEW_OPTION" build/include/sdkconfig.h || failure "sdkconfig.h should contain the compatibility macro" + grep "CONFIG_TEST_OLD_OPTION=y" build/include/config/auto.conf || failure "CONFIG_TEST_OLD_OPTION should be in auto.conf for backward compatibility" + grep "CONFIG_TEST_NEW_OPTION=y" build/include/config/auto.conf || failure "CONFIG_TEST_NEW_OPTION should be now in auto.conf" + rm -f sdkconfig sdkconfig.defaults + pushd ${IDF_PATH} + git checkout -- sdkconfig.rename Kconfig + popd + make defconfig + print_status "All tests completed" if [ -n "${FAILURES}" ]; then echo "Some failures were detected:" diff --git a/tools/ci/test_build_system_cmake.sh b/tools/ci/test_build_system_cmake.sh index 6dc10abca6..dc5ebe8ed6 100755 --- a/tools/ci/test_build_system_cmake.sh +++ b/tools/ci/test_build_system_cmake.sh @@ -366,6 +366,35 @@ EOF export PATH="$OLDPATH" rm ./python + print_status "Handling deprecated Kconfig options" + idf.py clean > /dev/null; + rm -f sdkconfig.defaults; + rm -f sdkconfig; + echo "" > ${IDF_PATH}/sdkconfig.rename; + idf.py build > /dev/null; + echo "CONFIG_TEST_OLD_OPTION=y" >> sdkconfig; + echo "CONFIG_TEST_OLD_OPTION CONFIG_TEST_NEW_OPTION" >> ${IDF_PATH}/sdkconfig.rename; + echo -e "\n\ +menu \"test\"\n\ + config TEST_NEW_OPTION\n\ + bool \"test\"\n\ + default \"n\"\n\ + help\n\ + TEST_NEW_OPTION description\n\ +endmenu\n" >> ${IDF_PATH}/Kconfig; + idf.py build > /dev/null; + grep "CONFIG_TEST_OLD_OPTION=y" sdkconfig || failure "CONFIG_TEST_OLD_OPTION should be in sdkconfig for backward compatibility" + grep "CONFIG_TEST_NEW_OPTION=y" sdkconfig || failure "CONFIG_TEST_NEW_OPTION should be now in sdkconfig" + grep "#define CONFIG_TEST_NEW_OPTION 1" build/config/sdkconfig.h || failure "sdkconfig.h should contain the new macro" + grep "#define CONFIG_TEST_OLD_OPTION CONFIG_TEST_NEW_OPTION" build/config/sdkconfig.h || failure "sdkconfig.h should contain the compatibility macro" + grep "set(CONFIG_TEST_OLD_OPTION \"y\")" build/config/sdkconfig.cmake || failure "CONFIG_TEST_OLD_OPTION should be in auto.conf for backward compatibility" + grep "set(CONFIG_TEST_NEW_OPTION \"y\")" build/config/sdkconfig.cmake || failure "CONFIG_TEST_NEW_OPTION should be now in auto.conf" + rm -f sdkconfig sdkconfig.defaults + pushd ${IDF_PATH} + git checkout -- sdkconfig.rename Kconfig + popd + idf.py build + print_status "All tests completed" if [ -n "${FAILURES}" ]; then echo "Some failures were detected:" diff --git a/tools/cmake/kconfig.cmake b/tools/cmake/kconfig.cmake index ed247fb798..3c8dfb2ccf 100644 --- a/tools/cmake/kconfig.cmake +++ b/tools/cmake/kconfig.cmake @@ -138,7 +138,11 @@ function(kconfig_process_config) "IDF_TARGET=${IDF_TARGET}" ${MCONF} ${ROOT_KCONFIG} VERBATIM - USES_TERMINAL) + USES_TERMINAL + # additional run of confgen esures that the deprecated options will be inserted into sdkconfig (for backward + # compatibility) + COMMAND ${confgen_basecommand} --env "IDF_TARGET=${IDF_TARGET}" --output config ${SDKCONFIG} + ) # Custom target to run confserver.py from the build tool add_custom_target(confserver @@ -191,4 +195,4 @@ function(kconfig_process_config) ADDITIONAL_MAKE_CLEAN_FILES "${SDKCONFIG_HEADER}" "${SDKCONFIG_CMAKE}") -endfunction() \ No newline at end of file +endfunction() diff --git a/tools/kconfig_new/confgen.py b/tools/kconfig_new/confgen.py index 4d8563d797..346b8352b4 100755 --- a/tools/kconfig_new/confgen.py +++ b/tools/kconfig_new/confgen.py @@ -22,12 +22,13 @@ # limitations under the License. from __future__ import print_function import argparse -import sys +import fnmatch +import json import os import os.path -import tempfile -import json import re +import sys +import tempfile import gen_kconfig_doc import kconfiglib @@ -38,6 +39,108 @@ if "IDF_CMAKE" not in os.environ: os.environ["IDF_CMAKE"] = "" +class DeprecatedOptions(object): + _REN_FILE = 'sdkconfig.rename' + _DEP_OP_BEGIN = '# Deprecated options for backward compatibility' + _DEP_OP_END = '# End of deprecated options' + _RE_DEP_OP_BEGIN = re.compile(_DEP_OP_BEGIN) + _RE_DEP_OP_END = re.compile(_DEP_OP_END) + + def __init__(self, config_prefix, path_rename_files): + self.config_prefix = config_prefix + # r_dic maps deprecated options to new options; rev_r_dic maps in the opposite direction + self.r_dic, self.rev_r_dic = self._parse_replacements(path_rename_files) + + # note the '=' at the end of regex for not getting partial match of configs + self._RE_CONFIG = re.compile(r'{}(\w+)='.format(self.config_prefix)) + + def _parse_replacements(self, repl_dir): + rep_dic = {} + rev_rep_dic = {} + + for root, dirnames, filenames in os.walk(repl_dir): + for filename in fnmatch.filter(filenames, self._REN_FILE): + rep_path = os.path.join(root, filename) + + with open(rep_path) as f_rep: + for line_number, line in enumerate(f_rep, start=1): + sp_line = line.split() + if len(sp_line) == 0 or sp_line[0].startswith('#'): + # empty line or comment + continue + if len(sp_line) != 2 or not all(x.startswith(self.config_prefix) for x in sp_line): + raise RuntimeError('Syntax error in {} (line {})'.format(rep_path, line_number)) + if sp_line[0] in rep_dic: + raise RuntimeError('Error in {} (line {}): Replacement {} exist for {} and new ' + 'replacement {} is defined'.format(rep_path, line_number, + rep_dic[sp_line[0]], sp_line[0], + sp_line[1])) + (dep_opt, new_opt) = (x.lstrip(self.config_prefix) for x in sp_line) + rep_dic[dep_opt] = new_opt + rev_rep_dic[new_opt] = dep_opt + return rep_dic, rev_rep_dic + + def get_deprecated_option(self, new_option): + return self.rev_r_dic.get(new_option, None) + + def get_new_option(self, deprecated_option): + return self.r_dic.get(deprecated_option, None) + + def replace(self, sdkconfig_in, sdkconfig_out): + replace_enabled = True + with open(sdkconfig_in, 'r') as f_in, open(sdkconfig_out, 'w') as f_out: + for line_num, line in enumerate(f_in, start=1): + if self._RE_DEP_OP_BEGIN.search(line): + replace_enabled = False + elif self._RE_DEP_OP_END.search(line): + replace_enabled = True + elif replace_enabled: + m = self._RE_CONFIG.search(line) + if m and m.group(1) in self.r_dic: + depr_opt = self.config_prefix + m.group(1) + new_opt = self.config_prefix + self.r_dic[m.group(1)] + line = line.replace(depr_opt, new_opt) + print('{}:{} {} was replaced with {}'.format(sdkconfig_in, line_num, depr_opt, new_opt)) + f_out.write(line) + + def append_doc(self, config, path_output): + if len(self.r_dic) > 0: + with open(path_output, 'a') as f_o: + header = 'Deprecated options and their replacements' + f_o.write('{}\n{}\n\n'.format(header, '-' * len(header))) + for key in sorted(self.r_dic): + f_o.write('- {}{}: :ref:`{}{}`\n'.format(config.config_prefix, key, + config.config_prefix, self.r_dic[key])) + + def append_config(self, config, path_output): + tmp_list = [] + + def append_config_node_process(node): + item = node.item + if isinstance(item, kconfiglib.Symbol) and item.env_var is None: + if item.name in self.rev_r_dic: + c_string = item.config_string + if c_string: + tmp_list.append(c_string.replace(self.config_prefix + item.name, + self.config_prefix + self.rev_r_dic[item.name])) + + config.walk_menu(append_config_node_process) + + if len(tmp_list) > 0: + with open(path_output, 'a') as f_o: + f_o.write('\n{}\n'.format(self._DEP_OP_BEGIN)) + f_o.writelines(tmp_list) + f_o.write('{}\n'.format(self._DEP_OP_END)) + + def append_header(self, config, path_output): + if len(self.r_dic) > 0: + with open(path_output, 'a') as f_o: + f_o.write('\n/* List of deprecated options */\n') + for dep_opt in sorted(self.r_dic): + new_opt = self.r_dic[dep_opt] + f_o.write('#define {}{} {}{}\n'.format(self.config_prefix, dep_opt, self.config_prefix, new_opt)) + + def main(): parser = argparse.ArgumentParser(description='confgen.py v%s - Config Generation Tool' % __version__, prog=os.path.basename(sys.argv[0])) @@ -94,16 +197,30 @@ def main(): raise RuntimeError("Defaults file not found: %s" % name) config.load_config(name, replace=False) + deprecated_options = DeprecatedOptions(config.config_prefix, path_rename_files=os.environ["IDF_PATH"]) + # If config file previously exists, load it if args.config and os.path.exists(args.config): - config.load_config(args.config, replace=False) + # ... but replace deprecated options before that + with tempfile.NamedTemporaryFile(prefix="confgen_tmp", delete=False) as f: + temp_file = f.name + try: + deprecated_options.replace(sdkconfig_in=args.config, sdkconfig_out=temp_file) + config.load_config(temp_file, replace=False) + update_if_changed(temp_file, args.config) + finally: + try: + os.remove(temp_file) + except OSError: + pass # Output the files specified in the arguments for output_type, filename in args.output: - temp_file = tempfile.mktemp(prefix="confgen_tmp") + with tempfile.NamedTemporaryFile(prefix="confgen_tmp", delete=False) as f: + temp_file = f.name try: output_function = OUTPUT_FORMATS[output_type] - output_function(config, temp_file) + output_function(deprecated_options, config, temp_file) update_if_changed(temp_file, filename) finally: try: @@ -112,16 +229,56 @@ def main(): pass -def write_config(config, filename): +def write_config(deprecated_options, config, filename): CONFIG_HEADING = """# # Automatically generated file. DO NOT EDIT. # Espressif IoT Development Framework (ESP-IDF) Project Configuration # """ config.write_config(filename, header=CONFIG_HEADING) + deprecated_options.append_config(config, filename) -def write_header(config, filename): +def write_makefile(deprecated_options, config, filename): + CONFIG_HEADING = """# +# Automatically generated file. DO NOT EDIT. +# Espressif IoT Development Framework (ESP-IDF) Project Makefile Configuration +# +""" + with open(filename, "w") as f: + tmp_dep_lines = [] + f.write(CONFIG_HEADING) + + def get_makefile_config_string(name, value, orig_type): + if orig_type in (kconfiglib.BOOL, kconfiglib.TRISTATE): + return "{}{}={}\n".format(config.config_prefix, name, '' if value == 'n' else value) + elif orig_type in (kconfiglib.INT, kconfiglib.HEX): + return "{}{}={}\n".format(config.config_prefix, name, value) + elif orig_type == kconfiglib.STRING: + return '{}{}="{}"\n'.format(config.config_prefix, name, kconfiglib.escape(value)) + else: + raise RuntimeError('{}{}: unknown type {}'.format(config.config_prefix, name, orig_type)) + + def write_makefile_node(node): + item = node.item + if isinstance(item, kconfiglib.Symbol) and item.env_var is None: + # item.config_string cannot be used because it ignores hidden config items + val = item.str_value + f.write(get_makefile_config_string(item.name, val, item.orig_type)) + + dep_opt = deprecated_options.get_deprecated_option(item.name) + if dep_opt: + # the same string but with the deprecated name + tmp_dep_lines.append(get_makefile_config_string(dep_opt, val, item.orig_type)) + + config.walk_menu(write_makefile_node, True) + + if len(tmp_dep_lines) > 0: + f.write('\n# List of deprecated options\n') + f.writelines(tmp_dep_lines) + + +def write_header(deprecated_options, config, filename): CONFIG_HEADING = """/* * Automatically generated file. DO NOT EDIT. * Espressif IoT Development Framework (ESP-IDF) Configuration Header @@ -129,10 +286,12 @@ def write_header(config, filename): #pragma once """ config.write_autoconf(filename, header=CONFIG_HEADING) + deprecated_options.append_header(config, filename) -def write_cmake(config, filename): +def write_cmake(deprecated_options, config, filename): with open(filename, "w") as f: + tmp_dep_list = [] write = f.write prefix = config.config_prefix @@ -155,8 +314,15 @@ def write_cmake(config, filename): val = "" # write unset values as empty variables write("set({}{} \"{}\")\n".format( prefix, sym.name, val)) + dep_opt = deprecated_options.get_deprecated_option(sym.name) + if dep_opt: + tmp_dep_list.append("set({}{} \"{}\")\n".format(prefix, dep_opt, val)) config.walk_menu(write_node) + if len(tmp_dep_list) > 0: + write('\n# List of deprecated options for backward compatibility\n') + f.writelines(tmp_dep_list) + def get_json_values(config): config_dict = {} @@ -179,7 +345,7 @@ def get_json_values(config): return config_dict -def write_json(config, filename): +def write_json(deprecated_options, config, filename): config_dict = get_json_values(config) with open(filename, "w") as f: json.dump(config_dict, f, indent=4, sort_keys=True) @@ -209,7 +375,7 @@ def get_menu_node_id(node): return result -def write_json_menus(config, filename): +def write_json_menus(deprecated_options, config, filename): existing_ids = set() result = [] # root level items node_lookup = {} # lookup from MenuNode to an item in result @@ -298,6 +464,11 @@ def write_json_menus(config, filename): f.write(json.dumps(result, sort_keys=True, indent=4)) +def write_docs(deprecated_options, config, filename): + gen_kconfig_doc.write_docs(config, filename) + deprecated_options.append_doc(config, filename) + + def update_if_changed(source, destination): with open(source, "r") as f: source_contents = f.read() @@ -313,9 +484,10 @@ def update_if_changed(source, destination): OUTPUT_FORMATS = {"config": write_config, + "makefile": write_makefile, # only used with make in order to generate auto.conf "header": write_header, "cmake": write_cmake, - "docs": gen_kconfig_doc.write_docs, + "docs": write_docs, "json": write_json, "json_menus": write_json_menus, } diff --git a/tools/kconfig_new/confserver.py b/tools/kconfig_new/confserver.py index fcb33e63d0..a5e5b48680 100755 --- a/tools/kconfig_new/confserver.py +++ b/tools/kconfig_new/confserver.py @@ -5,11 +5,12 @@ # from __future__ import print_function import argparse +import confgen import json import kconfiglib import os import sys -import confgen +import tempfile from confgen import FatalError, __version__ # Min/Max supported protocol versions @@ -58,6 +59,13 @@ def main(): def run_server(kconfig, sdkconfig, default_version=MAX_PROTOCOL_VERSION): config = kconfiglib.Kconfig(kconfig) + deprecated_options = confgen.DeprecatedOptions(config.config_prefix, path_rename_files=os.environ["IDF_PATH"]) + with tempfile.NamedTemporaryFile(mode='w+b') as f_o: + with open(sdkconfig, mode='rb') as f_i: + f_o.write(f_i.read()) + f_o.flush() + f_o.seek(0) + deprecated_options.replace(sdkconfig_in=f_o.name, sdkconfig_out=sdkconfig) config.load_config(sdkconfig) print("Server running, waiting for requests on stdin...", file=sys.stderr) @@ -111,7 +119,7 @@ def run_server(kconfig, sdkconfig, default_version=MAX_PROTOCOL_VERSION): else: sdkconfig = req["save"] - error = handle_request(config, req) + error = handle_request(deprecated_options, config, req) after = confgen.get_json_values(config) after_ranges = get_ranges(config) @@ -136,7 +144,7 @@ def run_server(kconfig, sdkconfig, default_version=MAX_PROTOCOL_VERSION): print("\n") -def handle_request(config, req): +def handle_request(deprecated_options, config, req): if "version" not in req: return ["All requests must have a 'version'"] @@ -161,7 +169,7 @@ def handle_request(config, req): if "save" in req: try: print("Saving config to %s..." % req["save"], file=sys.stderr) - confgen.write_config(config, req["save"]) + confgen.write_config(deprecated_options, config, req["save"]) except Exception as e: error += ["Failed to save to %s: %s" % (req["save"], e)] diff --git a/tools/ldgen/samples/sdkconfig b/tools/ldgen/samples/sdkconfig index 869e9bf0cb..4c3c94b973 100644 --- a/tools/ldgen/samples/sdkconfig +++ b/tools/ldgen/samples/sdkconfig @@ -1,9 +1,9 @@ # # SDK tool configuration # -CONFIG_TOOLPREFIX="xtensa-esp32-elf-" -CONFIG_PYTHON="python" -CONFIG_MAKE_WARN_UNDEFINED_VARIABLES=y +CONFIG_SDK_TOOLPREFIX="xtensa-esp32-elf-" +CONFIG_SDK_PYTHON="python" +CONFIG_SDK_MAKE_WARN_UNDEFINED_VARIABLES=y # # Bootloader config