Skip to content

Commit 3a2f4a3

Browse files
authored
Merge pull request #270 from BernardXiong/ebuild
Add ebuild (Embedded Build System)
2 parents 6103374 + 563a7af commit 3a2f4a3

22 files changed

Lines changed: 3139 additions & 0 deletions

ebuild/README.md

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
# EBuild 嵌入式构建系统
2+
3+
EBuild (Embedded Build System) 是一个基于 SCons 的统一嵌入式构建框架,为嵌入式项目提供配置管理、工具链配置、组件注册和工程导出等一站式解决方案。
4+
5+
## 特性
6+
7+
- **统一构建入口** - 通过 `PrepareBuilding`/`DoBuilding` 简化构建流程
8+
- **灵活配置管理** - 支持 menuconfig 图形配置和 attachconfig 快速配置方案
9+
- **智能工具链检测** - 自动从 `~/.env` 或项目配置检测 GCC 工具链路径
10+
- **组件化构建** - 支持 `DefineGroup``package.json` 两种组件组织方式
11+
- **多 IDE 支持** - 可导出 VS Code、CMake、Keil MDK 工程文件
12+
- **条件编译** - 基于配置项的依赖检查和条件编译支持
13+
14+
## 快速开始
15+
16+
### 基本使用
17+
18+
在项目根目录的 `SConstruct` 中:
19+
20+
```python
21+
from ebuild import PrepareBuilding, DoBuilding
22+
23+
# 准备构建环境
24+
env = Environment()
25+
build = PrepareBuilding(env, proj_config=proj_config)
26+
27+
# 注册组件(在 SConscript 中)
28+
# env.DefineGroup('my_component', ['src/*.c'], depend=['CONFIG_MY_FEATURE'])
29+
30+
# 执行构建
31+
DoBuilding(env, 'target.elf')
32+
```
33+
34+
### 配置项目
35+
36+
```bash
37+
# 打开图形配置界面
38+
scons --menuconfig
39+
40+
# 查看可用的 attachconfig 配置方案
41+
scons --attach=?
42+
43+
# 应用某个配置方案
44+
scons --attach=stm32f103-basic
45+
```
46+
47+
### 构建项目
48+
49+
```bash
50+
# 默认构建
51+
scons
52+
53+
# 清理构建
54+
scons -c
55+
56+
# 详细输出
57+
scons --verbose
58+
```
59+
60+
### 导出工程
61+
62+
```bash
63+
# 导出 VS Code 工程
64+
scons --target=vscode
65+
66+
# 导出 CMake 工程
67+
scons --target=cmake
68+
69+
# 导出 Keil MDK 工程
70+
scons --target=mdk5
71+
```
72+
73+
## 核心概念
74+
75+
### 配置文件
76+
77+
- **proj_config.py** - 项目配置,定义工具链、MCU 系列、工程名称等
78+
- **proj_config.h** - 由 menuconfig 生成的 C 头文件,包含所有配置宏
79+
- **Kconfig** - menuconfig 配置描述文件
80+
81+
ProjectRoot 指 SCons 的执行根目录(`scons``scons -C dir``dir`),上述配置文件与 `.config``.ci/attachconfig` 都应位于该目录下。
82+
83+
### 组件注册
84+
85+
EBuild 提供两种组件组织方式:
86+
87+
#### 1. DefineGroup
88+
89+
```python
90+
# 在 SConscript 中
91+
src = ['init.c', 'driver.c']
92+
depend = ['CONFIG_USE_DRIVER']
93+
CPPPATH = ['./include']
94+
CPPDEFINES = ['DEBUG_MODE=1']
95+
96+
env.DefineGroup('my_component', src, depend=depend, CPPPATH=CPPPATH, CPPDEFINES=CPPDEFINES)
97+
```
98+
99+
#### 2. package.json
100+
101+
```json
102+
{
103+
"type": "rt-thread-component",
104+
"name": "my_component",
105+
"dependencies": ["CONFIG_USE_DRIVER"],
106+
"defines": ["DEBUG_MODE=1"],
107+
"sources": [
108+
{
109+
"dependencies": [],
110+
"includes": ["./include"],
111+
"files": ["*.c"]
112+
}
113+
]
114+
}
115+
```
116+
117+
### 工具链配置
118+
119+
EBuild 支持多种工具链配置方式:
120+
121+
1. **自动检测** - 从 `~/.env/tools/scripts/packages` 自动检测
122+
2. **proj_config.py** - 设置 `EXEC_PATH``CC_PREFIX`
123+
3. **命令行参数** - 使用 `--cross-compile``--cpu`
124+
125+
```python
126+
# proj_config.py 示例
127+
TOOLCHAIN_CONFIG = {
128+
'CC_PREFIX': 'arm-none-eabi-',
129+
'EXEC_PATH': '/opt/gcc-arm-none-eabi/bin',
130+
'MCU_SERIES': {
131+
'CONFIG_STM32F103': {
132+
'cpu': 'cortex-m3',
133+
'link_script': 'linkstm32f103xe.ld'
134+
}
135+
},
136+
'BUILD': 'release' # or 'debug'
137+
}
138+
139+
# 可选:构建结束后执行的动作(如生成 bin)
140+
POST_ACTION = "$OBJCOPY -O binary $TARGET build/stm32f103.bin"
141+
```
142+
143+
非 GCC 工具链可通过以下配置项定制命令行参数:
144+
145+
- DEVICE_FLAGS:编译器的设备参数(支持 `{cpu}` 占位符)
146+
- AS_DEVICE_FLAGS:汇编器的设备参数(支持 `{cpu}` 占位符)
147+
- LINK_DEVICE_FLAGS:链接器的设备参数(支持 `{cpu}` 占位符)
148+
- LINK_SCRIPT_FLAG:链接脚本参数前缀(如 `-T``--scatter`
149+
150+
## 命令行选项
151+
152+
| 选项 | 说明 |
153+
|------|------|
154+
| `--target=TYPE` | 导出工程:mdk4/mdk5/cmake/vscode |
155+
| `--menuconfig` | 打开配置菜单 |
156+
| `--attach=NAME` | 应用 attachconfig 方案(`?` 查看列表,`default` 恢复) |
157+
| `--verbose` | 显示完整编译命令 |
158+
| `--cross-compile=PREFIX` | 交叉编译器前缀 |
159+
160+
## 支持的工具链
161+
162+
| 架构 | 配置模块 |
163+
|------|----------|
164+
| ARM | `ebuild.configs.arm_gcc` |
165+
| ARM (Keil MDK, ARMCC) | `ebuild.configs.armcc` |
166+
| ARM (Keil MDK, ARMCLANG) | `ebuild.configs.armclang` |
167+
| AArch64 | `ebuild.configs.aarch64_gcc` |
168+
| RISC-V | `ebuild.configs.riscv_gcc` |
169+
| Linux | `ebuild.configs.linux_gcc` |
170+
| Windows MSVC | `ebuild.configs.msvc` |
171+
172+
## 项目结构
173+
174+
```
175+
project/
176+
├── .config # menuconfig 配置输出
177+
├── proj_config.py # 项目配置
178+
├── proj_config.h # 生成的配置头文件
179+
├── Kconfig # 配置菜单定义
180+
├── SConstruct # 主构建脚本
181+
└── SConscript # 组件注册脚本
182+
```
183+
184+
## 高级功能
185+
186+
### AttachConfig 快速配置
187+
188+
AttachConfig 允许预定义常用配置方案,快速切换:
189+
190+
```bash
191+
# 查看可用方案
192+
scons --attach=?
193+
194+
# 应用方案
195+
scons --attach=nrf52832-peripheral
196+
197+
# 恢复默认配置
198+
scons --attach=default
199+
```
200+
201+
### 条件编译
202+
203+
```python
204+
# 仅当依赖满足时才编译该组件
205+
env.DefineGroup('feature_x', ['feature_x.c'], depend=['CONFIG_FEATURE_X'])
206+
```
207+
208+
### 包构建
209+
210+
```python
211+
# 扫描并构建当前目录下的 package.json
212+
env.BuildPackage('.')
213+
214+
# 构建指定路径的包
215+
env.BuildPackage('path/to/package')
216+
```
217+
218+
### 桥接模式
219+
220+
```python
221+
# 自动扫描子目录并执行其中的 SConscript
222+
groups = env.Bridge()
223+
```
224+
225+
## API 参考
226+
227+
### 核心函数
228+
229+
- `PrepareBuilding(env, proj_config)` - 初始化构建系统
230+
- `DoBuilding(env, target, objs)` - 执行构建或导出
231+
232+
### SCons 环境方法
233+
234+
- `env.DefineGroup(name, src, depend, **kwargs)` - 注册组件组
235+
- `env.BuildPackage(path)` - 构建 package.json 组件
236+
- `env.Bridge()` - 桥接子目录组件
237+
- `env.GetDepend(dep)` - 检查配置依赖
238+
- `env.GlobFiles(pattern)` - 获取文件列表
239+
- `env.SrcRemove(src, remove)` - 从源文件列表中移除
240+
- `env.DoBuilding(target, objs)` - 执行构建
241+
242+
## 安装依赖
243+
244+
```bash
245+
# 安装 SCons
246+
pip install scons
247+
248+
# 安装 kconfiglib(用于 menuconfig)
249+
pip install kconfiglib
250+
251+
# 安装 PyYAML(用于 attachconfig)
252+
pip install pyyaml
253+
```
254+
255+
## 许可证
256+
257+
本项目为内部构建工具,遵循项目许可证。

ebuild/__init__.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# -*- coding: utf-8 -*-
2+
"""Ebuild package entrypoint."""
3+
4+
from .system import BuildSystem, prepare
5+
6+
7+
def PrepareBuilding(env, proj_config=None):
8+
return prepare(env, config_module=proj_config)
9+
10+
11+
def DoBuilding(env, target, objs=None):
12+
build = getattr(env, '_BuildSystem', None) or BuildSystem.current()
13+
if not build:
14+
raise RuntimeError("BuildSystem not initialized.")
15+
return build.do_building(target, objs)
16+
17+
18+
__all__ = ['BuildSystem', 'prepare', 'PrepareBuilding', 'DoBuilding']

0 commit comments

Comments
 (0)