尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Ubuntu上基于QEMU搭建RT-Thread虚拟开发环境全攻略

Ubuntu上基于QEMU搭建RT-Thread虚拟开发环境全攻略 1. 项目概述为什么要在Ubuntu上搞RT-Thread如果你是一个嵌入式开发者或者对物联网、实时操作系统感兴趣那么“在Ubuntu上开发RT-Thread”这个标题可能瞬间就抓住了你的眼球。这听起来像是一个很“正”的开发环境配置指南但它的价值远不止于此。本质上这是一个关于如何搭建一个低成本、高效率、可深度定制的嵌入式开发与学习环境的实践。RT-Thread作为一个优秀的国产开源实时操作系统以其组件丰富、内核小巧、生态完善著称是学习嵌入式、进行产品原型开发的绝佳选择。而Ubuntu作为最流行的Linux发行版之一提供了稳定、强大的命令行环境和丰富的开发工具链。那么为什么要把这两者结合起来最直接的原因就是效率和便利性。传统的嵌入式开发你需要一块真实的开发板比如STM32、GD32等每次修改代码、编译、烧录、调试都是一个物理过程耗时且受硬件限制。而在Ubuntu上借助QEMU这样的开源硬件模拟器我们可以虚拟出一个ARM架构的“开发板”比如热词中提到的vexpress-a9直接在电脑上运行、调试RT-Thread。这意味着你可以随时随地开始编码、测试无需担心硬件损坏、接线错误编译速度也更快。这对于学习RT-Thread内核机制、驱动框架、网络协议栈甚至是进行早期的软件架构验证都具有无可比拟的优势。这个项目适合谁首先是嵌入式初学者你可以零成本入门不用担心买错板子或烧坏芯片。其次是有经验的嵌入式工程师你可以用它来快速验证想法、调试复杂问题或者为团队搭建统一的开发测试环境。最后对于任何对操作系统原理和ARM架构感兴趣的技术爱好者这都是一条绝佳的实践路径。接下来我将以一个资深嵌入式开发者的视角带你从零开始在Ubuntu上构建一个完整的RT-Thread开发、运行与调试环境并深入其中几个关键的技术环节。2. 环境搭建从零开始构建你的“虚拟实验室”工欲善其事必先利其器。在Ubuntu上开发RT-Thread核心是准备好三样东西RT-Thread源码、ARM交叉编译工具链、以及硬件模拟器QEMU。我们的目标是搭建一个闭环在Ubuntu上编写代码用ARM工具链编译最后在QEMU模拟的ARM板上运行。2.1 系统准备与基础依赖安装我假设你使用的是一台安装了Ubuntu 22.04 LTS或更新版本的电脑或虚拟机。首先打开终端更新软件包列表并安装一些基础编译工具和依赖库。这些是后续步骤的基石。sudo apt update sudo apt upgrade -y sudo apt install -y build-essential git wget flex bison libncurses-dev libssl-dev libelf-devbuild-essential: 包含了GCC、G、make等最基础的编译工具链是C/C开发的必需品。git: 用于克隆RT-Thread的源代码仓库。wget: 用于下载工具链等文件。flex,bison: 语法分析器生成器某些配置工具如menuconfig可能会用到。libncurses-dev: 提供字符终端下的图形界面库这是使用menuconfig进行可视化配置的关键。libssl-dev,libelf-dev: 一些底层库的开发文件确保编译过程不会因缺失头文件或库而报错。注意如果你的Ubuntu是最小化安装比如Ubuntu Server那么这些依赖项尤其重要。桌面版通常已包含大部分但手动安装一遍能避免很多奇怪的编译错误。2.2 ARM交叉编译工具链的获取与配置这是核心中的核心。我们的Ubuntu主机是x86_64架构而要编译的程序需要运行在ARM架构上如vexpress-a9这就需要交叉编译工具链。热词中提到了arm compiler 5但对于开源项目我们更常用的是GNU Arm Embedded Toolchain俗称gcc-arm-none-eabi。为什么选择这个工具链因为它免费、开源、功能完整且被ARM官方维护对Cortex-M/R/A系列处理器支持都很好与RT-Thread的构建系统scons兼容性极佳。安装步骤访问官网或使用包管理器最直接的方式是从ARM官网下载。但通过Ubuntu的包管理器安装更简单版本也足够新。sudo apt install -y gcc-arm-none-eabi安装完成后可以通过arm-none-eabi-gcc --version来验证。如果显示版本号如12.2.1说明安装成功。备选方案手动下载配置如果你想使用特定版本可以去ARM官网下载.tar.xz压缩包解压到/opt目录然后将其bin目录加入系统PATH环境变量。例如sudo tar -xf gcc-arm-none-eabi-12.2-x86_64-linux.tar.bz2 -C /opt echo export PATH/opt/gcc-arm-none-eabi-12.2/bin:$PATH ~/.bashrc source ~/.bashrc实操心得对于学习和一般开发直接apt install安装的版本完全够用省心省力。只有在项目对工具链版本有严格要求时比如兼容特定的编译器优化选项或库才需要手动管理特定版本。2.3 QEMU的安装与验证QEMU是我们的“虚拟开发板”。我们将用它来模拟ARM的vexpress-a9开发板。这是一个由ARM提供的虚拟平台常被用于软件开发和操作系统教学。安装QEMU系统模拟器sudo apt install -y qemu-system-arm这个包包含了针对ARM架构的全系统模拟器qemu-system-arm它能够模拟CPU、内存、外设等整个计算机系统。验证安装安装完成后可以运行qemu-system-arm -machine help来查看支持的机器类型。你应该能在列表中看到vexpress-a9。这一步确认了QEMU已就绪并且支持我们需要的目标平台。2.4 获取RT-Thread源代码RT-Thread的源代码托管在Gitee和GitHub上。我们使用Git来克隆。git clone https://github.com/RT-Thread/rt-thread.git cd rt-thread进入rt-thread目录后你会看到其丰富的源码结构包括内核、组件、驱动、libc等等。我们主要关注bsp板级支持包目录因为我们需要针对特定的“板子”即QEMU模拟的vexpress-a9进行配置和编译。3. 核心环节配置、编译与运行第一个RT-Thread程序环境搭好了现在让我们真正动手让RT-Thread在QEMU里跑起来。3.1 定位并进入目标BSP目录RT-Thread为不同的硬件平台提供了BSP。对于QEMU模拟的vexpress-a9其BSP位于bsp/qemu-vexpress-a9目录。cd bsp/qemu-vexpress-a9这个目录包含了针对这个特定“板子”的所有启动文件、链接脚本、驱动初始化和主应用程序。你可以把它理解为一个完整的、可独立编译的项目。3.2 使用menuconfig进行系统配置RT-Thread使用类似Linux内核的menuconfig工具进行可视化配置这是其强大和易用性的体现。我们可以通过它来裁剪内核功能、选择组件、配置驱动等。生成和打开配置界面scons --menuconfig第一次运行可能会提示安装pkconfig按提示安装即可sudo apt install pkg-config。命令执行后会弹出一个基于终端的图形配置界面。关键配置项解析对于初次运行RT-Thread Kernel确保内核功能如定时器、信号量、邮箱等是开启的。对于学习可以全部保持默认。RT-Thread Components这是配置的重头戏。DFS设备虚拟文件系统可以开启配合elmfat组件后续可以在QEMU中模拟SD卡文件系统。Network开启SalSocket抽象层和lwIP轻量级TCP/IP协议栈。这是让RT-Thread具备网络能力的关键也是很多物联网应用的基础。POSIX.1开启。这允许使用标准的POSIX API如open,read,write,socket极大地方便了从Linux/Unix环境移植代码。Utilities可以开启ulog超轻量级日志和Finsh命令行组件。Finsh非常重要它会在系统运行时提供一个交互式Shell你可以通过串口在QEMU中是标准输入输出输入命令来查看线程状态、内存使用、修改变量等是动态调试的利器。Board Configuration这里可以配置硬件相关参数如系统时钟、串口引脚等。对于QEMU模拟通常保持默认即可。Driver Configuration配置驱动如串口、以太网等。QEMU的vexpress-a9通常模拟了PL011串口和SMSC91C111以太网控制器对应的驱动需要开启。配置完成后选择 Save 保存然后选择 Exit 退出。配置会被保存到当前目录的.config文件中。注意事项menuconfig的导航键是方向键、回车和空格用于选择[*]编译进内核或[M]编译为模块。ESC键可以返回上级菜单。如果不小心改乱了可以删除.config文件然后重新运行scons --menuconfig它会加载默认配置。3.3 编译RT-Thread系统配置好后编译就非常简单了。在bsp/qemu-vexpress-a9目录下直接运行sconsscons是RT-Thread使用的构建工具类似于make但更强大。它会根据你的.config配置调用我们之前安装的arm-none-eabi-gcc交叉编译工具链编译所有选中的源代码。编译过程解读扫描scons会扫描当前目录的SConscript文件这是一个用Python语法写的构建脚本定义了源码文件、编译选项、链接规则等。编译将每个.c文件编译成.o目标文件。链接将所有.o文件、库文件按照链接脚本通常是link.lds的指示链接成一个最终的二进制文件通常是rtthread.elf和纯二进制镜像rtthread.bin。生成最终你会在当前目录下看到rtthread.elf和rtthread.bin等文件。rtthread.elf包含调试信息用于调试rtthread.bin是纯二进制镜像可以直接“烧录”运行。如果编译成功最后会输出类似LINK rtthread.elf和arm-none-eabi-objcopy -O binary rtthread.elf rtthread.bin的信息并显示生成文件的大小。3.4 在QEMU中启动RT-Thread激动人心的时刻到了我们将使用QEMU加载刚刚编译好的RT-Thread镜像。基本启动命令qemu-system-arm -M vexpress-a9 -kernel rtthread.elf -serial stdio -nographic让我们拆解这个命令-M vexpress-a9: 指定模拟的机器类型为vexpress-a9。-kernel rtthread.elf: 指定要加载的内核镜像文件。我们使用.elf文件因为它包含符号信息如果后续需要调试会更方便。-serial stdio: 将模拟板的第一个串口通常是UART0重定向到主机的标准输入输出stdio。这意味着你在终端里输入的内容会发送到“板子”的串口而“板子”串口的输出也会打印到这个终端。这就是我们与RT-Thread交互的“控制台”。-nographic: 不启动QEMU的图形化显示窗口。因为我们模拟的是一个无界面的嵌入式系统所有输出通过串口所以不需要图形界面。这也能节省资源。执行上述命令后QEMU会启动终端开始滚动输出RT-Thread的启动日志。你应该能看到RT-Thread的Logo、版本信息、CPU型号、内存大小最后出现msh 提示符。恭喜你RT-Thread已经在虚拟的ARM板上成功运行了在mshRT-Thread的shell提示符下你可以尝试输入一些命令help: 列出所有可用的命令。list_thread: 查看当前系统中所有线程的状态优先级、栈大小、剩余栈等。free: 查看系统内存使用情况。ps: 类似Linux的ps命令查看线程信息。要退出QEMU可以先按CtrlA然后松开再按X。或者直接在QEMU模拟器中发送关机信号如果系统支持但最简单直接的就是CtrlA, X。4. 进阶实战为虚拟开发板添加网络功能让RT-Thread跑起来只是第一步。一个真正的物联网设备往往需要网络连接。接下来我们配置并启用QEMU的虚拟网络让我们的RT-Thread具备网络能力。4.1 配置QEMU的虚拟网络TAP/TUNQEMU可以通过TAP/TUN设备为虚拟机创建虚拟网卡并连接到主机的网络。我们需要先创建一个TAP设备并配置主机的网络转发。步骤一安装网络工具并创建TAP设备sudo apt install -y uml-utilities bridge-utils # 安装管理TAP和网桥的工具 sudo ip tuntap add dev tap0 mode tap user $(whoami) # 创建名为tap0的TAP设备并让当前用户有权限访问 sudo ip link set tap0 up # 启动tap0设备步骤二配置主机网络转发与IP可选但推荐为了让RT-Thread能访问外网比如ping通百度需要配置主机的IP转发和NAT。sudo sysctl -w net.ipv4.ip_forward1 # 开启IPv4转发 sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE # 假设主机上网网卡是eth0请根据实际情况替换可能是wlan0, enp3s0等 sudo iptables -A FORWARD -i tap0 -o eth0 -j ACCEPT sudo iptables -A FORWARD -i eth0 -o tap0 -m state --state RELATED,ESTABLISHED -j ACCEPT重要提示上述iptables规则在重启后会失效。如果希望永久生效需要将规则保存到特定文件或使用iptables-persistent工具。对于实验环境每次启动前运行一次即可。步骤三为TAP设备分配IPsudo ip addr add 192.168.100.1/24 dev tap0 # 给主机端的tap0分配一个IP作为网关这样我们就创建了一个虚拟的局域网段192.168.100.0/24主机是192.168.100.1。4.2 在menuconfig中启用网络组件回到RT-Thread的BSP目录再次运行scons --menuconfig。进入RT-Thread Components - Network。开启[*] Enable network stack。在network stack子菜单中选择[*] light weight TCP/IP stack(lwIP)。在lwIP配置中可以保持默认或者根据需要调整内存池大小等参数。返回上级确保[*] Enable SAL (Socket Abstraction Layer)被选中。进入Driver Configuration - Network interface devices。找到并开启[*] Enable SMSC91C111X driver。QEMU的vexpress-a9模拟的正是这款以太网控制器芯片。保存配置并退出。4.3 修改网络初始化代码并重新编译通常BSP中已经包含了网络初始化的代码框架但我们需要确保它被正确调用并为网卡设置我们TAP网络对应的MAC地址和IP。找到BSP目录下的board.c或drv_eth.c等文件查找网络初始化函数可能是rt_hw_eth_init。你需要确保这个函数被系统初始化流程调用通常在rt_hw_board_init()函数末尾或单独的组件初始化中。一个更简单的办法是利用RT-Thread的Finsh命令来动态配置网络。但为了自动化我们可以在应用层代码比如main.c或applications目录下的文件中添加静态初始化。这里给出一个在main线程中初始化的示例思路#include rtthread.h #include netif/ethernetif.h #include “lwip/opt.h” #include “lwip/init.h” // ... 其他头文件 int main(void) { /* 用户代码入口 */ // ... 其他初始化 /* 设置网络接口参数 (示例具体函数名需参考BSP驱动) */ // 假设有一个函数叫 set_netif_info // set_netif_info(“tap0”, “00:11:22:33:44:55”, “192.168.100.2”, “255.255.255.0”, “192.168.100.1”); return 0; }实际上更常见的做法是不写死IP而是使用DHCP动态获取或者通过Finsh命令ifconfig来配置。对于QEMU的TAP网络主机192.168.100.1可以配置为DHCP服务器或者让RT-Thread使用静态IP192.168.100.2。由于不同BSP的网络驱动初始化方式略有差异最稳妥的方法是先按照上述menuconfig配置好。直接编译运行。在启动后的msh中使用ifconfig命令查看网络接口。如果驱动加载成功你会看到一个网络接口比如e0。如果接口没有IP使用命令手动设置msh ifconfig e0 192.168.100.2 # 为接口e0设置IP msh ifconfig e0 up # 启动接口测试网络msh ping 192.168.100.1 # 应该能ping通主机 msh ping 8.8.8.8 # 如果主机配置了NAT转发应该能ping通外网修改配置或代码后记得重新编译 (scons)。4.4 启动带网络支持的QEMU现在我们需要在启动QEMU时将虚拟机的网络接口连接到我们刚才创建的TAP设备tap0上。qemu-system-arm -M vexpress-a9 -kernel rtthread.elf -serial stdio -nographic \ -netdev tap,idmynet0,ifnametap0,scriptno,downscriptno \ -device smc91c111,netdevmynet0命令解析-netdev tap,idmynet0,ifnametap0,scriptno,downscriptno: 定义了一个后端网络设备netdev类型是tapID是mynet0连接到主机的tap0接口。scriptno和downscriptno告诉QEMU不要执行任何配置/清理脚本由我们手动管理。-device smc91c111,netdevmynet0: 在虚拟机上添加一个smc91c111网卡设备即QEMU模拟的vexpress-a9板载网卡型号并将其连接到后端网络设备mynet0。启动后按照上一节的步骤在RT-Thread的msh中配置IP并测试网络。如果一切顺利你的虚拟RT-Thread设备就具备了完整的网络功能。5. 开发与调试技巧提升效率的实战经验环境跑通了接下来就是真正的开发。如何在Ubuntu上高效地开发、调试RT-Thread应用这里分享几个核心技巧。5.1 利用VSCode打造集成开发环境虽然可以用任何文本编辑器但VSCode凭借其强大的扩展生态可以极大提升效率。安装VSCode及C/C扩展从官网下载安装VSCode然后在扩展商店搜索安装C/C扩展由Microsoft发布。打开项目文件夹用VSCode打开rt-thread/bsp/qemu-vexpress-a9目录。配置IntelliSenseVSCode需要知道头文件路径和编译定义。最简单的方法是让它基于编译数据库compile_commands.json工作。RT-Thread的scons支持生成它scons --targetvsc -s这个命令会在当前目录生成.vscode文件夹和c_cpp_properties.json配置文件自动包含了所有必要的头文件路径和宏定义。VSCode的C/C扩展会自动读取这些配置从而实现精准的代码补全、跳转和错误检查。配置构建任务在VSCode中按CtrlShiftP输入Tasks: Configure Task选择Create tasks.json file from template-Others。编辑生成的tasks.json添加一个构建任务{ “version”: “2.0.0”, “tasks”: [ { “label”: “Build RT-Thread”, “type”: “shell”, “command”: “scons”, “args”: [], “group”: { “kind”: “build”, “isDefault”: true }, “problemMatcher”: [“$gcc”] } ] }这样你就可以按CtrlShiftB直接编译项目了。配置调试环境可选但强大这是最精彩的部分。你可以用GDB远程调试运行在QEMU中的RT-Thread。首先需要安装GDB多架构版本sudo apt install gdb-multiarch。在VSCode中切换到“运行和调试”视图创建launch.json配置。一个基础的调试配置如下{ “version”: “0.2.0”, “configurations”: [ { “name”: “QEMU Debug RT-Thread”, “type”: “cppdbg”, “request”: “launch”, “program”: “${workspaceFolder}/rtthread.elf”, “miDebuggerServerAddress”: “localhost:1234”, // GDB服务器地址 “miDebuggerPath”: “/usr/bin/gdb-multiarch”, // 调试器路径 “setupCommands”: [ { “description”: “为 gdb 启用整齐打印”, “text”: “-enable-pretty-printing”, “ignoreFailures”: true }, { “text”: “target remote localhost:1234” } // 连接到远程目标 ], “cwd”: “${workspaceFolder}”, “externalConsole”: false, “MIMode”: “gdb” } ] }调试流程在一个终端中用调试模式启动QEMU并等待GDB连接qemu-system-arm -M vexpress-a9 -kernel rtthread.elf -serial stdio -nographic -s -S-s是-gdb tcp::1234的简写表示在1234端口开启GDB服务器。-S表示启动后暂停CPU等待调试器连接。在VSCode中按F5启动调试。VSCode的调试器会通过GDB连接到QEMU。现在你可以在源码中设置断点、单步执行、查看变量和内存了就像调试本地程序一样调试运行在虚拟ARM核心上的RT-Thread。5.2 使用scons命令的高级技巧scons不仅仅是make的替代品它有很多实用参数scons -c或scons --clean: 清理编译产物。scons --targetmdk5/scons --targetiar: 生成对应IDE的工程文件方便在Windows下用Keil或IAR打开如果你需要最终在真实硬件上验证。scons -jN: 启用N个线程并行编译大幅提升编译速度如scons -j8。scons --verbose: 显示详细的编译命令用于排查编译错误。scons --dist: 生成一个项目分发包包含所有必要的源码和配置便于分享或存档。5.3 管理多个应用程序/项目RT-Thread的BSP目录通常有一个applications文件夹用于存放用户应用代码。你可以在这里添加自己的.c文件并在SConscript中将其加入编译。但如果你有多个独立的应用项目更好的做法是利用RT-Thread的“项目”概念。在RT-Thread源码目录外使用rt-thread/tools目录下的menuconfig和scons或者使用Env工具可以创建一个独立于BSP的工程目录。这种方式更清晰便于版本管理。不过对于QEMU开发直接修改BSP下的applications并配合版本管理git也是完全可行的。6. 常见问题与深度排查指南在实际操作中你肯定会遇到各种各样的问题。这里汇总了一些典型问题及其解决方案。6.1 编译失败问题问题现象可能原因解决方案arm-none-eabi-gcc: command not found交叉编译工具链未安装或未加入PATH。确认已安装gcc-arm-none-eabi包或手动安装的工具链路径已正确添加到~/.bashrc并source。fatal error: rtconfig.h: No such file or directory缺少配置文件。先执行scons --menuconfig生成配置或者直接运行scons它通常会先自动调用配置。undefined reference to ‘xxx’链接错误函数未定义。1. 检查menuconfig中是否开启了包含该函数的功能组件。2. 检查对应的源文件是否被加入编译查看SConscript。3. 检查函数名拼写是否正确。scons: *** [rtthread.elf] Error 1一般性编译/链接错误。查看终端输出的最后几行错误信息通常会有具体的错误描述。使用scons --verbose查看详细命令定位到出错的源文件行号。6.2 QEMU运行与启动问题问题现象可能原因解决方案qemu-system-arm: command not foundQEMU未安装。执行sudo apt install qemu-system-arm。qemu-system-arm: Unable to find a valid CPU model-M参数指定的机器名错误。运行qemu-system-arm -machine help确认正确的机器名确保是vexpress-a9。启动后无输出卡住内核镜像文件错误或未指定串口输出。1. 确认-kernel参数指定的.elf或.bin文件路径正确且已成功编译。2. 确保包含了-serial stdio -nographic参数。启动后立即复位或报错编译的RT-Thread镜像与QEMU模拟的硬件不匹配。1. 确认BSP目录是否正确bsp/qemu-vexpress-a9。2. 尝试清理后重新编译scons -c scons。无法输入msh命令终端输入模式问题。确保你是在启动QEMU的那个终端里直接输入而不是在某个可能拦截按键的终端模拟器里。直接敲命令即可不需要额外按回车以外的键。6.3 网络功能相关问题问题现象可能原因解决方案ifconfig看不到网络接口1.menuconfig中网络驱动未开启。2. QEMU启动命令未添加网卡设备。1. 确认已开启SMSC91C111X driver。2. 确认QEMU启动命令包含了-netdev tap...和-device smc91c111...参数。能ping通主机但无法ping通外网(如8.8.8.8)主机未开启IP转发或NAT规则未设置。1. 确认执行了sudo sysctl -w net.ipv4.ip_forward1。2. 确认iptables的NAT和转发规则已正确添加且-o参数后的网卡名是主机实际上网的接口名用ip addr或ifconfig查看。3. 有时需要禁用主机的防火墙sudo ufw disable或添加相应规则。RT-Thread内无法通过DHCP获取IP1. 主机未运行DHCP服务器。2. 网络不通。1. 更简单的方式是使用静态IPifconfig e0 192.168.100.2。2. 如果想用DHCP可以在主机安装dnsmasq并配置为tap0提供服务但这增加了复杂度。QEMU启动报错Could not set up host forwarding rule ‘hostfwd’端口冲突或权限问题。检查是否有其他QEMU实例在运行。确保创建TAP设备的命令有sudo权限。6.4 调试相关技巧QEMU启动后无任何输出但CPU似乎在工作尝试在QEMU命令中增加-d in_asm,exec,cpu等日志参数输出到文件分析。但更常见的是镜像问题。GDB连接不上QEMU确认QEMU是以-s -S参数启动的并且VSCode的launch.json中miDebuggerServerAddress是localhost:1234。检查是否有防火墙阻止了本地回环地址的1234端口。断点不生效确保program路径指向的是包含调试信息的.elf文件而不是.bin文件。编译时scons默认会生成带调试信息的.elf。多线程调试在GDB中可以使用info threads查看所有线程thread id切换线程上下文进行调试。搭建这个环境的过程本身就是一个对嵌入式开发工具链、构建系统、硬件模拟和操作系统启动流程的深刻理解过程。它剥离了具体硬件的不确定性让你能聚焦于软件逻辑和系统本身。当你熟练之后甚至可以修改QEMU的设备树dts来模拟不同的硬件配置或者尝试将RT-Thread移植到其他QEMU支持的平台如virt机器。这个虚拟实验室的潜力只取决于你的探索欲。
返回列表