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

171 lines
5.0 KiB
Python

#!/usr/bin/env python3
"""
Base compiler interface for the build system.
Defines the abstract Compiler class that all specific compilers must implement.
"""
from abc import ABC, abstractmethod
from pathlib import Path
from typing import List, Optional
from dataclasses import dataclass
@dataclass
class CompileResult:
"""Result of a compilation operation."""
object_file: Path
dependency_file: Optional[Path] = None
success: bool = True
class Compiler(ABC):
"""Abstract base class for all compilers."""
def __init__(self, name: str, executable: str):
"""
Initialize the compiler.
Args:
name: Human-readable name of the compiler (e.g., "GCC", "MSVC")
executable: Executable name or path (e.g., "gcc", "cl")
"""
self.name = name
self.executable = executable
@abstractmethod
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 single source file to an object file.
Args:
source: Source file path
output: Output object file path
flags: Additional compiler flags
defines: Preprocessor defines (e.g., ["DEBUG", "VERSION=1.0"])
include_dirs: Additional include directories
dependency_file: Path for dependency file (.d file)
Returns:
CompileResult with object file path and success status
Raises:
subprocess.CalledProcessError: If compilation fails
"""
pass
@abstractmethod
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 or library.
Args:
objects: List of object file paths
output: Output executable or library path
flags: Additional linker flags
libraries: Libraries to link against (e.g., ["m", "pthread"])
library_dirs: Additional library search directories
Returns:
True if linking succeeded, False otherwise
Raises:
subprocess.CalledProcessError: If linking fails
"""
pass
@abstractmethod
def get_object_extension(self) -> str:
"""
Get the file extension for object files.
Returns:
Object file extension (e.g., ".o" or ".obj")
"""
pass
@abstractmethod
def get_dependency_extension(self) -> str:
"""
Get the file extension for dependency files.
Returns:
Dependency file extension (e.g., ".d")
"""
pass
def supports_dependency_generation(self) -> bool:
"""
Check if the compiler supports automatic dependency generation.
Returns:
True if dependency generation is supported, False otherwise
"""
return True
def get_define_flag(self, define: str) -> str:
"""
Get the compiler flag for a preprocessor define.
Args:
define: Define string (e.g., "DEBUG" or "VERSION=1.0")
Returns:
Compiler-specific define flag (e.g., "-DDEBUG" or "/DDEBUG")
"""
# Most compilers use -D, but can be overridden
return f"-D{define}"
def get_include_flag(self, include_dir: Path) -> str:
"""
Get the compiler flag for an include directory.
Args:
include_dir: Include directory path
Returns:
Compiler-specific include flag (e.g., "-Iinclude" or "/Iinclude")
"""
# Most compilers use -I, but can be overridden
return f"-I{include_dir}"
def get_output_flag(self, output: Path) -> List[str]:
"""
Get the compiler flag(s) for specifying output file.
Args:
output: Output file path
Returns:
List of flags (e.g., ["-o", "output.o"] or ["/Fooutput.obj"])
"""
# Most compilers use -o, but can be overridden
return ["-o", str(output)]
def get_compile_only_flag(self) -> str:
"""
Get the flag to compile without linking.
Returns:
Compile-only flag (e.g., "-c")
"""
return "-c"
def __str__(self) -> str:
"""String representation of the compiler."""
return f"{self.name} ({self.executable})"
def __repr__(self) -> str:
"""Detailed string representation."""
return f"Compiler(name='{self.name}', executable='{self.executable}')"