RT-Thread 构建系统实战:SCons 命令、SConscript 工程组织与配置管理全指南
发布时间:2026/10/5 1:52:46 锦皓数字建站

操作系统嵌入式物联网嵌入式OSRTOS【免费下载链接】rt-threadRT-Thread is an open source IoT Real-Time Operating System (RTOS). https://rt-thread.github.io/rt-thread/项目地址https://gitcode.com/gh_mirrors/rt/rt-thread点击查看免费下载RT-Thread 从 0.3.x 起全面引入 SCons 作为官方构建系统用 Python 脚本取代晦涩的 Makefile让开发者从复杂的编译配置中解放出来。本文以 documentation/4.tool/scons/scons.md 为骨架结合仓库内tools/building.py、tools/targets/、components/finsh/SConscript等真实源码系统讲解 SCons 的安装、常用命令、SConstruct/SConscript/rtconfig.py三文件组织方式、内置构建函数以及添加应用代码、自定义模块、链接静态库、配置编译器选项的完整流程。读完本文你将掌握在 RT-Thread 中编译 BSP、生成 MDK/IAR 工程、用 menuconfig 管理组件开关的完整能力。SCons 是什么Python 编写的开源构建工具SCons 是一个用 Python 语言编写的开源软件构建工具software construction tool定位上与 GNU Make 类似但它不使用 Makefile而是使用SConstruct和SConscript文件来描述构建规则。这两类文件本身就是 Python 脚本可以使用标准 Python 语法编写因此可以在其中直接调用 Python 标准库完成各种复杂处理不受 Makefile 规则集的限制。所谓构建工具本质上是把源代码按照一定规则或指令编译成可执行二进制程序的软件这是构建工具最基本也最重要的功能。通常这些规则具有特定语法并被组织成文件这些文件用来控制构建工具的行为——除了软件构建你还可以借它完成其他事情。当前最流行的构建工具是 GNU MakeLinux 内核等许多著名开源软件都使用 Make 构建。Make 通过读取 Makefile 检测文件的组织与依赖关系并执行其中指定的命令。但由于历史原因Makefile 语法混乱、对初学者不友好且在 Windows 平台使用不便需要安装 Cygwin 环境。为了克服这些缺点社区发展出了 CMake、SCons 等新一代构建工具。RT-Thread 为什么选择 SConsRT-Thread 早期使用 Make/Makefile 构建从 0.3.x 版本开始RT-Thread 开发团队逐步引入 SCons 构建系统唯一目标就是让开发者摆脱复杂的 Makefile 配置和 IDE 配置将精力集中在 RT-Thread 功能开发上。这里需要澄清构建工具与 IDE 的区别IDE 通过图形界面操作完成构建大多数 IDE 会基于用户添加的源码生成 Makefile 或 SConscript 这类脚本文件再调用 Make 或 SCons 等工具完成源码编译。也就是说SCons 与 IDE 并非对立关系——RT-Thread 的 SCons 恰恰可以直接生成MDK、IAR、Visual Studio 等 IDE 工程文件二者是协作关系。安装 SConsSCons 用 Python 编写使用前必须先安装 Python 运行时环境。Windows 平台RT-Thread 提供的 Env 配置工具自带 SCons 和 Python无需单独安装这两个软件。这是 Windows 上最省事的方式。Linux / BSD 平台Python 通常已预装多为 2.x 版本此时只需安装 SCons 即可。例如在 Ubuntu 上执行sudo apt-get install sconsSCons 基础用法编译器选择与直接编译RT-Thread 构建系统支持多种编译器包括 ARM GCC、MDKarmcc/armclang、IARiccarm、VisualStudio、Visual DSP 等。主流 ARM Cortex-M0/M3/M4 平台基本都支持 ARM GCC、MDK、IAR。某些 BSP 可能只支持一种编译器你可以查看该 BSP 目录下rtconfig.py中的CROSS_TOOL选项来了解当前支持的编译器。对于 ARM 平台的芯片在 Env 工具中进入 BSP 目录直接执行scons即可编译此时默认使用 ARM GCC 编译器因为 Env 工具自带 ARM GCC。如果希望改用 BSP 已支持的其他编译器或者 BSP 是非 ARM 平台芯片则不能直接用scons命令编译需要自行安装对应编译器并指定编译器路径。在 Env 命令行中可以通过下面两条命令指定编译器及路径以 MDK 为例set RTT_CCkeil set RTT_EXEC_PATHC:/Keilv5注意这种方式只在当前 Env 进程内生效重新打开 Env 后需要重新设置。若想永久生效应直接修改 BSP 下的rtconfig.py详见后文编译器选项配置小节。常用 SCons 命令SCons 不仅能完成基础编译还能生成 MDK/IAR/VS 等工程。以下命令均需在 BSP 目录下执行。scons 与 scons -s在 Env 命令行窗口进入要编译的 BSP 目录执行scons直接编译项目。若修改了部分源码后再执行sconsSCons 会做增量编译只编译被修改的源文件并重新链接。scons -s与scons的区别在于-s参数不打印具体内部命令输出更简洁。scons -c清除编译目标。该命令会清掉执行scons时生成的临时文件和目标文件如build目录下的中间产物。scons --targetXXX生成 IDE 工程如果使用 MDK/IAR 进行项目开发当打开或关闭某些组件后需要使用下面命令之一重新生成对应的定制工程再到 MDK/IAR 中编译下载scons --targetiar scons --targetmdk4 scons --targetmdk5在 Env 命令行进入 BSP 目录后执行scons --targetmdk5会在 BSP 目录生成新的 MDK 工程文件project.uvprojx双击打开即可用 MDK 编译调试执行scons --targetiar会生成新的 IAR 工程文件project.eww。不习惯用 SCons 的开发者可以完全走这条路。如果project.uvproj打开失败请删除project.uvopt后重新生成工程。在 bsp/simulator 目录下可以用以下命令生成 vs2012 或 vs2005 工程scons --targetvs2012 scons --targetvs2005如果 BSP 目录中提供了其他 IDE 的工程模板文件同样可以使用该命令生成对应新工程如ua、vs、cb、cdk等。该命令也可以加-s参数如scons --targetmdk5 -s执行时不打印具体内部命令。生成 MDK 或 IAR 工程文件的前提是BSP 目录中存在工程模板文件。SCons 会根据模板文件加入相关源码、头文件搜索路径、编译参数、链接参数等。至于工程面向哪颗芯片直接由该工程模板文件指定。因此在大多数情况下这个模板文件是一个空工程文件用来辅助 SCons 生成project.uvprojx或project.eww。从源码看工程生成逻辑集中在 tools/building.py 的GenTargetProject()约 925 行起--target为mdk/mdk4/mdk5时从targets.keil模块选择MDK2Project/MDK4Project/MDK5Project并依据template.uvprojx/template.uvproj/template.Uv2生成工程iar、vs、vs2012、cb、ua、vsc、cdk、ses、makefile、eclipse、codelite、cmake、xmake、esp-idf、zig等目标分别由 tools/targets 目录下的对应模块实现。这意味着只要你在 tools/targets 中看到对应生成器如keil.py、iar.py、vs2012.py、cdk.py、vsc.py该 BSP 就可以用--target生成对应工程。scons -jN多线程编译多线程编译目标可在多核电脑上加快编译速度。一般而言 1 个 CPU 核可支撑 2 个线程双核机器推荐使用scons -j4。如果只是想查看编译错误或警告最好不要加-j参数否则错误信息会与多个文件的并行输出混在一起。scons --dist构建可分发工程框架执行该命令会在 BSP 目录下生成dist目录这是开发工程的目录结构包含 RT-Thread 源码和该 BSP 相关工程无关的 BSP 文件夹和 libcpu 会被移除你可以把这个工作拷贝到任意目录使用。从源码看其核心逻辑在 tools/mkdist.py如bsp_copy_files负责复制 BSP 文件并排除build、dist、*.pyc、rtthread.bin、*.elf等中间产物EndBuilding()中会调用mkdist模块的MkDist/MkDist_Strip完成打包。scons --verbose显示完整编译参数默认情况下scons输出不显示编译参数形如D:\repository\rt-thread\bsp\stm32f10xscons scons: Reading SConscript files ... scons: done reading SConscript files. scons: Building targets ... scons: building associated VariantDir targets: build CC build\applications\application.o CC build\applications\startup.o CC build\components\drivers\serial\serial.o ...使用scons --verbose后则显示完整命令行参数便于排查编译问题armcc -o build\src\mempool.o -c --device DARMSTM --apcsinterwork -ID:/Keil/ARM/ RV31/INC -g -O0 -DUSE_STDPERIPH_DRIVER -DSTM32F10X_HD -Iapplications -IF:\Projec t\git\rt-thread\applications -I. -IF:\Project\git\rt-thread -Idrivers -IF:\Proje ct\git\rt-thread\drivers -ILibraries\STM32F10x_StdPeriph_Driver\inc -IF:\Project \git\rt-thread\Libraries\STM32F10x_StdPeriph_Driver\inc -ILibraries\STM32_USB-FS -Device_Driver\inc -IF:\Project\git\rt-thread\Libraries\STM32_USB-FS-Device_Driv er\inc -ILibraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x -IF:\Project\git\rt-thre ...SCons 进阶RT-Thread 的三文件构建骨架SCons 使用SConscript和SConstruct文件组织源码结构。通常一个项目只有一个SConstruct但会有多个SConscript一般每个存放源码的子目录都会放一个SConscript。为了让 RT-Thread 更好地支持多编译器并方便调整编译参数RT-Thread 为每个 BSP 单独创建了rtconfig.py文件。因此每个 RT-Thread BSP 目录下都有三个文件rtconfig.py、SConstruct、SConscript它们共同控制该 BSP 的编译。一个 BSP 只有一个SConstruct但SConscript可以有多个——可以说SConscript文件是组织源码的主力。RT-Thread 的大多数源码目录中也存在SConscript文件这些文件由 BSP 目录下的SConscript发现并执行从而把rtconfig.h中定义的宏所对应的源码添加到编译中。下文以 stm32f10x-HAL BSP 为例说明 SCons 如何构建工程。SConscript 内置函数如果想把自己的源码加入 SCons 构建环境通常做法是新建或修改一个SConscript文件。SConscript文件可以控制源文件的添加并指定文件的组别类似于 MDK/IAR 等 IDE 中的 Groups 概念。SCons 提供了大量内置函数帮助我们快速添加源码配合简单的 Python 语句即可向工程添加或移除源码。以下介绍常用函数。GetCurrentDir()获取当前目录。其实现位于 tools/building.py 的GetCurrentDir()约 804 行通过定位当前目录下的SConscript文件解析出该文件所在目录。Glob(*.c)获取当前目录下所有 C 文件。修改参数中的后缀即可匹配当前目录的任意类型文件如Glob(*.h)、Glob(*.s)。GetDepend(macro)该函数定义在tools目录下的脚本文件中从rtconfig.h读取指定宏的配置信息若rtconfig.h中开启了该宏则返回 true否则返回 false。在 tools/building.py 的GetDepend()约 511 行中可以看到当传入字符串时若宏不在BuildOptions中或值为 0 则返回 False若宏的值非空则直接返回该值当传入列表时任何一项未定义或为 0 都会使整体结果为 False即列表内所有依赖宏都必须满足。Split(str)把字符串 str 按空白拆分成列表。例如Split(board.c stm32f1xx_it.c)等价于[board.c, stm32f1xx_it.c]用于把多行文件列表紧凑地写成多行字符串。DefineGroup(name, src, depend, **parameters)这是 RT-Thread 基于 SCons 扩展的方法函数用于定义一个组件。一个组件可以是一个目录下辖文件或子目录也可以是在后续 IDE 工程文件中的 Group/文件夹。各参数说明如下参数说明nameGroup 的名称srcGroup 包含的文件一般指 C/C 源文件为方便起见也可以用Glob通配符列出SConscript所在目录中的匹配文件dependGroup 编译时所依赖的选项例如 FinSH 组件依赖RT_USING_FINSH宏定义。编译选项一般指rtconfig.h中定义的RT_USING_xxx宏当对应宏在rtconfig.h中被定义时该组才会被加入构建环境编译若依赖宏未定义则该组不参与编译。同样用 scons 生成 IDE 工程文件时若依赖宏未定义对应 Group 也不会出现在工程文件中parameters配置其他参数可取下表列出的值实际使用中无需全部配置可配置的 parameters参数说明CCFLAGS源文件编译参数CPPPATH头文件路径CPPDEFINES链接参数宏定义LIBRARY包含该参数时组件生成的目标文件会被打包成库文件从 tools/building.py 的DefineGroup()约 685 行实现可以看到更多细节函数首先调用GetDepend(depend)判断依赖是否满足不满足直接返回空列表随后把CFLAGS/CCFLAGS/CXXFLAGS/CPPPATH/CPPDEFINES/LINKFLAGS/ASFLAGS/LIBS/LIBPATH等参数通过Env.AppendUnique追加到全局构建环境若带LIBRARY参数则调用Env.Library(name, group[src])把组内源码打包成静态库最终把组按名称大小写有序插入全局Projects列表供后续工程文件生成MDK/IAR/VS 分组和scons --dist使用。此外还支持LOCAL_CFLAGS/LOCAL_CPPPATH/LOCAL_CPPDEFINES等仅对组内文件生效的局部参数。SConscript(dirs, variant_dir, duplicate)读取新的SConscript文件。参数说明如下参数说明dirsSConscript 文件路径variant_dir指定存放生成目标文件的路径duplicate设置是否将源文件复制或链接到 variant_dirSConscript 实战示例以下通过几个真实场景的SConscript示例说明 scons 工具的实际用法。SConscript 示例 1BSP 顶层 SConscript 汇总所有子目录以 stm32f10x-HAL BSP 目录下的SConscript为例它管理该 BSP 下所有其他SConscript文件import os cwd str(Dir(#)) objs [] list os.listdir(cwd) for d in list: path os.path.join(cwd, d) if os.path.isfile(os.path.join(path, SConscript)): objs objs SConscript(os.path.join(d, SConscript)) Return(objs)逐行解读import os导入 Python 系统编程 os 模块可调用 os 模块提供的函数处理文件和目录。cwd str(Dir(#))获取工程顶层目录并赋给字符串变量 cwd即工程SConstruct所在目录此处与cwd GetCurrentDir()效果相同。objs []定义一个空列表变量 objs。list os.listdir(cwd)获取当前目录下的所有子目录并保存到变量 list。随后是 Python for 循环遍历 BSP 的所有子目录并运行这些子目录的SConscript文件。具体操作是取出当前目录的一个子目录用os.path.join(cwd, d)拼接成完整路径然后判断该子目录中是否存在名为SConscript的文件若存在执行objs objs SConscript(os.path.join(d, SConscript))其中SConscript()是 SCons 提供的内置函数可以读入新的SConscript文件并把其中指定的源码加入源码编译列表 objs。借助这个SConscript文件BSP 工程所需的源码就被加入编译列表了。SConscript 示例 2drivers 目录按宏条件加入驱动再来看 drivers 目录下的SConscript它管理 drivers 目录下的源码drivers 目录存放基于 RT-Thread 驱动框架实现的底层驱动代码Import(rtconfig) from building import * cwd GetCurrentDir() # add the general drivers. src Split( board.c stm32f1xx_it.c ) if GetDepend([RT_USING_PIN]): src [drv_gpio.c] if GetDepend([RT_USING_SERIAL]): src [drv_usart.c] if GetDepend([RT_USING_SPI]): src [drv_spi.c] if GetDepend([RT_USING_USB_DEVICE]): src [drv_usb.c] if GetDepend([RT_USING_SDCARD]): src [drv_sdcard.c] if rtconfig.PLATFORM in [gcc]: src [gcc_startup.s] CPPPATH [cwd] group DefineGroup(Drivers, src, depend [], CPPPATH CPPPATH) Return(group)逐行解读Import(rtconfig)导入 rtconfig 对象后面用到的rtconfig.PLATFORM就定义在这个模块中。from building import *把 building 模块的所有内容导入当前模块后面用到的DefineGroup就定义在该模块中。cwd GetCurrentDir()获取当前路径并保存到字符串变量 cwd。下一行用Split()函数把文件字符串拆成列表效果等价于src [board.c, stm32f1xx_it.c]。随后用if判断和GetDepend()检查rtconfig.h中某个宏是否开启若开启则用src [src_name]把对应驱动源码追加到列表变量 src。这样drv_gpio.c、drv_usart.c等驱动只在对应外设宏开启时才参与编译。CPPPATH [cwd]把当前路径保存到列表变量 CPPPATH。最后一行用DefineGroup创建名为 Drivers 的组对应 MDK 或 IAR 中的分组。该组源码是 src 指定的文件依赖为空表示该组不依赖rtconfig.h的任何宏。CPPPATH CPPPATH的含义是把当前路径加入系统头文件路径。左侧的CPPPATH是DefineGroup中代表头文件路径的内置参数右侧的CPPPATH是本文上一行定义的变量——这样其他源码就可以引用 drivers 目录下的头文件了。SConscript 示例 3applications 目录批量加入应用源码再看 applications 目录下的SConscript它管理 applications 目录下用户自己的应用代码from building import * cwd GetCurrentDir() src Glob(*.c) CPPPATH [cwd, str(Dir(#))] group DefineGroup(Applications, src, depend [], CPPPATH CPPPATH) Return(group)src Glob(*.c)获取当前目录下所有 C 文件。CPPPATH [cwd, str(Dir(#))]把当前路径和工程SConstruct所在路径保存到列表变量 CPPPATH。最后一行用DefineGroup创建名为Applications的组源码为 src 指定的文件依赖为空表示不依赖任何rtconfig.h宏并把 CPPPATH 保存的路径加入系统头文件搜索路径这样 stm32f10x-HAL BSP 目录下的应用目录和头文件就可以被其他源码引用。综上这段程序会把当前目录下所有 C 程序加入Applications组因此在该目录添加或删除文件就相当于往工程中批量添加或删除文件非常适合批量管理应用源码。SConscript 示例 4finsh 组件源码管理含链接参数以下为 RT-Thread 源码components/finsh目录下的SConscript文件当前仓库版本管理 finsh 目录下的源码from building import * from gcc import GetGCCLikePLATFORM cwd GetCurrentDir() src Split( shell.c msh.c msh_parse.c ) CPPPATH [cwd] LOCAL_CFLAGS if rtconfig.PLATFORM in [gcc]: # only for GCC LOCAL_CFLAGS -Wstack-usage str(GetConfigValue(FINSH_THREAD_STACK_SIZE)) # check finsh thread stack size if GetDepend(MSH_USING_BUILT_IN_COMMANDS): src [cmd.c] if GetDepend(DFS_USING_POSIX): src [msh_file.c] group DefineGroup(Finsh, src, depend [RT_USING_FINSH], CPPPATH CPPPATH, LOCAL_CFLAGS LOCAL_CFLAGS) Return(group)这个真实版本与原文档中的示例略有演进但核心模式一致使用GetConfigValue(FINSH_THREAD_STACK_SIZE)读取配置值并拼入 GCC 的-Wstack-usage编译选项用于编译期检查 finsh 线程栈大小通过GetDepend()按宏条件追加cmd.c、msh_file.cDefineGroup(Finsh, src, depend [RT_USING_FINSH], ...)表明该组依赖rtconfig.h中的RT_USING_FINSH宏宏开启时编译 finsh 源码否则 SCons 不会编译同时把 finsh 目录加入系统头文件目录其他源码即可引用 finsh 目录下的头文件。原文档中的示例还展示了通过DefineGroup传递LINKFLAGS的做法当编译工具为 armcc/armclang 时设置LINKFLAGS --keep *.o(FSymTab)若未启用FINSH_USING_MSH_ONLY再追加--keep *.o(VSymTab)以此保留 finsh 符号表段。LINKFLAGS LINKFLAGS与CPPPATH CPPPATH含义相同左侧LINKFLAGS代表链接参数右侧LINKFLAGS是前面 if/else 语句定义的值即给整个工程指定链接参数。用 SCons 管理自己的项目前面对 RT-Thread 源码相关的 SConscript 做了详细讲解下面介绍如何用 SCons 管理自己的项目。添加应用代码如前所述BSP 下的 Applications 文件夹用于存放用户自己的应用代码目前只有一个 main.c。如果应用代码不多建议把相关源文件放在该文件夹下。例如在 Applications 文件夹下新增 hello.c 和 hello.h 两个文件/* file: hello.h */ #ifndef _HELLO_H_ #define _HELLO_H_ int hello_world(void); #endif /* _HELLO_H_ *//* file: hello.c */ #include stdio.h #include finsh.h #include rtthread.h int hello_world(void) { rt_kprintf(Hello, world!\n); return 0; } MSH_CMD_EXPORT(hello_world, Hello world!)applications 目录下的SConscript会把当前目录所有源文件加入工程但新增文件后需要执行scons --targetxxx命令把这两个新文件加入工程——注意每次添加新文件后都要重新生成工程。添加模块hello 模块 Kconfig menuconfig如果源码文件很多想创建自己的项目模块或者需要使用从别处获得的模块应该怎么做呢仍以 hello.c 和 hello.h 为例把这两个文件放到独立文件夹中管理使其在 MDK 工程文件中拥有独立分组并可通过 menuconfig 选择是否使用该模块。在 BSP 下新增 hello 文件夹注意该文件夹里多了一个SConscript文件——要把自己的源码加入 SCons 构建环境通常就是新建或修改SConscript文件。参照上文对 RT-Thread 源码 SConscript 的分析这个新 hello 模块的SConscript内容如下from building import * cwd GetCurrentDir() include_path [cwd] src [] if GetDepend([RT_USING_HELLO]): src [hello.c] group DefineGroup(hello, src, depend [], CPPPATH include_path) Return(group)通过上述几行代码就创建了一个新的 hello 组可以用宏定义控制加入组的源文件并把组所在目录加入系统头文件路径。那么自定义宏RT_USING_HELLO如何定义这里需要引入一个新文件Kconfig。Kconfig 用于配置内核用 Env 配置系统时执行的menuconfig命令所生成的配置界面依赖 Kconfig 文件——menuconfig通过读取工程的各种 Kconfig 文件生成配置界面供用户配置内核最后把所有与配置相关的宏定义自动保存到 BSP 目录下的rtconfig.h文件中。每个 BSP 都有一个rtconfig.h文件它就是这个 BSP 的配置信息。stm32f10x-HAL BSP 目录下已有该 BSP 的 Kconfig 文件可在此基础上添加需要的配置选项。hello 模块新增的配置选项如下#号后是注释menu hello module # 创建 hello module 菜单 config RT_USING_HELLO # RT_USING_HELLO 配置选项 bool Enable hello module # RT_USING_HELLO 是 bool 变量显示为 Enable hello module default y # RT_USING_HELLO 可取 y 和 n默认 y help # 使用 help会显示 this hello module only used for test this hello module only used for test config RT_HELLO_NAME # RT_HELLO_NAME 配置选项 string hello name # RT_HELLO_NAME 是字符串变量菜单显示为 hello name default hello # 默认名为 hello config RT_HELLO_VALUE # RT_HELLO_VALUE 配置选项 int hello value # RT_HELLO_VALUE 是 int 变量菜单显示为 hello value default 8 # 默认值为 8 endmenu # hello 菜单结束用 Env 工具进入 stm32f10x-HAL BSP 目录后执行menuconfig会在主页面底部看到新 hello 模块的配置菜单进入菜单后还可以修改 hello value 的值。保存配置并退出配置界面后打开 stm32f10x-HAL BSP 目录下的rtconfig.h即可看到 hello 模块的配置信息RT_USING_HELLO、RT_HELLO_NAME、RT_HELLO_VALUE等宏已经生成。注意每次 menuconfig 配置完成后都要用scons --targetXXX命令重新生成工程。由于rtconfig.h中已定义RT_USING_HELLO宏重新生成工程时 hello.c 源码就会被加入新工程。以上只是列举了在 Kconfig 文件中添加自己模块配置选项的简单方式更复杂的配置选项可参考 Env 相关文档ref page_env或 Kconfig 官方文档实现。添加库LIBS 与 LIBPATH 的命名规则如果要在工程中添加额外库需要特别注意不同工具链对二进制库命名的差异。例如 GCC 工具链识别libabc.a这类库名指定库时写abc而不是libabc。因此在链接额外库时要格外注意SConscript文件的写法并且指定库时最好同时指定对应的库搜索路径。示例Import(rtconfig) from building import * cwd GetCurrentDir() src Split( ) LIBPATH [cwd /libs] LIBS [abc] group DefineGroup(ABC, src, depend [], LIBS LIBS, LIBPATHLIBPATH)LIBPATH指定库路径LIBS指定库名。如果工具链是 GCC库名应为libabc.a如果工具链是 armcc库名应为abc.lib。LIBPATH [cwd /libs]表示库的搜索路径为当前目录下的libs目录。编译器选项配置rtconfig.py 详解rtconfig.py是 RT-Thread 标准的编译器配置文件控制大部分编译选项是一个用 Python 编写的脚本文件用于指定编译器从支持的多个编译器中选一个指定编译选项、链接选项等编译器参数。使用scons编译工程时工程按照rtconfig.py的编译器配置选项进行编译。以下是 stm32f10x-HAL BSP 目录下rtconfig.py的部分代码import os # toolchains options ARCHarm CPUcortex-m3 CROSS_TOOLgcc if os.getenv(RTT_CC): CROSS_TOOL os.getenv(RTT_CC) # cross_tool provides the cross compiler # EXEC_PATH is the compiler execute path, for example, CodeSourcery, Keil MDK, IAR if CROSS_TOOL gcc: PLATFORM gcc EXEC_PATH /usr/local/gcc-arm-none-eabi-5_4-2016q3/bin/ elif CROSS_TOOL keil: PLATFORM armcc EXEC_PATH C:/Keilv5 elif CROSS_TOOL iar: PLATFORM iccarm EXEC_PATH C:/Program Files/IAR Systems/Embedded Workbench 6.0 Evaluation if os.getenv(RTT_EXEC_PATH): EXEC_PATH os.getenv(RTT_EXEC_PATH) BUILD debug if PLATFORM gcc: # toolchains PREFIX arm-none-eabi- CC PREFIX gcc AS PREFIX gcc AR PREFIX ar LINK PREFIX gcc TARGET_EXT elf SIZE PREFIX size OBJDUMP PREFIX objdump OBJCPY PREFIX objcopy DEVICE -mcpucortex-m3 -mthumb -ffunction-sections -fdata-sections CFLAGS DEVICE AFLAGS -c DEVICE -x assembler-with-cpp LFLAGS DEVICE -Wl,--gc-sections,-Maprtthread-stm32.map,-cref,-u,Reset_Handler -T stm32_rom.ld其中CFLAGS是 C 文件的编译选项AFLAGS是汇编文件的编译选项LFLAGS是链接选项。BUILD变量控制代码优化级别默认取值为debug以调试模式编译优化级别为 0若把该变量修改为其他值则以优化级别 2 编译。以下是所有可能的写法简单说只要不是debug即可BUILD BUILD release BUILD hello, world建议开发阶段使用 debug 模式编译不优化产品稳定后再考虑优化。这些选项的具体含义需查阅编译器手册例如上面用到的armcc是 MDK 的底层编译器其编译选项含义详见 MDK 帮助。如前所述如果执行scons时想用另一个编译器编译工程可以在 Env 命令行用相关命令指定编译器和编译器路径但这种修改只对当前 Env 进程有效重新打开后需要重新设置。也可以直接修改rtconfig.py文件来永久配置编译器一般只需修改CROSS_TOOL和EXEC_PATH两个选项CROSS_TOOL指定编译器可选值为 keil、gcc、iar。浏览rtconfig.py可看到当前 BSP 支持的编译器。如果机器上安装了 MDK可以把CROSS_TOOL改为 keil用 MDK 编译工程。EXEC_PATH编译器的安装路径。有两点需要注意安装编译器如 MDK、GNU GCC、IAR 等时不要安装在含中文或空格的路径中否则解析路径时会出现一些错误。有些程序默认安装到C:\Program Files目录路径中间含空格建议安装时选择其他路径养成良好的开发习惯。修改EXEC_PATH时要注意路径格式。Windows 平台默认路径分隔符是反斜杠\而反斜杠在 C 和 Python 中都是转义字符所以修改路径时可以把\改为/或加上rPython 表示原始数据的语法。假设编译器安装在D:\Dir1\Dir2以下是正确写法EXEC_PATH rD:\Dir1\Dir2—— 字符串前加r\可以正常使用EXEC_PATH D:/Dir1/Dir2—— 使用/前面不需要rEXEC_PATH D:\\Dir1\\Dir2—— 使用转义\\转义\本身错误写法示例EXEC_PATH D:\Dir1\Dir2直接写单个反斜杠会被当作转义符。如果rtconfig.py文件中有以下代码在配置自己的编译器时应将其注释掉if os.getenv(RTT_CC): CROSS_TOOL os.getenv(RTT_CC) ... ... if os.getenv(RTT_EXEC_PATH): EXEC_PATH os.getenv(RTT_EXEC_PATH)上面两个if判断会把CROSS_TOOL和EXEC_PATH设置为 Env 的默认值。编译器配置完成后就可以用 SCons 编译 RT-Thread 的 BSP 了在 BSP 目录打开命令行窗口执行scons命令即开始编译。RT-Thread 辅助编译脚本在 RT-Thread 源码的 tools 目录中定义了 RT-Thread 的辅助编译脚本例如为某些 IDE 自动生成 RT-Thread 工程文件的脚本。其中最重要的是 tools/building.py它实现了GetDepend()、GetCurrentDir()、DefineGroup()、GenTargetProject()、EndBuilding()等核心函数以及AddDepend、GetConfigValue、RegisterPreBuildingAction、GroupLibName等辅助能力是整个 RT-Thread 构建体系的中枢。SCons 的进一步使用Export/Import 与跨目录组织对于复杂的大型系统源码显然不止一个目录里的几个文件往往是第一层就组合了多个文件夹。在 SCons 中可以为这些相对独立的目录编写SConscript脚本文件来编译其中的文件也可以使用 SCons 的Export和Import函数在SConstruct与SConscript文件之间共享数据即一个 Python 对象数据如示例中的rtconfig。Import(rtconfig)在本文多个 SConscript 示例中反复出现正是这一机制的体现。有关 SCons 更深入的使用方法可参考 SCons 官方文档。总结RT-Thread 的 SCons 构建体系由三层构成最上层是scons及其衍生命令-c、-jN、--target、--dist、--verbose等负责日常编译、清理、并行加速与 IDE 工程生成中间层是SConstructSConscriptrtconfig.py三文件骨架分别承担构建入口、源码组织与编译器配置的职责最底层是 tools/building.py 与 tools/targets 提供的DefineGroup、GetDepend等内置函数和多 IDE 工程生成器。理解并善用这套体系就能在 RT-Thread 中自由地编译任意 BSP、按宏条件裁剪源码、用 menuconfig 管理自己的模块并随时切换到 MDK/IAR/VS 等 IDE 工作流。赞分享操作系统嵌入式物联网嵌入式OSRTOS【免费下载链接】rt-threadRT-Thread is an open source IoT Real-Time Operating System (RTOS). https://rt-thread.github.io/rt-thread/项目地址https://gitcode.com/gh_mirrors/rt/rt-thread点击查看免费下载相关推荐RT-Thread Rockchip RK3300 BSPaarch64 工具链配置与 scons 完整构建指南RT Thread Rockchip RK3300 BSPaarch64 工具链配置与 scons 完整构建指南 本篇指南基于 RT Thread 仓库中的操作系统嵌入式物联网嵌入式OSRTOSRT-Thread Phytium BSP C 支持编译指南工具链选择、Kconfig 配置与 scons 构建实战RT Thread Phytium BSP C 支持编译指南工具链选择、Kconfig 配置与 scons 构建实战 本指南以 cpp_support.m操作系统嵌入式物联网嵌入式OSRTOSRT-Thread Rust 组件开发指南统一注册架构与特性配置系统实战RT Thread Rust 组件开发指南统一注册架构与特性配置系统实战 导读 本文基于 RT Thread 开源仓库中的 Rust 组件示例文档系统讲解如操作系统嵌入式物联网嵌入式OSRTOS上一篇如何用AI代码助手提升开发效率3个自动化测试技巧揭秘下一篇ExplorerPatcher Windows 11 界面定制快速上手指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。