From f1cf9dc11476b37a80523596132030e1eb156cc2 Mon Sep 17 00:00:00 2001 From: Kyler Date: Fri, 19 Dec 2025 14:59:24 -0700 Subject: [PATCH] Added riscv_gcc.py --- SLS_C/build_system/compilers/riscv_gcc.py | 180 ++++++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 SLS_C/build_system/compilers/riscv_gcc.py diff --git a/SLS_C/build_system/compilers/riscv_gcc.py b/SLS_C/build_system/compilers/riscv_gcc.py new file mode 100644 index 0000000..2fe55a4 --- /dev/null +++ b/SLS_C/build_system/compilers/riscv_gcc.py @@ -0,0 +1,180 @@ +#!/usr/bin/env python3 +""" +RISC-V GCC compiler implementation for embedded targets. +Used primarily for ESP32-C3 and other RISC-V microcontrollers. +""" + +from pathlib import Path +from typing import List, Optional +from .base_gcc import BaseGCCCompiler +from .base import CompileResult +from build_system.utils import run + + +class RISCVGCCCompiler(BaseGCCCompiler): + """RISC-V GCC compiler for embedded targets.""" + + def __init__(self, executable: str = "riscv32-esp-elf-gcc", arch: str = "rv32imc", abi: str = "ilp32"): + """ + Initialize RISC-V GCC compiler. + + Args: + executable: Compiler executable name + arch: Target architecture (e.g., "rv32imc", "rv32imac") + abi: Target ABI (e.g., "ilp32", "ilp32f") + """ + super().__init__("RISC-V GCC", executable) + self.arch = arch + self.abi = abi + + def _get_arch_flags(self) -> List[str]: + """ + Get architecture-specific flags. + + Returns: + List of architecture-specific compiler flags + """ + return [ + f"-march={self.arch}", + f"-mabi={self.abi}" + ] + + 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 RISC-V 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 + """ + # Prepend architecture-specific flags to user flags + arch_flags = self._get_arch_flags() + combined_flags = arch_flags + (flags or []) + + # Call parent compile with combined flags + return super().compile( + source=source, + output=output, + flags=combined_flags, + defines=defines, + include_dirs=include_dirs, + dependency_file=dependency_file + ) + + 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 RISC-V 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 + """ + # Prepend architecture-specific flags to user flags + arch_flags = self._get_arch_flags() + combined_flags = arch_flags + (flags or []) + + # Call parent link with combined flags + return super().link( + objects=objects, + output=output, + flags=combined_flags, + libraries=libraries, + library_dirs=library_dirs + ) + + def set_arch(self, arch: str) -> None: + """ + Set the target architecture. + + Args: + arch: Target architecture (e.g., "rv32imc", "rv32imac") + """ + self.arch = arch + + def set_abi(self, abi: str) -> None: + """ + Set the target ABI. + + Args: + abi: Target ABI (e.g., "ilp32", "ilp32f") + """ + self.abi = abi + + +def detect_riscv_gcc_compiler() -> Optional[RISCVGCCCompiler]: + """ + Detect and return an available RISC-V GCC compiler. + + Returns: + RISCVGCCCompiler instance if found, None otherwise + """ + from build_system.utils import which + + # Try to find RISC-V GCC (ESP32 toolchain first, then generic) + compilers = [ + "riscv32-esp-elf-gcc", # ESP-IDF toolchain + "riscv32-unknown-elf-gcc", # Generic RISC-V toolchain + "riscv64-unknown-elf-gcc" # 64-bit RISC-V toolchain + ] + + for compiler in compilers: + if which(compiler): + return RISCVGCCCompiler(compiler) + + return None + + +def check_riscv_toolchain() -> bool: + """ + Check if RISC-V toolchain is available. + + Returns: + True if RISC-V toolchain is found, False otherwise + """ + from build_system.utils import check_tool + + # Check for ESP32-C3 toolchain first + if check_tool("riscv32-esp-elf-gcc"): + return True + + # Check for generic RISC-V toolchain + if check_tool("riscv32-unknown-elf-gcc"): + return True + + print("ERROR: RISC-V toolchain not found. Install one of:") + print(" ESP32-C3: Install ESP-IDF (https://docs.espressif.com/projects/esp-idf/)") + print(" Generic RISC-V:") + print(" Ubuntu/Debian: sudo apt install gcc-riscv64-unknown-elf") + print(" macOS: brew tap riscv/riscv && brew install riscv-tools") + + return False