mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2026-09-26 14:54:35 +08:00
[Tools] Add documents for tools script; Add NG for tools
This commit is contained in:
@@ -0,0 +1,304 @@
|
||||
# -*- 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 or directory containing it
|
||||
|
||||
Returns:
|
||||
List of build objects
|
||||
"""
|
||||
import json
|
||||
|
||||
# Find package.json
|
||||
if package_path is None:
|
||||
package_path = 'package.json'
|
||||
elif os.path.isdir(package_path):
|
||||
package_path = os.path.join(package_path, 'package.json')
|
||||
|
||||
if not os.path.exists(package_path):
|
||||
env.GetContext().logger.error(f"Package file not found: {package_path}")
|
||||
return []
|
||||
|
||||
# Load package definition
|
||||
with open(package_path, 'r') as f:
|
||||
package = json.load(f)
|
||||
|
||||
# Process package
|
||||
name = package.get('name', 'unnamed')
|
||||
dependencies = package.get('dependencies', {})
|
||||
|
||||
# Check main dependency
|
||||
if 'RT_USING_' + name.upper() not in dependencies:
|
||||
main_depend = 'RT_USING_' + name.upper().replace('-', '_')
|
||||
else:
|
||||
main_depend = list(dependencies.keys())[0]
|
||||
|
||||
if not env.GetDepend(main_depend):
|
||||
return []
|
||||
|
||||
# Collect sources
|
||||
src = []
|
||||
include_paths = []
|
||||
|
||||
sources = package.get('sources', {})
|
||||
for category, config in sources.items():
|
||||
# Check condition
|
||||
condition = config.get('condition')
|
||||
if condition and not eval(condition, {'env': env, 'GetDepend': env.GetDepend}):
|
||||
continue
|
||||
|
||||
# Add source files
|
||||
source_files = config.get('source_files', [])
|
||||
for pattern in source_files:
|
||||
src.extend(env.Glob(pattern))
|
||||
|
||||
# Add header paths
|
||||
header_path = config.get('header_path', [])
|
||||
include_paths.extend(header_path)
|
||||
|
||||
# Create group
|
||||
return env.DefineGroup(name, src, depend=main_depend, CPPPATH=include_paths)
|
||||
|
||||
@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', '')
|
||||
Reference in New Issue
Block a user