#!/usr/bin/env python3 """ ARM GCC compiler implementation for embedded targets. Used primarily for RP2040 and other ARM Cortex-M microcontrollers. """ from pathlib import Path from typing import List, Optional from .base import Compiler, CompileResult from build_system.utils import run class ARMGCCCompiler(Compiler): """ARM GCC compiler for embedded targets.""" def __init__(self, executable: str = "arm-none-eabi-gcc", cpu: str = "cortex-m0plus"): """ Initialize ARM GCC compiler. Args: executable: Compiler executable name cpu: Target CPU (e.g., "cortex-m0plus", "cortex-m4") """ super().__init__("ARM GCC", executable) self.cpu = cpu self.thumb = True # Use Thumb instruction set by default 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 ARM GCC. 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 CPU-specific flags cmd.append(f"-mcpu={self.cpu}") if self.thumb: cmd.append("-mthumb") # 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 ARM GCC. 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 CPU-specific flags cmd.append(f"-mcpu={self.cpu}") if self.thumb: cmd.append("-mthumb") # 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 ARM GCC.""" return ".o" def get_dependency_extension(self) -> str: """Get dependency file extension for ARM GCC.""" return ".d" def supports_dependency_generation(self) -> bool: """ARM GCC supports automatic dependency generation.""" return True def set_cpu(self, cpu: str) -> None: """ Set the target CPU. Args: cpu: Target CPU name (e.g., "cortex-m0plus", "cortex-m4") """ self.cpu = cpu def set_thumb(self, enabled: bool) -> None: """ Enable or disable Thumb instruction set. Args: enabled: True to enable Thumb, False to disable """ self.thumb = enabled def check_arm_toolchain() -> bool: """ Check if ARM toolchain is available. Returns: True if ARM toolchain is found, False otherwise """ from build_system.utils import check_tool if check_tool("arm-none-eabi-gcc"): return True else: print( "ARM toolchain not found. Install arm-none-eabi-gcc:\n" " Ubuntu/Debian: sudo apt install gcc-arm-none-eabi\n" " macOS: brew install arm-none-eabi-gcc" )