#!/usr/bin/env python3 """ Base GCC-like compiler implementation. Provides common functionality for GCC, Clang, and other GCC-compatible compilers. """ from pathlib import Path from typing import List, Optional from .base import Compiler, CompileResult from build_system.utils import run class BaseGCCCompiler(Compiler): """Base class for GCC-compatible compilers (GCC, Clang, etc.).""" def __init__(self, name: str, executable: str): """ Initialize base GCC-compatible compiler. Args: name: Human-readable compiler name executable: Compiler executable name """ super().__init__(name, executable) def compile(self, source: Path, output: Path, flags: Optional[List[str]] = None, defines: Optional[List[str]] = None, include_dirs: Optional[List[Path]] = None, dependency_file: Optional[Path] = None) -> CompileResult: """ Compile a source file using GCC-compatible compiler. Args: source: Source file path output: Output object file path flags: Additional compiler flags defines: Preprocessor defines include_dirs: Additional include directories dependency_file: Path for dependency file (.d file) Returns: CompileResult with object file and dependency file paths Raises: subprocess.CalledProcessError: If compilation fails """ # Ensure output directory exists output.parent.mkdir(parents=True, exist_ok=True) # Build command cmd = [self.executable] # Add flags if flags: cmd.extend(flags) # Add compile-only flag cmd.append(self.get_compile_only_flag()) # Add defines if defines: cmd.extend([self.get_define_flag(d) for d in defines]) # Add include directories if include_dirs: cmd.extend([self.get_include_flag(d) for d in include_dirs]) # Add dependency generation if requested dep_file = None if dependency_file: cmd.extend(["-MMD", "-MP"]) dep_file = dependency_file # Add source file cmd.append(str(source)) # Add output file cmd.extend(self.get_output_flag(output)) # Run compilation run(cmd) # type: ignore return CompileResult( object_file=output, dependency_file=dep_file, success=True ) def link(self, objects: List[Path], output: Path, flags: Optional[List[str]] = None, libraries: Optional[List[str]] = None, library_dirs: Optional[List[Path]] = None) -> bool: """ Link object files into an executable using GCC-compatible compiler. Args: objects: List of object file paths output: Output executable path flags: Additional linker flags libraries: Libraries to link against library_dirs: Additional library search directories Returns: True if linking succeeded Raises: subprocess.CalledProcessError: If linking fails """ # Ensure output directory exists output.parent.mkdir(parents=True, exist_ok=True) # Build command cmd = [self.executable] # Add object files cmd.extend([str(obj) for obj in objects]) # Add linker flags if flags: cmd.extend(flags) # Add library directories if library_dirs: cmd.extend([f"-L{lib_dir}" for lib_dir in library_dirs]) # Add libraries if libraries: cmd.extend([f"-l{lib}" for lib in libraries]) # Add output file cmd.extend(["-o", str(output)]) # Run linker run(cmd) # type: ignore return True def get_object_extension(self) -> str: """Get object file extension for GCC-compatible compilers.""" return ".o" def get_dependency_extension(self) -> str: """Get dependency file extension for GCC-compatible compilers.""" return ".d" def supports_dependency_generation(self) -> bool: """GCC-compatible compilers support automatic dependency generation.""" return True