2121_FILENAME_PATTERN = r'^\..*\.cmd$'
2222_LINE_PATTERN = r'^(saved)?cmd_[^ ]*\.o := (?P<command_prefix>.* )(?P<file_path>[^ ]*\.[cS]) *(;|$)'
2323_VALID_LOG_LEVELS = ['DEBUG' , 'INFO' , 'WARNING' , 'ERROR' , 'CRITICAL' ]
24-
25- # Pre-compiled regexes for better performance
26- _INCLUDE_PATTERN = re .compile (r'^\s*#\s*include\s*[<"]([^>"]*)[>"]' )
27- _C_INCLUDE_PATTERN = re .compile (r'^\s*#\s*include\s*"([^"]*\.c)"\s*$' )
28- _FILENAME_MATCHER = re .compile (_FILENAME_PATTERN )
29-
3024# The tools/ directory adopts a different build system, and produces .cmd
3125# files in a different format. Do not support it.
3226_EXCLUDE_DIRS = ['.git' , 'Documentation' , 'include' , 'tools' ]
@@ -88,6 +82,7 @@ def cmdfiles_in_dir(directory):
8882 The path to a .cmd file.
8983 """
9084
85+ filename_matcher = re .compile (_FILENAME_PATTERN )
9186 exclude_dirs = [ os .path .join (directory , d ) for d in _EXCLUDE_DIRS ]
9287
9388 for dirpath , dirnames , filenames in os .walk (directory , topdown = True ):
@@ -97,7 +92,7 @@ def cmdfiles_in_dir(directory):
9792 continue
9893
9994 for filename in filenames :
100- if _FILENAME_MATCHER .match (filename ):
95+ if filename_matcher .match (filename ):
10196 yield os .path .join (dirpath , filename )
10297
10398
@@ -154,87 +149,8 @@ def cmdfiles_for_modorder(modorder):
154149 yield to_cmdfile (mod_line .rstrip ())
155150
156151
157- def extract_includes_from_file (source_file , root_directory ):
158- """Extract #include statements from a C file.
159-
160- Args:
161- source_file: Path to the source .c file to analyze
162- root_directory: Root directory for resolving relative paths
163-
164- Returns:
165- List of header files that should be included (without quotes/brackets)
166- """
167- includes = []
168- if not os .path .exists (source_file ):
169- return includes
170-
171- try :
172- with open (source_file , 'r' ) as f :
173- for line in f :
174- line = line .strip ()
175- # Look for #include statements.
176- # Match both #include "header.h" and #include <header.h>.
177- match = _INCLUDE_PATTERN .match (line )
178- if match :
179- header = match .group (1 )
180- # Skip including other .c files to avoid circular includes.
181- if not header .endswith ('.c' ):
182- # For relative includes (quoted), resolve path relative to source file.
183- if '"' in line :
184- src_dir = os .path .dirname (source_file )
185- header_path = os .path .join (src_dir , header )
186- if os .path .exists (header_path ):
187- rel_header = os .path .relpath (header_path , root_directory )
188- includes .append (rel_header )
189- else :
190- includes .append (header )
191- else :
192- # System include like <linux/sched.h>.
193- includes .append (header )
194- except IOError :
195- pass
196-
197- return includes
198-
199-
200- def find_included_c_files (source_file , root_directory ):
201- """Find .c files that are included by the given source file.
202-
203- Args:
204- source_file: Path to the source .c file
205- root_directory: Root directory for resolving relative paths
206-
207- Yields:
208- Full paths to included .c files
209- """
210- if not os .path .exists (source_file ):
211- return
212-
213- try :
214- with open (source_file , 'r' ) as f :
215- for line in f :
216- line = line .strip ()
217- # Look for #include "*.c" patterns.
218- match = _C_INCLUDE_PATTERN .match (line )
219- if match :
220- included_file = match .group (1 )
221- # Handle relative paths.
222- if not os .path .isabs (included_file ):
223- src_dir = os .path .dirname (source_file )
224- included_file = os .path .join (src_dir , included_file )
225-
226- # Normalize the path.
227- included_file = os .path .normpath (included_file )
228-
229- # Check if the file exists.
230- if os .path .exists (included_file ):
231- yield included_file
232- except IOError :
233- pass
234-
235-
236152def process_line (root_directory , command_prefix , file_path ):
237- """Extracts information from a .cmd line and creates entries from it.
153+ """Extracts information from a .cmd line and creates an entry from it.
238154
239155 Args:
240156 root_directory: The directory that was searched for .cmd files. Usually
@@ -244,8 +160,7 @@ def process_line(root_directory, command_prefix, file_path):
244160 Usually relative to root_directory, but sometimes absolute.
245161
246162 Returns:
247- A list of entries to append to compile_commands (may include multiple
248- entries if the source file includes other .c files).
163+ An entry to append to compile_commands.
249164
250165 Raises:
251166 ValueError: Could not find the extracted file based on file_path and
@@ -261,47 +176,11 @@ def process_line(root_directory, command_prefix, file_path):
261176 abs_path = os .path .realpath (os .path .join (root_directory , file_path ))
262177 if not os .path .exists (abs_path ):
263178 raise ValueError ('File %s not found' % abs_path )
264-
265- entries = []
266-
267- # Create entry for the main source file.
268- main_entry = {
179+ return {
269180 'directory' : root_directory ,
270181 'file' : abs_path ,
271182 'command' : prefix + file_path ,
272183 }
273- entries .append (main_entry )
274-
275- # Find and create entries for included .c files.
276- for included_c_file in find_included_c_files (abs_path , root_directory ):
277- # For included .c files, create a compilation command that:
278- # 1. Uses the same compilation flags as the parent file
279- # 2. But compiles the included file directly (not the parent)
280- # 3. Includes necessary headers from the parent file for proper macro resolution
281-
282- # Convert absolute path to relative for the command.
283- rel_path = os .path .relpath (included_c_file , root_directory )
284-
285- # Extract includes from the parent file to provide proper compilation context.
286- extra_includes = ''
287- try :
288- parent_includes = extract_includes_from_file (abs_path , root_directory )
289- if parent_includes :
290- extra_includes = ' ' + ' ' .join ('-include ' + inc for inc in parent_includes )
291- except IOError :
292- pass
293-
294- included_entry = {
295- 'directory' : root_directory ,
296- 'file' : included_c_file ,
297- # Use the same compilation prefix but target the included file directly.
298- # Add extra headers for proper macro resolution.
299- 'command' : prefix + extra_includes + ' ' + rel_path ,
300- }
301- entries .append (included_entry )
302- logging .debug ('Added entry for included file: %s' , included_c_file )
303-
304- return entries
305184
306185
307186def main ():
@@ -334,9 +213,9 @@ def main():
334213 result = line_matcher .match (f .readline ())
335214 if result :
336215 try :
337- entries = process_line (directory , result .group ('command_prefix' ),
216+ entry = process_line (directory , result .group ('command_prefix' ),
338217 result .group ('file_path' ))
339- compile_commands .extend ( entries )
218+ compile_commands .append ( entry )
340219 except ValueError as err :
341220 logging .info ('Could not add line from %s: %s' ,
342221 cmdfile , err )
0 commit comments