Skip to content

Commit 8c6a774

Browse files
committed
Fix usermod validation portability
Use proper path analysis instead of bare text matching.
1 parent 53d6c4b commit 8c6a774

1 file changed

Lines changed: 22 additions & 11 deletions

File tree

pio-scripts/validate_modules.py

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -49,25 +49,36 @@ def check_elf_modules(elf_path: Path, env, module_lib_builders) -> set[str]:
4949
secho(f"WARNING: nm failed ({e}); skipping per-module validation", fg="yellow", err=True)
5050
return {Path(b.build_dir).name for b in module_lib_builders} # conservative pass
5151

52-
# Build a filtered set of lines that have a nonzero address.
52+
# Collect source file Paths from placed symbols (nonzero address only).
5353
# nm --defined-only still includes debugging symbols (type 'N') such as the
5454
# per-CU markers GCC emits in .debug_info (e.g. "usermod_example_cpp_6734d48d").
5555
# These live at address 0x00000000 in their debug section — not in any load
5656
# segment — so filtering them out leaves only genuinely placed symbols.
57-
placed_lines = [
58-
line for line in nm_output.splitlines()
59-
if (parts := line.split(None, 1)) and parts[0].lstrip('0')
60-
]
61-
placed_output = "\n".join(placed_lines)
57+
# nm -l appends a tab-separated "file:lineno" location to each symbol line.
58+
placed_paths: set[Path] = set()
59+
for line in nm_output.splitlines():
60+
parts = line.split(None, 1)
61+
if not (parts and parts[0].lstrip('0')):
62+
continue # zero address — skip debug-section marker
63+
if '\t' in line:
64+
loc = line.rsplit('\t', 1)[1]
65+
# Strip trailing :lineno (e.g. "/path/to/foo.cpp:42" → "/path/to/foo.cpp")
66+
file_part = loc.rsplit(':', 1)[0]
67+
placed_paths.add(Path(file_part))
6268

6369
found = set()
6470
for builder in module_lib_builders:
6571
# builder.src_dir is the library source directory (used by is_wled_module() too)
66-
src_dir = str(builder.src_dir).rstrip("/\\")
67-
# Guard against prefix collisions (e.g. /path/to/mod vs /path/to/mod-extra)
68-
# by requiring a path separator immediately after the directory name.
69-
if re.search(re.escape(src_dir) + r'[/\\]', placed_output):
70-
found.add(Path(builder.build_dir).name)
72+
src_dir = Path(str(builder.src_dir))
73+
# Path.is_relative_to() / relative_to() handles OS-specific separators
74+
# correctly without any regex, avoiding Windows path escaping issues.
75+
for p in placed_paths:
76+
try:
77+
p.relative_to(src_dir)
78+
found.add(Path(builder.build_dir).name)
79+
break
80+
except ValueError:
81+
pass
7182
return found
7283

7384

0 commit comments

Comments
 (0)