1# -*- coding: utf-8 -*- 2""" 3Core module for RT-Thread build system. 4 5This module provides the central BuildContext class that manages the build state 6and coordinates between different components. 7""" 8 9import os 10import logging 11from typing import Dict, List, Optional, Any 12from dataclasses import dataclass, field 13 14from .config import ConfigManager 15from .project import ProjectRegistry 16from .toolchain import ToolchainManager 17from .generator import GeneratorRegistry 18from .utils import PathService 19 20 21class BuildContext: 22 """ 23 Central build context that manages all build-related state. 24 25 This class replaces the global variables in building.py with a proper 26 object-oriented design while maintaining compatibility. 27 """ 28 29 # Class variable to store the current context (for backward compatibility) 30 _current_context: Optional['BuildContext'] = None 31 32 def __init__(self, root_directory: str): 33 """ 34 Initialize build context. 35 36 Args: 37 root_directory: RT-Thread root directory path 38 """ 39 self.root_directory = os.path.abspath(root_directory) 40 self.bsp_directory = os.getcwd() 41 42 # Initialize managers 43 self.config_manager = ConfigManager() 44 self.project_registry = ProjectRegistry() 45 self.toolchain_manager = ToolchainManager() 46 self.generator_registry = GeneratorRegistry() 47 self.path_service = PathService(self.bsp_directory) 48 49 # Build environment 50 self.environment = None 51 self.build_options = {} 52 53 # Logging 54 self.logger = self._setup_logger() 55 56 # Set as current context 57 BuildContext._current_context = self 58 59 @classmethod 60 def get_current(cls) -> Optional['BuildContext']: 61 """Get the current build context.""" 62 return cls._current_context 63 64 @classmethod 65 def set_current(cls, context: Optional['BuildContext']) -> None: 66 """Set the current build context.""" 67 cls._current_context = context 68 69 def _setup_logger(self) -> logging.Logger: 70 """Setup logger for build system.""" 71 logger = logging.getLogger('rtthread.build') 72 if not logger.handlers: 73 handler = logging.StreamHandler() 74 formatter = logging.Formatter('[%(levelname)s] %(message)s') 75 handler.setFormatter(formatter) 76 logger.addHandler(handler) 77 logger.setLevel(logging.INFO) 78 return logger 79 80 def prepare_environment(self, env) -> None: 81 """ 82 Prepare the build environment. 83 84 Args: 85 env: SCons Environment object 86 """ 87 self.environment = env 88 89 # Set environment variables 90 env['RTT_ROOT'] = self.root_directory 91 env['BSP_ROOT'] = self.bsp_directory 92 93 # Add to Python path 94 import sys 95 tools_path = os.path.join(self.root_directory, 'tools') 96 if tools_path not in sys.path: 97 sys.path.insert(0, tools_path) 98 99 self.logger.debug(f"Prepared environment with RTT_ROOT={self.root_directory}") 100 101 def load_configuration(self, config_file: str = 'rtconfig.h') -> None: 102 """ 103 Load configuration from rtconfig.h. 104 105 Args: 106 config_file: Path to configuration file 107 """ 108 config_path = os.path.join(self.bsp_directory, config_file) 109 if os.path.exists(config_path): 110 self.config_manager.load_from_file(config_path) 111 self.build_options = self.config_manager.get_all_options() 112 self.logger.info(f"Loaded configuration from {config_file}") 113 else: 114 self.logger.warning(f"Configuration file {config_file} not found") 115 116 def get_dependency(self, depend: Any) -> bool: 117 """ 118 Check if dependency is satisfied. 119 120 Args: 121 depend: Dependency name or list of names 122 123 Returns: 124 True if dependency is satisfied 125 """ 126 return self.config_manager.get_dependency(depend) 127 128 def register_project_group(self, group) -> None: 129 """ 130 Register a project group. 131 132 Args: 133 group: ProjectGroup instance 134 """ 135 self.project_registry.register_group(group) 136 137 def merge_groups(self) -> List: 138 """ 139 Merge all registered project groups. 140 141 Returns: 142 List of build objects 143 """ 144 return self.project_registry.merge_groups(self.environment) 145 146 147@dataclass 148class BuildOptions: 149 """Build options container.""" 150 verbose: bool = False 151 strict: bool = False 152 target: Optional[str] = None 153 jobs: int = 1 154 clean: bool = False 155 156 157@dataclass 158class ProjectInfo: 159 """Project information for generators.""" 160 name: str = "rtthread" 161 target_name: str = "rtthread.elf" 162 163 # File collections 164 source_files: List[str] = field(default_factory=list) 165 include_paths: List[str] = field(default_factory=list) 166 defines: Dict[str, str] = field(default_factory=dict) 167 168 # Compiler options 169 cflags: str = "" 170 cxxflags: str = "" 171 asflags: str = "" 172 ldflags: str = "" 173 174 # Libraries 175 libs: List[str] = field(default_factory=list) 176 lib_paths: List[str] = field(default_factory=list)