| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- # -*- coding: utf-8 -*-
- """
- Environment extensions for RT-Thread build system.
- This module provides methods that are injected into the SCons Environment object
- to provide RT-Thread-specific functionality.
- """
- import os
- from typing import List, Union, Dict, Any, Optional
- from SCons.Script import *
- from .core import BuildContext
- from .project import ProjectGroup
- class RTEnv:
- """
- RT-Thread environment extensions (RTEnv).
-
- This class provides methods that are added to the SCons Environment object.
- """
-
- @staticmethod
- def inject_methods(env):
- """
- Inject RT-Thread methods into SCons Environment.
-
- Args:
- env: SCons Environment object
- """
- # Core build methods
- env.AddMethod(RTEnv.DefineGroup, 'DefineGroup')
- env.AddMethod(RTEnv.GetDepend, 'GetDepend')
- env.AddMethod(RTEnv.SrcRemove, 'SrcRemove')
- env.AddMethod(RTEnv.GetCurrentDir, 'GetCurrentDir')
- env.AddMethod(RTEnv.BuildPackage, 'BuildPackage')
-
- # Utility methods
- env.AddMethod(RTEnv.Glob, 'GlobFiles')
- env.AddMethod(RTEnv.GetBuildOptions, 'GetBuildOptions')
- env.AddMethod(RTEnv.GetContext, 'GetContext')
-
- # Path utilities
- env.AddMethod(RTEnv.GetRTTRoot, 'GetRTTRoot')
- env.AddMethod(RTEnv.GetBSPRoot, 'GetBSPRoot')
-
- @staticmethod
- def DefineGroup(env, name: str, src: List[str], depend: Any = None, **kwargs) -> List:
- """
- Define a component group.
-
- This method maintains compatibility with the original DefineGroup function
- while using the new object-oriented implementation.
-
- Args:
- env: SCons Environment
- name: Group name
- src: Source file list
- depend: Dependency conditions
- **kwargs: Additional parameters (CPPPATH, CPPDEFINES, etc.)
-
- Returns:
- List of build objects
- """
- context = BuildContext.get_current()
- if not context:
- raise RuntimeError("BuildContext not initialized")
-
- # Check dependencies
- if depend and not env.GetDepend(depend):
- return []
-
- # Process source files
- if isinstance(src, str):
- src = [src]
-
- # Create project group
- group = ProjectGroup(
- name=name,
- sources=src,
- dependencies=depend if isinstance(depend, list) else [depend] if depend else [],
- environment=env
- )
-
- # Process parameters
- group.include_paths = kwargs.get('CPPPATH', [])
- group.defines = kwargs.get('CPPDEFINES', {})
- group.cflags = kwargs.get('CFLAGS', '')
- group.cxxflags = kwargs.get('CXXFLAGS', '')
- group.local_cflags = kwargs.get('LOCAL_CFLAGS', '')
- group.local_cxxflags = kwargs.get('LOCAL_CXXFLAGS', '')
- group.local_include_paths = kwargs.get('LOCAL_CPPPATH', [])
- group.local_defines = kwargs.get('LOCAL_CPPDEFINES', {})
- group.libs = kwargs.get('LIBS', [])
- group.lib_paths = kwargs.get('LIBPATH', [])
-
- # Build objects
- objects = group.build(env)
-
- # Register group
- context.register_project_group(group)
-
- return objects
-
- @staticmethod
- def GetDepend(env, depend: Any) -> bool:
- """
- Check if dependency is satisfied.
-
- Args:
- env: SCons Environment
- depend: Dependency name or list of names
-
- Returns:
- True if dependency is satisfied
- """
- context = BuildContext.get_current()
- if not context:
- # Fallback to checking environment variables
- if isinstance(depend, str):
- return env.get(depend, False)
- elif isinstance(depend, list):
- return all(env.get(d, False) for d in depend)
- return False
-
- return context.get_dependency(depend)
-
- @staticmethod
- def SrcRemove(env, src: List[str], remove: List[str]) -> None:
- """
- Remove files from source list.
-
- Args:
- env: SCons Environment
- src: Source file list (modified in place)
- remove: Files to remove
- """
- if not isinstance(remove, list):
- remove = [remove]
-
- for item in remove:
- # Handle both exact matches and pattern matches
- if item in src:
- src.remove(item)
- else:
- # Try pattern matching
- import fnmatch
- to_remove = [f for f in src if fnmatch.fnmatch(f, item)]
- for f in to_remove:
- src.remove(f)
-
- @staticmethod
- def GetCurrentDir(env) -> str:
- """
- Get current directory.
-
- Args:
- env: SCons Environment
-
- Returns:
- Current directory path
- """
- return Dir('.').abspath
-
- @staticmethod
- def BuildPackage(env, package_path: str = None) -> List:
- """
- Build package from package.json.
-
- Args:
- env: SCons Environment
- package_path: Path to package.json. If None, looks for package.json in current directory.
-
- Returns:
- List of build objects
- """
- # Import the existing package module
- import sys
- import os
-
- # Get the building module path
- building_path = os.path.dirname(os.path.abspath(__file__))
- tools_path = os.path.dirname(building_path)
-
- # Add to path if not already there
- if tools_path not in sys.path:
- sys.path.insert(0, tools_path)
-
- # Import and use the existing BuildPackage
- try:
- from package import BuildPackage as build_package_func
-
- # BuildPackage uses global functions, so we need to set up the context
- # Save current directory
- current_dir = os.getcwd()
-
- # Change to the directory where we want to build
- if package_path is None:
- work_dir = env.GetCurrentDir()
- elif os.path.isdir(package_path):
- work_dir = package_path
- else:
- work_dir = os.path.dirname(package_path)
-
- os.chdir(work_dir)
-
- try:
- # Call the original BuildPackage
- result = build_package_func(package_path)
- finally:
- # Restore directory
- os.chdir(current_dir)
-
- return result
-
- except ImportError:
- # Fallback if import fails
- context = BuildContext.get_current()
- if context:
- context.logger.error("Failed to import package module")
- return []
-
- @staticmethod
- def Glob(env, pattern: str) -> List[str]:
- """
- Enhanced glob with better error handling.
-
- Args:
- env: SCons Environment
- pattern: File pattern
-
- Returns:
- List of matching files
- """
- try:
- files = Glob(pattern, strings=True)
- return sorted(files) # Sort for consistent ordering
- except Exception as e:
- context = BuildContext.get_current()
- if context:
- context.logger.warning(f"Glob pattern '{pattern}' failed: {e}")
- return []
-
- @staticmethod
- def GetBuildOptions(env) -> Dict[str, Any]:
- """
- Get build options.
-
- Args:
- env: SCons Environment
-
- Returns:
- Dictionary of build options
- """
- context = BuildContext.get_current()
- if context:
- return context.build_options
- return {}
-
- @staticmethod
- def GetContext(env) -> Optional[BuildContext]:
- """
- Get current build context.
-
- Args:
- env: SCons Environment
-
- Returns:
- BuildContext instance or None
- """
- return BuildContext.get_current()
-
- @staticmethod
- def GetRTTRoot(env) -> str:
- """
- Get RT-Thread root directory.
-
- Args:
- env: SCons Environment
-
- Returns:
- RT-Thread root path
- """
- return env.get('RTT_ROOT', '')
-
- @staticmethod
- def GetBSPRoot(env) -> str:
- """
- Get BSP root directory.
-
- Args:
- env: SCons Environment
-
- Returns:
- BSP root path
- """
- return env.get('BSP_ROOT', '')
|