衡山派开发板模块框架搭建指南基于RT-Thread与SCons的代码移植实战最近在衡山派HSPI开发板上做项目想把一些自己写的驱动或者从别处移植过来的代码规规矩矩地集成到RT-Thread的工程里。很多朋友刚开始用衡山派面对luban-lite这个工程目录结构可能有点无从下手不知道代码该往哪放怎么让RT-Thread的构建系统认识你的代码。今天我就来手把手带你走一遍这个流程。咱们的目标很明确在衡山派官方的luban-lite应用工程里创建一个属于你自己的模块代码文件夹并配置好构建脚本让你后续添加的任何驱动或模块代码都能像RT-Thread内置的组件一样通过menuconfig方便地开启或关闭并且能自动编译。这个过程就像是给你的代码在RT-Thread这个“大社区”里安个家、上个户口。学会了它你以后移植任何代码都会变得非常轻松。1. 准备工作与环境理解在开始动手之前咱们先快速了解一下要用到的两个核心工具SCons和Kconfig。理解了它们后面的操作你就知道“为什么”要这么做了。SCons这是RT-Thread默认使用的构建工具类似Makefile。SConscript文件就是它的“施工图纸”告诉SCons去哪里找源代码.c文件、头文件.h文件以及如何编译它们。我们创建SConscript就是为了告诉构建系统“嘿我这儿有些新代码请把它们也纳入编译流程。”Kconfig这是RT-Thread的配置系统。咱们用menuconfig命令看到的那个图形化配置界面就是由Kconfig文件驱动的。我们修改Kconfig文件就是为了在配置菜单里增加一个选项让用户能选择是否编译我们添加的模块代码。好了理论部分点到为止接下来咱们进入实战环节。请打开你的luban-lite工程目录。2. 创建模块代码专属文件夹首先我们需要一个“根据地”来存放所有你打算移植或自己编写的模块代码。按照衡山派的模块移植规范这个根据地通常放在应用示例目录下。操作步骤导航到你的luban-lite工程根目录。依次进入application/rt-thread/helloworld/。这个helloworld是一个RT-Thread的应用示例目录我们就在它的基础上进行扩展。在helloworld文件夹内新建一个文件夹命名为user-bsp。提示user-bsp这个名字是建议的清晰表明这是用户自定义的板级支持包BSP相关代码。你也可以用其他名字但后续的配置需要相应修改。完成这一步后你的目录结构应该类似这样luban-lite/ └── application/ └── rt-thread/ └── helloworld/ ├── main.c 原有的helloworld示例代码 ├── Kconfig 原有的配置菜单文件 └── user-bsp/ 我们刚刚新建的文件夹未来所有模块代码放这里这个user-bsp文件夹就是我们未来所有自定义驱动、模块代码的“家”。3. 编写SConscript构建脚本现在我们有了房子user-bsp文件夹但还没通水电构建系统不认识它。接下来我们就要给这个房子接通“水电”——创建SConscript文件。操作步骤进入刚才创建的user-bsp文件夹。在该文件夹内新建一个文件命名为SConscript注意没有后缀名。用文本编辑器如VSCode、Notepad等打开这个SConscript文件将以下代码完整地复制进去# user-bsp/SConscript Import(AIC_ROOT) Import(rtconfig) from building import * # 获取当前SConscript文件所在的目录路径赋值给cwd变量 # 这个路径就是我们的user-bsp文件夹的绝对路径 cwd GetCurrentDir() # 定义头文件搜索路径。编译器在找#include xxx.h时会来这里找 # 这里我们把当前目录user-bsp加入搜索路径这样该文件夹下的.h文件就能被找到了 CPPPATH [cwd] # 定义一个空的源文件列表。目前我们这个文件夹下还没有具体的.c文件 # 后续在每个具体的模块子文件夹里它们的SConscript会把自己添加进来 src [] # 定义一个构建组可以理解为一个代码模块的集合 # 名字叫‘lckfb-user-bsp’依赖为空并指定头文件搜索路径为CPPPATH group DefineGroup(lckfb-user-bsp, src, depend [], CPPPATH CPPPATH) # 关键步骤自动扫描子目录 # 获取当前目录user-bsp下的所有文件和文件夹列表 list os.listdir(cwd) for item in list: # 检查每个条目如果它是一个文件夹并且该文件夹内包含一个SConscript文件 if os.path.isfile(os.path.join(cwd, item, SConscript)): # 那么就执行包含那个子文件夹里的SConscript脚本 # 并将其返回的构建组加入到我们当前的主构建组group中 group group SConscript(os.path.join(item, SConscript)) # 最后将这个构建组返回给上一级helloworld目录的SConscript # 这样我们的代码就被正式“挂载”到RT-Thread的构建树上了 Return(group)代码逐行解读Import和from ... import *导入RT-Thread构建系统需要的环境和函数。cwd GetCurrentDir()获取当前脚本所在目录方便后续使用。CPPPATH [cwd]设置头文件路径。假设你在user-bsp/led/下有个led.h在led.c里#include “led.h”编译器就能在user-bsp目录下找到它。group DefineGroup(...)创建一个名为lckfb-user-bsp的代码组。这个名字会在编译日志中看到。for item in list:循环这是本脚本的精髓。它会自动遍历user-bsp文件夹下的所有子文件夹。如果某个子文件夹例如你以后创建的led、uart驱动文件夹里也有一个SConscript文件那么系统就会去执行那个子文件夹的构建脚本并把它的代码合并到当前组。这意味着你以后在user-bsp下新增模块只需要在模块自己的文件夹里写一个简单的SConscript就会被自动发现和编译无需再修改这个根SConscript。Return(group)将最终组装好的构建组返回给调用者即上一级目录的SConscript。这个脚本设计得非常巧妙一次编写后续增加模块几乎不用再动它实现了模块化的管理。4. 配置Kconfig菜单选项通了“水电”构建我们还得做个“门牌”配置菜单让用户能通过menuconfig决定是否要使用我们这个模块代码包。操作步骤回到上一级目录即luban-lite/application/rt-thread/helloworld/。用文本编辑器打开该目录下的Kconfig文件。在这个文件的末尾endif语句的前面追加以下内容# 在helloworld/Kconfig文件末尾追加 comment LCKFB Module transplant code menuconfig USING_LCKFB_TRANSPLANT_CODE bool Porting code using the LCKFB module default n help Official Website : www.lckfb.com # 如果使用立创开发板的模块移植代码则开启下面的选项 if USING_LCKFB_TRANSPLANT_CODE endif # 结束⚠ 特别注意这是最容易出错的一步在原始Kconfig文件中最后通常有一个endif语句。你追加的上述代码必须放在这个已有的endif之前。并且在你自己添加的endif # 结束这一行之后必须至少保留一个空行否则运行menuconfig时会解析报错。保险的做法是总是在文件末尾留出一两行空行。配置项解读comment “…”在menuconfig界面中显示一行注释起说明作用。menuconfig USING_LCKFB_TRANSPLANT_CODE创建一个菜单配置项其配置变量名为USING_LCKFB_TRANSPLANT_CODE。bool “…”表示这是一个布尔类型是/否的选项在菜单中显示的描述为“Porting code using the LCKFB module”。default n默认状态为“否”不选中。help为该选项提供帮助信息。if USING_LCKFB_TRANSPLANT_CODE...endif这是一个条件块。当用户在menuconfig中选中了这个选项即USING_LCKFB_TRANSPLANT_CODE y那么未来在这个if和endif之间添加的任何子配置项比如选择具体某个驱动才会生效。目前我们先搭好框架里面是空的。保存并关闭Kconfig文件。5. 验证框架是否生效框架搭建好了我们来验收一下成果。在luban-lite工程根目录下打开终端或RT-Thread env工具执行命令scons --menuconfig。这会启动RT-Thread的配置界面。使用方向键导航找到“RT-Thread online packages”-“misc samples”-“a hello world sample”这个路径对应helloworld应用。进入“a hello world sample”后你应该能看到我们刚刚添加的配置项“Porting code using the LCKFB module”。按空格键可以选中显示为[*]或取消显示为[ ]这个选项。选中它然后保存并退出配置界面。如果配置界面能正常打开、看到这个选项并且能操作说明Kconfig修改正确。接下来即使user-bsp文件夹里还没有实际代码你也可以尝试执行scons命令编译一下工程应该不会报错可能只有警告这证明SConscript脚本也被成功识别了。下一步做什么恭喜至此衡山派开发板上基于RT-Thread的模块化代码框架就搭建完毕了。这个框架的优势在于模块化以后你的每一个驱动比如LED、按键、UART、I2C传感器驱动都可以在user-bsp下单独创建一个文件夹例如user-bsp/led/。自动集成在每个驱动文件夹里你只需要放置led.c、led.h并编写一个简单的SConscript里面指定要编译的源文件。由于根SConscript的自动扫描功能新驱动会被自动加入编译。可配置通过在Kconfig的if USING_LCKFB_TRANSPLANT_CODE块内添加子选项你可以让用户精细地选择编译哪个驱动。有了这个坚实的基础后续进行具体的驱动开发或代码移植就只剩下“填空”的工作了效率和规范性都会大大提高。你可以愉快地去使用和填充你的模块代码仓库了
衡山派开发板模块框架搭建指南:基于RT-Thread与SCons的代码移植实战
衡山派开发板模块框架搭建指南基于RT-Thread与SCons的代码移植实战最近在衡山派HSPI开发板上做项目想把一些自己写的驱动或者从别处移植过来的代码规规矩矩地集成到RT-Thread的工程里。很多朋友刚开始用衡山派面对luban-lite这个工程目录结构可能有点无从下手不知道代码该往哪放怎么让RT-Thread的构建系统认识你的代码。今天我就来手把手带你走一遍这个流程。咱们的目标很明确在衡山派官方的luban-lite应用工程里创建一个属于你自己的模块代码文件夹并配置好构建脚本让你后续添加的任何驱动或模块代码都能像RT-Thread内置的组件一样通过menuconfig方便地开启或关闭并且能自动编译。这个过程就像是给你的代码在RT-Thread这个“大社区”里安个家、上个户口。学会了它你以后移植任何代码都会变得非常轻松。1. 准备工作与环境理解在开始动手之前咱们先快速了解一下要用到的两个核心工具SCons和Kconfig。理解了它们后面的操作你就知道“为什么”要这么做了。SCons这是RT-Thread默认使用的构建工具类似Makefile。SConscript文件就是它的“施工图纸”告诉SCons去哪里找源代码.c文件、头文件.h文件以及如何编译它们。我们创建SConscript就是为了告诉构建系统“嘿我这儿有些新代码请把它们也纳入编译流程。”Kconfig这是RT-Thread的配置系统。咱们用menuconfig命令看到的那个图形化配置界面就是由Kconfig文件驱动的。我们修改Kconfig文件就是为了在配置菜单里增加一个选项让用户能选择是否编译我们添加的模块代码。好了理论部分点到为止接下来咱们进入实战环节。请打开你的luban-lite工程目录。2. 创建模块代码专属文件夹首先我们需要一个“根据地”来存放所有你打算移植或自己编写的模块代码。按照衡山派的模块移植规范这个根据地通常放在应用示例目录下。操作步骤导航到你的luban-lite工程根目录。依次进入application/rt-thread/helloworld/。这个helloworld是一个RT-Thread的应用示例目录我们就在它的基础上进行扩展。在helloworld文件夹内新建一个文件夹命名为user-bsp。提示user-bsp这个名字是建议的清晰表明这是用户自定义的板级支持包BSP相关代码。你也可以用其他名字但后续的配置需要相应修改。完成这一步后你的目录结构应该类似这样luban-lite/ └── application/ └── rt-thread/ └── helloworld/ ├── main.c 原有的helloworld示例代码 ├── Kconfig 原有的配置菜单文件 └── user-bsp/ 我们刚刚新建的文件夹未来所有模块代码放这里这个user-bsp文件夹就是我们未来所有自定义驱动、模块代码的“家”。3. 编写SConscript构建脚本现在我们有了房子user-bsp文件夹但还没通水电构建系统不认识它。接下来我们就要给这个房子接通“水电”——创建SConscript文件。操作步骤进入刚才创建的user-bsp文件夹。在该文件夹内新建一个文件命名为SConscript注意没有后缀名。用文本编辑器如VSCode、Notepad等打开这个SConscript文件将以下代码完整地复制进去# user-bsp/SConscript Import(AIC_ROOT) Import(rtconfig) from building import * # 获取当前SConscript文件所在的目录路径赋值给cwd变量 # 这个路径就是我们的user-bsp文件夹的绝对路径 cwd GetCurrentDir() # 定义头文件搜索路径。编译器在找#include xxx.h时会来这里找 # 这里我们把当前目录user-bsp加入搜索路径这样该文件夹下的.h文件就能被找到了 CPPPATH [cwd] # 定义一个空的源文件列表。目前我们这个文件夹下还没有具体的.c文件 # 后续在每个具体的模块子文件夹里它们的SConscript会把自己添加进来 src [] # 定义一个构建组可以理解为一个代码模块的集合 # 名字叫‘lckfb-user-bsp’依赖为空并指定头文件搜索路径为CPPPATH group DefineGroup(lckfb-user-bsp, src, depend [], CPPPATH CPPPATH) # 关键步骤自动扫描子目录 # 获取当前目录user-bsp下的所有文件和文件夹列表 list os.listdir(cwd) for item in list: # 检查每个条目如果它是一个文件夹并且该文件夹内包含一个SConscript文件 if os.path.isfile(os.path.join(cwd, item, SConscript)): # 那么就执行包含那个子文件夹里的SConscript脚本 # 并将其返回的构建组加入到我们当前的主构建组group中 group group SConscript(os.path.join(item, SConscript)) # 最后将这个构建组返回给上一级helloworld目录的SConscript # 这样我们的代码就被正式“挂载”到RT-Thread的构建树上了 Return(group)代码逐行解读Import和from ... import *导入RT-Thread构建系统需要的环境和函数。cwd GetCurrentDir()获取当前脚本所在目录方便后续使用。CPPPATH [cwd]设置头文件路径。假设你在user-bsp/led/下有个led.h在led.c里#include “led.h”编译器就能在user-bsp目录下找到它。group DefineGroup(...)创建一个名为lckfb-user-bsp的代码组。这个名字会在编译日志中看到。for item in list:循环这是本脚本的精髓。它会自动遍历user-bsp文件夹下的所有子文件夹。如果某个子文件夹例如你以后创建的led、uart驱动文件夹里也有一个SConscript文件那么系统就会去执行那个子文件夹的构建脚本并把它的代码合并到当前组。这意味着你以后在user-bsp下新增模块只需要在模块自己的文件夹里写一个简单的SConscript就会被自动发现和编译无需再修改这个根SConscript。Return(group)将最终组装好的构建组返回给调用者即上一级目录的SConscript。这个脚本设计得非常巧妙一次编写后续增加模块几乎不用再动它实现了模块化的管理。4. 配置Kconfig菜单选项通了“水电”构建我们还得做个“门牌”配置菜单让用户能通过menuconfig决定是否要使用我们这个模块代码包。操作步骤回到上一级目录即luban-lite/application/rt-thread/helloworld/。用文本编辑器打开该目录下的Kconfig文件。在这个文件的末尾endif语句的前面追加以下内容# 在helloworld/Kconfig文件末尾追加 comment LCKFB Module transplant code menuconfig USING_LCKFB_TRANSPLANT_CODE bool Porting code using the LCKFB module default n help Official Website : www.lckfb.com # 如果使用立创开发板的模块移植代码则开启下面的选项 if USING_LCKFB_TRANSPLANT_CODE endif # 结束⚠ 特别注意这是最容易出错的一步在原始Kconfig文件中最后通常有一个endif语句。你追加的上述代码必须放在这个已有的endif之前。并且在你自己添加的endif # 结束这一行之后必须至少保留一个空行否则运行menuconfig时会解析报错。保险的做法是总是在文件末尾留出一两行空行。配置项解读comment “…”在menuconfig界面中显示一行注释起说明作用。menuconfig USING_LCKFB_TRANSPLANT_CODE创建一个菜单配置项其配置变量名为USING_LCKFB_TRANSPLANT_CODE。bool “…”表示这是一个布尔类型是/否的选项在菜单中显示的描述为“Porting code using the LCKFB module”。default n默认状态为“否”不选中。help为该选项提供帮助信息。if USING_LCKFB_TRANSPLANT_CODE...endif这是一个条件块。当用户在menuconfig中选中了这个选项即USING_LCKFB_TRANSPLANT_CODE y那么未来在这个if和endif之间添加的任何子配置项比如选择具体某个驱动才会生效。目前我们先搭好框架里面是空的。保存并关闭Kconfig文件。5. 验证框架是否生效框架搭建好了我们来验收一下成果。在luban-lite工程根目录下打开终端或RT-Thread env工具执行命令scons --menuconfig。这会启动RT-Thread的配置界面。使用方向键导航找到“RT-Thread online packages”-“misc samples”-“a hello world sample”这个路径对应helloworld应用。进入“a hello world sample”后你应该能看到我们刚刚添加的配置项“Porting code using the LCKFB module”。按空格键可以选中显示为[*]或取消显示为[ ]这个选项。选中它然后保存并退出配置界面。如果配置界面能正常打开、看到这个选项并且能操作说明Kconfig修改正确。接下来即使user-bsp文件夹里还没有实际代码你也可以尝试执行scons命令编译一下工程应该不会报错可能只有警告这证明SConscript脚本也被成功识别了。下一步做什么恭喜至此衡山派开发板上基于RT-Thread的模块化代码框架就搭建完毕了。这个框架的优势在于模块化以后你的每一个驱动比如LED、按键、UART、I2C传感器驱动都可以在user-bsp下单独创建一个文件夹例如user-bsp/led/。自动集成在每个驱动文件夹里你只需要放置led.c、led.h并编写一个简单的SConscript里面指定要编译的源文件。由于根SConscript的自动扫描功能新驱动会被自动加入编译。可配置通过在Kconfig的if USING_LCKFB_TRANSPLANT_CODE块内添加子选项你可以让用户精细地选择编译哪个驱动。有了这个坚实的基础后续进行具体的驱动开发或代码移植就只剩下“填空”的工作了效率和规范性都会大大提高。你可以愉快地去使用和填充你的模块代码仓库了