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 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.txt: 261 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.py中 566 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 595在rtconfig.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的构建系统提供了强大而灵活的项目管理能力。通过合理使用各种构建选项和功能,可以高效地进行嵌入式软件开发。建议开发者深入理解构建系统的工作原理,以便更好地利用其功能。