Skip to content

Commit 8d3df5e

Browse files
willmmilesclaude
andcommitted
Speed up usermod validation
Avoid checking usermods we've already matched, and exit early if we've got everything. Co-authored-by: Claude <noreply@anthropic.com>
1 parent 3bfdb73 commit 8d3df5e

1 file changed

Lines changed: 18 additions & 17 deletions

File tree

pio-scripts/validate_modules.py

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -49,36 +49,37 @@ 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-
# Collect source file Paths from placed symbols (nonzero address only).
52+
# Match placed symbols against builders as we parse nm output, exiting early
53+
# once all builders are accounted for.
5354
# nm --defined-only still includes debugging symbols (type 'N') such as the
5455
# per-CU markers GCC emits in .debug_info (e.g. "usermod_example_cpp_6734d48d").
5556
# These live at address 0x00000000 in their debug section — not in any load
5657
# segment — so filtering them out leaves only genuinely placed symbols.
5758
# nm -l appends a tab-separated "file:lineno" location to each symbol line.
58-
placed_paths: set[Path] = set()
59+
remaining = {Path(str(b.src_dir)): Path(b.build_dir).name for b in module_lib_builders}
60+
found = set()
61+
5962
for line in nm_output.splitlines():
63+
if not remaining:
64+
break # all builders matched
6065
parts = line.split(None, 1)
6166
if not (parts and parts[0].lstrip('0')):
6267
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))
68-
69-
found = set()
70-
for builder in module_lib_builders:
71-
# builder.src_dir is the library source directory (used by is_wled_module() too)
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:
68+
if '\t' not in line:
69+
continue
70+
loc = line.rsplit('\t', 1)[1]
71+
# Strip trailing :lineno (e.g. "/path/to/foo.cpp:42" → "/path/to/foo.cpp")
72+
src_path = Path(loc.rsplit(':', 1)[0])
73+
# Path.relative_to() handles OS-specific separators correctly without
74+
# any regex, avoiding Windows path escaping issues.
75+
for src_dir in list(remaining):
7676
try:
77-
p.relative_to(src_dir)
78-
found.add(Path(builder.build_dir).name)
77+
src_path.relative_to(src_dir)
78+
found.add(remaining.pop(src_dir))
7979
break
8080
except ValueError:
8181
pass
82+
8283
return found
8384

8485

0 commit comments

Comments
 (0)