blob: 1ed65405de154b81a59586e70df5fadb9c74fc7e [file] [log] [blame]
From 5b50e16456988db75cad1cca7751ac55323b9870 Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Fri, 14 Jan 2022 16:03:43 -0700
Subject: [PATCH 1/2] Support a list of search paths for Kconfig files
Projects such as Zephyr OS have a module system, where Kconfig files can
exist in multiple directories that are effectively merged together by the
build system. In other words, one project directory can refer to
subdir/Kconfig where subdir/ is actually in another project directory.
As an example:
zephyr/ - main source directory
Kconfig - main Kconfig file
module/ec - module directory
motion/ - motion subsystem
Kconfig - Kconfig file for motion subsystem
Wtih the above, we might have, in zephyr/Kconfig:
source "motion/Kconfig"
and it automatically locates the file in the module/ec directory.
Add support for this, by allowing a list of search paths to be supplied to
Kconfiglib.
Signed-off-by: Simon Glass <sjg@chromium.org>
---
kconfiglib.py | 25 ++++++++++++++++++++++---
1 file changed, 22 insertions(+), 3 deletions(-)
diff --git a/kconfiglib.py b/kconfiglib.py
index c67895c..e3105c2 100644
--- a/kconfiglib.py
+++ b/kconfiglib.py
@@ -834,6 +834,7 @@ class Kconfig(object):
"n",
"named_choices",
"srctree",
+ "search_paths",
"syms",
"top_node",
"unique_choices",
@@ -865,7 +866,7 @@ class Kconfig(object):
#
def __init__(self, filename="Kconfig", warn=True, warn_to_stderr=True,
- encoding="utf-8", suppress_traceback=False):
+ encoding="utf-8", suppress_traceback=False, search_paths=None):
"""
Creates a new Kconfig object by parsing Kconfig files.
Note that Kconfig files are not the same as .config files (which store
@@ -942,9 +943,23 @@ def __init__(self, filename="Kconfig", warn=True, warn_to_stderr=True,
Other exceptions besides EnvironmentError and KconfigError are still
propagated when suppress_traceback is True.
+
+ search_paths (default: None):
+ List of paths to search for Kconfig files. This is needed when the
+ files are split between two project directories, as is done with
+ Zephyr OS, for example. It allows files in one project to reference
+ files in another.
+
+ This argument affects the operation of commands which include other
+ Kconfig files, such as `source` and `rsource`.
+
+ When not None, it should be a list of paths to directories to search.
+ Each search path is prepended to the relative filename to assist in
+ finding the file. The proeect directories should have distinct
+ filenames and/or subdirectory structures, so avoid ambiguity.
"""
try:
- self._init(filename, warn, warn_to_stderr, encoding)
+ self._init(filename, warn, warn_to_stderr, encoding, search_paths)
except (EnvironmentError, KconfigError) as e:
if suppress_traceback:
cmd = sys.argv[0] # Empty string if missing
@@ -956,7 +971,7 @@ def __init__(self, filename="Kconfig", warn=True, warn_to_stderr=True,
sys.exit(cmd + str(e).strip())
raise
- def _init(self, filename, warn, warn_to_stderr, encoding):
+ def _init(self, filename, warn, warn_to_stderr, encoding, search_paths):
# See __init__()
self._encoding = encoding
@@ -966,6 +981,7 @@ def _init(self, filename, warn, warn_to_stderr, encoding):
# relative to $srctree. relpath() can cause issues for symlinks,
# because it assumes symlink/../foo is the same as foo/.
self._srctree_prefix = realpath(self.srctree) + os.sep
+ self.search_paths = search_paths
self.warn = warn
self.warn_to_stderr = warn_to_stderr
@@ -2972,6 +2988,9 @@ def _parse_block(self, end_token, parent, prev):
# Kconfig symbols, which indirectly ensures a consistent
# ordering in e.g. .config files
filenames = sorted(iglob(join(self._srctree_prefix, pattern)))
+ if self.search_paths:
+ for prefix in self.search_paths:
+ filenames += sorted(iglob(join(prefix, pattern)))
if not filenames and t0 in _OBL_SOURCE_TOKENS:
raise KconfigError(
From 10d9d988cdaf1cf49e5a8007994463c42bdb66ab Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Fri, 14 Jan 2022 16:30:24 -0700
Subject: [PATCH 2/2] Add an option to allow empty macros
When parsing Kconfig which include macros it is currently necessary to
provide a value for all macros in advance. This may not be possible in
some cases, e.g. when the caller is performing checks on the Kconfig
options but is not running a full build of the project.
Add an option to support this. This allows parsing of Zephyr Kconfig
files without specifying a particular board, etc.
Signed-off-by: Simon Glass <sjg@chromium.org>
---
kconfiglib.py | 25 +++++++++++++++++++++----
1 file changed, 21 insertions(+), 4 deletions(-)
diff --git a/kconfiglib.py b/kconfiglib.py
index e3105c2..0e05aaa 100644
--- a/kconfiglib.py
+++ b/kconfiglib.py
@@ -817,6 +817,7 @@ class Kconfig(object):
"_srctree_prefix",
"_unset_match",
"_warn_assign_no_prompt",
+ "allow_empty_macros",
"choices",
"comments",
"config_header",
@@ -866,7 +867,8 @@ class Kconfig(object):
#
def __init__(self, filename="Kconfig", warn=True, warn_to_stderr=True,
- encoding="utf-8", suppress_traceback=False, search_paths=None):
+ encoding="utf-8", suppress_traceback=False, search_paths=None,
+ allow_empty_macros=False):
"""
Creates a new Kconfig object by parsing Kconfig files.
Note that Kconfig files are not the same as .config files (which store
@@ -957,9 +959,21 @@ def __init__(self, filename="Kconfig", warn=True, warn_to_stderr=True,
Each search path is prepended to the relative filename to assist in
finding the file. The proeect directories should have distinct
filenames and/or subdirectory structures, so avoid ambiguity.
+
+ allow_empty_macros (default: False):
+ Normally when macros expand to empty it means that the macro is not
+ defined. This is considered an error and parsing of the Kconfig files
+ aborts with an exception. In some cases it is useful to continue
+ parsing, to obtain what information is available.
+
+ An example is where the value of various macros is not known but the
+ caller simply wants to get a list of the available Kconfig options.
+
+ Pass True here to allow empty / undefined macros.
"""
try:
- self._init(filename, warn, warn_to_stderr, encoding, search_paths)
+ self._init(filename, warn, warn_to_stderr, encoding, search_paths,
+ allow_empty_macros)
except (EnvironmentError, KconfigError) as e:
if suppress_traceback:
cmd = sys.argv[0] # Empty string if missing
@@ -971,7 +985,8 @@ def __init__(self, filename="Kconfig", warn=True, warn_to_stderr=True,
sys.exit(cmd + str(e).strip())
raise
- def _init(self, filename, warn, warn_to_stderr, encoding, search_paths):
+ def _init(self, filename, warn, warn_to_stderr, encoding, search_paths,
+ allow_empty_macros):
# See __init__()
self._encoding = encoding
@@ -982,6 +997,7 @@ def _init(self, filename, warn, warn_to_stderr, encoding, search_paths):
# because it assumes symlink/../foo is the same as foo/.
self._srctree_prefix = realpath(self.srctree) + os.sep
self.search_paths = search_paths
+ self.allow_empty_macros = allow_empty_macros
self.warn = warn
self.warn_to_stderr = warn_to_stderr
@@ -2701,7 +2717,8 @@ def _expand_name(self, s, i):
if not name.strip():
# Avoid creating a Kconfig symbol with a blank name. It's almost
# guaranteed to be an error.
- self._parse_error("macro expanded to blank string")
+ if not self.allow_empty_macros:
+ self._parse_error("macro expanded to blank string")
# Skip trailing whitespace
while end_i < len(s) and s[end_i].isspace():