From de45874719772a40f1d8d244e2f5a6c6036415ac Mon Sep 17 00:00:00 2001 From: Ulf Magnusson Date: Sun, 17 Nov 2019 03:41:12 +0100 Subject: Make header strings customizable via the environment If no header string is specified in write_(min_)config() or write_autoconf(), use the values of the environment variables KCONFIG_CONFIG_HEADER and KCONFIG_AUTOHEADER_HEADER, respectively, if set. KCONFIG_AUTOHEADER_HEADER is consistent with KCONFIG_AUTOHEADER (the header path), which will be added soon. Using environment variables avoids having to add separate flags to each tool that writes configuration files or headers. Like for $prefix and $CONFIG_, store the values of the environment variables when the Kconfig instance is created, and expose them via Kconfig.config_header and Kconfig.header_header. This if flexible and avoids gotchas when working with multiple Kconfig instances. Also remove the old default header and make the default no header. Less advertising, but it felt a bit silly to add workarounds to keep it. Came up in https://github.com/ulfalizer/Kconfiglib/pull/80. --- genconfig.py | 7 ++++ kconfiglib.py | 109 ++++++++++++++++++++++++++++++++++++++-------------------- tests/Kheader | 5 +++ testsuite.py | 49 ++++++++++++++++++++++---- 4 files changed, 126 insertions(+), 44 deletions(-) create mode 100644 tests/Kheader diff --git a/genconfig.py b/genconfig.py index bb3e6ff..96124c5 100755 --- a/genconfig.py +++ b/genconfig.py @@ -20,6 +20,13 @@ might save work depending on your build setup. By default, the configuration is generated from '.config'. A different configuration file can be passed in the KCONFIG_CONFIG environment variable. + +A custom header string can be inserted at the beginning of generated +configuration and header files by setting the KCONFIG_CONFIG_HEADER and +KCONFIG_AUTOHEADER_HEADER environment variables, respectively (this also works +for other scripts). The string is not automatically made a comment (this is by +design, to allow anything to be added), and no trailing newline is added, so +add '/* */', '#', and newlines as appropriate. """ import argparse import os diff --git a/kconfiglib.py b/kconfiglib.py index 37ba501..079c363 100644 --- a/kconfiglib.py +++ b/kconfiglib.py @@ -773,8 +773,8 @@ class Kconfig(object): See Kconfig.load_config() as well. srctree: - The value of the $srctree environment variable when the configuration was - loaded, or the empty string if $srctree wasn't set. This gives nice + The value the $srctree environment variable had when the Kconfig instance + was created, or the empty string if $srctree wasn't set. This gives nice behavior with os.path.join(), which treats "" as the current directory, without adding "./". @@ -789,13 +789,22 @@ class Kconfig(object): if multiple configurations are loaded with different values for $srctree. config_prefix: - The value of the $CONFIG_ environment variable when the configuration was - loaded. This is the prefix used (and expected) on symbol names in .config - files and C headers. Defaults to "CONFIG_". Used in the same way in the C - tools. - - Like for srctree, only the value of $CONFIG_ when the configuration is - loaded matters. + The value the CONFIG_ environment variable had when the Kconfig instance + was created, or "CONFIG_" if CONFIG_ wasn't set. This is the prefix used + (and expected) on symbol names in .config files and C headers. Used in + the same way in the C tools. + + config_header: + The value the KCONFIG_CONFIG_HEADER environment variable had when the + Kconfig instance was created, or the empty string if + KCONFIG_CONFIG_HEADER wasn't set. This string is inserted verbatim at the + beginning of configuration files. See write_config(). + + header_header: + The value the KCONFIG_AUTOHEADER_HEADER environment variable had when the + Kconfig instance was created, or the empty string if + KCONFIG_AUTOHEADER_HEADER wasn't set. This string is inserted verbatim at + the beginning of header files. See write_autoconf(). filename/linenr: The current parsing location, for use in Python preprocessor functions. @@ -810,11 +819,13 @@ class Kconfig(object): "_warn_assign_no_prompt", "choices", "comments", + "config_header", "config_prefix", "const_syms", "defconfig_list", "defined_syms", "env_vars", + "header_header", "kconfig_filenames", "m", "menus", @@ -943,6 +954,9 @@ class Kconfig(object): self._unset_match = _re_match(r"# {}([^ ]+) is not set".format( self.config_prefix)) + self.config_header = os.getenv("KCONFIG_CONFIG_HEADER", "") + self.header_header = os.getenv("KCONFIG_AUTOHEADER_HEADER", "") + self.syms = {} self.const_syms = {} self.defined_syms = [] @@ -1349,8 +1363,7 @@ class Kconfig(object): elif self.warn_assign_override: self._warn(msg, filename, linenr) - def write_autoconf(self, filename, - header="/* Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib) */\n"): + def write_autoconf(self, filename, header=None): r""" Writes out symbol values as a C header file, matching the format used by include/generated/autoconf.h in the kernel. @@ -1367,19 +1380,26 @@ class Kconfig(object): filename: Self-explanatory. - header (default: "/* Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib) */\n"): - Text that will be inserted verbatim at the beginning of the file. You - would usually want it enclosed in '/* */' to make it a C comment, - and include a final terminating newline. + header (default: None): + Text inserted verbatim at the beginning of the file. You would + usually want it enclosed in '/* */' to make it a C comment, and + include a trailing newline. + + If None (the default), the value of the environment variable + KCONFIG_AUTOHEADER_HEADER had when the Kconfig instance was created + will be used if it was set, and no header otherwise. See the + Kconfig.header_header attribute. """ self._write_if_changed(filename, self._autoconf_contents(header)) def _autoconf_contents(self, header): # write_autoconf() helper. Returns the contents to write as a string, - # with 'header' at the beginning. + # with 'header' or KCONFIG_AUTOHEADER_HEADER at the beginning. - # "".join()ed later - chunks = [header] + if header is None: + header = self.header_header + + chunks = [header] # "".join()ed later add = chunks.append for sym in self.unique_defined_syms: @@ -1415,9 +1435,8 @@ class Kconfig(object): return "".join(chunks) - def write_config(self, filename=None, - header="# Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib)\n", - save_old=True, verbose=None): + def write_config(self, filename=None, header=None, save_old=True, + verbose=None): r""" Writes out symbol values in the .config format. The format matches the C implementation, including ordering. @@ -1445,10 +1464,15 @@ class Kconfig(object): KCONFIG_CONFIG is used if set, and ".config" otherwise. See standard_config_filename(). - header (default: "# Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib)\n"): - Text that will be inserted verbatim at the beginning of the file. You - would usually want each line to start with '#' to make it a comment, - and include a final terminating newline. + header (default: None): + Text inserted verbatim at the beginning of the file. You would + usually want each line to start with '#' to make it a comment, and + include a trailing newline. + + if None (the default), the value of the environment variable + KCONFIG_CONFIG_HEADER had when the Kconfig instance was created will + be used if it was set, and no header otherwise. See the + Kconfig.config_header attribute. save_old (default: True): If True and already exists, a copy of it will be saved to @@ -1493,7 +1517,7 @@ class Kconfig(object): def _config_contents(self, header): # write_config() helper. Returns the contents to write as a string, - # with 'header' at the beginning. + # with 'header' or KCONFIG_CONFIG_HEADER at the beginning. # # More memory friendly would be to 'yield' the strings and # "".join(_config_contents()), but it was a bit slower on my system. @@ -1505,13 +1529,15 @@ class Kconfig(object): for sym in self.unique_defined_syms: sym._visited = False - # Did we just print an '# end of ...' comment? - after_end_comment = False + if header is None: + header = self.config_header - # "".join()ed later - chunks = [header] + chunks = [header] # "".join()ed later add = chunks.append + # Did we just print an '# end of ...' comment? + after_end_comment = False + node = self.top_node while 1: # Jump to the next node with an iterative tree walk @@ -1564,8 +1590,7 @@ class Kconfig(object): add("\n#\n# {}\n#\n".format(node.prompt[0])) after_end_comment = False - def write_min_config(self, filename, - header="# Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib)\n"): + def write_min_config(self, filename, header=None): """ Writes out a "minimal" configuration file, omitting symbols whose value matches their default value. The format matches the one produced by @@ -1583,10 +1608,15 @@ class Kconfig(object): filename: Self-explanatory. - header (default: "# Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib)\n"): - Text that will be inserted verbatim at the beginning of the file. You - would usually want each line to start with '#' to make it a comment, - and include a final terminating newline. + header (default: None): + Text inserted verbatim at the beginning of the file. You would + usually want each line to start with '#' to make it a comment, and + include a final terminating newline. + + if None (the default), the value of the environment variable + KCONFIG_CONFIG_HEADER had when the Kconfig instance was created will + be used if it was set, and no header otherwise. See the + Kconfig.config_header attribute. Returns a string with a message saying which file got saved. This is meant to reduce boilerplate in tools, which can do e.g. @@ -1603,9 +1633,12 @@ class Kconfig(object): def _min_config_contents(self, header): # write_min_config() helper. Returns the contents to write as a string, - # with 'header' at the beginning. + # with 'header' or KCONFIG_CONFIG_HEADER at the beginning. + + if header is None: + header = self.config_header - chunks = [header] + chunks = [header] # "".join()ed later add = chunks.append for sym in self.unique_defined_syms: diff --git a/tests/Kheader b/tests/Kheader new file mode 100644 index 0000000..495afc6 --- /dev/null +++ b/tests/Kheader @@ -0,0 +1,5 @@ +# Used to test headers in .config and header files + +config FOO + bool "foo" + default y diff --git a/testsuite.py b/testsuite.py index 6fd8d83..fc61a16 100644 --- a/testsuite.py +++ b/testsuite.py @@ -1926,12 +1926,12 @@ tests/Krecursive2:1 c = Kconfig("Kconfiglib/tests/Kescape") # Test the default value - c.write_config(config_test_file + "_from_def", header="") + c.write_config(config_test_file + "_from_def") verify_file_contents(config_test_file + "_from_def", r'''CONFIG_STRING="\"\\"''' "\n") # Write our own value c.syms["STRING"].set_value(r'''\"a'\\''') - c.write_config(config_test_file + "_from_user", header="") + c.write_config(config_test_file + "_from_user") verify_file_contents(config_test_file + "_from_user", r'''CONFIG_STRING="\\\"a'\\\\"''' "\n") @@ -1977,7 +1977,7 @@ tests/Krecursive2:1 c = Kconfig("Kconfiglib/tests/Korder") - c.write_autoconf(config_test_file, header="") + c.write_autoconf(config_test_file) verify_file_contents(config_test_file, """ #define CONFIG_O 0 #define CONFIG_R 1 @@ -1996,7 +1996,7 @@ tests/Krecursive2:1 c.syms["R2"].set_value("-1") c.syms["N"].set_value("-1") c.syms["G"].set_value("-1") - c.write_min_config(config_test_file, header="") + c.write_min_config(config_test_file) verify_file_contents(config_test_file, """ CONFIG_O=-1 CONFIG_R=-1 @@ -2006,6 +2006,44 @@ CONFIG_N=-1 CONFIG_G=-1 """[1:]) + # Test header strings in configuration files and headers + + os.environ["KCONFIG_CONFIG_HEADER"] = "config header from env.\n" + os.environ["KCONFIG_AUTOHEADER_HEADER"] = "header header from env.\n" + + c = Kconfig("Kconfiglib/tests/Kheader") + c.write_config(config_test_file, header="config header from param\n") + verify_file_contents(config_test_file, """\ +config header from param +CONFIG_FOO=y +""") + c.write_min_config(config_test_file, header="min. config header from param\n") + verify_file_contents(config_test_file, """\ +min. config header from param +""") + c.write_config(config_test_file) + verify_file_contents(config_test_file, """\ +config header from env. +CONFIG_FOO=y +""") + c.write_min_config(config_test_file) + verify_file_contents(config_test_file, """\ +config header from env. +""") + c.write_autoconf(config_test_file, header="header header from param\n") + verify_file_contents(config_test_file, """\ +header header from param +#define CONFIG_FOO 1 +""") + c.write_autoconf(config_test_file) + verify_file_contents(config_test_file, """\ +header header from env. +#define CONFIG_FOO 1 +""") + + del os.environ["KCONFIG_CONFIG_HEADER"] + del os.environ["KCONFIG_AUTOHEADER_HEADER"] + print("Testing Kconfig fetching and separation") @@ -3148,8 +3186,7 @@ def equal_configs(): return False else: with f: - # [1:] strips the default header - our = f.readlines()[1:] + our = f.readlines() if their == our: return True -- cgit v1.2.3