1# RT-Thread 构建系统使用指南
2
3## 目录
4
51. [概述](#概述)
62. [快速开始](#快速开始)
73. [命令行选项详解](#命令行选项详解)
84. [工具链配置](#工具链配置)
95. [项目生成](#项目生成)
106. [软件包管理](#软件包管理)
117. [高级功能](#高级功能)
128. [常见问题](#常见问题)
13
14## 概述
15
16RT-Thread使用基于SCons的构建系统,提供了统一的跨平台构建体验。构建系统支持:
17
18- 多种编译器和IDE(GCC、Keil、IAR、VS Code等)
19- 模块化的组件管理
20- 灵活的配置系统
21- 自动化的依赖处理
22- 软件包管理功能
23
24### 系统架构图
25
26![arch](./guide_arch.drawio.png)
27
28## 快速开始
29
30### 基本编译流程
31
321. **进入BSP目录**
33   ```bash
34   cd bsp/stm32/stm32f103-blue-pill
35   ```
36
372. **配置系统**(可选)
38   ```bash
39   menuconfig        # 图形化配置
40   ```
41
423. **编译项目**
43   ```bash
44   scons            # 默认编译
45   scons -j8        # 多线程编译
46   ```
47
484. **生成IDE项目**
49   ```bash
50   scons --target=mdk5     # 生成Keil MDK5项目
51   scons --target=iar      # 生成IAR项目
52   scons --target=vsc      # 生成VS Code项目
53   ```
54
55### 清理和重建
56
57```bash
58scons -c                    # 清理编译产物
59scons -c --target=mdk5      # 清理MDK5项目文件
60scons --dist                # 生成分发包
61```
62
63## 命令行选项详解
64
65### 基础编译选项
66
67| 选项 | 说明 | 示例 |
68|------|------|------|
69| `-j N` | 多线程编译,N为线程数 | `scons -j8` |
70| `-c` | 清理编译产物 | `scons -c` |
71| `-s` | 静默模式,不显示命令 | `scons -s` |
72| `--verbose` | 详细输出模式 | `scons --verbose` |
73
74### 项目生成选项
75
76| 选项 | 说明 | 生成的文件 |
77|------|------|------------|
78| `--target=mdk4` | Keil MDK4项目 | project.uvproj |
79| `--target=mdk5` | Keil MDK5项目 | project.uvprojx |
80| `--target=iar` | IAR工作区 | project.eww |
81| `--target=vs2012` | Visual Studio项目 | project.vcxproj |
82| `--target=vsc` | VS Code配置 | .vscode/目录 |
83| `--target=eclipse` | Eclipse CDT项目 | .project, .cproject |
84| `--target=cmake` | CMake项目 | CMakeLists.txt |
85| `--target=makefile` | 通用Makefile | Makefile |
86
87### 配置管理选项
88
89| 选项 | 说明 | 使用场景 |
90|------|------|----------|
91| `--menuconfig` | 启动图形配置界面 | 修改功能配置 |
92| `--pyconfig` | 通过Python脚本配置 | 自动化配置 |
93| `--pyconfig-silent` | 静默Python配置 | CI/CD环境 |
94| `--genconfig` | 从rtconfig.h生成.config | 配置迁移 |
95| `--useconfig=xxx` | 使用指定配置文件 | 切换配置 |
96
97### 工具链选项
98
99| 选项 | 说明 | 示例 |
100|------|------|------|
101| `--exec-path=PATH` | 指定工具链路径 | `--exec-path=/opt/gcc-arm/bin` |
102| `--exec-prefix=PREFIX` | 指定工具链前缀 | `--exec-prefix=arm-none-eabi-` |
103| `--strict` | 严格编译模式 | 开启-Werror |
104
105### 分发和调试选项
106
107| 选项 | 说明 | 用途 |
108|------|------|------|
109| `--dist` | 生成分发包 | 项目发布 |
110| `--dist-strip` | 生成精简分发包 | 最小化项目 |
111| `--dist-ide` | 生成RT-Thread Studio项目 | Studio开发 |
112| `--cscope` | 生成cscope数据库 | 代码导航 |
113| `--clang-analyzer` | 运行Clang静态分析 | 代码质量检查 |
114
115## 工具链配置
116
117### rtconfig.py配置文件
118
119每个BSP都有一个`rtconfig.py`文件,定义了工具链配置:
120
121```python
122import os
123
124# 工具链定义
125CROSS_TOOL = 'gcc'              # 工具链类型: gcc/keil/iar
126PLATFORM   = 'armcc'            # 平台标识
127
128# 编译器路径
129if os.getenv('RTT_EXEC_PATH'):
130    EXEC_PATH = os.getenv('RTT_EXEC_PATH')
131else:
132    EXEC_PATH = r'C:/Keil_v5/ARM/ARMCC/bin'
133
134# 编译器前缀(GCC工具链)
135PREFIX = 'arm-none-eabi-'
136
137# 编译器定义
138CC = PREFIX + 'gcc'
139CXX = PREFIX + 'g++'
140AS = PREFIX + 'gcc'
141AR = PREFIX + 'ar'
142LINK = PREFIX + 'gcc'
143SIZE = PREFIX + 'size'
144OBJDUMP = PREFIX + 'objdump'
145OBJCPY = PREFIX + 'objcopy'
146
147# 设备相关参数
148DEVICE = ' -mcpu=cortex-m3 -mthumb -ffunction-sections -fdata-sections'
149
150# 编译标志
151CFLAGS = DEVICE + ' -Dgcc'
152AFLAGS = ' -c' + DEVICE + ' -x assembler-with-cpp -Wa,-mimplicit-it=thumb '
153LFLAGS = DEVICE + ' -Wl,--gc-sections,-Map=rtthread.map,-cref,-u,Reset_Handler -T link.lds'
154
155# 路径定义
156CPATH = ''
157LPATH = ''
158
159# 链接脚本
160LINK_SCRIPT = 'link.lds'
161
162# 后处理命令
163POST_ACTION = OBJCPY + ' -O binary $TARGET rtthread.bin\n' + SIZE + ' $TARGET \n'
164```
165
166### 支持的工具链
167
1681. **GCC工具链**
169   ```python
170   CROSS_TOOL = 'gcc'
171   PREFIX = 'arm-none-eabi-'
172   ```
173
1742. **Keil MDK**
175   ```python
176   CROSS_TOOL = 'keil'
177   PLATFORM = 'armcc'      # ARM Compiler 5
178   # 或
179   PLATFORM = 'armclang'   # ARM Compiler 6
180   ```
181
1823. **IAR**
183   ```python
184   CROSS_TOOL = 'iar'
185   PLATFORM = 'iccarm'
186   ```
187
1884. **RISC-V GCC**
189   ```python
190   CROSS_TOOL = 'gcc'
191   PREFIX = 'riscv64-unknown-elf-'
192   ```
193
194### 环境变量支持
195
196构建系统支持通过环境变量覆盖配置:
197
198```bash
199# 设置工具链路径
200export RTT_EXEC_PATH=/opt/gcc-arm-none-eabi-10-2020-q4-major/bin
201
202# 设置工具链前缀
203export RTT_CC_PREFIX=arm-none-eabi-
204
205# 设置工具链类型
206export RTT_CC=gcc
207```
208
209## 项目生成
210
211### VS Code项目配置
212
213使用`scons --target=vsc`生成VS Code项目,会创建以下配置文件:
214
215**.vscode/c_cpp_properties.json** - IntelliSense配置
216```json
217{
218    "configurations": [
219        {
220            "name": "RT-Thread",
221            "includePath": [
222                "${workspaceFolder}/**",
223                "${workspaceFolder}/../../components/finsh",
224                "${workspaceFolder}/../../include"
225            ],
226            "defines": [
227                "RT_USING_FINSH",
228                "RT_USING_SERIAL",
229                "__GNUC__"
230            ],
231            "compilerPath": "/opt/gcc-arm/bin/arm-none-eabi-gcc",
232            "cStandard": "c99",
233            "cppStandard": "c++11"
234        }
235    ]
236}
237```
238
239**.vscode/tasks.json** - 构建任务配置
240```json
241{
242    "version": "2.0.0",
243    "tasks": [
244        {
245            "label": "build",
246            "type": "shell",
247            "command": "scons",
248            "problemMatcher": "$gcc",
249            "group": {
250                "kind": "build",
251                "isDefault": true
252            }
253        }
254    ]
255}
256```
257
258### CMake项目生成
259
260使用`scons --target=cmake`生成CMakeLists.txt261
262```cmake
263cmake_minimum_required(VERSION 3.10)
264
265# 工具链设置
266set(CMAKE_SYSTEM_NAME Generic)
267set(CMAKE_SYSTEM_PROCESSOR cortex-m3)
268set(CMAKE_C_COMPILER arm-none-eabi-gcc)
269set(CMAKE_ASM_COMPILER arm-none-eabi-gcc)
270
271project(rtthread C ASM)
272
273# 编译选项
274add_compile_options(
275    -mcpu=cortex-m3
276    -mthumb
277    -ffunction-sections
278    -fdata-sections
279    -Wall
280    -O0
281    -g
282)
283
284# 头文件路径
285include_directories(
286    ${CMAKE_CURRENT_SOURCE_DIR}
287    ${CMAKE_CURRENT_SOURCE_DIR}/../../include
288)
289
290# 源文件
291set(SOURCES
292    applications/main.c
293    ../../src/clock.c
294    ../../src/components.c
295)
296
297# 生成可执行文件
298add_executable(${PROJECT_NAME}.elf ${SOURCES})
299
300# 链接选项
301target_link_options(${PROJECT_NAME}.elf PRIVATE
302    -T${CMAKE_CURRENT_SOURCE_DIR}/link.lds
303    -Wl,-Map=${PROJECT_NAME}.map,--cref
304    -Wl,--gc-sections
305)
306```
307
308## 软件包管理
309
310### 使用package.json定义组件
311
312RT-Thread支持使用`package.json`文件定义软件包:
313
314```json
315{
316    "name": "my-driver",
317    "version": "1.0.0",
318    "type": "rt-thread-component",
319    "license": "Apache-2.0",
320    "dependencies": {
321        "RT_USING_DEVICE": "latest"
322    },
323    "sources": {
324        "common": {
325            "source_files": ["src/*.c"],
326            "header_files": ["inc/*.h"],
327            "header_path": ["inc"]
328        },
329        "cortex-m": {
330            "condition": "defined(ARCH_ARM_CORTEX_M)",
331            "source_files": ["port/cortex-m/*.c"]
332        }
333    }
334}
335```
336
337### 在SConscript中使用BuildPackage
338
339```python
340from building import *
341import os
342
343# 使用package.json构建
344objs = BuildPackage('package.json')
345
346# 或者手动指定包路径
347pkg_path = os.path.join(GetCurrentDir(), 'package.json')
348objs = BuildPackage(pkg_path)
349
350Return('objs')
351```
352
353## 高级功能
354
355### 1. 条件编译和依赖管理
356
357**基于宏定义的条件编译**
358```python
359src = ['common.c']
360
361if GetDepend('RT_USING_SERIAL'):
362    src += ['serial.c']
363
364if GetDepend(['RT_USING_SPI', 'RT_USING_SFUD']):
365    src += ['spi_flash.c']
366
367group = DefineGroup('Drivers', src, depend = ['RT_USING_DEVICE'])
368```
369
370**复杂依赖表达式**
371```python
372# 依赖可以是列表(AND关系)
373depend = ['RT_USING_LWIP', 'RT_USING_NETDEV']
374
375# 或者使用GetDepend进行复杂判断
376if GetDepend('RT_USING_LWIP') and not GetDepend('RT_USING_SAL'):
377    print('配置错误:LWIP需要SAL支持')
378```
379
380### 2. 本地编译选项
381
382为特定模块设置独立的编译选项:
383
384```python
385# 全局编译选项
386CPPPATH = [GetCurrentDir()]
387CPPDEFINES = ['MODULE_VERSION=1']
388
389# 本地编译选项(仅对当前group有效)
390LOCAL_CFLAGS = '-O3 -funroll-loops'
391LOCAL_CPPPATH = ['./private']
392LOCAL_CPPDEFINES = {'BUFFER_SIZE': 1024}
393
394group = DefineGroup('Module', src, depend = [''],
395    CPPPATH = CPPPATH,
396    CPPDEFINES = CPPDEFINES,
397    LOCAL_CFLAGS = LOCAL_CFLAGS,
398    LOCAL_CPPPATH = LOCAL_CPPPATH,
399    LOCAL_CPPDEFINES = LOCAL_CPPDEFINES
400)
401```
402
403### 3. 递归构建子目录
404
405自动扫描并构建子目录:
406
407```python
408import os
409from building import *
410
411objs = []
412cwd = GetCurrentDir()
413dirs = os.listdir(cwd)
414
415# 黑名单目录
416skip_dirs = ['test', 'doc', 'example']
417
418for d in dirs:
419    if d in skip_dirs:
420        continue
421
422    path = os.path.join(cwd, d)
423    if os.path.isdir(path):
424        sconscript = os.path.join(path, 'SConscript')
425        if os.path.isfile(sconscript):
426            objs += SConscript(sconscript)
427
428Return('objs')
429```
430
431### 4. 自定义构建动作
432
433添加构建前后的自定义动作:
434
435```python
436from building import *
437
438def pre_build_action(target, source, env):
439    print('开始构建:', target[0])
440    # 执行预处理操作
441
442def post_build_action(target, source, env):
443    print('构建完成:', target[0])
444    # 生成额外文件,如hex文件
445    import subprocess
446    subprocess.call(['arm-none-eabi-objcopy', '-O', 'ihex',
447                     str(target[0]), str(target[0]) + '.hex'])
448
449# 注册构建动作
450if GetOption('target') == None:
451    rtconfig.POST_ACTION = post_build_action
452```
453
454### 5. 分发包定制
455
456创建自定义分发包:
457
458```python
459# 在BSP的SConstruct中添加
460def dist_handle(BSP_ROOT, dist_dir):
461    import shutil
462
463    # 复制必要文件
464    src_files = ['applications', 'board', 'rtconfig.py', 'SConstruct']
465    for src in src_files:
466        src_path = os.path.join(BSP_ROOT, src)
467        dst_path = os.path.join(dist_dir, src)
468        if os.path.isdir(src_path):
469            shutil.copytree(src_path, dst_path)
470        else:
471            shutil.copy2(src_path, dst_path)
472
473    # 创建README
474    with open(os.path.join(dist_dir, 'README.md'), 'w') as f:
475        f.write('# RT-Thread BSP 分发包\n')
476        f.write('构建时间: ' + time.strftime('%Y-%m-%d %H:%M:%S\n'))
477
478# 注册分发处理函数
479AddOption('--dist-handle',
480          dest = 'dist-handle',
481          action = 'store_true',
482          default = False,
483          help = 'Enable dist handle')
484
485if GetOption('dist-handle'):
486    dist_handle(BSP_ROOT, dist_dir)
487```
488
489### 6. 代码分析集成
490
491**Clang静态分析**
492```bash
493scons --clang-analyzer
494```
495
496**生成compile_commands.json**
497```bash
498scons --target=cmake  # CMake项目会包含compile_commands.json
499# 或使用
500scons --compile-commands
501```
502
503**生成Cscope数据库**
504```bash
505scons --cscope
506```
507
508## 常见问题
509
510### Q1: 如何添加新的源文件?
511
512在相应目录的SConscript中添加:
513```python
514src = Glob('*.c')  # 自动包含所有.c文件
515# 或
516src = ['file1.c', 'file2.c']  # 手动指定
517```
518
519### Q2: 如何排除特定文件?
520
521```python
522src = Glob('*.c')
523SrcRemove(src, ['test.c', 'debug.c'])
524```
525
526### Q3: 如何处理不同配置下的源文件?
527
528```python
529src = ['common.c']
530
531if rtconfig.PLATFORM == 'gcc':
532    src += ['gcc_specific.c']
533elif rtconfig.PLATFORM == 'armcc':
534    src += ['keil_specific.c']
535```
536
537### Q4: 如何调试构建问题?
538
5391. 使用详细输出模式:
540   ```bash
541   scons --verbose
542   ```
543
5442. 查看预处理结果:
545   ```bash
546   scons --target=mdk5 --verbose  # 查看生成的项目配置
547   ```
548
5493. 检查依赖关系:
550   ```python
551   # 在SConscript中添加调试输出
552   print('GetDepend result:', GetDepend('RT_USING_XXX'))
553   ```
554
555### Q5: 如何加快编译速度?
556
5571. 使用多线程编译:
558   ```bash
559   scons -j$(nproc)  # Linux/macOS
560   scons -j8         # Windows
561   ```
562
5632. 使用ccache(GCC):
564   ```python
565   # 在rtconfig.py566   CC = 'ccache ' + PREFIX + 'gcc'
567   ```
568
5693. 优化依赖关系,避免不必要的重编译
570
571### Q6: 如何处理第三方库?
572
5731. **作为源码包含**
574   ```python
575   # libraries/foo/SConscript
576   src = Glob('src/*.c')
577   CPPPATH = [GetCurrentDir() + '/include']
578
579   group = DefineGroup('foo', src, depend = ['RT_USING_FOO'],
580                       CPPPATH = CPPPATH)
581   ```
582
5832. **作为预编译库**
584   ```python
585   # 添加库文件
586   LIBS = ['foo']
587   LIBPATH = [GetCurrentDir() + '/lib']
588
589   group = DefineGroup('foo', [], depend = ['RT_USING_FOO'],
590                       LIBS = LIBS, LIBPATH = LIBPATH)
591   ```
592
593### Q7: 如何自定义链接脚本?
594
595rtconfig.py中指定:
596```python
597# GCC工具链
598LINK_SCRIPT = 'board/link.lds'
599
600# Keil MDK
601LINK_SCRIPT = 'board/link.sct'
602
603# IAR
604LINK_SCRIPT = 'board/link.icf'
605```
606
607## 最佳实践
608
6091. **模块化设计**:每个功能模块使用独立的SConscript
6102. **依赖管理**:正确设置depend参数,避免编译不需要的代码
6113. **路径处理**:使用GetCurrentDir()获取当前路径,避免硬编码
6124. **条件编译**:合理使用GetDepend进行条件判断
6135. **编译选项**:全局选项放在rtconfig.py,局部选项使用LOCAL_xxx
6146. **文档维护**:在SConscript中添加必要的注释说明
615
616## 总结
617
618RT-Thread的构建系统提供了强大而灵活的项目管理能力。通过合理使用各种构建选项和功能,可以高效地进行嵌入式软件开发。建议开发者深入理解构建系统的工作原理,以便更好地利用其功能。