YREA-SLS/SLS_C/build_system/compilers/gcc.py

154 lines
4.5 KiB
Python

#!/usr/bin/env python3
"""
GCC/Clang compiler implementation.
Handles both GCC and Clang as they use similar command-line interfaces.
"""
from pathlib import Path
from typing import List, Optional
from .base import Compiler, CompileResult
from build_system.utils import run
class GCCCompiler(Compiler):
"""GCC or Clang compiler implementation."""
def __init__(self, executable: str = "gcc"):
"""
Initialize GCC/Clang compiler.
Args:
executable: Compiler executable name ("gcc" or "clang")
"""
name = "Clang" if "clang" in executable.lower() else "GCC"
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/Clang.
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/Clang.
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/Clang."""
return ".o"
def get_dependency_extension(self) -> str:
"""Get dependency file extension for GCC/Clang."""
return ".d"
def supports_dependency_generation(self) -> bool:
"""GCC/Clang supports automatic dependency generation."""
return True