mirror of
https://github.com/wled/WLED.git
synced 2026-04-25 16:42:44 +00:00
Fix usermod validation portability
Use proper path analysis instead of bare text matching. Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -49,25 +49,36 @@ def check_elf_modules(elf_path: Path, env, module_lib_builders) -> set[str]:
|
||||
secho(f"WARNING: nm failed ({e}); skipping per-module validation", fg="yellow", err=True)
|
||||
return {Path(b.build_dir).name for b in module_lib_builders} # conservative pass
|
||||
|
||||
# Build a filtered set of lines that have a nonzero address.
|
||||
# Collect source file Paths from placed symbols (nonzero address only).
|
||||
# nm --defined-only still includes debugging symbols (type 'N') such as the
|
||||
# per-CU markers GCC emits in .debug_info (e.g. "usermod_example_cpp_6734d48d").
|
||||
# These live at address 0x00000000 in their debug section — not in any load
|
||||
# segment — so filtering them out leaves only genuinely placed symbols.
|
||||
placed_lines = [
|
||||
line for line in nm_output.splitlines()
|
||||
if (parts := line.split(None, 1)) and parts[0].lstrip('0')
|
||||
]
|
||||
placed_output = "\n".join(placed_lines)
|
||||
# nm -l appends a tab-separated "file:lineno" location to each symbol line.
|
||||
placed_paths: set[Path] = set()
|
||||
for line in nm_output.splitlines():
|
||||
parts = line.split(None, 1)
|
||||
if not (parts and parts[0].lstrip('0')):
|
||||
continue # zero address — skip debug-section marker
|
||||
if '\t' in line:
|
||||
loc = line.rsplit('\t', 1)[1]
|
||||
# Strip trailing :lineno (e.g. "/path/to/foo.cpp:42" → "/path/to/foo.cpp")
|
||||
file_part = loc.rsplit(':', 1)[0]
|
||||
placed_paths.add(Path(file_part))
|
||||
|
||||
found = set()
|
||||
for builder in module_lib_builders:
|
||||
# builder.src_dir is the library source directory (used by is_wled_module() too)
|
||||
src_dir = str(builder.src_dir).rstrip("/\\")
|
||||
# Guard against prefix collisions (e.g. /path/to/mod vs /path/to/mod-extra)
|
||||
# by requiring a path separator immediately after the directory name.
|
||||
if re.search(re.escape(src_dir) + r'[/\\]', placed_output):
|
||||
found.add(Path(builder.build_dir).name)
|
||||
src_dir = Path(str(builder.src_dir))
|
||||
# Path.is_relative_to() / relative_to() handles OS-specific separators
|
||||
# correctly without any regex, avoiding Windows path escaping issues.
|
||||
for p in placed_paths:
|
||||
try:
|
||||
p.relative_to(src_dir)
|
||||
found.add(Path(builder.build_dir).name)
|
||||
break
|
||||
except ValueError:
|
||||
pass
|
||||
return found
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user