summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/docs/README.md162
-rw-r--r--tools/docs/SConscript编写指南.md948
-rw-r--r--tools/docs/构建系统使用指南.md643
-rw-r--r--tools/docs/构建系统技术原理.md912
-rw-r--r--tools/ng/README.md345
-rw-r--r--tools/ng/__init__.py25
-rw-r--r--tools/ng/adapter.py218
-rw-r--r--tools/ng/building_ng.py115
-rw-r--r--tools/ng/config.py297
-rw-r--r--tools/ng/core.py176
-rw-r--r--tools/ng/environment.py304
-rw-r--r--tools/ng/generator.py368
-rw-r--r--tools/ng/integration_example.py178
-rw-r--r--tools/ng/project.py260
-rw-r--r--tools/ng/toolchain.py396
-rw-r--r--tools/ng/utils.py339
16 files changed, 5686 insertions, 0 deletions
diff --git a/tools/docs/README.md b/tools/docs/README.md
new file mode 100644
index 0000000000..295f6a4c03
--- /dev/null
+++ b/tools/docs/README.md
@@ -0,0 +1,162 @@
+# RT-Thread 构建系统文档
+
+欢迎使用RT-Thread构建系统文档。本文档集详细介绍了RT-Thread基于SCons的构建系统的使用方法和技术原理。
+
+## 文档目录
+
+### 📚 用户指南
+
+1. **[构建系统使用指南](构建系统使用指南.md)**
+ - 快速开始
+ - 命令行选项详解
+ - 工具链配置
+ - 项目生成
+ - 软件包管理
+ - 高级功能
+ - 常见问题解答
+
+2. **[SConscript编写指南](SConscript编写指南.md)**
+ - 基础语法
+ - 常用模式
+ - 高级技巧
+ - 最佳实践
+ - 示例集合
+
+### 🔧 技术文档
+
+3. **[构建系统技术原理](构建系统技术原理.md)**
+ - 系统架构设计
+ - 核心模块分析
+ - 构建流程详解
+ - 依赖管理机制
+ - 工具链适配层
+ - 项目生成器架构
+ - 扩展机制
+
+## 快速导航
+
+### 常用命令
+
+```bash
+# 基础编译
+scons # 默认编译
+scons -j8 # 8线程并行编译
+scons -c # 清理编译产物
+
+# 配置管理
+menuconfig # 图形化配置
+scons --pyconfig # Python脚本配置
+
+# 项目生成
+scons --target=mdk5 # 生成Keil MDK5项目
+scons --target=iar # 生成IAR项目
+scons --target=vsc # 生成VS Code项目
+scons --target=cmake # 生成CMake项目
+
+# 软件包管理
+pkgs --update # 更新软件包
+pkgs --list # 列出已安装包
+```
+
+### 核心概念
+
+- **SConstruct**: BSP根目录的主构建脚本
+- **SConscript**: 各个组件/目录的构建脚本
+- **rtconfig.py**: 工具链和平台配置
+- **rtconfig.h**: RT-Thread功能配置
+- **DefineGroup**: 定义组件的核心函数
+- **GetDepend**: 检查依赖的核心函数
+
+## 构建系统架构图
+
+```
+┌─────────────────────────────────────┐
+│ 用户命令 (scons) │
+└──────────────┬──────────────────────┘
+ │
+┌──────────────▼──────────────────────┐
+│ SConstruct (主脚本) │
+│ ┌─────────────────────┐ │
+│ │ PrepareBuilding() │ │
+│ │ 环境初始化 │ │
+│ └──────────┬──────────┘ │
+└────────────────┼───────────────────┘
+ │
+┌────────────────▼────────────────────┐
+│ building.py │
+│ ┌──────────┬──────────┐ │
+│ │ 组件收集 │ 依赖处理 │ │
+│ └──────────┴──────────┘ │
+└─────────────────────────────────────┘
+ │
+ ┌────────┴────────┐
+ │ │
+┌───────▼──────┐ ┌────────▼────────┐
+│ SConscript │ │ rtconfig.h │
+│ 组件脚本 │ │ 功能配置 │
+└──────────────┘ └─────────────────┘
+```
+
+## 主要特性
+
+✅ **多工具链支持**
+- GCC (ARM/RISC-V/x86)
+- Keil MDK (ARMCC/ARMClang)
+- IAR
+- Visual Studio
+
+✅ **灵活的配置系统**
+- Kconfig图形配置
+- 条件编译支持
+- 本地编译选项
+
+✅ **丰富的项目生成器**
+- IDE项目文件生成
+- CMake支持
+- Makefile生成
+- VS Code配置
+
+✅ **模块化设计**
+- 组件独立构建
+- 清晰的依赖管理
+- 可扩展架构
+
+## 开发工作流
+
+```mermaid
+graph LR
+ A[配置系统] --> B[编写代码]
+ B --> C[构建项目]
+ C --> D[调试运行]
+ D --> E{是否完成?}
+ E -->|否| B
+ E -->|是| F[发布]
+
+ A1[menuconfig] -.-> A
+ C1[scons] -.-> C
+ C2[IDE项目] -.-> C
+```
+
+## 相关链接
+
+- [RT-Thread官网](https://www.rt-thread.org)
+- [RT-Thread GitHub](https://github.com/RT-Thread/rt-thread)
+- [SCons官方文档](https://scons.org/documentation.html)
+
+## 贡献指南
+
+如果您发现文档中的错误或有改进建议,欢迎:
+
+1. 在GitHub上提交Issue
+2. 提交Pull Request
+3. 在RT-Thread社区论坛反馈
+
+## 版本信息
+
+- 文档版本:1.0.0
+- 更新日期:2024-01
+- 适用版本:RT-Thread 4.1.0+
+
+---
+
+**注意**:本文档基于RT-Thread最新版本编写,部分功能可能需要特定版本支持。使用前请确认您的RT-Thread版本。 \ No newline at end of file
diff --git a/tools/docs/SConscript编写指南.md b/tools/docs/SConscript编写指南.md
new file mode 100644
index 0000000000..f7d7490b4b
--- /dev/null
+++ b/tools/docs/SConscript编写指南.md
@@ -0,0 +1,948 @@
+# RT-Thread SConscript 编写指南
+
+## 目录
+
+1. [概述](#概述)
+2. [基础语法](#基础语法)
+3. [常用模式](#常用模式)
+4. [高级技巧](#高级技巧)
+5. [最佳实践](#最佳实践)
+6. [示例集合](#示例集合)
+7. [常见问题](#常见问题)
+
+## 概述
+
+SConscript是RT-Thread构建系统中的模块构建脚本,每个组件或目录都可以有自己的SConscript文件。本指南将详细介绍如何编写高质量的SConscript文件。
+
+### SConscript在构建系统中的位置
+
+```
+项目根目录/
+├── SConstruct # 主构建脚本
+├── applications/
+│ └── SConscript # 应用层构建脚本
+├── drivers/
+│ └── SConscript # 驱动层构建脚本
+└── components/
+ ├── SConscript # 组件主脚本
+ └── finsh/
+ └── SConscript # 子组件脚本
+```
+
+## 基础语法
+
+### 1. 基本结构
+
+```python
+# 导入构建模块
+from building import *
+
+# 获取当前目录
+cwd = GetCurrentDir()
+
+# 定义源文件
+src = ['main.c', 'app.c']
+
+# 定义头文件路径
+CPPPATH = [cwd]
+
+# 定义组
+group = DefineGroup('Applications', src, depend = [''], CPPPATH = CPPPATH)
+
+# 返回组对象
+Return('group')
+```
+
+### 2. 导入building模块
+
+```python
+from building import *
+```
+
+这行代码导入了RT-Thread构建系统的所有函数,包括:
+- `GetCurrentDir()` - 获取当前目录
+- `DefineGroup()` - 定义组件组
+- `GetDepend()` - 检查依赖
+- `Glob()` - 文件通配符匹配
+- `SrcRemove()` - 移除源文件
+- `DoBuilding()` - 执行构建
+
+### 3. 源文件定义
+
+#### 手动指定文件列表
+```python
+src = ['file1.c', 'file2.c', 'file3.c']
+```
+
+#### 使用通配符
+```python
+src = Glob('*.c') # 当前目录所有.c文件
+src = Glob('src/*.c') # src子目录所有.c文件
+src = Glob('**/*.c') # 递归所有子目录的.c文件
+```
+
+#### 混合使用
+```python
+src = ['main.c'] + Glob('drivers/*.c')
+```
+
+### 4. 条件编译
+
+#### 基于宏定义
+```python
+src = ['common.c']
+
+if GetDepend('RT_USING_SERIAL'):
+ src += ['serial.c']
+
+if GetDepend('RT_USING_I2C'):
+ src += ['i2c.c']
+```
+
+#### 基于平台
+```python
+import rtconfig
+
+if rtconfig.PLATFORM == 'gcc':
+ src += ['gcc_specific.c']
+elif rtconfig.PLATFORM == 'armcc':
+ src += ['keil_specific.c']
+```
+
+### 5. 移除文件
+
+```python
+src = Glob('*.c')
+SrcRemove(src, ['test.c', 'debug.c']) # 移除不需要的文件
+```
+
+## 常用模式
+
+### 1. 简单组件模式
+
+最基础的SConscript模式:
+
+```python
+from building import *
+
+src = Glob('*.c')
+CPPPATH = [GetCurrentDir()]
+
+group = DefineGroup('MyComponent', src, depend = ['RT_USING_MYCOMPONENT'],
+ CPPPATH = CPPPATH)
+
+Return('group')
+```
+
+### 2. 条件编译模式
+
+根据配置选项包含不同的源文件:
+
+```python
+from building import *
+
+src = ['core.c']
+CPPPATH = [GetCurrentDir()]
+
+# 功能模块条件编译
+if GetDepend('MYCOMPONENT_USING_FEATURE_A'):
+ src += ['feature_a.c']
+
+if GetDepend('MYCOMPONENT_USING_FEATURE_B'):
+ src += ['feature_b.c']
+
+# 平台相关代码
+if rtconfig.PLATFORM == 'gcc':
+ src += ['port_gcc.c']
+elif rtconfig.PLATFORM == 'armcc':
+ src += ['port_keil.c']
+elif rtconfig.PLATFORM == 'iccarm':
+ src += ['port_iar.c']
+
+group = DefineGroup('MyComponent', src, depend = ['RT_USING_MYCOMPONENT'],
+ CPPPATH = CPPPATH)
+
+Return('group')
+```
+
+### 3. 多目录组织模式
+
+处理复杂的目录结构:
+
+```python
+from building import *
+
+cwd = GetCurrentDir()
+
+# 源文件来自多个目录
+src = Glob('src/*.c')
+src += Glob('port/*.c')
+src += Glob('hal/*.c')
+
+# 多个头文件路径
+CPPPATH = [
+ cwd,
+ cwd + '/include',
+ cwd + '/internal',
+ cwd + '/port'
+]
+
+# 根据配置添加特定目录
+if GetDepend('RT_USING_LWIP'):
+ src += Glob('lwip/*.c')
+ CPPPATH += [cwd + '/lwip']
+
+group = DefineGroup('Network', src, depend = ['RT_USING_NETWORK'],
+ CPPPATH = CPPPATH)
+
+Return('group')
+```
+
+### 4. 递归子目录模式
+
+自动处理所有子目录的SConscript:
+
+```python
+import os
+from building import *
+
+objs = []
+cwd = GetCurrentDir()
+
+# 获取所有子目录
+list = os.listdir(cwd)
+
+# 需要跳过的目录
+skip_dirs = ['test', 'doc', 'examples', '.git']
+
+for d in list:
+ path = os.path.join(cwd, d)
+ # 检查是否是目录且包含SConscript
+ if os.path.isdir(path) and d not in skip_dirs:
+ if os.path.isfile(os.path.join(path, 'SConscript')):
+ objs = objs + SConscript(os.path.join(d, 'SConscript'))
+
+Return('objs')
+```
+
+### 5. 库文件链接模式
+
+链接预编译的库文件:
+
+```python
+from building import *
+import os
+
+cwd = GetCurrentDir()
+
+# 只包含必要的接口文件
+src = ['lib_interface.c']
+
+CPPPATH = [cwd + '/include']
+
+# 库文件配置
+LIBS = []
+LIBPATH = []
+
+# 根据架构选择库文件
+import rtconfig
+if rtconfig.ARCH == 'arm':
+ if rtconfig.CPU == 'cortex-m4':
+ LIBS += ['mylib_cm4']
+ LIBPATH += [cwd + '/lib/cortex-m4']
+ elif rtconfig.CPU == 'cortex-m3':
+ LIBS += ['mylib_cm3']
+ LIBPATH += [cwd + '/lib/cortex-m3']
+
+group = DefineGroup('MyLib', src, depend = ['RT_USING_MYLIB'],
+ CPPPATH = CPPPATH, LIBS = LIBS, LIBPATH = LIBPATH)
+
+Return('group')
+```
+
+## 高级技巧
+
+### 1. 本地编译选项
+
+为特定模块设置独立的编译选项:
+
+```python
+from building import *
+
+src = Glob('*.c')
+CPPPATH = [GetCurrentDir()]
+
+# 全局编译选项(影响依赖此组件的其他组件)
+CPPDEFINES = ['GLOBAL_DEFINE']
+
+# 本地编译选项(仅影响当前组件)
+LOCAL_CFLAGS = ''
+LOCAL_CPPDEFINES = ['LOCAL_DEFINE']
+LOCAL_CPPPATH = ['./private']
+
+# 根据编译器设置优化选项
+import rtconfig
+if rtconfig.PLATFORM == 'gcc':
+ LOCAL_CFLAGS += ' -O3 -funroll-loops'
+elif rtconfig.PLATFORM == 'armcc':
+ LOCAL_CFLAGS += ' -O3 --loop_optimization_level=2'
+
+group = DefineGroup('HighPerf', src, depend = ['RT_USING_HIGHPERF'],
+ CPPPATH = CPPPATH,
+ CPPDEFINES = CPPDEFINES,
+ LOCAL_CFLAGS = LOCAL_CFLAGS,
+ LOCAL_CPPDEFINES = LOCAL_CPPDEFINES,
+ LOCAL_CPPPATH = LOCAL_CPPPATH
+)
+
+Return('group')
+```
+
+### 2. 动态源文件生成
+
+在构建时生成源文件:
+
+```python
+from building import *
+import time
+
+def generate_version_file():
+ """生成版本信息文件"""
+ version_c = '''
+/* Auto-generated file, do not edit! */
+#include "version.h"
+
+const char *build_time = "%s";
+const char *version = "%s";
+''' % (time.strftime('%Y-%m-%d %H:%M:%S'), '1.0.0')
+
+ with open('version_gen.c', 'w') as f:
+ f.write(version_c)
+
+# 生成文件
+generate_version_file()
+
+src = ['main.c', 'version_gen.c']
+CPPPATH = [GetCurrentDir()]
+
+group = DefineGroup('App', src, depend = [''], CPPPATH = CPPPATH)
+
+Return('group')
+```
+
+### 3. 复杂依赖处理
+
+处理复杂的依赖关系:
+
+```python
+from building import *
+
+src = []
+CPPPATH = [GetCurrentDir()]
+CPPDEFINES = []
+
+# 基础功能
+if GetDepend('RT_USING_DEVICE'):
+ src += ['device_core.c']
+
+ # 串口驱动(依赖设备框架)
+ if GetDepend('RT_USING_SERIAL'):
+ src += ['serial.c']
+
+ # 串口DMA(依赖串口驱动)
+ if GetDepend('RT_SERIAL_USING_DMA'):
+ src += ['serial_dma.c']
+ CPPDEFINES += ['SERIAL_USING_DMA']
+
+ # SPI驱动(依赖设备框架)
+ if GetDepend('RT_USING_SPI'):
+ src += ['spi.c']
+
+ # SPI DMA(依赖SPI驱动)
+ if GetDepend('RT_SPI_USING_DMA'):
+ src += ['spi_dma.c']
+
+# 错误检查
+if GetDepend('RT_SERIAL_USING_DMA') and not GetDepend('RT_USING_SERIAL'):
+ print('Error: RT_SERIAL_USING_DMA requires RT_USING_SERIAL!')
+ exit(1)
+
+group = DefineGroup('Drivers', src, depend = ['RT_USING_DEVICE'],
+ CPPPATH = CPPPATH, CPPDEFINES = CPPDEFINES)
+
+Return('group')
+```
+
+### 4. 平台特定实现
+
+根据不同平台包含不同实现:
+
+```python
+from building import *
+import rtconfig
+
+cwd = GetCurrentDir()
+src = ['common.c']
+CPPPATH = [cwd, cwd + '/include']
+
+# 架构相关目录映射
+arch_map = {
+ 'arm': {
+ 'cortex-m3': 'arm/cortex-m3',
+ 'cortex-m4': 'arm/cortex-m4',
+ 'cortex-m7': 'arm/cortex-m7',
+ 'cortex-a': 'arm/cortex-a'
+ },
+ 'risc-v': {
+ 'rv32': 'riscv/rv32',
+ 'rv64': 'riscv/rv64'
+ },
+ 'x86': {
+ 'i386': 'x86/i386',
+ 'x86_64': 'x86/x86_64'
+ }
+}
+
+# 根据架构和CPU选择实现
+if hasattr(rtconfig, 'ARCH') and hasattr(rtconfig, 'CPU'):
+ arch = rtconfig.ARCH
+ cpu = rtconfig.CPU
+
+ if arch in arch_map and cpu in arch_map[arch]:
+ port_dir = arch_map[arch][cpu]
+ port_src = Glob(port_dir + '/*.c')
+ port_src += Glob(port_dir + '/*.S')
+ src += port_src
+ CPPPATH += [cwd + '/' + port_dir]
+ else:
+ print('Warning: No port for %s - %s' % (arch, cpu))
+
+group = DefineGroup('MyDriver', src, depend = ['RT_USING_MYDRIVER'],
+ CPPPATH = CPPPATH)
+
+Return('group')
+```
+
+### 5. 第三方库集成
+
+集成第三方库的模板:
+
+```python
+from building import *
+import os
+
+cwd = GetCurrentDir()
+
+# 第三方库路径
+lib_path = cwd + '/3rdparty/libfoo'
+
+# 检查库是否存在
+if not os.path.exists(lib_path):
+ print('Error: libfoo not found at', lib_path)
+ print('Please run: git submodule update --init')
+ Return('group')
+
+# 库源文件
+src = Glob(lib_path + '/src/*.c')
+
+# 移除不需要的文件
+SrcRemove(src, [
+ lib_path + '/src/test.c',
+ lib_path + '/src/example.c'
+])
+
+# 头文件路径
+CPPPATH = [
+ lib_path + '/include',
+ cwd + '/port' # 移植层头文件
+]
+
+# 添加移植层
+src += Glob('port/*.c')
+
+# 配置宏定义
+CPPDEFINES = ['LIBFOO_RTOS_RTTHREAD']
+
+# 根据配置启用功能
+if GetDepend('LIBFOO_ENABLE_FLOAT'):
+ CPPDEFINES += ['LIBFOO_USE_FLOAT']
+
+if GetDepend('LIBFOO_ENABLE_STDIO'):
+ CPPDEFINES += ['LIBFOO_USE_STDIO']
+
+group = DefineGroup('libfoo', src, depend = ['RT_USING_LIBFOO'],
+ CPPPATH = CPPPATH, CPPDEFINES = CPPDEFINES)
+
+Return('group')
+```
+
+### 6. 条件导出符号
+
+根据配置导出不同的API:
+
+```python
+from building import *
+
+src = ['core.c']
+CPPPATH = [GetCurrentDir()]
+
+# API版本控制
+if GetDepend('RT_USING_MODULE_API_V2'):
+ src += ['api_v2.c']
+ CPPDEFINES = ['MODULE_API_VERSION=2']
+else:
+ src += ['api_v1.c']
+ CPPDEFINES = ['MODULE_API_VERSION=1']
+
+# 根据配置级别导出不同功能
+if GetDepend('MODULE_EXPERT_MODE'):
+ src += ['expert_api.c']
+ CPPDEFINES += ['EXPORT_EXPERT_API']
+
+group = DefineGroup('Module', src, depend = ['RT_USING_MODULE'],
+ CPPPATH = CPPPATH, CPPDEFINES = CPPDEFINES)
+
+Return('group')
+```
+
+## 最佳实践
+
+### 1. 文件组织原则
+
+```
+component/
+├── SConscript # 主构建脚本
+├── Kconfig # 配置选项
+├── README.md # 组件说明
+├── include/ # 公开头文件
+│ └── component.h
+├── src/ # 源文件
+│ ├── core.c
+│ └── utils.c
+├── port/ # 平台相关代码
+│ ├── cortex-m/
+│ └── risc-v/
+└── examples/ # 示例代码
+ └── example.c
+```
+
+### 2. 依赖管理最佳实践
+
+```python
+from building import *
+
+# 1. 明确声明依赖
+REQUIRED_DEPS = ['RT_USING_DEVICE', 'RT_USING_HEAP']
+
+# 2. 检查必要依赖
+for dep in REQUIRED_DEPS:
+ if not GetDepend(dep):
+ print('Error: %s requires %s' % ('MyComponent', dep))
+ Return('group')
+
+# 3. 可选依赖
+src = ['core.c']
+
+# 可选功能
+OPTIONAL_FEATURES = {
+ 'RT_MYCOMPONENT_USING_DMA': 'dma.c',
+ 'RT_MYCOMPONENT_USING_INTERRUPT': 'interrupt.c',
+ 'RT_MYCOMPONENT_USING_STATS': 'statistics.c'
+}
+
+for macro, file in OPTIONAL_FEATURES.items():
+ if GetDepend(macro):
+ src += [file]
+
+group = DefineGroup('MyComponent', src, depend = ['RT_USING_MYCOMPONENT'])
+Return('group')
+```
+
+### 3. 错误处理
+
+```python
+from building import *
+import os
+
+# 检查关键文件
+critical_files = ['config.h', 'version.h']
+for f in critical_files:
+ if not os.path.exists(f):
+ print('Error: Missing required file:', f)
+ # 返回空组,不中断整体构建
+ group = DefineGroup('MyComponent', [], depend = [''])
+ Return('group')
+
+# 检查工具链
+import rtconfig
+supported_toolchains = ['gcc', 'armcc', 'iar']
+if rtconfig.PLATFORM not in supported_toolchains:
+ print('Warning: Toolchain %s not tested' % rtconfig.PLATFORM)
+
+# 正常构建流程
+src = Glob('*.c')
+group = DefineGroup('MyComponent', src, depend = ['RT_USING_MYCOMPONENT'])
+Return('group')
+```
+
+### 4. 性能优化
+
+```python
+from building import *
+import os
+
+# 1. 缓存文件列表(避免重复扫描)
+_file_cache = {}
+
+def cached_glob(pattern):
+ if pattern not in _file_cache:
+ _file_cache[pattern] = Glob(pattern)
+ return _file_cache[pattern]
+
+# 2. 延迟加载(仅在需要时扫描)
+src = []
+if GetDepend('RT_USING_MYCOMPONENT'):
+ src = cached_glob('*.c')
+
+ if GetDepend('RT_MYCOMPONENT_USING_EXTRA'):
+ src += cached_glob('extra/*.c')
+
+# 3. 避免深度递归(使用显式路径)
+# 不好的做法
+# src = Glob('**/*.c') # 递归所有子目录
+
+# 好的做法
+src = Glob('*.c')
+src += Glob('core/*.c')
+src += Glob('hal/*.c')
+
+group = DefineGroup('MyComponent', src, depend = ['RT_USING_MYCOMPONENT'])
+Return('group')
+```
+
+### 5. 文档化
+
+```python
+"""
+SConscript for MyComponent
+
+This component provides [功能描述]
+
+Configuration:
+ RT_USING_MYCOMPONENT - Enable this component
+ RT_MYCOMPONENT_USING_DMA - Enable DMA support
+ RT_MYCOMPONENT_BUFFER_SIZE - Buffer size (default: 256)
+
+Dependencies:
+ - RT_USING_DEVICE (required)
+ - RT_USING_DMA (optional, for DMA support)
+"""
+
+from building import *
+
+# ... 构建脚本内容 ...
+```
+
+## 示例集合
+
+### 示例1:设备驱动SConscript
+
+```python
+from building import *
+
+cwd = GetCurrentDir()
+
+# 驱动源文件
+src = []
+CPPPATH = [cwd + '/../inc']
+
+# I2C驱动
+if GetDepend('RT_USING_I2C'):
+ src += ['drv_i2c.c']
+
+# SPI驱动
+if GetDepend('RT_USING_SPI'):
+ src += ['drv_spi.c']
+
+ # QSPI支持
+ if GetDepend('RT_USING_QSPI'):
+ src += ['drv_qspi.c']
+
+# USB驱动
+if GetDepend('RT_USING_USB'):
+ src += ['drv_usb.c']
+ if GetDepend('RT_USING_USB_HOST'):
+ src += ['drv_usbh.c']
+ if GetDepend('RT_USING_USB_DEVICE'):
+ src += ['drv_usbd.c']
+
+# SDIO驱动
+if GetDepend('RT_USING_SDIO'):
+ src += ['drv_sdio.c']
+
+group = DefineGroup('Drivers', src, depend = [''], CPPPATH = CPPPATH)
+
+Return('group')
+```
+
+### 示例2:网络组件SConscript
+
+```python
+from building import *
+
+cwd = GetCurrentDir()
+src = []
+CPPPATH = [cwd]
+
+# 网络接口层
+if GetDepend('RT_USING_NETDEV'):
+ src += Glob('netdev/*.c')
+ CPPPATH += [cwd + '/netdev']
+
+# SAL套接字抽象层
+if GetDepend('RT_USING_SAL'):
+ src += Glob('sal/src/*.c')
+ src += Glob('sal/socket/*.c')
+ CPPPATH += [cwd + '/sal/include']
+
+ # AT指令支持
+ if GetDepend('SAL_USING_AT'):
+ src += Glob('sal/impl/af_inet_at.c')
+
+ # LwIP支持
+ if GetDepend('SAL_USING_LWIP'):
+ src += Glob('sal/impl/af_inet_lwip.c')
+
+# AT指令框架
+if GetDepend('RT_USING_AT'):
+ src += Glob('at/src/*.c')
+ CPPPATH += [cwd + '/at/include']
+
+ # AT Socket
+ if GetDepend('AT_USING_SOCKET'):
+ src += Glob('at/at_socket/*.c')
+
+group = DefineGroup('Network', src, depend = [''], CPPPATH = CPPPATH)
+
+Return('group')
+```
+
+### 示例3:文件系统SConscript
+
+```python
+from building import *
+
+cwd = GetCurrentDir()
+src = []
+CPPPATH = [cwd + '/include']
+
+# DFS框架
+if GetDepend('RT_USING_DFS'):
+ src += Glob('src/*.c')
+
+ # ELM FatFS
+ if GetDepend('RT_USING_DFS_ELMFAT'):
+ src += Glob('filesystems/elmfat/*.c')
+ # FatFS版本选择
+ if GetDepend('RT_DFS_ELM_USE_LFN'):
+ src += ['filesystems/elmfat/ffunicode.c']
+
+ # ROMFS
+ if GetDepend('RT_USING_DFS_ROMFS'):
+ src += ['filesystems/romfs/dfs_romfs.c']
+
+ # DevFS
+ if GetDepend('RT_USING_DFS_DEVFS'):
+ src += ['filesystems/devfs/devfs.c']
+
+ # NFS
+ if GetDepend('RT_USING_DFS_NFS'):
+ src += Glob('filesystems/nfs/*.c')
+ CPPPATH += [cwd + '/filesystems/nfs']
+
+group = DefineGroup('Filesystem', src, depend = ['RT_USING_DFS'],
+ CPPPATH = CPPPATH)
+
+Return('group')
+```
+
+### 示例4:使用package.json的SConscript
+
+```python
+from building import *
+import os
+import json
+
+cwd = GetCurrentDir()
+
+# 尝试使用package.json
+package_file = os.path.join(cwd, 'package.json')
+if os.path.exists(package_file):
+ # 使用自动构建
+ objs = BuildPackage(package_file)
+else:
+ # 手动构建
+ src = Glob('src/*.c')
+ CPPPATH = [cwd + '/include']
+
+ # 读取配置
+ config_file = os.path.join(cwd, 'config.json')
+ if os.path.exists(config_file):
+ with open(config_file, 'r') as f:
+ config = json.load(f)
+
+ # 根据配置添加源文件
+ for feature in config.get('features', []):
+ if GetDepend('RT_USING_' + feature.upper()):
+ src += Glob('src/%s/*.c' % feature)
+
+ objs = DefineGroup('MyPackage', src, depend = ['RT_USING_MYPACKAGE'],
+ CPPPATH = CPPPATH)
+
+Return('objs')
+```
+
+## 常见问题
+
+### Q1: 如何调试SConscript?
+
+```python
+from building import *
+
+# 1. 打印调试信息
+print('Current directory:', GetCurrentDir())
+print('GetDepend RT_USING_XXX:', GetDepend('RT_USING_XXX'))
+
+# 2. 打印源文件列表
+src = Glob('*.c')
+print('Source files:', src)
+
+# 3. 条件调试输出
+if GetOption('verbose'):
+ print('Detailed debug info...')
+
+# 4. 检查环境变量
+import os
+print('RTT_ROOT:', os.getenv('RTT_ROOT'))
+```
+
+### Q2: 如何处理可选的依赖?
+
+```python
+from building import *
+
+src = ['core.c']
+
+# 可选依赖处理
+optional_deps = {
+ 'RT_USING_SERIAL': ['serial.c', 'serial_ops.c'],
+ 'RT_USING_CAN': ['can.c', 'can_ops.c'],
+ 'RT_USING_I2C': ['i2c.c', 'i2c_ops.c']
+}
+
+for dep, files in optional_deps.items():
+ if GetDepend(dep):
+ src += files
+
+# 检查组合依赖
+if GetDepend('RT_USING_SERIAL') and GetDepend('RT_USING_DMA'):
+ src += ['serial_dma.c']
+
+group = DefineGroup('Drivers', src, depend = ['RT_USING_DEVICE'])
+Return('group')
+```
+
+### Q3: 如何支持多个工具链?
+
+```python
+from building import *
+import rtconfig
+
+src = ['common.c']
+
+# 工具链特定文件
+toolchain_files = {
+ 'gcc': ['gcc_startup.S', 'gcc_specific.c'],
+ 'armcc': ['keil_startup.s', 'keil_specific.c'],
+ 'iccarm': ['iar_startup.s', 'iar_specific.c']
+}
+
+if rtconfig.PLATFORM in toolchain_files:
+ src += toolchain_files[rtconfig.PLATFORM]
+else:
+ print('Warning: Unknown toolchain', rtconfig.PLATFORM)
+
+# 工具链特定编译选项
+LOCAL_CFLAGS = ''
+if rtconfig.PLATFORM == 'gcc':
+ LOCAL_CFLAGS = '-Wno-unused-function'
+elif rtconfig.PLATFORM == 'armcc':
+ LOCAL_CFLAGS = '--diag_suppress=177'
+
+group = DefineGroup('MyComponent', src, depend = [''],
+ LOCAL_CFLAGS = LOCAL_CFLAGS)
+Return('group')
+```
+
+### Q4: 如何处理生成的代码?
+
+```python
+from building import *
+import subprocess
+
+def generate_code():
+ """生成代码"""
+ # 运行代码生成器
+ cmd = ['python', 'codegen.py', '-o', 'generated.c']
+ subprocess.check_call(cmd)
+
+# 确保生成代码
+if GetDepend('RT_USING_CODEGEN'):
+ generate_code()
+ src = ['generated.c']
+else:
+ src = ['default.c']
+
+group = DefineGroup('Generated', src, depend = [''])
+Return('group')
+```
+
+### Q5: 如何组织大型项目?
+
+```python
+# 主SConscript
+from building import *
+
+objs = []
+
+# 子模块列表
+modules = [
+ 'core',
+ 'drivers',
+ 'network',
+ 'filesystem',
+ 'gui'
+]
+
+# 根据配置包含模块
+for module in modules:
+ # 检查模块是否启用
+ if GetDepend('RT_USING_' + module.upper()):
+ # 构建子模块
+ objs += SConscript(module + '/SConscript')
+
+Return('objs')
+```
+
+## 总结
+
+编写高质量的SConscript需要:
+
+1. **清晰的结构**:合理组织源文件和目录
+2. **正确的依赖**:准确声明和检查依赖关系
+3. **平台兼容**:处理不同工具链和平台的差异
+4. **性能考虑**:避免不必要的文件扫描
+5. **错误处理**:优雅处理各种异常情况
+6. **文档完善**:添加必要的注释和说明
+
+通过遵循本指南的建议和最佳实践,可以编写出易维护、可扩展的构建脚本,为RT-Thread项目的构建提供坚实的基础。 \ No newline at end of file
diff --git a/tools/docs/构建系统使用指南.md b/tools/docs/构建系统使用指南.md
new file mode 100644
index 0000000000..1e54f1d4d9
--- /dev/null
+++ b/tools/docs/构建系统使用指南.md
@@ -0,0 +1,643 @@
+# RT-Thread 构建系统使用指南
+
+## 目录
+
+1. [概述](#概述)
+2. [快速开始](#快速开始)
+3. [命令行选项详解](#命令行选项详解)
+4. [工具链配置](#工具链配置)
+5. [项目生成](#项目生成)
+6. [软件包管理](#软件包管理)
+7. [高级功能](#高级功能)
+8. [常见问题](#常见问题)
+
+## 概述
+
+RT-Thread使用基于SCons的构建系统,提供了统一的跨平台构建体验。构建系统支持:
+
+- 多种编译器和IDE(GCC、Keil、IAR、VS Code等)
+- 模块化的组件管理
+- 灵活的配置系统
+- 自动化的依赖处理
+- 软件包管理功能
+
+### 系统架构图
+
+```
+┌─────────────────────────────────────────────────────────────┐
+│ 用户命令 │
+│ (scons, scons --target=xxx) │
+└─────────────────────┬───────────────────────────────────────┘
+ │
+┌─────────────────────▼───────────────────────────────────────┐
+│ SConstruct │
+│ (BSP根目录构建脚本) │
+└─────────────────────┬───────────────────────────────────────┘
+ │
+┌─────────────────────▼───────────────────────────────────────┐
+│ building.py │
+│ (核心构建引擎和函数库) │
+├─────────────────────┬───────────────────────────────────────┤
+│ PrepareBuilding() │ DefineGroup() │ DoBuilding() │
+│ 环境初始化 │ 组件定义 │ 执行构建 │
+└─────────────────────┴─────────┬─────────────────────────────┘
+ │
+ ┌───────────────────────┼───────────────────────┐
+ │ │ │
+┌───────▼────────┐ ┌────────▼────────┐ ┌────────▼────────┐
+│ SConscript │ │ rtconfig.py │ │ rtconfig.h │
+│ (组件脚本) │ │ (工具链配置) │ │ (功能配置) │
+└────────────────┘ └─────────────────┘ └─────────────────┘
+```
+
+## 快速开始
+
+### 基本编译流程
+
+1. **进入BSP目录**
+ ```bash
+ cd bsp/stm32/stm32f103-blue-pill
+ ```
+
+2. **配置系统**(可选)
+ ```bash
+ menuconfig # 图形化配置
+ ```
+
+3. **编译项目**
+ ```bash
+ scons # 默认编译
+ scons -j8 # 多线程编译
+ ```
+
+4. **生成IDE项目**
+ ```bash
+ scons --target=mdk5 # 生成Keil MDK5项目
+ scons --target=iar # 生成IAR项目
+ scons --target=vsc # 生成VS Code项目
+ ```
+
+### 清理和重建
+
+```bash
+scons -c # 清理编译产物
+scons -c --target=mdk5 # 清理MDK5项目文件
+scons --dist # 生成分发包
+```
+
+## 命令行选项详解
+
+### 基础编译选项
+
+| 选项 | 说明 | 示例 |
+|------|------|------|
+| `-j N` | 多线程编译,N为线程数 | `scons -j8` |
+| `-c` | 清理编译产物 | `scons -c` |
+| `-s` | 静默模式,不显示命令 | `scons -s` |
+| `--verbose` | 详细输出模式 | `scons --verbose` |
+
+### 项目生成选项
+
+| 选项 | 说明 | 生成的文件 |
+|------|------|------------|
+| `--target=mdk4` | Keil MDK4项目 | project.uvproj |
+| `--target=mdk5` | Keil MDK5项目 | project.uvprojx |
+| `--target=iar` | IAR工作区 | project.eww |
+| `--target=vs2012` | Visual Studio项目 | project.vcxproj |
+| `--target=vsc` | VS Code配置 | .vscode/目录 |
+| `--target=eclipse` | Eclipse CDT项目 | .project, .cproject |
+| `--target=cmake` | CMake项目 | CMakeLists.txt |
+| `--target=makefile` | 通用Makefile | Makefile |
+
+### 配置管理选项
+
+| 选项 | 说明 | 使用场景 |
+|------|------|----------|
+| `--menuconfig` | 启动图形配置界面 | 修改功能配置 |
+| `--pyconfig` | 通过Python脚本配置 | 自动化配置 |
+| `--pyconfig-silent` | 静默Python配置 | CI/CD环境 |
+| `--genconfig` | 从rtconfig.h生成.config | 配置迁移 |
+| `--useconfig=xxx` | 使用指定配置文件 | 切换配置 |
+
+### 工具链选项
+
+| 选项 | 说明 | 示例 |
+|------|------|------|
+| `--exec-path=PATH` | 指定工具链路径 | `--exec-path=/opt/gcc-arm/bin` |
+| `--exec-prefix=PREFIX` | 指定工具链前缀 | `--exec-prefix=arm-none-eabi-` |
+| `--strict` | 严格编译模式 | 开启-Werror |
+
+### 分发和调试选项
+
+| 选项 | 说明 | 用途 |
+|------|------|------|
+| `--dist` | 生成分发包 | 项目发布 |
+| `--dist-strip` | 生成精简分发包 | 最小化项目 |
+| `--dist-ide` | 生成RT-Thread Studio项目 | Studio开发 |
+| `--cscope` | 生成cscope数据库 | 代码导航 |
+| `--clang-analyzer` | 运行Clang静态分析 | 代码质量检查 |
+
+## 工具链配置
+
+### rtconfig.py配置文件
+
+每个BSP都有一个`rtconfig.py`文件,定义了工具链配置:
+
+```python
+import os
+
+# 工具链定义
+CROSS_TOOL = 'gcc' # 工具链类型: gcc/keil/iar
+PLATFORM = 'armcc' # 平台标识
+
+# 编译器路径
+if os.getenv('RTT_EXEC_PATH'):
+ EXEC_PATH = os.getenv('RTT_EXEC_PATH')
+else:
+ EXEC_PATH = r'C:/Keil_v5/ARM/ARMCC/bin'
+
+# 编译器前缀(GCC工具链)
+PREFIX = 'arm-none-eabi-'
+
+# 编译器定义
+CC = PREFIX + 'gcc'
+CXX = PREFIX + 'g++'
+AS = PREFIX + 'gcc'
+AR = PREFIX + 'ar'
+LINK = PREFIX + 'gcc'
+SIZE = PREFIX + 'size'
+OBJDUMP = PREFIX + 'objdump'
+OBJCPY = PREFIX + 'objcopy'
+
+# 设备相关参数
+DEVICE = ' -mcpu=cortex-m3 -mthumb -ffunction-sections -fdata-sections'
+
+# 编译标志
+CFLAGS = DEVICE + ' -Dgcc'
+AFLAGS = ' -c' + DEVICE + ' -x assembler-with-cpp -Wa,-mimplicit-it=thumb '
+LFLAGS = DEVICE + ' -Wl,--gc-sections,-Map=rtthread.map,-cref,-u,Reset_Handler -T link.lds'
+
+# 路径定义
+CPATH = ''
+LPATH = ''
+
+# 链接脚本
+LINK_SCRIPT = 'link.lds'
+
+# 后处理命令
+POST_ACTION = OBJCPY + ' -O binary $TARGET rtthread.bin\n' + SIZE + ' $TARGET \n'
+```
+
+### 支持的工具链
+
+1. **GCC工具链**
+ ```python
+ CROSS_TOOL = 'gcc'
+ PREFIX = 'arm-none-eabi-'
+ ```
+
+2. **Keil MDK**
+ ```python
+ CROSS_TOOL = 'keil'
+ PLATFORM = 'armcc' # ARM Compiler 5
+ # 或
+ PLATFORM = 'armclang' # ARM Compiler 6
+ ```
+
+3. **IAR**
+ ```python
+ CROSS_TOOL = 'iar'
+ PLATFORM = 'iccarm'
+ ```
+
+4. **RISC-V GCC**
+ ```python
+ CROSS_TOOL = 'gcc'
+ PREFIX = 'riscv64-unknown-elf-'
+ ```
+
+### 环境变量支持
+
+构建系统支持通过环境变量覆盖配置:
+
+```bash
+# 设置工具链路径
+export RTT_EXEC_PATH=/opt/gcc-arm-none-eabi-10-2020-q4-major/bin
+
+# 设置工具链前缀
+export RTT_CC_PREFIX=arm-none-eabi-
+
+# 设置工具链类型
+export RTT_CC=gcc
+```
+
+## 项目生成
+
+### VS Code项目配置
+
+使用`scons --target=vsc`生成VS Code项目,会创建以下配置文件:
+
+**.vscode/c_cpp_properties.json** - IntelliSense配置
+```json
+{
+ "configurations": [
+ {
+ "name": "RT-Thread",
+ "includePath": [
+ "${workspaceFolder}/**",
+ "${workspaceFolder}/../../components/finsh",
+ "${workspaceFolder}/../../include"
+ ],
+ "defines": [
+ "RT_USING_FINSH",
+ "RT_USING_SERIAL",
+ "__GNUC__"
+ ],
+ "compilerPath": "/opt/gcc-arm/bin/arm-none-eabi-gcc",
+ "cStandard": "c99",
+ "cppStandard": "c++11"
+ }
+ ]
+}
+```
+
+**.vscode/tasks.json** - 构建任务配置
+```json
+{
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "label": "build",
+ "type": "shell",
+ "command": "scons",
+ "problemMatcher": "$gcc",
+ "group": {
+ "kind": "build",
+ "isDefault": true
+ }
+ }
+ ]
+}
+```
+
+### CMake项目生成
+
+使用`scons --target=cmake`生成CMakeLists.txt:
+
+```cmake
+cmake_minimum_required(VERSION 3.10)
+
+# 工具链设置
+set(CMAKE_SYSTEM_NAME Generic)
+set(CMAKE_SYSTEM_PROCESSOR cortex-m3)
+set(CMAKE_C_COMPILER arm-none-eabi-gcc)
+set(CMAKE_ASM_COMPILER arm-none-eabi-gcc)
+
+project(rtthread C ASM)
+
+# 编译选项
+add_compile_options(
+ -mcpu=cortex-m3
+ -mthumb
+ -ffunction-sections
+ -fdata-sections
+ -Wall
+ -O0
+ -g
+)
+
+# 头文件路径
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../include
+)
+
+# 源文件
+set(SOURCES
+ applications/main.c
+ ../../src/clock.c
+ ../../src/components.c
+)
+
+# 生成可执行文件
+add_executable(${PROJECT_NAME}.elf ${SOURCES})
+
+# 链接选项
+target_link_options(${PROJECT_NAME}.elf PRIVATE
+ -T${CMAKE_CURRENT_SOURCE_DIR}/link.lds
+ -Wl,-Map=${PROJECT_NAME}.map,--cref
+ -Wl,--gc-sections
+)
+```
+
+## 软件包管理
+
+### 使用package.json定义组件
+
+RT-Thread支持使用`package.json`文件定义软件包:
+
+```json
+{
+ "name": "my-driver",
+ "version": "1.0.0",
+ "type": "rt-thread-component",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "RT_USING_DEVICE": "latest"
+ },
+ "sources": {
+ "common": {
+ "source_files": ["src/*.c"],
+ "header_files": ["inc/*.h"],
+ "header_path": ["inc"]
+ },
+ "cortex-m": {
+ "condition": "defined(ARCH_ARM_CORTEX_M)",
+ "source_files": ["port/cortex-m/*.c"]
+ }
+ }
+}
+```
+
+### 在SConscript中使用BuildPackage
+
+```python
+from building import *
+import os
+
+# 使用package.json构建
+objs = BuildPackage('package.json')
+
+# 或者手动指定包路径
+pkg_path = os.path.join(GetCurrentDir(), 'package.json')
+objs = BuildPackage(pkg_path)
+
+Return('objs')
+```
+
+## 高级功能
+
+### 1. 条件编译和依赖管理
+
+**基于宏定义的条件编译**
+```python
+src = ['common.c']
+
+if GetDepend('RT_USING_SERIAL'):
+ src += ['serial.c']
+
+if GetDepend(['RT_USING_SPI', 'RT_USING_SFUD']):
+ src += ['spi_flash.c']
+
+group = DefineGroup('Drivers', src, depend = ['RT_USING_DEVICE'])
+```
+
+**复杂依赖表达式**
+```python
+# 依赖可以是列表(AND关系)
+depend = ['RT_USING_LWIP', 'RT_USING_NETDEV']
+
+# 或者使用GetDepend进行复杂判断
+if GetDepend('RT_USING_LWIP') and not GetDepend('RT_USING_SAL'):
+ print('配置错误:LWIP需要SAL支持')
+```
+
+### 2. 本地编译选项
+
+为特定模块设置独立的编译选项:
+
+```python
+# 全局编译选项
+CPPPATH = [GetCurrentDir()]
+CPPDEFINES = ['MODULE_VERSION=1']
+
+# 本地编译选项(仅对当前group有效)
+LOCAL_CFLAGS = '-O3 -funroll-loops'
+LOCAL_CPPPATH = ['./private']
+LOCAL_CPPDEFINES = {'BUFFER_SIZE': 1024}
+
+group = DefineGroup('Module', src, depend = [''],
+ CPPPATH = CPPPATH,
+ CPPDEFINES = CPPDEFINES,
+ LOCAL_CFLAGS = LOCAL_CFLAGS,
+ LOCAL_CPPPATH = LOCAL_CPPPATH,
+ LOCAL_CPPDEFINES = LOCAL_CPPDEFINES
+)
+```
+
+### 3. 递归构建子目录
+
+自动扫描并构建子目录:
+
+```python
+import os
+from building import *
+
+objs = []
+cwd = GetCurrentDir()
+dirs = os.listdir(cwd)
+
+# 黑名单目录
+skip_dirs = ['test', 'doc', 'example']
+
+for d in dirs:
+ if d in skip_dirs:
+ continue
+
+ path = os.path.join(cwd, d)
+ if os.path.isdir(path):
+ sconscript = os.path.join(path, 'SConscript')
+ if os.path.isfile(sconscript):
+ objs += SConscript(sconscript)
+
+Return('objs')
+```
+
+### 4. 自定义构建动作
+
+添加构建前后的自定义动作:
+
+```python
+from building import *
+
+def pre_build_action(target, source, env):
+ print('开始构建:', target[0])
+ # 执行预处理操作
+
+def post_build_action(target, source, env):
+ print('构建完成:', target[0])
+ # 生成额外文件,如hex文件
+ import subprocess
+ subprocess.call(['arm-none-eabi-objcopy', '-O', 'ihex',
+ str(target[0]), str(target[0]) + '.hex'])
+
+# 注册构建动作
+if GetOption('target') == None:
+ rtconfig.POST_ACTION = post_build_action
+```
+
+### 5. 分发包定制
+
+创建自定义分发包:
+
+```python
+# 在BSP的SConstruct中添加
+def dist_handle(BSP_ROOT, dist_dir):
+ import shutil
+
+ # 复制必要文件
+ src_files = ['applications', 'board', 'rtconfig.py', 'SConstruct']
+ for src in src_files:
+ src_path = os.path.join(BSP_ROOT, src)
+ dst_path = os.path.join(dist_dir, src)
+ if os.path.isdir(src_path):
+ shutil.copytree(src_path, dst_path)
+ else:
+ shutil.copy2(src_path, dst_path)
+
+ # 创建README
+ with open(os.path.join(dist_dir, 'README.md'), 'w') as f:
+ f.write('# RT-Thread BSP 分发包\n')
+ f.write('构建时间: ' + time.strftime('%Y-%m-%d %H:%M:%S\n'))
+
+# 注册分发处理函数
+AddOption('--dist-handle',
+ dest = 'dist-handle',
+ action = 'store_true',
+ default = False,
+ help = 'Enable dist handle')
+
+if GetOption('dist-handle'):
+ dist_handle(BSP_ROOT, dist_dir)
+```
+
+### 6. 代码分析集成
+
+**Clang静态分析**
+```bash
+scons --clang-analyzer
+```
+
+**生成compile_commands.json**
+```bash
+scons --target=cmake # CMake项目会包含compile_commands.json
+# 或使用
+scons --compile-commands
+```
+
+**生成Cscope数据库**
+```bash
+scons --cscope
+```
+
+## 常见问题
+
+### Q1: 如何添加新的源文件?
+
+在相应目录的SConscript中添加:
+```python
+src = Glob('*.c') # 自动包含所有.c文件
+# 或
+src = ['file1.c', 'file2.c'] # 手动指定
+```
+
+### Q2: 如何排除特定文件?
+
+```python
+src = Glob('*.c')
+SrcRemove(src, ['test.c', 'debug.c'])
+```
+
+### Q3: 如何处理不同配置下的源文件?
+
+```python
+src = ['common.c']
+
+if rtconfig.PLATFORM == 'gcc':
+ src += ['gcc_specific.c']
+elif rtconfig.PLATFORM == 'armcc':
+ src += ['keil_specific.c']
+```
+
+### Q4: 如何调试构建问题?
+
+1. 使用详细输出模式:
+ ```bash
+ scons --verbose
+ ```
+
+2. 查看预处理结果:
+ ```bash
+ scons --target=mdk5 --verbose # 查看生成的项目配置
+ ```
+
+3. 检查依赖关系:
+ ```python
+ # 在SConscript中添加调试输出
+ print('GetDepend result:', GetDepend('RT_USING_XXX'))
+ ```
+
+### Q5: 如何加快编译速度?
+
+1. 使用多线程编译:
+ ```bash
+ scons -j$(nproc) # Linux/macOS
+ scons -j8 # Windows
+ ```
+
+2. 使用ccache(GCC):
+ ```python
+ # 在rtconfig.py中
+ CC = 'ccache ' + PREFIX + 'gcc'
+ ```
+
+3. 优化依赖关系,避免不必要的重编译
+
+### Q6: 如何处理第三方库?
+
+1. **作为源码包含**
+ ```python
+ # libraries/foo/SConscript
+ src = Glob('src/*.c')
+ CPPPATH = [GetCurrentDir() + '/include']
+
+ group = DefineGroup('foo', src, depend = ['RT_USING_FOO'],
+ CPPPATH = CPPPATH)
+ ```
+
+2. **作为预编译库**
+ ```python
+ # 添加库文件
+ LIBS = ['foo']
+ LIBPATH = [GetCurrentDir() + '/lib']
+
+ group = DefineGroup('foo', [], depend = ['RT_USING_FOO'],
+ LIBS = LIBS, LIBPATH = LIBPATH)
+ ```
+
+### Q7: 如何自定义链接脚本?
+
+在rtconfig.py中指定:
+```python
+# GCC工具链
+LINK_SCRIPT = 'board/link.lds'
+
+# Keil MDK
+LINK_SCRIPT = 'board/link.sct'
+
+# IAR
+LINK_SCRIPT = 'board/link.icf'
+```
+
+## 最佳实践
+
+1. **模块化设计**:每个功能模块使用独立的SConscript
+2. **依赖管理**:正确设置depend参数,避免编译不需要的代码
+3. **路径处理**:使用GetCurrentDir()获取当前路径,避免硬编码
+4. **条件编译**:合理使用GetDepend进行条件判断
+5. **编译选项**:全局选项放在rtconfig.py,局部选项使用LOCAL_xxx
+6. **文档维护**:在SConscript中添加必要的注释说明
+
+## 总结
+
+RT-Thread的构建系统提供了强大而灵活的项目管理能力。通过合理使用各种构建选项和功能,可以高效地进行嵌入式软件开发。建议开发者深入理解构建系统的工作原理,以便更好地利用其功能。 \ No newline at end of file
diff --git a/tools/docs/构建系统技术原理.md b/tools/docs/构建系统技术原理.md
new file mode 100644
index 0000000000..d0a9ac0aaa
--- /dev/null
+++ b/tools/docs/构建系统技术原理.md
@@ -0,0 +1,912 @@
+# RT-Thread 构建系统技术原理
+
+## 目录
+
+1. [系统架构设计](#系统架构设计)
+2. [核心模块分析](#核心模块分析)
+3. [构建流程详解](#构建流程详解)
+4. [依赖管理机制](#依赖管理机制)
+5. [工具链适配层](#工具链适配层)
+6. [项目生成器架构](#项目生成器架构)
+7. [配置系统实现](#配置系统实现)
+8. [扩展机制](#扩展机制)
+
+## 系统架构设计
+
+### 整体架构图
+
+```
+┌────────────────────────────────────────────────────────────────────┐
+│ 用户接口层 │
+│ ┌─────────────┐ ┌──────────────┐ ┌─────────────┐ ┌──────────┐│
+│ │ 命令行接口 │ │ menuconfig │ │ 环境变量 │ │ 配置文件 ││
+│ │ (scons) │ │ (Kconfig) │ │ (RTT_xxx) │ │ (.config)││
+│ └──────┬──────┘ └──────┬───────┘ └──────┬──────┘ └─────┬────┘│
+└─────────┼─────────────────┼──────────────────┼───────────────┼─────┘
+ │ │ │ │
+┌─────────▼─────────────────▼──────────────────▼───────────────▼─────┐
+│ 构建引擎层 │
+│ ┌─────────────────────────────────────────────────────────────┐ │
+│ │ building.py │ │
+│ ├─────────────┬───────────────┬─────────────┬────────────────┤ │
+│ │ 环境准备 │ 组件收集 │ 依赖处理 │ 构建执行 │ │
+│ │ Prepare │ DefineGroup │ GetDepend │ DoBuilding │ │
+│ └─────────────┴───────────────┴─────────────┴────────────────┘ │
+└────────────────────────────────────────────────────────────────────┘
+ │ │ │ │
+┌─────────▼─────────────────▼──────────────────▼───────────────▼─────┐
+│ 工具支撑层 │
+│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────┐ ┌──────┐│
+│ │ utils.py │ │options.py│ │package.py│ │mkdist.py│ │预处理││
+│ │ 工具函数 │ │命令选项 │ │包管理 │ │分发打包 │ │器 ││
+│ └──────────┘ └──────────┘ └──────────┘ └─────────┘ └──────┘│
+└────────────────────────────────────────────────────────────────────┘
+ │ │ │ │
+┌─────────▼─────────────────▼──────────────────▼───────────────▼─────┐
+│ 目标生成器层 │
+│ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────────┐ │
+│ │keil.py │ │iar.py │ │gcc.py │ │vsc.py │ │cmake.py等 │ │
+│ └────────┘ └────────┘ └────────┘ └────────┘ └────────────┘ │
+└────────────────────────────────────────────────────────────────────┘
+```
+
+### 设计原则
+
+1. **模块化设计**:每个功能模块独立,通过明确的接口交互
+2. **可扩展性**:易于添加新的工具链支持和目标生成器
+3. **跨平台兼容**:统一的抽象层处理平台差异
+4. **配置驱动**:通过配置文件控制构建行为
+
+## 核心模块分析
+
+### 1. building.py - 构建引擎核心
+
+#### 1.1 全局变量管理
+
+```python
+BuildOptions = {} # 存储从rtconfig.h解析的宏定义
+Projects = [] # 存储所有的组件对象
+Rtt_Root = '' # RT-Thread根目录
+Env = None # SCons环境对象
+```
+
+#### 1.2 PrepareBuilding 函数实现
+
+```python
+def PrepareBuilding(env, root_directory, has_libcpu=False, remove_components = []):
+ """
+ 准备构建环境
+
+ 参数:
+ env: SCons环境对象
+ root_directory: RT-Thread根目录
+ has_libcpu: 是否包含libcpu
+ remove_components: 需要移除的组件列表
+ """
+ # 1. 添加命令行选项
+ AddOptions()
+
+ # 2. 设置全局环境变量
+ global Env, Rtt_Root
+ Env = env
+ Rtt_Root = os.path.abspath(root_directory)
+
+ # 3. 配置日志系统
+ logging.basicConfig(level=logging.INFO)
+ logger = logging.getLogger('rt-scons')
+ Env['log'] = logger
+
+ # 4. 工具链检测和配置
+ if not utils.CmdExists(os.path.join(rtconfig.EXEC_PATH, rtconfig.CC)):
+ # 尝试自动检测工具链
+ try:
+ envm = utils.ImportModule('env_utility')
+ exec_path = envm.GetSDKPath(rtconfig.CC)
+ if exec_path:
+ rtconfig.EXEC_PATH = exec_path
+ except:
+ pass
+
+ # 5. 解析rtconfig.h配置
+ PreProcessor = create_preprocessor_instance()
+ with open('rtconfig.h', 'r') as f:
+ PreProcessor.process_contents(f.read())
+ BuildOptions = PreProcessor.cpp_namespace
+
+ # 6. 处理目标平台
+ if GetOption('target'):
+ # 根据目标设置工具链
+ rtconfig.CROSS_TOOL, rtconfig.PLATFORM = tgt_dict[tgt_name]
+
+ return objs
+```
+
+#### 1.3 DefineGroup 函数实现
+
+```python
+def DefineGroup(name, src, depend, **parameters):
+ """
+ 定义一个组件组
+
+ 参数:
+ name: 组名称
+ src: 源文件列表
+ depend: 依赖条件
+ **parameters: 编译参数(CPPPATH, CPPDEFINES, LIBS等)
+
+ 返回:
+ 组对象列表
+ """
+ # 1. 检查依赖条件
+ if not GetDepend(depend):
+ return []
+
+ # 2. 处理源文件
+ if isinstance(src, list):
+ # 过滤掉被移除的文件
+ src = [s for s in src if s not in removed_src]
+
+ # 3. 创建组对象
+ group = {}
+ group['name'] = name
+ group['src'] = src
+
+ # 4. 处理编译参数
+ # 全局参数
+ if 'CPPPATH' in parameters:
+ group['CPPPATH'] = parameters['CPPPATH']
+
+ # 本地参数(仅对当前组有效)
+ if 'LOCAL_CPPPATH' in parameters:
+ paths = parameters['LOCAL_CPPPATH']
+ group['LOCAL_CPPPATH'] = [os.path.abspath(p) for p in paths]
+
+ # 5. 注册到全局项目列表
+ Projects.append(group)
+
+ # 6. 返回SCons对象
+ if src:
+ objs = Env.Object(src)
+ else:
+ objs = []
+
+ return objs
+```
+
+### 2. 依赖管理机制
+
+#### 2.1 GetDepend 实现
+
+```python
+def GetDepend(depend):
+ """
+ 检查依赖条件是否满足
+
+ 参数:
+ depend: 字符串或字符串列表
+
+ 返回:
+ True: 依赖满足
+ False: 依赖不满足
+ """
+ # 1. 处理空依赖
+ if not depend:
+ return True
+
+ # 2. 处理字符串依赖
+ if isinstance(depend, str):
+ return _CheckSingleDepend(depend)
+
+ # 3. 处理列表依赖(AND关系)
+ if isinstance(depend, list):
+ for d in depend:
+ if not _CheckSingleDepend(d):
+ return False
+ return True
+
+ return False
+
+def _CheckSingleDepend(depend):
+ """检查单个依赖"""
+ # 1. 检查是否在BuildOptions中定义
+ if depend in BuildOptions:
+ # 2. 检查值是否为真
+ return BuildOptions[depend] != '0'
+ return False
+```
+
+#### 2.2 依赖表达式支持
+
+```python
+# 支持的依赖表达式
+depend = 'RT_USING_SERIAL' # 单个依赖
+depend = ['RT_USING_LWIP', 'SAL'] # AND关系
+depend = '' # 无条件包含
+
+# 高级用法 - 在SConscript中
+if GetDepend('RT_USING_LWIP'):
+ if GetDepend('RT_USING_LWIP_TCP'):
+ src += ['tcp.c']
+ if GetDepend('RT_USING_LWIP_UDP'):
+ src += ['udp.c']
+```
+
+### 3. 配置解析系统
+
+#### 3.1 预处理器实现
+
+```python
+class PreProcessor:
+ """
+ C预处理器实现,用于解析rtconfig.h
+ """
+ def __init__(self):
+ self.cpp_namespace = {}
+ self.defines = {}
+
+ def process_contents(self, contents):
+ """处理文件内容"""
+ lines = contents.split('\n')
+
+ for line in lines:
+ # 处理 #define 指令
+ if line.startswith('#define'):
+ self._process_define(line)
+ # 处理 #ifdef 等条件编译
+ elif line.startswith('#ifdef'):
+ self._process_ifdef(line)
+
+ def _process_define(self, line):
+ """处理宏定义"""
+ # #define RT_NAME_MAX 8
+ parts = line.split(None, 2)
+ if len(parts) >= 2:
+ name = parts[1]
+ value = parts[2] if len(parts) > 2 else '1'
+ self.cpp_namespace[name] = value
+```
+
+#### 3.2 配置文件格式
+
+**rtconfig.h 示例**
+```c
+/* RT-Thread 配置文件 */
+#ifndef RT_CONFIG_H__
+#define RT_CONFIG_H__
+
+/* 内核配置 */
+#define RT_THREAD_PRIORITY_32
+#define RT_THREAD_PRIORITY_MAX 32
+#define RT_TICK_PER_SECOND 100
+#define RT_USING_TIMER_SOFT
+
+/* 组件配置 */
+#define RT_USING_DEVICE
+#define RT_USING_SERIAL
+#define RT_SERIAL_RB_BUFSZ 64
+
+/* 条件配置 */
+#ifdef RT_USING_SERIAL
+ #define RT_SERIAL_USING_DMA
+#endif
+
+#endif /* RT_CONFIG_H__ */
+```
+
+### 4. 工具链适配层
+
+#### 4.1 工具链抽象接口
+
+```python
+class ToolchainBase:
+ """工具链基类"""
+ def __init__(self):
+ self.name = ''
+ self.prefix = ''
+ self.suffix = ''
+
+ def get_cc(self):
+ """获取C编译器"""
+ raise NotImplementedError
+
+ def get_cflags(self):
+ """获取C编译选项"""
+ raise NotImplementedError
+
+ def get_linkflags(self):
+ """获取链接选项"""
+ raise NotImplementedError
+```
+
+#### 4.2 GCC工具链实现
+
+```python
+class GccToolchain(ToolchainBase):
+ def __init__(self, prefix=''):
+ self.name = 'gcc'
+ self.prefix = prefix
+ self.suffix = ''
+
+ def get_cc(self):
+ return self.prefix + 'gcc'
+
+ def get_cflags(self):
+ flags = []
+ # 基础选项
+ flags += ['-Wall', '-g']
+ # 优化选项
+ if GetOption('optimization') == 'size':
+ flags += ['-Os']
+ else:
+ flags += ['-O0']
+ # 架构选项
+ flags += ['-mcpu=cortex-m3', '-mthumb']
+ return ' '.join(flags)
+```
+
+#### 4.3 Keil MDK适配
+
+```python
+class KeilToolchain(ToolchainBase):
+ def __init__(self):
+ self.name = 'keil'
+
+ def setup_environment(self, env):
+ """设置Keil特定的环境变量"""
+ # 修改文件扩展名
+ env['OBJSUFFIX'] = '.o'
+ env['LIBPREFIX'] = ''
+ env['LIBSUFFIX'] = '.lib'
+
+ # 设置编译命令
+ env['CC'] = 'armcc'
+ env['AS'] = 'armasm'
+ env['AR'] = 'armar'
+ env['LINK'] = 'armlink'
+
+ # 设置命令格式
+ env['ARCOM'] = '$AR --create $TARGET $SOURCES'
+```
+
+### 5. 项目生成器架构
+
+#### 5.1 生成器基类
+
+```python
+class ProjectGenerator:
+ """项目生成器基类"""
+ def __init__(self, env, project):
+ self.env = env
+ self.project = project
+ self.template_dir = ''
+
+ def generate(self):
+ """生成项目文件"""
+ self._prepare()
+ self._generate_project_file()
+ self._generate_workspace_file()
+ self._copy_template_files()
+ self._post_process()
+
+ def _collect_source_files(self):
+ """收集源文件"""
+ sources = []
+ for group in self.project:
+ sources.extend(group['src'])
+ return sources
+
+ def _collect_include_paths(self):
+ """收集头文件路径"""
+ paths = []
+ for group in self.project:
+ if 'CPPPATH' in group:
+ paths.extend(group['CPPPATH'])
+ return list(set(paths)) # 去重
+```
+
+#### 5.2 VS Code生成器实现
+
+```python
+class VSCodeGenerator(ProjectGenerator):
+ """VS Code项目生成器"""
+
+ def _generate_project_file(self):
+ """生成VS Code配置文件"""
+ # 创建.vscode目录
+ vscode_dir = os.path.join(self.env['BSP_ROOT'], '.vscode')
+ if not os.path.exists(vscode_dir):
+ os.makedirs(vscode_dir)
+
+ # 生成c_cpp_properties.json
+ self._generate_cpp_properties()
+
+ # 生成tasks.json
+ self._generate_tasks()
+
+ # 生成launch.json
+ self._generate_launch()
+
+ def _generate_cpp_properties(self):
+ """生成IntelliSense配置"""
+ config = {
+ "configurations": [{
+ "name": "RT-Thread",
+ "includePath": self._collect_include_paths(),
+ "defines": self._collect_defines(),
+ "compilerPath": self._get_compiler_path(),
+ "cStandard": "c99",
+ "cppStandard": "c++11",
+ "intelliSenseMode": "gcc-arm"
+ }],
+ "version": 4
+ }
+
+ # 写入文件
+ file_path = os.path.join('.vscode', 'c_cpp_properties.json')
+ with open(file_path, 'w') as f:
+ json.dump(config, f, indent=4)
+```
+
+#### 5.3 Keil MDK5生成器
+
+```python
+class MDK5Generator(ProjectGenerator):
+ """Keil MDK5项目生成器"""
+
+ def _generate_project_file(self):
+ """生成uvprojx文件"""
+ # 加载XML模板
+ tree = etree.parse(self.template_file)
+ root = tree.getroot()
+
+ # 更新目标配置
+ self._update_target_options(root)
+
+ # 添加文件组
+ groups_node = root.find('.//Groups')
+ for group in self.project:
+ self._add_file_group(groups_node, group)
+
+ # 保存项目文件
+ tree.write('project.uvprojx', encoding='utf-8',
+ xml_declaration=True)
+
+ def _add_file_group(self, parent, group):
+ """添加文件组"""
+ group_elem = etree.SubElement(parent, 'Group')
+
+ # 组名
+ name_elem = etree.SubElement(group_elem, 'GroupName')
+ name_elem.text = group['name']
+
+ # 文件列表
+ files_elem = etree.SubElement(group_elem, 'Files')
+ for src in group['src']:
+ self._add_file(files_elem, src)
+```
+
+### 6. 编译数据库生成
+
+#### 6.1 compile_commands.json生成
+
+```python
+def generate_compile_commands(env, project):
+ """
+ 生成compile_commands.json用于代码分析工具
+ """
+ commands = []
+
+ for group in project:
+ for src in group['src']:
+ if src.endswith('.c') or src.endswith('.cpp'):
+ cmd = {
+ "directory": env['BSP_ROOT'],
+ "file": os.path.abspath(src),
+ "command": _generate_compile_command(env, src, group)
+ }
+ commands.append(cmd)
+
+ # 写入文件
+ with open('compile_commands.json', 'w') as f:
+ json.dump(commands, f, indent=2)
+
+def _generate_compile_command(env, src, group):
+ """生成单个文件的编译命令"""
+ cmd = []
+
+ # 编译器
+ cmd.append(env['CC'])
+
+ # 编译选项
+ cmd.extend(env['CFLAGS'].split())
+
+ # 头文件路径
+ for path in group.get('CPPPATH', []):
+ cmd.append('-I' + path)
+
+ # 宏定义
+ for define in group.get('CPPDEFINES', []):
+ if isinstance(define, tuple):
+ cmd.append('-D{}={}'.format(define[0], define[1]))
+ else:
+ cmd.append('-D' + define)
+
+ # 源文件
+ cmd.append(src)
+
+ return ' '.join(cmd)
+```
+
+### 7. 分发系统实现
+
+#### 7.1 分发包生成流程
+
+```python
+def MkDist(program, BSP_ROOT, RTT_ROOT, Env, project):
+ """生成分发包"""
+ # 1. 创建分发目录
+ dist_name = os.path.basename(BSP_ROOT)
+ dist_dir = os.path.join(BSP_ROOT, 'dist', dist_name)
+
+ # 2. 复制RT-Thread内核
+ print('=> copy RT-Thread kernel')
+ copytree(os.path.join(RTT_ROOT, 'src'),
+ os.path.join(dist_dir, 'rt-thread', 'src'))
+ copytree(os.path.join(RTT_ROOT, 'include'),
+ os.path.join(dist_dir, 'rt-thread', 'include'))
+
+ # 3. 复制使用的组件
+ print('=> copy components')
+ for group in project:
+ _copy_group_files(group, dist_dir)
+
+ # 4. 生成Kconfig文件
+ _generate_kconfig(dist_dir, project)
+
+ # 5. 打包
+ make_zip(dist_dir, dist_name + '.zip')
+```
+
+#### 7.2 精简分发包生成
+
+```python
+def MkDist_Strip(program, BSP_ROOT, RTT_ROOT, Env):
+ """
+ 基于compile_commands.json生成精简分发包
+ 只包含实际使用的文件
+ """
+ # 1. 解析compile_commands.json
+ with open('compile_commands.json', 'r') as f:
+ commands = json.load(f)
+
+ # 2. 提取使用的文件
+ used_files = set()
+ for cmd in commands:
+ # 源文件
+ used_files.add(cmd['file'])
+
+ # 解析包含的头文件
+ includes = _parse_includes(cmd['file'], cmd['command'])
+ used_files.update(includes)
+
+ # 3. 复制文件
+ for file in used_files:
+ _copy_with_structure(file, dist_dir)
+```
+
+## 构建流程详解
+
+### 完整构建流程图
+
+```
+┌──────────────┐
+│ 用户输入 │
+│ scons │
+└──────┬───────┘
+ │
+┌──────▼───────┐
+│ SConstruct │ ← 读取rtconfig.py
+│ 主脚本 │ ← 调用PrepareBuilding
+└──────┬───────┘
+ │
+┌──────▼───────┐
+│ 环境初始化 │
+│ ·设置路径 │
+│ ·检测工具链 │
+│ ·解析配置 │
+└──────┬───────┘
+ │
+┌──────▼───────┐
+│ 递归处理 │
+│ SConscript │ ← 调用DefineGroup
+│ ·收集源文件 │ ← 检查依赖GetDepend
+│ ·设置参数 │
+└──────┬───────┘
+ │
+┌──────▼───────┐
+│ 构建执行 │
+│ DoBuilding │
+│ ·合并对象 │
+│ ·链接程序 │
+└──────┬───────┘
+ │
+┌──────▼───────┐
+│ 后处理 │
+│ ·生成bin文件 │
+│ ·显示大小 │
+│ ·自定义动作 │
+└──────────────┘
+```
+
+### 依赖解析流程
+
+```python
+def dependency_resolution_flow():
+ """
+ 依赖解析流程示例
+ """
+ # 1. 从rtconfig.h读取所有宏定义
+ macros = parse_rtconfig_h()
+ # 例: {'RT_USING_SERIAL': '1', 'RT_USING_PIN': '1'}
+
+ # 2. 处理单个组件
+ for component in components:
+ # 3. 检查依赖条件
+ if check_dependencies(component.depends, macros):
+ # 4. 包含组件
+ include_component(component)
+ else:
+ # 5. 跳过组件
+ skip_component(component)
+
+ # 6. 递归处理子依赖
+ resolve_sub_dependencies()
+```
+
+## 扩展机制
+
+### 1. 添加新的工具链支持
+
+```python
+# 1. 在tgt_dict中添加映射
+tgt_dict['mycc'] = ('mycc', 'mycc')
+
+# 2. 创建tools/mycc.py
+import os
+from building import *
+
+def generate_project(env, project):
+ """生成项目文件"""
+ print("Generating MyCC project...")
+
+ # 收集信息
+ info = ProjectInfo(env, project)
+
+ # 生成项目文件
+ # ...
+
+# 3. 在rtconfig.py中配置
+CROSS_TOOL = 'mycc'
+PLATFORM = 'mycc'
+```
+
+### 2. 添加自定义构建步骤
+
+```python
+# 在SConstruct或SConscript中
+def custom_builder(target, source, env):
+ """自定义构建器"""
+ # 执行自定义操作
+ cmd = 'custom_tool -o {} {}'.format(target[0], source[0])
+ os.system(cmd)
+
+# 注册构建器
+env['BUILDERS']['CustomBuild'] = Builder(action=custom_builder,
+ suffix='.out',
+ src_suffix='.in')
+
+# 使用构建器
+custom_out = env.CustomBuild('output.out', 'input.in')
+```
+
+### 3. 扩展配置解析器
+
+```python
+class ExtendedPreProcessor(PreProcessor):
+ """扩展的预处理器"""
+
+ def __init__(self):
+ super().__init__()
+ self.custom_handlers = {}
+
+ def register_handler(self, directive, handler):
+ """注册自定义指令处理器"""
+ self.custom_handlers[directive] = handler
+
+ def process_line(self, line):
+ """处理单行"""
+ # 检查自定义指令
+ for directive, handler in self.custom_handlers.items():
+ if line.startswith(directive):
+ return handler(line)
+
+ # 默认处理
+ return super().process_line(line)
+```
+
+### 4. 插件系统实现
+
+```python
+class BuildPlugin:
+ """构建插件基类"""
+
+ def __init__(self, name):
+ self.name = name
+
+ def pre_build(self, env, project):
+ """构建前钩子"""
+ pass
+
+ def post_build(self, env, project):
+ """构建后钩子"""
+ pass
+
+ def configure(self, env):
+ """配置环境"""
+ pass
+
+# 插件管理器
+class PluginManager:
+ def __init__(self):
+ self.plugins = []
+
+ def register(self, plugin):
+ self.plugins.append(plugin)
+
+ def run_pre_build(self, env, project):
+ for plugin in self.plugins:
+ plugin.pre_build(env, project)
+```
+
+## 性能优化
+
+### 1. 构建缓存机制
+
+```python
+class BuildCache:
+ """构建缓存"""
+
+ def __init__(self, cache_dir='.scache'):
+ self.cache_dir = cache_dir
+ self.cache_db = os.path.join(cache_dir, 'cache.db')
+
+ def get_hash(self, file):
+ """计算文件哈希"""
+ import hashlib
+ with open(file, 'rb') as f:
+ return hashlib.md5(f.read()).hexdigest()
+
+ def is_cached(self, source, target):
+ """检查是否已缓存"""
+ # 检查目标文件是否存在
+ if not os.path.exists(target):
+ return False
+
+ # 检查源文件是否更新
+ source_hash = self.get_hash(source)
+ cached_hash = self.load_hash(source)
+
+ return source_hash == cached_hash
+```
+
+### 2. 并行构建优化
+
+```python
+def optimize_parallel_build(env, project):
+ """优化并行构建"""
+ # 1. 分析依赖关系
+ dep_graph = analyze_dependencies(project)
+
+ # 2. 计算最优构建顺序
+ build_order = topological_sort(dep_graph)
+
+ # 3. 分组独立任务
+ parallel_groups = []
+ for level in build_order:
+ # 同一层级可以并行
+ parallel_groups.append(level)
+
+ # 4. 设置并行度
+ import multiprocessing
+ num_jobs = multiprocessing.cpu_count()
+ env.SetOption('num_jobs', num_jobs)
+
+ return parallel_groups
+```
+
+## 调试技巧
+
+### 1. 构建日志分析
+
+```python
+# 启用详细日志
+def enable_build_logging():
+ # 设置SCons日志
+ env.SetOption('debug', 'explain')
+
+ # 自定义日志
+ class BuildLogger:
+ def __init__(self, logfile):
+ self.logfile = logfile
+
+ def __call__(self, msg, *args):
+ with open(self.logfile, 'a') as f:
+ f.write(msg % args + '\n')
+
+ logger = BuildLogger('build.log')
+ env['PRINT_CMD_LINE_FUNC'] = logger
+```
+
+### 2. 依赖关系可视化
+
+```python
+def visualize_dependencies(project):
+ """生成依赖关系图"""
+ import graphviz
+
+ dot = graphviz.Digraph(comment='Dependencies')
+
+ # 添加节点
+ for group in project:
+ dot.node(group['name'])
+
+ # 添加边
+ for group in project:
+ for dep in group.get('depends', []):
+ if find_group(dep):
+ dot.edge(dep, group['name'])
+
+ # 渲染
+ dot.render('dependencies', format='png')
+```
+
+## 最佳实践
+
+### 1. 模块化设计原则
+
+- 每个功能模块独立的SConscript
+- 明确的依赖关系声明
+- 避免循环依赖
+- 使用统一的命名规范
+
+### 2. 性能优化建议
+
+- 使用Glob谨慎,大目录下性能差
+- 合理设置并行编译数
+- 使用增量编译
+- 避免重复的文件扫描
+
+### 3. 可维护性建议
+
+- 添加充分的注释
+- 使用有意义的变量名
+- 遵循Python PEP8规范
+- 定期清理无用代码
+
+### 4. 跨平台兼容性
+
+- 使用os.path处理路径
+- 避免平台特定的命令
+- 测试多平台构建
+- 处理路径分隔符差异
+
+## 总结
+
+RT-Thread的构建系统是一个精心设计的模块化系统,通过清晰的架构和灵活的扩展机制,为嵌入式开发提供了强大的构建能力。理解其内部原理有助于:
+
+1. 更好地使用和优化构建流程
+2. 快速定位和解决构建问题
+3. 扩展支持新的工具链和平台
+4. 为项目定制构建流程
+
+构建系统的核心价值在于将复杂的嵌入式构建过程标准化和自动化,让开发者能够专注于功能开发而不是构建配置。 \ No newline at end of file
diff --git a/tools/ng/README.md b/tools/ng/README.md
new file mode 100644
index 0000000000..021a796e49
--- /dev/null
+++ b/tools/ng/README.md
@@ -0,0 +1,345 @@
+# RT-Thread Next Generation Build System
+
+## 概述
+
+RT-Thread NG(Next Generation)构建系统是对现有构建系统的面向对象重构,在保持完全向后兼容的同时,提供了更清晰的架构和更强的可扩展性。
+
+## 特性
+
+- ✅ **完全向后兼容**:现有的SConscript无需修改
+- ✅ **面向对象设计**:清晰的类层次结构和职责分离
+- ✅ **SCons最佳实践**:充分利用SCons的Environment对象
+- ✅ **可扩展架构**:易于添加新的工具链和项目生成器
+- ✅ **类型安全**:更好的类型提示和错误处理
+
+## 架构设计
+
+### 核心模块
+
+```
+ng/
+├── __init__.py # 包初始化
+├── core.py # 核心类:BuildContext
+├── environment.py # 环境扩展:RTEnv类,注入到SCons Environment
+├── config.py # 配置管理:解析rtconfig.h
+├── project.py # 项目管理:ProjectGroup和Registry
+├── toolchain.py # 工具链抽象:GCC、Keil、IAR等
+├── generator.py # 项目生成器:VS Code、CMake等
+├── utils.py # 工具函数:路径、版本等
+├── adapter.py # 适配器:与building.py集成
+└── building_ng.py # 示例:最小化修改的building.py
+```
+
+### 类图
+
+```mermaid
+classDiagram
+ class BuildContext {
+ +root_directory: str
+ +config_manager: ConfigManager
+ +project_registry: ProjectRegistry
+ +toolchain_manager: ToolchainManager
+ +prepare_environment(env)
+ +get_dependency(depend): bool
+ }
+
+ class ConfigManager {
+ +load_from_file(filepath)
+ +get_dependency(depend): bool
+ +get_option(name): ConfigOption
+ }
+
+ class ProjectGroup {
+ +name: str
+ +sources: List[str]
+ +dependencies: List[str]
+ +build(env): List[Object]
+ }
+
+ class Toolchain {
+ <<abstract>>
+ +get_name(): str
+ +detect(): bool
+ +configure_environment(env)
+ }
+
+ class ProjectGenerator {
+ <<abstract>>
+ +generate(context, info): bool
+ +clean(): bool
+ }
+
+ BuildContext --> ConfigManager
+ BuildContext --> ProjectRegistry
+ BuildContext --> ToolchainManager
+ ProjectRegistry --> ProjectGroup
+ ToolchainManager --> Toolchain
+```
+
+## 使用方法
+
+### 1. 最小化集成(推荐)
+
+在building.py中添加少量代码即可集成新系统:
+
+```python
+# 在building.py的开头添加
+try:
+ from ng.adapter import (
+ init_build_context,
+ inject_environment_methods,
+ load_rtconfig as ng_load_rtconfig
+ )
+ USE_NG = True
+except ImportError:
+ USE_NG = False
+
+# 在PrepareBuilding函数中添加
+def PrepareBuilding(env, root_directory, has_libcpu=False, remove_components=[]):
+ # ... 原有代码 ...
+
+ # 集成新系统
+ if USE_NG:
+ context = init_build_context(root_directory)
+ inject_environment_methods(env)
+ ng_load_rtconfig('rtconfig.h')
+
+ # ... 继续原有代码 ...
+```
+
+### 2. 使用新的环境方法
+
+集成后,SCons Environment对象会自动获得新方法:
+
+```python
+# 在SConscript中使用新方法
+Import('env')
+
+# 使用环境方法(推荐)
+src = env.GlobFiles('*.c')
+group = env.DefineGroup('MyComponent', src, depend=['RT_USING_XXX'])
+
+# 也可以使用传统方式(保持兼容)
+from building import *
+group = DefineGroup('MyComponent', src, depend=['RT_USING_XXX'])
+```
+
+### 3. 新的项目生成器
+
+新系统提供了改进的项目生成器:
+
+```bash
+# 生成VS Code项目
+scons --target=vscode
+
+# 生成CMake项目
+scons --target=cmake
+```
+
+## API参考
+
+### 环境方法
+
+所有方法都被注入到SCons Environment对象中:
+
+#### env.DefineGroup(name, src, depend, **kwargs)
+定义一个组件组。
+
+**参数:**
+- `name`: 组名称
+- `src`: 源文件列表
+- `depend`: 依赖条件(字符串或列表)
+- `**kwargs`: 额外参数
+ - `CPPPATH`: 头文件路径
+ - `CPPDEFINES`: 宏定义
+ - `CFLAGS`/`CXXFLAGS`: 编译选项
+ - `LOCAL_CFLAGS`/`LOCAL_CPPPATH`: 仅对当前组有效的选项
+ - `LIBS`/`LIBPATH`: 库配置
+
+**返回:** 构建对象列表
+
+**示例:**
+```python
+src = ['driver.c', 'hal.c']
+group = env.DefineGroup('Driver',
+ src,
+ depend=['RT_USING_DEVICE'],
+ CPPPATH=[env.GetCurrentDir()],
+ LOCAL_CFLAGS='-O3'
+)
+```
+
+#### env.GetDepend(depend)
+检查依赖是否满足。
+
+**参数:**
+- `depend`: 依赖名称或列表
+
+**返回:** True如果依赖满足
+
+**示例:**
+```python
+if env.GetDepend('RT_USING_SERIAL'):
+ src += ['serial.c']
+
+if env.GetDepend(['RT_USING_SERIAL', 'RT_SERIAL_USING_DMA']):
+ src += ['serial_dma.c']
+```
+
+#### env.SrcRemove(src, remove)
+从源文件列表中移除文件。
+
+**参数:**
+- `src`: 源文件列表(就地修改)
+- `remove`: 要移除的文件
+
+**示例:**
+```python
+src = env.GlobFiles('*.c')
+env.SrcRemove(src, ['test.c', 'debug.c'])
+```
+
+#### env.BuildPackage(package_path)
+从package.json构建软件包。
+
+**参数:**
+- `package_path`: package.json路径
+
+**返回:** 构建对象列表
+
+**示例:**
+```python
+objs = env.BuildPackage('package.json')
+```
+
+#### env.GetContext()
+获取当前构建上下文。
+
+**返回:** BuildContext实例
+
+**示例:**
+```python
+context = env.GetContext()
+if context:
+ context.logger.info("Building component...")
+```
+
+## 高级特性
+
+### 1. 自定义工具链
+
+创建自定义工具链:
+
+```python
+from ng.toolchain import Toolchain
+
+class MyToolchain(Toolchain):
+ def get_name(self):
+ return "mycc"
+
+ def detect(self):
+ # 检测工具链
+ return shutil.which("mycc") is not None
+
+ def configure_environment(self, env):
+ env['CC'] = 'mycc'
+ env['CFLAGS'] = '-O2 -Wall'
+
+# 注册工具链
+context = env.GetContext()
+context.toolchain_manager.register_toolchain('mycc', MyToolchain())
+```
+
+### 2. 自定义项目生成器
+
+创建自定义项目生成器:
+
+```python
+from ng.generator import ProjectGenerator
+
+class MyGenerator(ProjectGenerator):
+ def get_name(self):
+ return "myide"
+
+ def generate(self, context, project_info):
+ # 生成项目文件
+ self._ensure_output_dir()
+ # ... 生成逻辑 ...
+ return True
+
+# 注册生成器
+context.generator_registry.register('myide', MyGenerator)
+```
+
+### 3. 构建钩子
+
+使用构建上下文添加钩子:
+
+```python
+context = env.GetContext()
+
+# 添加日志
+context.logger.info("Starting build...")
+
+# 访问配置
+if context.config_manager.get_option('RT_THREAD_PRIORITY_MAX'):
+ print("Max priority:", context.config_manager.get_value('RT_THREAD_PRIORITY_MAX'))
+
+# 获取项目信息
+info = context.project_registry.get_project_info()
+print(f"Total sources: {len(info['all_sources'])}")
+```
+
+## 迁移指南
+
+### 从旧版本迁移
+
+1. **无需修改**:现有的SConscript文件无需任何修改即可工作
+2. **可选升级**:可以逐步将`DefineGroup`调用改为`env.DefineGroup`
+3. **新功能**:可以开始使用新的特性如`env.BuildPackage`
+
+### 最佳实践
+
+1. **使用环境方法**:优先使用`env.DefineGroup`而不是全局函数
+2. **类型提示**:在Python 3.5+中使用类型提示
+3. **错误处理**:使用context.logger记录错误和警告
+4. **路径处理**:使用PathService处理跨平台路径
+
+## 性能优化
+
+新系统包含多项性能优化:
+
+1. **配置缓存**:依赖检查结果会被缓存
+2. **延迟加载**:工具链和生成器按需加载
+3. **并行支持**:项目生成可以并行执行
+
+## 测试
+
+运行测试套件:
+
+```bash
+cd tools/ng
+python -m pytest tests/
+```
+
+## 贡献
+
+欢迎贡献代码!请遵循以下准则:
+
+1. 保持向后兼容性
+2. 添加类型提示
+3. 编写单元测试
+4. 更新文档
+
+## 路线图
+
+- [ ] 完整的测试覆盖
+- [ ] 性能基准测试
+- [ ] 插件系统
+- [ ] 更多项目生成器(Eclipse、Qt Creator等)
+- [ ] 构建缓存系统
+- [ ] 分布式构建支持
+
+## 许可证
+
+本项目遵循RT-Thread的Apache License 2.0许可证。 \ No newline at end of file
diff --git a/tools/ng/__init__.py b/tools/ng/__init__.py
new file mode 100644
index 0000000000..4ce70feea3
--- /dev/null
+++ b/tools/ng/__init__.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+"""
+RT-Thread Next Generation Build System
+
+This module provides an object-oriented implementation of the RT-Thread build system
+while maintaining backward compatibility with the existing building.py interface.
+"""
+
+from .core import BuildContext
+from .environment import RTEnv
+from .config import ConfigManager
+from .project import ProjectRegistry, ProjectGroup
+from .toolchain import ToolchainManager
+from .generator import GeneratorRegistry
+
+__version__ = "1.0.0"
+__all__ = [
+ 'BuildContext',
+ 'RTEnv',
+ 'ConfigManager',
+ 'ProjectRegistry',
+ 'ProjectGroup',
+ 'ToolchainManager',
+ 'GeneratorRegistry'
+] \ No newline at end of file
diff --git a/tools/ng/adapter.py b/tools/ng/adapter.py
new file mode 100644
index 0000000000..64a2a17dfc
--- /dev/null
+++ b/tools/ng/adapter.py
@@ -0,0 +1,218 @@
+# -*- coding: utf-8 -*-
+"""
+Adapter module to integrate new OOP implementation with existing building.py.
+
+This module provides the bridge between the legacy function-based API and the new
+object-oriented implementation, ensuring backward compatibility.
+"""
+
+import os
+from typing import List, Dict, Any, Optional
+
+from .core import BuildContext
+from .environment import RTEnv
+from .generator import GeneratorConfig, GeneratorRegistry
+
+
+# Global variables for compatibility
+_context: Optional[BuildContext] = None
+
+
+def init_build_context(root_directory: str) -> BuildContext:
+ """
+ Initialize the build context.
+
+ This function should be called early in PrepareBuilding.
+
+ Args:
+ root_directory: RT-Thread root directory
+
+ Returns:
+ BuildContext instance
+ """
+ global _context
+ _context = BuildContext(root_directory)
+ return _context
+
+
+def get_build_context() -> Optional[BuildContext]:
+ """Get the current build context."""
+ return _context
+
+
+def inject_environment_methods(env) -> None:
+ """
+ Inject RT-Thread methods into SCons Environment.
+
+ This should be called in PrepareBuilding after environment setup.
+
+ Args:
+ env: SCons Environment object
+ """
+ RTEnv.inject_methods(env)
+
+ # Also set the environment in context
+ if _context:
+ _context.prepare_environment(env)
+
+
+def load_rtconfig(config_file: str = 'rtconfig.h') -> Dict[str, Any]:
+ """
+ Load configuration from rtconfig.h.
+
+ Args:
+ config_file: Configuration file name
+
+ Returns:
+ Dictionary of build options
+ """
+ if _context:
+ _context.load_configuration(config_file)
+ return _context.build_options
+ return {}
+
+
+def DefineGroup(name: str, src: List[str], depend: Any = None, **kwargs) -> List:
+ """
+ Legacy DefineGroup function for backward compatibility.
+
+ This function delegates to the environment method.
+
+ Args:
+ name: Group name
+ src: Source files
+ depend: Dependencies
+ **kwargs: Additional parameters
+
+ Returns:
+ List of build objects
+ """
+ if _context and _context.environment:
+ return _context.environment.DefineGroup(name, src, depend, **kwargs)
+ else:
+ # Fallback behavior
+ print(f"Warning: DefineGroup called before environment setup for group '{name}'")
+ return []
+
+
+def GetDepend(depend: Any) -> bool:
+ """
+ Legacy GetDepend function for backward compatibility.
+
+ Args:
+ depend: Dependency to check
+
+ Returns:
+ True if dependency is satisfied
+ """
+ if _context:
+ return _context.get_dependency(depend)
+ return False
+
+
+def GetCurrentDir() -> str:
+ """
+ Get current directory.
+
+ Returns:
+ Current directory path
+ """
+ return os.path.abspath('.')
+
+
+def SrcRemove(src: List[str], remove: List[str]) -> None:
+ """
+ Remove files from source list.
+
+ Args:
+ src: Source list (modified in place)
+ remove: Files to remove
+ """
+ if not isinstance(remove, list):
+ remove = [remove]
+
+ for item in remove:
+ if item in src:
+ src.remove(item)
+
+
+def GetBuildOptions() -> Dict[str, Any]:
+ """
+ Get build options.
+
+ Returns:
+ Dictionary of build options
+ """
+ if _context:
+ return _context.build_options
+ return {}
+
+
+def MergeGroups() -> List:
+ """
+ Merge all registered groups.
+
+ Returns:
+ List of all build objects
+ """
+ if _context:
+ return _context.merge_groups()
+ return []
+
+
+def GenerateProject(target: str, env, projects: List) -> None:
+ """
+ Generate IDE project files.
+
+ Args:
+ target: Target type (mdk5, iar, vscode, etc.)
+ env: SCons Environment
+ projects: Project list
+ """
+ if not _context:
+ print("Error: Build context not initialized")
+ return
+
+ # Get project info from registry
+ project_info = _context.project_registry.get_project_info()
+
+ # Create generator config
+ config = GeneratorConfig(
+ output_dir=os.getcwd(),
+ project_name=os.path.basename(os.getcwd()),
+ target_name="rtthread.elf"
+ )
+
+ # Create and run generator
+ try:
+ generator = _context.generator_registry.create_generator(target, config)
+ if generator.generate(_context, project_info):
+ print(f"Successfully generated {target} project files")
+ else:
+ print(f"Failed to generate {target} project files")
+ except Exception as e:
+ print(f"Error generating {target} project: {e}")
+
+
+def PrepareModuleBuilding(env, root_directory, bsp_directory) -> None:
+ """
+ Prepare for building a module.
+
+ This is a simplified version of PrepareBuilding for module compilation.
+
+ Args:
+ env: SCons Environment
+ root_directory: RT-Thread root directory
+ bsp_directory: BSP directory
+ """
+ # Initialize context
+ context = init_build_context(root_directory)
+ context.bsp_directory = bsp_directory
+
+ # Inject methods
+ inject_environment_methods(env)
+
+ # Load configuration
+ config_path = os.path.join(bsp_directory, 'rtconfig.h')
+ if os.path.exists(config_path):
+ load_rtconfig(config_path) \ No newline at end of file
diff --git a/tools/ng/building_ng.py b/tools/ng/building_ng.py
new file mode 100644
index 0000000000..09d8a8f7ec
--- /dev/null
+++ b/tools/ng/building_ng.py
@@ -0,0 +1,115 @@
+# -*- coding: utf-8 -*-
+"""
+Next Generation building.py with minimal modifications.
+
+This file shows how to integrate the new OOP system with minimal changes to building.py.
+The actual implementation would modify the original building.py file.
+"""
+
+# Import everything from original building.py
+import sys
+import os
+
+# Add parent directory to path to import original building
+sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+from building import *
+
+# Import new OOP modules
+from ng.adapter import (
+ init_build_context,
+ inject_environment_methods,
+ load_rtconfig as ng_load_rtconfig,
+ GenerateProject as ng_GenerateProject
+)
+
+
+# Override PrepareBuilding to integrate new system
+_original_PrepareBuilding = PrepareBuilding
+
+def PrepareBuilding(env, root_directory, has_libcpu=False, remove_components=[]):
+ """
+ Enhanced PrepareBuilding that integrates the new OOP system.
+
+ This function wraps the original PrepareBuilding and adds OOP functionality.
+ """
+ # Initialize new build context
+ context = init_build_context(root_directory)
+
+ # Call original PrepareBuilding
+ result = _original_PrepareBuilding(env, root_directory, has_libcpu, remove_components)
+
+ # Inject new methods into environment
+ inject_environment_methods(env)
+
+ # Load configuration into new system
+ ng_load_rtconfig('rtconfig.h')
+
+ # Store context in environment for access
+ env['_BuildContext'] = context
+
+ return result
+
+
+# Override DefineGroup to use new implementation
+_original_DefineGroup = DefineGroup
+
+def DefineGroup(name, src, depend, **parameters):
+ """
+ Enhanced DefineGroup that uses the new OOP implementation.
+
+ This maintains backward compatibility while using the new system internally.
+ """
+ # Get environment from global Env
+ global Env
+ if Env and hasattr(Env, 'DefineGroup'):
+ # Use new method if available
+ return Env.DefineGroup(name, src, depend, **parameters)
+ else:
+ # Fallback to original
+ return _original_DefineGroup(name, src, depend, **parameters)
+
+
+# Override GetDepend to use new implementation
+_original_GetDepend = GetDepend
+
+def GetDepend(depend):
+ """
+ Enhanced GetDepend that uses the new OOP implementation.
+ """
+ global Env
+ if Env and hasattr(Env, 'GetDepend'):
+ # Use new method if available
+ return Env.GetDepend(depend)
+ else:
+ # Fallback to original
+ return _original_GetDepend(depend)
+
+
+# Override DoBuilding to integrate project generation
+_original_DoBuilding = DoBuilding
+
+def DoBuilding(target, objects):
+ """
+ Enhanced DoBuilding that integrates new project generation.
+ """
+ # Call original DoBuilding
+ _original_DoBuilding(target, objects)
+
+ # Handle project generation with new system
+ if GetOption('target'):
+ target_name = GetOption('target')
+ global Env, Projects
+
+ # Use new generator if available
+ try:
+ ng_GenerateProject(target_name, Env, Projects)
+ except Exception as e:
+ print(f"Falling back to original generator: {e}")
+ # Call original GenTargetProject
+ from building import GenTargetProject
+ GenTargetProject(Projects, program=target)
+
+
+# Export enhanced functions
+__all__ = ['PrepareBuilding', 'DefineGroup', 'GetDepend', 'DoBuilding'] + \
+ [name for name in dir(sys.modules['building']) if not name.startswith('_')] \ No newline at end of file
diff --git a/tools/ng/config.py b/tools/ng/config.py
new file mode 100644
index 0000000000..fbf54431ea
--- /dev/null
+++ b/tools/ng/config.py
@@ -0,0 +1,297 @@
+# -*- coding: utf-8 -*-
+"""
+Configuration management for RT-Thread build system.
+
+This module handles parsing and managing configuration from rtconfig.h files.
+"""
+
+import re
+import os
+from typing import Dict, List, Any, Optional, Union
+from dataclasses import dataclass
+from enum import Enum
+
+
+class ConfigType(Enum):
+ """Configuration value types."""
+ BOOLEAN = "boolean"
+ INTEGER = "integer"
+ STRING = "string"
+ UNDEFINED = "undefined"
+
+
+@dataclass
+class ConfigOption:
+ """Configuration option with metadata."""
+ name: str
+ value: Any
+ type: ConfigType
+ line_number: int = 0
+ comment: str = ""
+
+ def as_bool(self) -> bool:
+ """Get value as boolean."""
+ if self.type == ConfigType.BOOLEAN:
+ return bool(self.value)
+ elif self.type == ConfigType.INTEGER:
+ return self.value != 0
+ elif self.type == ConfigType.STRING:
+ return bool(self.value)
+ return False
+
+ def as_int(self) -> int:
+ """Get value as integer."""
+ if self.type == ConfigType.INTEGER:
+ return self.value
+ elif self.type == ConfigType.BOOLEAN:
+ return 1 if self.value else 0
+ elif self.type == ConfigType.STRING:
+ try:
+ return int(self.value)
+ except ValueError:
+ return 0
+ return 0
+
+ def as_str(self) -> str:
+ """Get value as string."""
+ if self.type == ConfigType.STRING:
+ return self.value
+ return str(self.value)
+
+
+class ConfigParser:
+ """Parser for rtconfig.h files."""
+
+ # Regular expressions for parsing
+ RE_DEFINE = re.compile(r'^\s*#\s*define\s+(\w+)(?:\s+(.*))?', re.MULTILINE)
+ RE_UNDEF = re.compile(r'^\s*#\s*undef\s+(\w+)', re.MULTILINE)
+ RE_IFDEF = re.compile(r'^\s*#\s*ifdef\s+(\w+)', re.MULTILINE)
+ RE_IFNDEF = re.compile(r'^\s*#\s*ifndef\s+(\w+)', re.MULTILINE)
+ RE_ENDIF = re.compile(r'^\s*#\s*endif', re.MULTILINE)
+ RE_COMMENT = re.compile(r'/\*.*?\*/', re.DOTALL)
+ RE_LINE_COMMENT = re.compile(r'//.*$', re.MULTILINE)
+
+ def __init__(self):
+ self.options: Dict[str, ConfigOption] = {}
+ self.conditions: List[str] = []
+
+ def parse_file(self, filepath: str) -> Dict[str, ConfigOption]:
+ """
+ Parse configuration file.
+
+ Args:
+ filepath: Path to rtconfig.h
+
+ Returns:
+ Dictionary of configuration options
+ """
+ if not os.path.exists(filepath):
+ raise FileNotFoundError(f"Configuration file not found: {filepath}")
+
+ with open(filepath, 'r', encoding='utf-8') as f:
+ content = f.read()
+
+ return self.parse_content(content)
+
+ def parse_content(self, content: str) -> Dict[str, ConfigOption]:
+ """
+ Parse configuration content.
+
+ Args:
+ content: File content
+
+ Returns:
+ Dictionary of configuration options
+ """
+ # Remove comments
+ content = self.RE_COMMENT.sub('', content)
+ content = self.RE_LINE_COMMENT.sub('', content)
+
+ # Parse line by line
+ lines = content.split('\n')
+ for i, line in enumerate(lines):
+ self._parse_line(line, i + 1)
+
+ return self.options
+
+ def _parse_line(self, line: str, line_number: int) -> None:
+ """Parse a single line."""
+ # Check for #define
+ match = self.RE_DEFINE.match(line)
+ if match:
+ name = match.group(1)
+ value = match.group(2) if match.group(2) else '1'
+
+ # Parse value
+ parsed_value, value_type = self._parse_value(value.strip())
+
+ # Create option
+ option = ConfigOption(
+ name=name,
+ value=parsed_value,
+ type=value_type,
+ line_number=line_number
+ )
+
+ self.options[name] = option
+ return
+
+ # Check for #undef
+ match = self.RE_UNDEF.match(line)
+ if match:
+ name = match.group(1)
+ if name in self.options:
+ del self.options[name]
+ return
+
+ def _parse_value(self, value: str) -> tuple:
+ """
+ Parse configuration value.
+
+ Returns:
+ Tuple of (parsed_value, ConfigType)
+ """
+ if not value or value == '1':
+ return (True, ConfigType.BOOLEAN)
+
+ # Try integer
+ try:
+ return (int(value, 0), ConfigType.INTEGER) # Support hex/octal
+ except ValueError:
+ pass
+
+ # Try string (remove quotes)
+ if value.startswith('"') and value.endswith('"'):
+ return (value[1:-1], ConfigType.STRING)
+
+ # Default to string
+ return (value, ConfigType.STRING)
+
+
+class ConfigManager:
+ """
+ Configuration manager for build system.
+
+ This class manages configuration options and provides dependency checking.
+ """
+
+ def __init__(self):
+ self.parser = ConfigParser()
+ self.options: Dict[str, ConfigOption] = {}
+ self.cache: Dict[str, bool] = {}
+
+ def load_from_file(self, filepath: str) -> None:
+ """
+ Load configuration from file.
+
+ Args:
+ filepath: Path to rtconfig.h
+ """
+ self.options = self.parser.parse_file(filepath)
+ self.cache.clear() # Clear dependency cache
+
+ def get_option(self, name: str) -> Optional[ConfigOption]:
+ """
+ Get configuration option.
+
+ Args:
+ name: Option name
+
+ Returns:
+ ConfigOption or None
+ """
+ return self.options.get(name)
+
+ def get_value(self, name: str, default: Any = None) -> Any:
+ """
+ Get configuration value.
+
+ Args:
+ name: Option name
+ default: Default value if not found
+
+ Returns:
+ Configuration value
+ """
+ option = self.options.get(name)
+ if option:
+ return option.value
+ return default
+
+ def get_dependency(self, depend: Union[str, List[str]]) -> bool:
+ """
+ Check if dependency is satisfied.
+
+ Args:
+ depend: Single dependency or list of dependencies
+
+ Returns:
+ True if all dependencies are satisfied
+ """
+ # Handle empty dependency
+ if not depend:
+ return True
+
+ # Convert to list
+ if isinstance(depend, str):
+ depend = [depend]
+
+ # Check cache
+ cache_key = ','.join(sorted(depend))
+ if cache_key in self.cache:
+ return self.cache[cache_key]
+
+ # Check all dependencies (AND logic)
+ result = all(self._check_single_dependency(d) for d in depend)
+
+ # Cache result
+ self.cache[cache_key] = result
+ return result
+
+ def _check_single_dependency(self, name: str) -> bool:
+ """Check a single dependency."""
+ option = self.options.get(name)
+ if not option:
+ return False
+
+ # For RT-Thread, any defined macro is considered True
+ # except if explicitly set to 0
+ if option.type == ConfigType.INTEGER:
+ return option.value != 0
+ elif option.type == ConfigType.BOOLEAN:
+ return option.value
+ elif option.type == ConfigType.STRING:
+ return bool(option.value)
+
+ return True
+
+ def get_all_options(self) -> Dict[str, Any]:
+ """
+ Get all configuration options as a simple dictionary.
+
+ Returns:
+ Dictionary of option names to values
+ """
+ return {name: opt.value for name, opt in self.options.items()}
+
+ def validate(self) -> List[str]:
+ """
+ Validate configuration.
+
+ Returns:
+ List of validation errors
+ """
+ errors = []
+
+ # Check for common issues
+ if 'RT_NAME_MAX' in self.options:
+ name_max = self.options['RT_NAME_MAX'].as_int()
+ if name_max < 4:
+ errors.append("RT_NAME_MAX should be at least 4")
+
+ if 'RT_THREAD_PRIORITY_MAX' in self.options:
+ prio_max = self.options['RT_THREAD_PRIORITY_MAX'].as_int()
+ if prio_max not in [8, 32, 256]:
+ errors.append("RT_THREAD_PRIORITY_MAX should be 8, 32, or 256")
+
+ return errors \ No newline at end of file
diff --git a/tools/ng/core.py b/tools/ng/core.py
new file mode 100644
index 0000000000..c1960862d8
--- /dev/null
+++ b/tools/ng/core.py
@@ -0,0 +1,176 @@
+# -*- coding: utf-8 -*-
+"""
+Core module for RT-Thread build system.
+
+This module provides the central BuildContext class that manages the build state
+and coordinates between different components.
+"""
+
+import os
+import logging
+from typing import Dict, List, Optional, Any
+from dataclasses import dataclass, field
+
+from .config import ConfigManager
+from .project import ProjectRegistry
+from .toolchain import ToolchainManager
+from .generator import GeneratorRegistry
+from .utils import PathService
+
+
+class BuildContext:
+ """
+ Central build context that manages all build-related state.
+
+ This class replaces the global variables in building.py with a proper
+ object-oriented design while maintaining compatibility.
+ """
+
+ # Class variable to store the current context (for backward compatibility)
+ _current_context: Optional['BuildContext'] = None
+
+ def __init__(self, root_directory: str):
+ """
+ Initialize build context.
+
+ Args:
+ root_directory: RT-Thread root directory path
+ """
+ self.root_directory = os.path.abspath(root_directory)
+ self.bsp_directory = os.getcwd()
+
+ # Initialize managers
+ self.config_manager = ConfigManager()
+ self.project_registry = ProjectRegistry()
+ self.toolchain_manager = ToolchainManager()
+ self.generator_registry = GeneratorRegistry()
+ self.path_service = PathService(self.bsp_directory)
+
+ # Build environment
+ self.environment = None
+ self.build_options = {}
+
+ # Logging
+ self.logger = self._setup_logger()
+
+ # Set as current context
+ BuildContext._current_context = self
+
+ @classmethod
+ def get_current(cls) -> Optional['BuildContext']:
+ """Get the current build context."""
+ return cls._current_context
+
+ @classmethod
+ def set_current(cls, context: Optional['BuildContext']) -> None:
+ """Set the current build context."""
+ cls._current_context = context
+
+ def _setup_logger(self) -> logging.Logger:
+ """Setup logger for build system."""
+ logger = logging.getLogger('rtthread.build')
+ if not logger.handlers:
+ handler = logging.StreamHandler()
+ formatter = logging.Formatter('[%(levelname)s] %(message)s')
+ handler.setFormatter(formatter)
+ logger.addHandler(handler)
+ logger.setLevel(logging.INFO)
+ return logger
+
+ def prepare_environment(self, env) -> None:
+ """
+ Prepare the build environment.
+
+ Args:
+ env: SCons Environment object
+ """
+ self.environment = env
+
+ # Set environment variables
+ env['RTT_ROOT'] = self.root_directory
+ env['BSP_ROOT'] = self.bsp_directory
+
+ # Add to Python path
+ import sys
+ tools_path = os.path.join(self.root_directory, 'tools')
+ if tools_path not in sys.path:
+ sys.path.insert(0, tools_path)
+
+ self.logger.debug(f"Prepared environment with RTT_ROOT={self.root_directory}")
+
+ def load_configuration(self, config_file: str = 'rtconfig.h') -> None:
+ """
+ Load configuration from rtconfig.h.
+
+ Args:
+ config_file: Path to configuration file
+ """
+ config_path = os.path.join(self.bsp_directory, config_file)
+ if os.path.exists(config_path):
+ self.config_manager.load_from_file(config_path)
+ self.build_options = self.config_manager.get_all_options()
+ self.logger.info(f"Loaded configuration from {config_file}")
+ else:
+ self.logger.warning(f"Configuration file {config_file} not found")
+
+ def get_dependency(self, depend: Any) -> bool:
+ """
+ Check if dependency is satisfied.
+
+ Args:
+ depend: Dependency name or list of names
+
+ Returns:
+ True if dependency is satisfied
+ """
+ return self.config_manager.get_dependency(depend)
+
+ def register_project_group(self, group) -> None:
+ """
+ Register a project group.
+
+ Args:
+ group: ProjectGroup instance
+ """
+ self.project_registry.register_group(group)
+
+ def merge_groups(self) -> List:
+ """
+ Merge all registered project groups.
+
+ Returns:
+ List of build objects
+ """
+ return self.project_registry.merge_groups(self.environment)
+
+
+@dataclass
+class BuildOptions:
+ """Build options container."""
+ verbose: bool = False
+ strict: bool = False
+ target: Optional[str] = None
+ jobs: int = 1
+ clean: bool = False
+
+
+@dataclass
+class ProjectInfo:
+ """Project information for generators."""
+ name: str = "rtthread"
+ target_name: str = "rtthread.elf"
+
+ # File collections
+ source_files: List[str] = field(default_factory=list)
+ include_paths: List[str] = field(default_factory=list)
+ defines: Dict[str, str] = field(default_factory=dict)
+
+ # Compiler options
+ cflags: str = ""
+ cxxflags: str = ""
+ asflags: str = ""
+ ldflags: str = ""
+
+ # Libraries
+ libs: List[str] = field(default_factory=list)
+ lib_paths: List[str] = field(default_factory=list) \ No newline at end of file
diff --git a/tools/ng/environment.py b/tools/ng/environment.py
new file mode 100644
index 0000000000..3646cfad7d
--- /dev/null
+++ b/tools/ng/environment.py
@@ -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', '') \ No newline at end of file
diff --git a/tools/ng/generator.py b/tools/ng/generator.py
new file mode 100644
index 0000000000..6c252d84cb
--- /dev/null
+++ b/tools/ng/generator.py
@@ -0,0 +1,368 @@
+# -*- coding: utf-8 -*-
+"""
+Project generator framework for RT-Thread build system.
+
+This module provides the base classes for project generators (MDK, IAR, VS Code, etc.).
+"""
+
+import os
+import shutil
+import json
+import xml.etree.ElementTree as ET
+from abc import ABC, abstractmethod
+from typing import Dict, List, Any, Optional
+from dataclasses import dataclass
+
+from .utils import PathService
+
+
+@dataclass
+class GeneratorConfig:
+ """Configuration for project generators."""
+ output_dir: str
+ project_name: str = "rtthread"
+ target_name: str = "rtthread.elf"
+
+
+class ProjectGenerator(ABC):
+ """Abstract base class for project generators."""
+
+ def __init__(self, config: GeneratorConfig):
+ self.config = config
+ self.path_service = PathService(os.getcwd())
+
+ @abstractmethod
+ def get_name(self) -> str:
+ """Get generator name."""
+ pass
+
+ @abstractmethod
+ def generate(self, context, project_info: Dict[str, Any]) -> bool:
+ """
+ Generate project files.
+
+ Args:
+ context: BuildContext instance
+ project_info: Project information from registry
+
+ Returns:
+ True if successful
+ """
+ pass
+
+ @abstractmethod
+ def clean(self) -> bool:
+ """
+ Clean generated files.
+
+ Returns:
+ True if successful
+ """
+ pass
+
+ def _ensure_output_dir(self) -> None:
+ """Ensure output directory exists."""
+ os.makedirs(self.config.output_dir, exist_ok=True)
+
+ def _copy_template(self, template_name: str, output_name: str = None) -> str:
+ """
+ Copy template file to output directory.
+
+ Args:
+ template_name: Template file name
+ output_name: Output file name (defaults to template_name)
+
+ Returns:
+ Output file path
+ """
+ if output_name is None:
+ output_name = template_name
+
+ template_dir = os.path.join(os.path.dirname(__file__), '..', 'targets')
+ template_path = os.path.join(template_dir, template_name)
+ output_path = os.path.join(self.config.output_dir, output_name)
+
+ if os.path.exists(template_path):
+ shutil.copy2(template_path, output_path)
+ return output_path
+ else:
+ raise FileNotFoundError(f"Template not found: {template_path}")
+
+
+class VscodeGenerator(ProjectGenerator):
+ """Visual Studio Code project generator."""
+
+ def get_name(self) -> str:
+ return "vscode"
+
+ def generate(self, context, project_info: Dict[str, Any]) -> bool:
+ """Generate VS Code project files."""
+ self._ensure_output_dir()
+
+ # Create .vscode directory
+ vscode_dir = os.path.join(self.config.output_dir, '.vscode')
+ os.makedirs(vscode_dir, exist_ok=True)
+
+ # Generate c_cpp_properties.json
+ self._generate_cpp_properties(vscode_dir, context, project_info)
+
+ # Generate tasks.json
+ self._generate_tasks(vscode_dir, context)
+
+ # Generate launch.json
+ self._generate_launch(vscode_dir, context)
+
+ # Generate settings.json
+ self._generate_settings(vscode_dir)
+
+ return True
+
+ def clean(self) -> bool:
+ """Clean VS Code files."""
+ vscode_dir = os.path.join(self.config.output_dir, '.vscode')
+ if os.path.exists(vscode_dir):
+ shutil.rmtree(vscode_dir)
+ return True
+
+ def _generate_cpp_properties(self, vscode_dir: str, context, project_info: Dict) -> None:
+ """Generate c_cpp_properties.json."""
+ # Get toolchain info
+ toolchain = context.toolchain_manager.get_current()
+ compiler_path = ""
+ if toolchain and toolchain.info:
+ if toolchain.get_name() == "gcc":
+ compiler_path = os.path.join(toolchain.info.path, toolchain.info.prefix + "gcc")
+
+ config = {
+ "configurations": [
+ {
+ "name": "RT-Thread",
+ "includePath": [
+ "${workspaceFolder}/**"
+ ] + project_info.get('all_includes', []),
+ "defines": [f"{k}={v}" if v != '1' else k
+ for k, v in project_info.get('all_defines', {}).items()],
+ "compilerPath": compiler_path,
+ "cStandard": "c99",
+ "cppStandard": "c++11",
+ "intelliSenseMode": "gcc-arm" if "arm" in compiler_path else "gcc-x64"
+ }
+ ],
+ "version": 4
+ }
+
+ output_path = os.path.join(vscode_dir, 'c_cpp_properties.json')
+ with open(output_path, 'w') as f:
+ json.dump(config, f, indent=4)
+
+ def _generate_tasks(self, vscode_dir: str, context) -> None:
+ """Generate tasks.json."""
+ tasks = {
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "label": "build",
+ "type": "shell",
+ "command": "scons",
+ "problemMatcher": "$gcc",
+ "group": {
+ "kind": "build",
+ "isDefault": True
+ }
+ },
+ {
+ "label": "clean",
+ "type": "shell",
+ "command": "scons -c",
+ "problemMatcher": "$gcc"
+ },
+ {
+ "label": "rebuild",
+ "type": "shell",
+ "command": "scons -c && scons",
+ "problemMatcher": "$gcc"
+ }
+ ]
+ }
+
+ output_path = os.path.join(vscode_dir, 'tasks.json')
+ with open(output_path, 'w') as f:
+ json.dump(tasks, f, indent=4)
+
+ def _generate_launch(self, vscode_dir: str, context) -> None:
+ """Generate launch.json."""
+ launch = {
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "Cortex Debug",
+ "type": "cortex-debug",
+ "request": "launch",
+ "servertype": "openocd",
+ "cwd": "${workspaceRoot}",
+ "executable": "${workspaceRoot}/" + self.config.target_name,
+ "device": "STM32F103C8",
+ "configFiles": [
+ "interface/stlink-v2.cfg",
+ "target/stm32f1x.cfg"
+ ]
+ }
+ ]
+ }
+
+ output_path = os.path.join(vscode_dir, 'launch.json')
+ with open(output_path, 'w') as f:
+ json.dump(launch, f, indent=4)
+
+ def _generate_settings(self, vscode_dir: str) -> None:
+ """Generate settings.json."""
+ settings = {
+ "files.associations": {
+ "*.h": "c",
+ "*.c": "c",
+ "*.cpp": "cpp",
+ "*.cc": "cpp",
+ "*.cxx": "cpp"
+ },
+ "C_Cpp.errorSquiggles": "Enabled"
+ }
+
+ output_path = os.path.join(vscode_dir, 'settings.json')
+ with open(output_path, 'w') as f:
+ json.dump(settings, f, indent=4)
+
+
+class CMakeGenerator(ProjectGenerator):
+ """CMake project generator."""
+
+ def get_name(self) -> str:
+ return "cmake"
+
+ def generate(self, context, project_info: Dict[str, Any]) -> bool:
+ """Generate CMakeLists.txt."""
+ self._ensure_output_dir()
+
+ # Get toolchain info
+ toolchain = context.toolchain_manager.get_current()
+
+ lines = [
+ "cmake_minimum_required(VERSION 3.10)",
+ "",
+ "# RT-Thread CMake Project",
+ f"project({self.config.project_name} C CXX ASM)",
+ "",
+ "# C Standard",
+ "set(CMAKE_C_STANDARD 99)",
+ "set(CMAKE_CXX_STANDARD 11)",
+ ""
+ ]
+
+ # Toolchain configuration
+ if toolchain and toolchain.get_name() == "gcc":
+ lines.extend([
+ "# Toolchain",
+ f"set(CMAKE_C_COMPILER {toolchain.info.prefix}gcc)",
+ f"set(CMAKE_CXX_COMPILER {toolchain.info.prefix}g++)",
+ f"set(CMAKE_ASM_COMPILER {toolchain.info.prefix}gcc)",
+ ""
+ ])
+
+ # Include directories
+ lines.extend([
+ "# Include directories",
+ "include_directories("
+ ])
+ for inc in project_info.get('all_includes', []):
+ lines.append(f" {inc}")
+ lines.extend([")", ""])
+
+ # Definitions
+ lines.extend([
+ "# Definitions",
+ "add_definitions("
+ ])
+ for k, v in project_info.get('all_defines', {}).items():
+ if v == '1':
+ lines.append(f" -D{k}")
+ else:
+ lines.append(f" -D{k}={v}")
+ lines.extend([")", ""])
+
+ # Source files
+ lines.extend([
+ "# Source files",
+ "set(SOURCES"
+ ])
+ for src in project_info.get('all_sources', []):
+ lines.append(f" {src}")
+ lines.extend([")", ""])
+
+ # Executable
+ lines.extend([
+ "# Executable",
+ f"add_executable(${{PROJECT_NAME}} ${{SOURCES}})",
+ ""
+ ])
+
+ # Libraries
+ if project_info.get('all_libs'):
+ lines.extend([
+ "# Libraries",
+ f"target_link_libraries(${{PROJECT_NAME}}"
+ ])
+ for lib in project_info['all_libs']:
+ lines.append(f" {lib}")
+ lines.extend([")", ""])
+
+ # Write file
+ output_path = os.path.join(self.config.output_dir, 'CMakeLists.txt')
+ with open(output_path, 'w') as f:
+ f.write('\n'.join(lines))
+
+ return True
+
+ def clean(self) -> bool:
+ """Clean CMake files."""
+ files_to_remove = ['CMakeLists.txt', 'CMakeCache.txt']
+ dirs_to_remove = ['CMakeFiles']
+
+ for file in files_to_remove:
+ file_path = os.path.join(self.config.output_dir, file)
+ if os.path.exists(file_path):
+ os.remove(file_path)
+
+ for dir in dirs_to_remove:
+ dir_path = os.path.join(self.config.output_dir, dir)
+ if os.path.exists(dir_path):
+ shutil.rmtree(dir_path)
+
+ return True
+
+
+class GeneratorRegistry:
+ """Registry for project generators."""
+
+ def __init__(self):
+ self.generators: Dict[str, type] = {}
+ self._register_default_generators()
+
+ def _register_default_generators(self) -> None:
+ """Register default generators."""
+ self.register("vscode", VscodeGenerator)
+ self.register("vsc", VscodeGenerator) # Alias
+ self.register("cmake", CMakeGenerator)
+
+ def register(self, name: str, generator_class: type) -> None:
+ """Register a generator class."""
+ self.generators[name] = generator_class
+
+ def create_generator(self, name: str, config: GeneratorConfig) -> ProjectGenerator:
+ """Create a generator instance."""
+ if name not in self.generators:
+ raise ValueError(f"Unknown generator: {name}")
+
+ return self.generators[name](config)
+
+ def list_generators(self) -> List[str]:
+ """List available generators."""
+ return list(self.generators.keys()) \ No newline at end of file
diff --git a/tools/ng/integration_example.py b/tools/ng/integration_example.py
new file mode 100644
index 0000000000..22b1bd5c2f
--- /dev/null
+++ b/tools/ng/integration_example.py
@@ -0,0 +1,178 @@
+# -*- coding: utf-8 -*-
+"""
+Example of minimal changes needed in building.py to integrate the new OOP system.
+
+This file shows the exact changes that would be made to the original building.py.
+"""
+
+# =============================================================================
+# CHANGES TO ADD AT THE BEGINNING OF building.py
+# =============================================================================
+
+"""
+# Add after the imports section in building.py (around line 45)
+
+# Try to import new OOP system
+try:
+ from ng.adapter import (
+ init_build_context,
+ inject_environment_methods,
+ load_rtconfig as ng_load_rtconfig,
+ MergeGroups as ng_MergeGroups
+ )
+ NG_AVAILABLE = True
+except ImportError:
+ NG_AVAILABLE = False
+"""
+
+# =============================================================================
+# CHANGES IN PrepareBuilding FUNCTION
+# =============================================================================
+
+"""
+# Add these lines in PrepareBuilding function after setting up Env (around line 70)
+
+ # Initialize new OOP system if available
+ if NG_AVAILABLE:
+ # Initialize build context
+ ng_context = init_build_context(Rtt_Root)
+
+ # Inject methods into environment
+ inject_environment_methods(Env)
+
+ # Store context reference
+ Env['__NG_Context'] = ng_context
+"""
+
+# =============================================================================
+# CHANGES AFTER PARSING rtconfig.h
+# =============================================================================
+
+"""
+# Add after parsing rtconfig.h (around line 430)
+
+ # Load configuration into new system
+ if NG_AVAILABLE and 'rtconfig.h' in os.listdir(Bsp_Root):
+ ng_load_rtconfig('rtconfig.h')
+"""
+
+# =============================================================================
+# ENHANCED DefineGroup FUNCTION
+# =============================================================================
+
+"""
+# Replace the original DefineGroup function (around line 565) with:
+
+def DefineGroup(name, src, depend, **parameters):
+ global Env
+ if Env is None:
+ return []
+
+ # Try to use new implementation if available
+ if NG_AVAILABLE and hasattr(Env, 'DefineGroup'):
+ return Env.DefineGroup(name, src, depend, **parameters)
+
+ # Original implementation continues below...
+ # [Keep all the original DefineGroup code here]
+"""
+
+# =============================================================================
+# ENHANCED GetDepend FUNCTION
+# =============================================================================
+
+"""
+# Replace the original GetDepend function (around line 655) with:
+
+def GetDepend(depend):
+ global Env
+
+ # Try to use new implementation if available
+ if NG_AVAILABLE and Env and hasattr(Env, 'GetDepend'):
+ return Env.GetDepend(depend)
+
+ # Original implementation continues below...
+ # [Keep all the original GetDepend code here]
+"""
+
+# =============================================================================
+# ENHANCED MergeGroup FUNCTION
+# =============================================================================
+
+"""
+# Replace the original MergeGroup function (around line 700) with:
+
+def MergeGroup(src_group, group):
+ # Try to use new implementation if available
+ if NG_AVAILABLE and Env and hasattr(Env, '__NG_Context'):
+ context = Env['__NG_Context']
+ if context:
+ # Register groups with new system
+ from ng.project import ProjectGroup
+ for g in group:
+ if 'name' in g:
+ pg = ProjectGroup(
+ name=g['name'],
+ sources=g.get('src', []),
+ dependencies=[],
+ environment=Env
+ )
+ context.register_project_group(pg)
+
+ # Original implementation continues below...
+ # [Keep all the original MergeGroup code here]
+"""
+
+# =============================================================================
+# EXAMPLE USAGE IN SCONSCRIPT
+# =============================================================================
+
+def example_sconscript():
+ """
+ Example of how to use the new features in a SConscript file.
+ """
+ sconscript_content = '''
+from building import *
+
+# Get environment
+env = GetEnvironment()
+
+# Method 1: Use new environment methods (if available)
+if hasattr(env, 'DefineGroup'):
+ # New OOP style
+ src = env.GlobFiles('*.c')
+ group = env.DefineGroup('MyComponent', src, depend=['RT_USING_XXX'])
+else:
+ # Fallback to traditional style
+ src = Glob('*.c')
+ group = DefineGroup('MyComponent', src, depend=['RT_USING_XXX'])
+
+# Method 2: Always compatible style
+src = Glob('*.c')
+group = DefineGroup('MyComponent', src, depend=['RT_USING_XXX'])
+
+Return('group')
+'''
+ return sconscript_content
+
+# =============================================================================
+# MINIMAL CHANGES SUMMARY
+# =============================================================================
+
+"""
+Summary of changes needed in building.py:
+
+1. Add imports at the beginning (5 lines)
+2. Add initialization in PrepareBuilding (6 lines)
+3. Add config loading after rtconfig.h parsing (3 lines)
+4. Modify DefineGroup to check for new method (3 lines)
+5. Modify GetDepend to check for new method (3 lines)
+6. Enhance MergeGroup to register with new system (15 lines)
+
+Total: ~35 lines of code added/modified in building.py
+
+Benefits:
+- Fully backward compatible
+- Opt-in design (works even if ng module is not present)
+- Gradual migration path
+- No changes needed in existing SConscript files
+""" \ No newline at end of file
diff --git a/tools/ng/project.py b/tools/ng/project.py
new file mode 100644
index 0000000000..4bd3bfab50
--- /dev/null
+++ b/tools/ng/project.py
@@ -0,0 +1,260 @@
+# -*- coding: utf-8 -*-
+"""
+Project and group management for RT-Thread build system.
+
+This module provides classes for managing project groups and their compilation.
+"""
+
+import os
+from typing import List, Dict, Any, Optional
+from dataclasses import dataclass, field
+from SCons.Script import *
+
+
+@dataclass
+class ProjectGroup:
+ """
+ Represents a project group (component).
+
+ This class encapsulates the information from DefineGroup calls.
+ """
+ name: str
+ sources: List[str]
+ dependencies: List[str] = field(default_factory=list)
+ environment: Any = None # SCons Environment
+
+ # Paths and defines
+ include_paths: List[str] = field(default_factory=list)
+ defines: Dict[str, str] = field(default_factory=dict)
+
+ # Compiler flags
+ cflags: str = ""
+ cxxflags: str = ""
+ asflags: str = ""
+ ldflags: str = ""
+
+ # Local options (only for this group)
+ local_cflags: str = ""
+ local_cxxflags: str = ""
+ local_include_paths: List[str] = field(default_factory=list)
+ local_defines: Dict[str, str] = field(default_factory=dict)
+
+ # Libraries
+ libs: List[str] = field(default_factory=list)
+ lib_paths: List[str] = field(default_factory=list)
+
+ # Build objects
+ objects: List[Any] = field(default_factory=list)
+
+ def build(self, env) -> List:
+ """
+ Build the group and return objects.
+
+ Args:
+ env: SCons Environment
+
+ Returns:
+ List of build objects
+ """
+ if not self.sources:
+ return []
+
+ # Clone environment if we have local options
+ build_env = env
+ if self._has_local_options():
+ build_env = env.Clone()
+ self._apply_local_options(build_env)
+
+ # Apply global options
+ self._apply_global_options(build_env)
+
+ # Build objects
+ self.objects = []
+ for src in self.sources:
+ if isinstance(src, str):
+ # Build single file
+ obj = build_env.Object(src)
+ self.objects.extend(obj if isinstance(obj, list) else [obj])
+ else:
+ # Already a Node
+ self.objects.append(src)
+
+ return self.objects
+
+ def _has_local_options(self) -> bool:
+ """Check if group has local options."""
+ return bool(
+ self.local_cflags or
+ self.local_cxxflags or
+ self.local_include_paths or
+ self.local_defines
+ )
+
+ def _apply_local_options(self, env) -> None:
+ """Apply local options to environment."""
+ if self.local_cflags:
+ env.AppendUnique(CFLAGS=self.local_cflags.split())
+
+ if self.local_cxxflags:
+ env.AppendUnique(CXXFLAGS=self.local_cxxflags.split())
+
+ if self.local_include_paths:
+ paths = [os.path.abspath(p) for p in self.local_include_paths]
+ env.AppendUnique(CPPPATH=paths)
+
+ if self.local_defines:
+ env.AppendUnique(CPPDEFINES=self.local_defines)
+
+ def _apply_global_options(self, env) -> None:
+ """Apply global options to environment."""
+ # These options affect dependent groups too
+ if self.include_paths:
+ paths = [os.path.abspath(p) for p in self.include_paths]
+ env.AppendUnique(CPPPATH=paths)
+
+ if self.defines:
+ env.AppendUnique(CPPDEFINES=self.defines)
+
+ if self.cflags and 'CFLAGS' not in env:
+ env['CFLAGS'] = self.cflags
+
+ if self.cxxflags and 'CXXFLAGS' not in env:
+ env['CXXFLAGS'] = self.cxxflags
+
+ if self.libs:
+ env.AppendUnique(LIBS=self.libs)
+
+ if self.lib_paths:
+ paths = [os.path.abspath(p) for p in self.lib_paths]
+ env.AppendUnique(LIBPATH=paths)
+
+ def get_info(self) -> Dict[str, Any]:
+ """
+ Get group information for project generators.
+
+ Returns:
+ Dictionary with group information
+ """
+ return {
+ 'name': self.name,
+ 'sources': self.sources,
+ 'include_paths': self.include_paths + self.local_include_paths,
+ 'defines': {**self.defines, **self.local_defines},
+ 'cflags': f"{self.cflags} {self.local_cflags}".strip(),
+ 'cxxflags': f"{self.cxxflags} {self.local_cxxflags}".strip(),
+ 'libs': self.libs,
+ 'lib_paths': self.lib_paths
+ }
+
+
+class ProjectRegistry:
+ """
+ Registry for all project groups.
+
+ This class manages all registered project groups and provides
+ methods for querying and merging them.
+ """
+
+ def __init__(self):
+ self.groups: List[ProjectGroup] = []
+ self._group_index: Dict[str, ProjectGroup] = {}
+
+ def register_group(self, group: ProjectGroup) -> None:
+ """
+ Register a project group.
+
+ Args:
+ group: ProjectGroup instance
+ """
+ self.groups.append(group)
+ self._group_index[group.name] = group
+
+ def get_group(self, name: str) -> Optional[ProjectGroup]:
+ """
+ Get group by name.
+
+ Args:
+ name: Group name
+
+ Returns:
+ ProjectGroup or None
+ """
+ return self._group_index.get(name)
+
+ def get_all_groups(self) -> List[ProjectGroup]:
+ """Get all registered groups."""
+ return self.groups.copy()
+
+ def get_groups_by_dependency(self, dependency: str) -> List[ProjectGroup]:
+ """
+ Get groups that depend on a specific macro.
+
+ Args:
+ dependency: Dependency name
+
+ Returns:
+ List of matching groups
+ """
+ return [g for g in self.groups if dependency in g.dependencies]
+
+ def merge_groups(self, env) -> List:
+ """
+ Merge all groups into a single list of objects.
+
+ Args:
+ env: SCons Environment
+
+ Returns:
+ List of all build objects
+ """
+ all_objects = []
+
+ for group in self.groups:
+ if group.objects:
+ all_objects.extend(group.objects)
+
+ return all_objects
+
+ def get_project_info(self) -> Dict[str, Any]:
+ """
+ Get complete project information for generators.
+
+ Returns:
+ Dictionary with project information
+ """
+ # Collect all unique values
+ all_sources = []
+ all_includes = set()
+ all_defines = {}
+ all_libs = []
+ all_lib_paths = set()
+
+ for group in self.groups:
+ info = group.get_info()
+
+ # Sources
+ all_sources.extend(info['sources'])
+
+ # Include paths
+ all_includes.update(info['include_paths'])
+
+ # Defines
+ all_defines.update(info['defines'])
+
+ # Libraries
+ all_libs.extend(info['libs'])
+ all_lib_paths.update(info['lib_paths'])
+
+ return {
+ 'groups': [g.get_info() for g in self.groups],
+ 'all_sources': all_sources,
+ 'all_includes': sorted(list(all_includes)),
+ 'all_defines': all_defines,
+ 'all_libs': all_libs,
+ 'all_lib_paths': sorted(list(all_lib_paths))
+ }
+
+ def clear(self) -> None:
+ """Clear all registered groups."""
+ self.groups.clear()
+ self._group_index.clear() \ No newline at end of file
diff --git a/tools/ng/toolchain.py b/tools/ng/toolchain.py
new file mode 100644
index 0000000000..007ccf94ad
--- /dev/null
+++ b/tools/ng/toolchain.py
@@ -0,0 +1,396 @@
+# -*- coding: utf-8 -*-
+"""
+Toolchain management for RT-Thread build system.
+
+This module provides abstraction for different toolchains (GCC, Keil, IAR, etc.).
+"""
+
+import os
+import shutil
+import subprocess
+from abc import ABC, abstractmethod
+from typing import Dict, List, Optional, Tuple
+from dataclasses import dataclass
+
+
+@dataclass
+class ToolchainInfo:
+ """Toolchain information."""
+ name: str
+ version: str
+ path: str
+ prefix: str = ""
+ suffix: str = ""
+
+
+class Toolchain(ABC):
+ """Abstract base class for toolchains."""
+
+ def __init__(self):
+ self.info = None
+
+ @abstractmethod
+ def get_name(self) -> str:
+ """Get toolchain name."""
+ pass
+
+ @abstractmethod
+ def detect(self) -> bool:
+ """Detect if toolchain is available."""
+ pass
+
+ @abstractmethod
+ def configure_environment(self, env) -> None:
+ """Configure SCons environment for this toolchain."""
+ pass
+
+ @abstractmethod
+ def get_compile_flags(self, cpu: str, fpu: str = None, float_abi: str = None) -> Dict[str, str]:
+ """Get compilation flags for target CPU."""
+ pass
+
+ def get_version(self) -> Optional[str]:
+ """Get toolchain version."""
+ return self.info.version if self.info else None
+
+ def _run_command(self, cmd: List[str]) -> Tuple[int, str, str]:
+ """Run command and return (returncode, stdout, stderr)."""
+ try:
+ result = subprocess.run(cmd, capture_output=True, text=True)
+ return result.returncode, result.stdout, result.stderr
+ except Exception as e:
+ return -1, "", str(e)
+
+
+class GccToolchain(Toolchain):
+ """GCC toolchain implementation."""
+
+ def __init__(self, prefix: str = ""):
+ super().__init__()
+ self.prefix = prefix or "arm-none-eabi-"
+
+ def get_name(self) -> str:
+ return "gcc"
+
+ def detect(self) -> bool:
+ """Detect GCC toolchain."""
+ gcc_path = shutil.which(self.prefix + "gcc")
+ if not gcc_path:
+ return False
+
+ # Get version
+ ret, stdout, _ = self._run_command([gcc_path, "--version"])
+ if ret == 0:
+ lines = stdout.split('\n')
+ if lines:
+ version = lines[0].split()[-1]
+ self.info = ToolchainInfo(
+ name="gcc",
+ version=version,
+ path=os.path.dirname(gcc_path),
+ prefix=self.prefix
+ )
+ return True
+
+ return False
+
+ def configure_environment(self, env) -> None:
+ """Configure environment for GCC."""
+ env['CC'] = self.prefix + 'gcc'
+ env['CXX'] = self.prefix + 'g++'
+ env['AS'] = self.prefix + 'gcc'
+ env['AR'] = self.prefix + 'ar'
+ env['LINK'] = self.prefix + 'gcc'
+ env['SIZE'] = self.prefix + 'size'
+ env['OBJDUMP'] = self.prefix + 'objdump'
+ env['OBJCPY'] = self.prefix + 'objcopy'
+
+ # Set default flags
+ env['ARFLAGS'] = '-rc'
+ env['ASFLAGS'] = '-x assembler-with-cpp'
+
+ # Path
+ if self.info and self.info.path:
+ env.PrependENVPath('PATH', self.info.path)
+
+ def get_compile_flags(self, cpu: str, fpu: str = None, float_abi: str = None) -> Dict[str, str]:
+ """Get GCC compilation flags."""
+ flags = {
+ 'CFLAGS': [],
+ 'CXXFLAGS': [],
+ 'ASFLAGS': [],
+ 'LDFLAGS': []
+ }
+
+ # CPU flags
+ cpu_flags = {
+ 'cortex-m0': '-mcpu=cortex-m0 -mthumb',
+ 'cortex-m0+': '-mcpu=cortex-m0plus -mthumb',
+ 'cortex-m3': '-mcpu=cortex-m3 -mthumb',
+ 'cortex-m4': '-mcpu=cortex-m4 -mthumb',
+ 'cortex-m7': '-mcpu=cortex-m7 -mthumb',
+ 'cortex-m23': '-mcpu=cortex-m23 -mthumb',
+ 'cortex-m33': '-mcpu=cortex-m33 -mthumb',
+ 'cortex-a7': '-mcpu=cortex-a7',
+ 'cortex-a9': '-mcpu=cortex-a9'
+ }
+
+ if cpu in cpu_flags:
+ base_flags = cpu_flags[cpu]
+ for key in ['CFLAGS', 'CXXFLAGS', 'ASFLAGS']:
+ flags[key].append(base_flags)
+
+ # FPU flags
+ if fpu:
+ fpu_flag = f'-mfpu={fpu}'
+ for key in ['CFLAGS', 'CXXFLAGS']:
+ flags[key].append(fpu_flag)
+
+ # Float ABI
+ if float_abi:
+ abi_flag = f'-mfloat-abi={float_abi}'
+ for key in ['CFLAGS', 'CXXFLAGS']:
+ flags[key].append(abi_flag)
+
+ # Common flags
+ common_flags = ['-ffunction-sections', '-fdata-sections']
+ flags['CFLAGS'].extend(common_flags)
+ flags['CXXFLAGS'].extend(common_flags)
+
+ # Linker flags
+ flags['LDFLAGS'].extend(['-Wl,--gc-sections'])
+
+ # Convert lists to strings
+ return {k: ' '.join(v) for k, v in flags.items()}
+
+
+class ArmccToolchain(Toolchain):
+ """ARM Compiler (Keil) toolchain implementation."""
+
+ def get_name(self) -> str:
+ return "armcc"
+
+ def detect(self) -> bool:
+ """Detect ARM Compiler toolchain."""
+ armcc_path = shutil.which("armcc")
+ if not armcc_path:
+ # Try common Keil installation paths
+ keil_paths = [
+ r"C:\Keil_v5\ARM\ARMCC\bin",
+ r"C:\Keil\ARM\ARMCC\bin",
+ "/opt/arm/bin"
+ ]
+ for path in keil_paths:
+ test_path = os.path.join(path, "armcc")
+ if os.path.exists(test_path):
+ armcc_path = test_path
+ break
+
+ if not armcc_path:
+ return False
+
+ # Get version
+ ret, stdout, _ = self._run_command([armcc_path, "--version"])
+ if ret == 0:
+ lines = stdout.split('\n')
+ for line in lines:
+ if "ARM Compiler" in line:
+ version = line.split()[-1]
+ self.info = ToolchainInfo(
+ name="armcc",
+ version=version,
+ path=os.path.dirname(armcc_path)
+ )
+ return True
+
+ return False
+
+ def configure_environment(self, env) -> None:
+ """Configure environment for ARM Compiler."""
+ env['CC'] = 'armcc'
+ env['CXX'] = 'armcc'
+ env['AS'] = 'armasm'
+ env['AR'] = 'armar'
+ env['LINK'] = 'armlink'
+
+ # ARM Compiler specific settings
+ env['ARCOM'] = '$AR --create $TARGET $SOURCES'
+ env['LIBPREFIX'] = ''
+ env['LIBSUFFIX'] = '.lib'
+ env['LIBLINKPREFIX'] = ''
+ env['LIBLINKSUFFIX'] = '.lib'
+ env['LIBDIRPREFIX'] = '--userlibpath '
+
+ # Path
+ if self.info and self.info.path:
+ env.PrependENVPath('PATH', self.info.path)
+
+ def get_compile_flags(self, cpu: str, fpu: str = None, float_abi: str = None) -> Dict[str, str]:
+ """Get ARM Compiler flags."""
+ flags = {
+ 'CFLAGS': [],
+ 'CXXFLAGS': [],
+ 'ASFLAGS': [],
+ 'LDFLAGS': []
+ }
+
+ # CPU selection
+ cpu_map = {
+ 'cortex-m0': '--cpu Cortex-M0',
+ 'cortex-m0+': '--cpu Cortex-M0+',
+ 'cortex-m3': '--cpu Cortex-M3',
+ 'cortex-m4': '--cpu Cortex-M4',
+ 'cortex-m7': '--cpu Cortex-M7'
+ }
+
+ if cpu in cpu_map:
+ cpu_flag = cpu_map[cpu]
+ for key in flags:
+ flags[key].append(cpu_flag)
+
+ # Common flags
+ flags['CFLAGS'].extend(['--c99', '--gnu'])
+ flags['CXXFLAGS'].extend(['--cpp', '--gnu'])
+
+ return {k: ' '.join(v) for k, v in flags.items()}
+
+
+class IarToolchain(Toolchain):
+ """IAR toolchain implementation."""
+
+ def get_name(self) -> str:
+ return "iar"
+
+ def detect(self) -> bool:
+ """Detect IAR toolchain."""
+ iccarm_path = shutil.which("iccarm")
+ if not iccarm_path:
+ # Try common IAR installation paths
+ iar_paths = [
+ r"C:\Program Files (x86)\IAR Systems\Embedded Workbench 8.0\arm\bin",
+ r"C:\Program Files\IAR Systems\Embedded Workbench 8.0\arm\bin",
+ "/opt/iar/bin"
+ ]
+ for path in iar_paths:
+ test_path = os.path.join(path, "iccarm.exe" if os.name == 'nt' else "iccarm")
+ if os.path.exists(test_path):
+ iccarm_path = test_path
+ break
+
+ if not iccarm_path:
+ return False
+
+ self.info = ToolchainInfo(
+ name="iar",
+ version="8.x", # IAR version detection is complex
+ path=os.path.dirname(iccarm_path)
+ )
+ return True
+
+ def configure_environment(self, env) -> None:
+ """Configure environment for IAR."""
+ env['CC'] = 'iccarm'
+ env['CXX'] = 'iccarm'
+ env['AS'] = 'iasmarm'
+ env['AR'] = 'iarchive'
+ env['LINK'] = 'ilinkarm'
+
+ # IAR specific settings
+ env['LIBPREFIX'] = ''
+ env['LIBSUFFIX'] = '.a'
+ env['LIBLINKPREFIX'] = ''
+ env['LIBLINKSUFFIX'] = '.a'
+
+ # Path
+ if self.info and self.info.path:
+ env.PrependENVPath('PATH', self.info.path)
+
+ def get_compile_flags(self, cpu: str, fpu: str = None, float_abi: str = None) -> Dict[str, str]:
+ """Get IAR flags."""
+ flags = {
+ 'CFLAGS': [],
+ 'CXXFLAGS': [],
+ 'ASFLAGS': [],
+ 'LDFLAGS': []
+ }
+
+ # CPU selection
+ cpu_map = {
+ 'cortex-m0': '--cpu=Cortex-M0',
+ 'cortex-m0+': '--cpu=Cortex-M0+',
+ 'cortex-m3': '--cpu=Cortex-M3',
+ 'cortex-m4': '--cpu=Cortex-M4',
+ 'cortex-m7': '--cpu=Cortex-M7'
+ }
+
+ if cpu in cpu_map:
+ cpu_flag = cpu_map[cpu]
+ flags['CFLAGS'].append(cpu_flag)
+ flags['CXXFLAGS'].append(cpu_flag)
+
+ # Common flags
+ flags['CFLAGS'].extend(['-e', '--dlib_config', 'DLib_Config_Normal.h'])
+
+ return {k: ' '.join(v) for k, v in flags.items()}
+
+
+class ToolchainManager:
+ """Manager for toolchain selection and configuration."""
+
+ def __init__(self):
+ self.toolchains: Dict[str, Toolchain] = {}
+ self.current_toolchain: Optional[Toolchain] = None
+ self._register_default_toolchains()
+
+ def _register_default_toolchains(self) -> None:
+ """Register default toolchains."""
+ # Try to detect available toolchains
+ toolchain_classes = [
+ (GccToolchain, ['arm-none-eabi-', 'riscv32-unknown-elf-', 'riscv64-unknown-elf-']),
+ (ArmccToolchain, ['']),
+ (IarToolchain, [''])
+ ]
+
+ for toolchain_class, prefixes in toolchain_classes:
+ for prefix in prefixes:
+ if toolchain_class == GccToolchain:
+ tc = toolchain_class(prefix)
+ else:
+ tc = toolchain_class()
+
+ if tc.detect():
+ name = f"{tc.get_name()}-{prefix}" if prefix else tc.get_name()
+ self.register_toolchain(name, tc)
+
+ def register_toolchain(self, name: str, toolchain: Toolchain) -> None:
+ """Register a toolchain."""
+ self.toolchains[name] = toolchain
+
+ def select_toolchain(self, name: str) -> Toolchain:
+ """Select a toolchain by name."""
+ if name not in self.toolchains:
+ # Try to create it
+ if name == 'gcc':
+ tc = GccToolchain()
+ elif name == 'armcc' or name == 'keil':
+ tc = ArmccToolchain()
+ elif name == 'iar':
+ tc = IarToolchain()
+ else:
+ raise ValueError(f"Unknown toolchain: {name}")
+
+ if tc.detect():
+ self.register_toolchain(name, tc)
+ else:
+ raise RuntimeError(f"Toolchain '{name}' not found")
+
+ self.current_toolchain = self.toolchains[name]
+ return self.current_toolchain
+
+ def get_current(self) -> Optional[Toolchain]:
+ """Get current toolchain."""
+ return self.current_toolchain
+
+ def list_toolchains(self) -> List[str]:
+ """List available toolchains."""
+ return list(self.toolchains.keys()) \ No newline at end of file
diff --git a/tools/ng/utils.py b/tools/ng/utils.py
new file mode 100644
index 0000000000..a0503ea481
--- /dev/null
+++ b/tools/ng/utils.py
@@ -0,0 +1,339 @@
+# -*- coding: utf-8 -*-
+"""
+Utility functions for RT-Thread build system.
+
+This module provides common utility functions used throughout the build system.
+"""
+
+import os
+import sys
+import platform
+from typing import List, Tuple, Optional
+
+
+class PathService:
+ """Service for path manipulation and normalization."""
+
+ def __init__(self, base_path: str = None):
+ self.base_path = base_path or os.getcwd()
+
+ def normalize_path(self, path: str) -> str:
+ """
+ Normalize path for cross-platform compatibility.
+
+ Args:
+ path: Path to normalize
+
+ Returns:
+ Normalized path
+ """
+ # Convert to absolute path if relative
+ if not os.path.isabs(path):
+ path = os.path.abspath(os.path.join(self.base_path, path))
+
+ # Normalize separators
+ path = os.path.normpath(path)
+
+ # Convert to forward slashes for consistency
+ if platform.system() == 'Windows':
+ path = path.replace('\\', '/')
+
+ return path
+
+ def make_relative(self, path: str, base: str = None) -> str:
+ """
+ Make path relative to base.
+
+ Args:
+ path: Path to make relative
+ base: Base path (defaults to self.base_path)
+
+ Returns:
+ Relative path
+ """
+ if base is None:
+ base = self.base_path
+
+ path = self.normalize_path(path)
+ base = self.normalize_path(base)
+
+ try:
+ rel_path = os.path.relpath(path, base)
+ # Convert to forward slashes
+ if platform.system() == 'Windows':
+ rel_path = rel_path.replace('\\', '/')
+ return rel_path
+ except ValueError:
+ # Different drives on Windows
+ return path
+
+ def split_path(self, path: str) -> List[str]:
+ """
+ Split path into components.
+
+ Args:
+ path: Path to split
+
+ Returns:
+ List of path components
+ """
+ path = self.normalize_path(path)
+ parts = []
+
+ while True:
+ head, tail = os.path.split(path)
+ if tail:
+ parts.insert(0, tail)
+ if head == path: # Reached root
+ if head:
+ parts.insert(0, head)
+ break
+ path = head
+
+ return parts
+
+ def common_prefix(self, paths: List[str]) -> str:
+ """
+ Find common prefix of multiple paths.
+
+ Args:
+ paths: List of paths
+
+ Returns:
+ Common prefix path
+ """
+ if not paths:
+ return ""
+
+ # Normalize all paths
+ normalized = [self.normalize_path(p) for p in paths]
+
+ # Find common prefix
+ prefix = os.path.commonpath(normalized)
+
+ return self.normalize_path(prefix)
+
+
+class PlatformInfo:
+ """Platform and system information."""
+
+ @staticmethod
+ def get_platform() -> str:
+ """Get platform name (Windows, Linux, Darwin)."""
+ return platform.system()
+
+ @staticmethod
+ def get_architecture() -> str:
+ """Get system architecture."""
+ return platform.machine()
+
+ @staticmethod
+ def is_windows() -> bool:
+ """Check if running on Windows."""
+ return platform.system() == 'Windows'
+
+ @staticmethod
+ def is_linux() -> bool:
+ """Check if running on Linux."""
+ return platform.system() == 'Linux'
+
+ @staticmethod
+ def is_macos() -> bool:
+ """Check if running on macOS."""
+ return platform.system() == 'Darwin'
+
+ @staticmethod
+ def get_python_version() -> Tuple[int, int, int]:
+ """Get Python version tuple."""
+ return sys.version_info[:3]
+
+ @staticmethod
+ def check_python_version(min_version: Tuple[int, int]) -> bool:
+ """
+ Check if Python version meets minimum requirement.
+
+ Args:
+ min_version: Minimum version tuple (major, minor)
+
+ Returns:
+ True if version is sufficient
+ """
+ current = sys.version_info[:2]
+ return current >= min_version
+
+
+class FileUtils:
+ """File operation utilities."""
+
+ @staticmethod
+ def read_file(filepath: str, encoding: str = 'utf-8') -> str:
+ """
+ Read file content.
+
+ Args:
+ filepath: File path
+ encoding: File encoding
+
+ Returns:
+ File content
+ """
+ with open(filepath, 'r', encoding=encoding) as f:
+ return f.read()
+
+ @staticmethod
+ def write_file(filepath: str, content: str, encoding: str = 'utf-8') -> None:
+ """
+ Write content to file.
+
+ Args:
+ filepath: File path
+ content: Content to write
+ encoding: File encoding
+ """
+ # Ensure directory exists
+ directory = os.path.dirname(filepath)
+ if directory:
+ os.makedirs(directory, exist_ok=True)
+
+ with open(filepath, 'w', encoding=encoding) as f:
+ f.write(content)
+
+ @staticmethod
+ def copy_file(src: str, dst: str) -> None:
+ """
+ Copy file from src to dst.
+
+ Args:
+ src: Source file path
+ dst: Destination file path
+ """
+ import shutil
+
+ # Ensure destination directory exists
+ dst_dir = os.path.dirname(dst)
+ if dst_dir:
+ os.makedirs(dst_dir, exist_ok=True)
+
+ shutil.copy2(src, dst)
+
+ @staticmethod
+ def find_files(directory: str, pattern: str, recursive: bool = True) -> List[str]:
+ """
+ Find files matching pattern.
+
+ Args:
+ directory: Directory to search
+ pattern: File pattern (supports wildcards)
+ recursive: Search recursively
+
+ Returns:
+ List of matching file paths
+ """
+ import fnmatch
+
+ matches = []
+
+ if recursive:
+ for root, dirnames, filenames in os.walk(directory):
+ for filename in filenames:
+ if fnmatch.fnmatch(filename, pattern):
+ matches.append(os.path.join(root, filename))
+ else:
+ try:
+ filenames = os.listdir(directory)
+ for filename in filenames:
+ if fnmatch.fnmatch(filename, pattern):
+ filepath = os.path.join(directory, filename)
+ if os.path.isfile(filepath):
+ matches.append(filepath)
+ except OSError:
+ pass
+
+ return sorted(matches)
+
+
+class VersionUtils:
+ """Version comparison utilities."""
+
+ @staticmethod
+ def parse_version(version_str: str) -> Tuple[int, ...]:
+ """
+ Parse version string to tuple.
+
+ Args:
+ version_str: Version string (e.g., "1.2.3")
+
+ Returns:
+ Version tuple
+ """
+ try:
+ parts = version_str.split('.')
+ return tuple(int(p) for p in parts if p.isdigit())
+ except (ValueError, AttributeError):
+ return (0,)
+
+ @staticmethod
+ def compare_versions(v1: str, v2: str) -> int:
+ """
+ Compare two version strings.
+
+ Args:
+ v1: First version
+ v2: Second version
+
+ Returns:
+ -1 if v1 < v2, 0 if equal, 1 if v1 > v2
+ """
+ t1 = VersionUtils.parse_version(v1)
+ t2 = VersionUtils.parse_version(v2)
+
+ # Pad shorter version with zeros
+ if len(t1) < len(t2):
+ t1 = t1 + (0,) * (len(t2) - len(t1))
+ elif len(t2) < len(t1):
+ t2 = t2 + (0,) * (len(t1) - len(t2))
+
+ if t1 < t2:
+ return -1
+ elif t1 > t2:
+ return 1
+ else:
+ return 0
+
+ @staticmethod
+ def version_satisfies(version: str, requirement: str) -> bool:
+ """
+ Check if version satisfies requirement.
+
+ Args:
+ version: Version string
+ requirement: Requirement string (e.g., ">=1.2.0")
+
+ Returns:
+ True if satisfied
+ """
+ import re
+
+ # Parse requirement
+ match = re.match(r'([<>=]+)\s*(.+)', requirement)
+ if not match:
+ # Exact match required
+ return version == requirement
+
+ op, req_version = match.groups()
+ cmp = VersionUtils.compare_versions(version, req_version)
+
+ if op == '>=':
+ return cmp >= 0
+ elif op == '<=':
+ return cmp <= 0
+ elif op == '>':
+ return cmp > 0
+ elif op == '<':
+ return cmp < 0
+ elif op == '==':
+ return cmp == 0
+ elif op == '!=':
+ return cmp != 0
+ else:
+ return False \ No newline at end of file