@@ -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