""" ARM GCC compiler implementation for embedded targets. This module implements the Compiler interface for ARM GCC toolchain, used for cross-compiling to ARM Cortex-M processors (e.g., RP2040). """ from pathlib import Path from typing import List, Optional from .gcc import GCCCompiler class ARMGCCCompiler(GCCCompiler): """ ARM GCC compiler implementation for embedded targets. Uses the arm-none-eabi-gcc toolchain for bare-metal ARM development. Extends GCCCompiler with ARM Cortex-M specific flags. """ def __init__( self, executable: str = "arm-none-eabi-gcc", cpu: str = "cortex-m0plus" ): """ Initialize ARM GCC compiler. Args: executable: ARM GCC executable (default: "arm-none-eabi-gcc") cpu: Target CPU architecture (default: "cortex-m0plus" for RP2040) """ super().__init__(executable=executable, is_clang=False) self.cpu = cpu self.fpu = None self.float_abi = None self.additional_arch_flags = [] def set_cpu(self, cpu: str): """ Set target CPU architecture. Args: cpu: CPU name (e.g., "cortex-m0plus", "cortex-m4", "cortex-m7") Returns: Self for method chaining """ self.cpu = cpu return self def set_fpu(self, fpu: str, float_abi: str = "hard"): """ Set FPU configuration (for Cortex-M4F, M7, etc.). Args: fpu: FPU type (e.g., "fpv4-sp-d16", "fpv5-d16") float_abi: Float ABI ("soft", "softfp", or "hard") Returns: Self for method chaining """ self.fpu = fpu self.float_abi = float_abi return self def add_arch_flags(self, flags: List[str]): """ Add additional architecture-specific flags. Args: flags: List of flags to add Returns: Self for method chaining """ self.additional_arch_flags.extend(flags) return self 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 using ARM GCC with embedded-specific flags. Adds ARM Cortex-M architecture flags before calling parent compile. """ flags = flags or [] # ARM architecture flags (must come early) arch_flags = [ f"-mcpu={self.cpu}", "-mthumb", # Use Thumb instruction set ] # FPU flags if configured if self.fpu: arch_flags.append(f"-mfpu={self.fpu}") arch_flags.append(f"-mfloat-abi={self.float_abi}") # Additional architecture flags arch_flags.extend(self.additional_arch_flags) # Prepend architecture flags (they need to come before other flags) flags = arch_flags + flags return super().compile( source, output, includes=includes, defines=defines, flags=flags, generate_deps=generate_deps, is_test=is_test ) def link( self, objects: List[Path], output: Path, *, libraries: Optional[List[str]] = None, library_paths: Optional[List[Path]] = None, flags: Optional[List[str]] = None, linker_script: Optional[Path] = None, specs: Optional[str] = None ) -> Path: """ Link using ARM GCC with embedded-specific flags. Args: objects: Object files to link output: Output executable path libraries: Libraries to link library_paths: Library search paths flags: Additional linker flags linker_script: Path to linker script (.ld file) specs: Specs file (e.g., "nosys.specs", "nano.specs") Returns: Path to linked executable """ flags = flags or [] # ARM architecture flags (need to be passed to linker too) arch_flags = [ f"-mcpu={self.cpu}", "-mthumb", ] # FPU flags if self.fpu: arch_flags.append(f"-mfpu={self.fpu}") arch_flags.append(f"-mfloat-abi={self.float_abi}") # Additional architecture flags arch_flags.extend(self.additional_arch_flags) # Linker script if linker_script: arch_flags.append(f"-T{linker_script}") # Specs file (for selecting C library variant) if specs: arch_flags.append(f"--specs={specs}") # Prepend architecture flags flags = arch_flags + flags return super().link( objects, output, libraries=libraries, library_paths=library_paths, flags=flags ) def get_executable_extension(self) -> str: """ Get executable extension for ARM embedded. Returns .elf for embedded binaries (can be converted to .bin, .hex, .uf2) """ return ".elf" class RP2040Compiler(ARMGCCCompiler): """ Specialized ARM GCC compiler for RP2040 (Raspberry Pi Pico). Pre-configured for Cortex-M0+ with RP2040-specific settings. """ def __init__(self, executable: str = "arm-none-eabi-gcc"): """Initialize compiler for RP2040.""" super().__init__(executable=executable, cpu="cortex-m0plus")