@@ -104,7 +104,10 @@ def get_statements(filename, absolute_filename, base_name):
lineno = lineno + 1
s = f.readline()
if not s: break
- s = s.rstrip()
+ raw = s.rstrip('\n').rstrip('\r')
+ s = raw.rstrip()
+ if s and raw != s:
+ bb.warn("Trailing whitespace in %s, line %s" % (filename, lineno))
feeder(lineno, s, filename, base_name, statements)
if __inpython__:
@@ -134,12 +134,18 @@ def handle(fn, data, include, baseconfig=False):
# skip empty lines
if not w:
continue
- s = s.rstrip()
+ raw = s.rstrip('\n').rstrip('\r')
+ s = raw.rstrip()
+ if s and raw != s:
+ bb.warn("Trailing whitespace in %s, line %s" % (fn, lineno))
while s[-1] == '\\':
line = f.readline()
origline += line
- s2 = line.rstrip()
+ raw2 = line.rstrip('\n').rstrip('\r')
+ s2 = raw2.rstrip()
lineno = lineno + 1
+ if s2 and raw2 != s2:
+ bb.warn("Trailing whitespace in %s, line %s" % (fn, lineno))
if (not s2 or s2 and s2[0] != "#") and s[0] == "#" :
bb.fatal("There is a confusing multiline, partially commented expression starting on line %s of file %s:\n%s\nPlease clarify whether this is all a comment or should be parsed." % (origlineno, fn, origline))
@@ -638,3 +638,31 @@ EXTRA_OECONF:append = " foobar"
output = run_bitbake(["bitbake", "-e", "recipe-file1"], builddir, extraenv).splitlines()
self.assertIn('BBCLASS_FILE="recipe-file.inc"', output)
self.assertIn(f'BBCLASS_RECIPE_FILE="recipe-file1.bb"', output)
+
+ trailing_whitespace_continuation = "A = \"1 \\\t \n2\"\n"
+
+ def test_parse_trailing_whitespace_continuation(self):
+ """Test that trailing whitespace after backslash continuation emits a warning"""
+ with self.parsehelper(self.trailing_whitespace_continuation) as f:
+ with self.assertLogs('BitBake', level='WARNING') as cm:
+ d = bb.parse.handle(f.name, self.d)['']
+ self.assertTrue(any("Trailing whitespace" in msg for msg in cm.output))
+ self.assertEqual(d.getVar("A"), "1 2")
+
+ trailing_whitespace_after_value = 'A = "1" \n'
+
+ def test_parse_trailing_whitespace_after_value(self):
+ """Test that trailing whitespace after a normal value emits a warning"""
+ with self.parsehelper(self.trailing_whitespace_after_value) as f:
+ with self.assertLogs('BitBake', level='WARNING') as cm:
+ d = bb.parse.handle(f.name, self.d)['']
+ self.assertTrue(any("Trailing whitespace" in msg for msg in cm.output))
+ self.assertEqual(d.getVar("A"), "1")
+
+ clean_continuation = "A = \"1 \\\n2\"\n"
+
+ def test_parse_clean_continuation_no_warning(self):
+ """Test that clean backslash continuation does not warn"""
+ with self.parsehelper(self.clean_continuation) as f:
+ d = bb.parse.handle(f.name, self.d)['']
+ self.assertEqual(d.getVar("A"), "1 2")
rstrip() silently strips trailing whitespace before processing. This hides invisible spaces or tabs that end up in patch context and cause patches to fail to apply across branches. Warn on any line with trailing whitespace so developers can fix it early. Signed-off-by: Jaipaul Cheernam <jaipaul.cheernam@est.tech> --- Changes since v1: - Broadened from just backslash continuation to any trailing whitespace, as suggested by Richard. Real example from oe-core master (libssh2_1.11.1.bb, line 18): file://CVE-2025-15661-3.patch \<TAB> This caused CVE patches to fail to apply on wrynose where the trailing tab was absent — invisible context mismatch. Full parse (bitbake -p) across oe-core + meta-openembedded (2970 recipes): - 228 unique trailing whitespace instances (verified, 0 false positives) - 82 files affected (53 .bb, 19 .bbclass, 8 .inc, 2 .conf) - 92 in oe-core, 136 in meta-openembedded bbclass files like useradd.bbclass, sanity.bbclass, buildstats.bbclass account for most of the warning noise since they are re-parsed for every recipe that inherits them. Tested with bitbake-selftest: $ PYTHONPATH=lib python3 -m unittest lib.bb.tests.parse.ParseTest -v 3 new tests pass, no regressions. A separate cleanup series will follow to fix the affected files. lib/bb/parse/parse_py/BBHandler.py | 5 ++++- lib/bb/parse/parse_py/ConfHandler.py | 10 ++++++++-- lib/bb/tests/parse.py | 28 ++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 3 deletions(-)