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

186 lines
5.0 KiB
Python

"""
GCC and Clang compiler implementation.
This module implements the Compiler interface for GCC and Clang,
which share similar command-line interfaces.
"""
from pathlib import Path
from typing import List, Optional
import subprocess
from .base import Compiler
class GCCCompiler(Compiler):
"""
GCC/Clang compiler implementation.
Works with both gcc and clang as they use compatible command-line syntax.
"""
def __init__(self, executable: str = "gcc", is_clang: bool = False):
"""
Initialize GCC/Clang compiler.
Args:
executable: Compiler executable name (default: "gcc")
is_clang: Whether this is clang (affects some flags)
"""
super().__init__(executable)
self.is_clang = is_clang
def compile(
self,
source: Path,
output: Path,
*,
includes: Optional[List[Path]] = None,
defines: Optional[dict] = None,
flags: Optional[List[str]] = None,
generate_deps: bool = True,
is_test: bool = False
) -> Path:
"""
Compile a source file using GCC/Clang.
Args:
source: Path to source file
output: Path to output object file
includes: Include directories
defines: Preprocessor defines
flags: Additional compiler flags
generate_deps: Generate dependency file
is_test: Test build (disables optimization)
Returns:
Path to compiled object file
"""
cmd = [self.executable]
# Add user flags first (can be overridden by later flags)
if flags:
cmd.extend(flags)
# Standard flags
cmd.extend([
"-std=c99",
"-Wall",
"-Wextra",
"-Werror",
"-g" # Debug symbols
])
# Test builds: disable optimization and allow unused functions
if is_test:
cmd.extend(["-O0", "-Wno-unused-function"])
# Include directories
if includes:
for inc in includes:
cmd.append(f"-I{inc}")
# Defines
if defines:
for name, value in defines.items():
if value is None:
cmd.append(f"-D{name}")
else:
# Properly escape string values
if isinstance(value, str):
cmd.append(f"-D{name}=\"{value}\"")
else:
cmd.append(f"-D{name}={value}")
# Dependency generation
if generate_deps:
cmd.extend(["-MMD", "-MP"])
# Compile only
cmd.extend(["-c", str(source)])
# Output file
cmd.extend(["-o", str(output)])
# Ensure output directory exists
output.parent.mkdir(parents=True, exist_ok=True)
# Run compilation
self._run(cmd)
return output
def link(
self,
objects: List[Path],
output: Path,
*,
libraries: Optional[List[str]] = None,
library_paths: Optional[List[Path]] = None,
flags: Optional[List[str]] = None
) -> Path:
"""
Link object files into an executable using GCC/Clang.
Args:
objects: Object files to link
output: Output executable path
libraries: Libraries to link (e.g., ['m', 'pthread'])
library_paths: Library search paths
flags: Additional linker flags
Returns:
Path to linked executable
"""
cmd = [self.executable]
# Add user flags first
if flags:
cmd.extend(flags)
# Object files
cmd.extend(str(obj) for obj in objects)
# Library paths
if library_paths:
for path in library_paths:
cmd.append(f"-L{path}")
# Libraries
if libraries:
for lib in libraries:
cmd.append(f"-l{lib}")
# Output file
cmd.extend(["-o", str(output)])
# Ensure output directory exists
output.parent.mkdir(parents=True, exist_ok=True)
# Run linker
self._run(cmd)
return output
def get_object_extension(self) -> str:
"""Get object file extension for GCC/Clang."""
return ".o"
def get_executable_extension(self) -> str:
"""Get executable extension (empty for Unix-like systems)."""
return ""
def _run(self, cmd: List[str]):
"""
Execute a command and handle errors.
Args:
cmd: Command to execute
Raises:
subprocess.CalledProcessError: If compilation/linking fails
"""
print(">>", " ".join(str(c) for c in cmd))
subprocess.check_call(cmd)