@@ -482,6 +482,18 @@ class CookerDataBuilder(object):
" invoked bitbake from the wrong directory?")
bb.fatal(msg)
+ # A directory listed more than once in BBPATH is a configuration
+ # error, e.g. a layer in both the BBPATH env var and BBLAYERS. Compare
+ # resolved paths so "dir" and "dir/" or a symlink to it also match, and
+ # ignore the empty entries left by stray colons
+ entries = {}
+ for p in data.getVar("BBPATH").split(":"):
+ if p:
+ entries.setdefault(os.path.realpath(p), []).append(p)
+ duplicates = [" ".join(paths) for paths in entries.values() if len(paths) > 1]
+ if duplicates:
+ bb.fatal("BBPATH contains duplicate entries:\n %s\nCheck the BBPATH environment variable, bblayers.conf and the layer.conf files." % "\n ".join(duplicates))
+
if not data.getVar("TOPDIR"):
data.setVar("TOPDIR", os.path.abspath(os.getcwd()))
if not data.getVar("BB_CACHEDIR"):
@@ -531,6 +531,33 @@ EXTRA_OECONF:append = " foobar"
self.assertEqual(d.getVar("EXTRA_OECONF"), " foo bar")
self.assertEqual(logs.output, ["WARNING:BitBake.Parsing:parse done"])
+ def test_duplicate_bbpath(self):
+ # A directory listed more than once in BBPATH is fatal
+ bbpath = os.path.realpath(os.path.join(os.path.dirname(__file__), "parse-tests"))
+ with tempfile.TemporaryDirectory(prefix="parsetest") as builddir:
+ def run_bitbake(entries):
+ env = os.environ.copy()
+ env["BBPATH"] = ":".join(entries)
+ env["BB_ENV_PASSTHROUGH_ADDITIONS"] = "TOPDIR"
+ env["TOPDIR"] = builddir
+ return subprocess.run(["bitbake", "-e"], env=env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, cwd=builddir)
+
+ link = os.path.join(builddir, "link")
+ os.symlink(bbpath, link)
+
+ # The same directory spelled the same, with a trailing slash or
+ # through a symlink is a duplicate
+ for dup in (bbpath, bbpath + "/", link):
+ with self.subTest(dup=dup):
+ result = run_bitbake([bbpath, dup])
+ self.assertNotEqual(result.returncode, 0)
+ self.assertIn("BBPATH contains duplicate entries:\n %s %s\n" % (bbpath, dup), result.stdout)
+
+ # Empty entries from stray colons are not duplicates
+ result = run_bitbake(["", bbpath, "", ""])
+ self.assertEqual(result.returncode, 0, result.stdout)
+ self.assertNotIn("BBPATH contains duplicate entries", result.stdout)
+
def test_file_variables(self):
# Tests the values of FILE and __BB_RECIPE_FILE in different
# combinations of bbappends, includes, and inherits
A directory listed more than once in BBPATH makes include_all apply the same file repeatedly. Fail once the layer configuration is parsed, so the error points at the configuration rather than surfacing later as duplicate inclusion warnings. Paths are compared after resolving them, and empty entries are ignored. Tested with bitbake-selftest and an oe-core tinfoil config parse. Suggested-by: Richard Purdie <richard.purdie@linuxfoundation.org> AI-Generated: Uses Claude Code (Claude Opus 5.5) Signed-off-by: Tim Orling <tim.orling@konsulko.com> --- lib/bb/cookerdata.py | 12 ++++++++++++ lib/bb/tests/parse.py | 27 +++++++++++++++++++++++++++ 2 files changed, 39 insertions(+)