ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Zephyr RTOS环境搭建全攻略:从Ubuntu到QEMU与真实开发板跑通

Zephyr RTOS环境搭建全攻略:从Ubuntu到QEMU与真实开发板跑通 Zephyr这个词做嵌入式尤其是物联网方向的工程师这两年应该越来越常听到。它是Linux基金会旗下的开源RTOS跟FreeRTOS这类“裸机调度器”不一样Zephyr给人的感觉更像一套完整的现代化嵌入式开发平台设备树、驱动框架、BLE/WiFi/Thread协议栈、低功耗管理、统一的构建系统全部集成好你要做的不是从零拼积木而是基于一个成体系的软件框架去做应用。我最早是被它的蓝牙协议栈吸引的后来发现它的驱动模型和构建工具链在可维护性上确实比传统RTOS舒服太多。这篇文章我就从零开始完整记录一遍在Ubuntu上安装、配置Zephyr环境、编译hello_world并在QEMU和真实开发板上跑通的整个过程。踩过的坑、排查的思路、版本选择的细节都会写出来适合刚准备入坑Zephyr、正在纠结环境怎么搭的朋友参考。我的实际体验是Zephyr环境搭建真正麻烦的地方不在编译本身而在工具链和多仓库代码管理这两层抽象上。如果你只是照着README敲命令大概率会在west init、SDK路径、Python版本这些地方卡住几次。所以下面我会把每一步的“为什么”也讲清楚而不是只丢给你一串命令。1. 环境准备与方案选型先想清楚你在哪搭、怎么搭1.1 为什么首选Linux而不是Windows或macOSZephyr官方长期支持的宿主机系统就是Ubuntu这类Linux发行版。原因很朴素交叉编译工具链、设备树编译器DTC、各种烧录调试工具在Linux下的维护状态最稳定出问题的概率最低社区和官方CI也都是以Linux为主。Windows虽然现在WSL2也能跑但USB设备直通、串口权限、QEMU网络这些环节时不时会出幺蛾子新手一旦踩中会非常挫败。macOS的问题则是brew安装的cmake和dtc版本经常和Zephyr要求的不一致而且ARM交叉工具链在macOS上的支持也相对边缘。所以我的建议很直接如果你有一台能装Linux的电脑哪怕是用虚拟机都优先在Linux下搭。你省下的折腾时间远比切换系统的成本多。我自己就是在一台配置很普通的笔记本上先用VMware虚拟机过了全流程后来才移到物理机上整个过程除了QEMU图形显示稍慢一点没有任何本质区别。1.2 Ubuntu版本怎么选22.04 LTS是目前最稳的起点Zephyr对Ubuntu版本没有硬性要求但工具链的最低版本限制摆在那里CMake 3.20以上、Python 3.8以上、Ninja、DTC。Ubuntu 24.04 LTS默认的软件源版本都比较新装完基本不用折腾Ubuntu 22.04 LTS则是我目前最推荐的选择原因是它默认的gcc、python3、cmake版本都恰好能满足Zephyr 3.x的要求而且如果你后面要装其他嵌入式工具链比如ARM自家工具链、OpenOCD22.04的兼容性验证案例最多。20.04及更早的版本要注意系统自带的cmake是3.16低于Zephyr要求的3.20需要额外升级这个我在后面“常见问题”里会专门讲。另外不管用哪个版本装完系统后第一件事建议先做两件基础操作把apt软件源换成访问速度更合适的国内镜像源然后执行一次sudo apt update sudo apt upgrade把系统补丁打全。这一步不做后面安装依赖时经常出现404或版本过旧的问题。你可以在Ubuntu软件和更新里通过图形界面选择镜像源也可以直接编辑/etc/apt/sources.list文件替换URL操作都不难。1.3 虚拟机还是物理机影响的是调试体验不是学习效果如果你手头没有现成的Linux机器用VMware或VirtualBox装一个Ubuntu 22.04完全够用。我给虚拟机分配4GB内存、2个CPU核心、60GB磁盘跑west update和QEMU仿真都没压力。有一点要注意虚拟机的网络模式建议用“桥接”而不是“NAT”否则后面west init从GitHub拉取代码时偶尔会连接超时桥接能明显改善这个问题。当然如果你要接USB调试器烧录真实开发板VMware需要安装扩展工具才能把USB设备透传给宿主机VirtualBox也要装Extension Pack这一步记得提前做。物理机方案更省心的地方在于串口和USB调试器的权限管理更直接不需要经过虚拟化层。如果你主要目标是评估Zephyr本身、跑QEMU仿真虚拟机完全足够如果是要连着蓝牙设备、USB转串口模块做真机调试我建议优先考虑物理机安装或者至少用虚拟机时提前测试好USB透传。1.4 Zephyr环境本质上是“四个独立组件”的拼装理解Zephyr环境最关键的是把它拆成四个相对独立的部分Python环境包含west命令、Zephyr代码仓库包含zephyr主仓库和众多模块仓库、Zephyr SDK包含交叉编译器、QEMU、host工具、以及系统级依赖cmake、ninja、dtc等。这四个部分每个都可以单独安装和单独出问题排查时也是按这四个维度来定位的。很多初学者把“安装Zephyr”理解成“运行一个安装脚本”然后一切自动搞定这是最大的误解。官方其实没有给你一个一键安装脚本而是刻意把他拆开学会管理这几个组件的版本和路径本身就是用Zephyr进行嵌入式开发的基础功。后面的小节我会按照这个组件维度逐一拆解。2. 系统依赖安装与工具链选型把基础软件一次装齐2.1 用一条apt命令装齐基础依赖在Ubuntu 22.04上Zephyr官方文档列出的依赖包可以用一条命令装完。我实际执行时用到的完整列表如下sudo apt install --no-install-recommends git cmake ninja-build gperf \ ccache dfu-util device-tree-compiler wget \ python3-dev python3-pip python3-setuptools python3-tk python3-wheel \ xz-utils file make gcc gcc-multilib g-multilib \ libsdl2-dev libmagic1这里重点解释几个容易被忽略的包device-tree-compiler提供dtc命令Zephyr的编译过程必须用它把设备树源文件编译成dtb缺少这个会在构建中后段报Could not find DTCgcc-multilib和g-multilib的作用是让宿主机的gcc能生成32位代码Zephyr SDK里有些host工具和QEMU在开发模式下会用到多库支持不装会在链接时报找不到libgcc这类错误libsdl2-dev则关系到QEMU的图形输出少了它QEMU带-display sdl的配置可能无法工作。ccache这个包建议一定装上。Zephyr编译过程涉及大量重复的编译缓存ccache能把二次构建速度提升好几倍尤其是你反复修改一个Kconfig配置然后重新构建时体感差异非常明显。装好之后你不需要做额外配置Zephyr的构建系统检测到ccache会自动启用。2.2 CMake vs Ninja为什么Zephyr选了这对组合Zephyr的构建体系选型很有代表性它用CMake描述整个构建过程但是实际的编译驱动使用Ninja而不是make。原因在于Ninja的目标就是“快”它在增量构建和并行调度上的表现比GNU make好很多。Zephyr项目体量大每次改动设备树或者Kconfig都会触发大量重编译用Ninja可以把增量构建时间压缩到非常可观的程度。你在配置Zephyr环境时不需要手动去管Ninjawest build默认就会调用Ninja生成build目录。只需要确保系统里有ninja-build这个命令。我见过有人装完cmake后把ninja漏掉编译时报CMake Error: Could not find Ninja其实就是因为少了这一个包。2.3 Python版本与虚拟环境强烈建议用venv隔离Zephyr的west工具链和脚本都基于Python官方要求Python 3.8以上。Ubuntu 22.04自带的Python 3.10完全够用。但这里有一个非常重要的实践建议不要直接把west装到系统全局Python环境里。我最早就是图省事直接pip install west结果后来升级包或者装其他Python工具时要么权限冲突要么依赖互相覆盖问题很恶心。推荐的做法是在你自己的项目目录下创建一个Python虚拟环境mkdir ~/zephyrproject cd ~/zephyrproject python3 -m venv .venv source .venv/bin/activate以后每次打开终端时先执行source ~/zephyrproject/.venv/bin/activate再使用west命令。这样west以及它依赖的pyelftools、click、colorama等包都隔离在虚拟环境里以后要清理环境直接删掉目录就行不影响系统。Ubuntu 22.04的pip有时会因为PEP 668限制拒绝往系统环境装包使用venv正好绕开了这个限制。2.4 版本兼容速查哪些坑是版本问题Zephyr对工具链版本比较挑剔但也没有苛刻到必须最新。我整理一个常见版本对照表方便你自查组件最低版本Ubuntu 22.04默认版本说明CMake3.20.03.22.1满足要求无需额外升级Python3.83.10满足要求DTC1.4.6建议1.51.6.1满足要求Ninja1.91.10满足要求GCC宿主机无特别限制11.4满足要求如果你用的是Ubuntu 20.04cmake 3.16就成问题了升级方式有两个一是用pip install --user cmake装新版到用户目录二是添加Kitware的apt源后用apt升级。前者更简单装完记得把~/.local/bin加入PATH。如果dtc版本过低编译设备树时会报解析错误同样只能通过升级解决但22.04基本没有这个烦恼。3. west工具链Zephyr的多仓库管理核心3.1 为什么Zephyr不能直接git clone完事用过Zephyr之后你会发现它不像普通嵌入式库那样一个仓库就搞定。Zephyr主仓库只是核心它通过manifest文件引用了一系列子模块hal_*系列硬件抽象层、zephyr_modules里的第三方库、tools_*工具集等加起来十几个仓库。如果全用git submodule来管理版本一致性和仓库切换会非常痛苦。west就是Zephyr官方为解决这个问题做的元工具。它做的事情本质上和Google的repo类似但实现更轻量。west通过一个west.ymlmanifest文件定义整个项目的仓库集合和每个仓库应该检出的版本你执行一次west update就能把所有子仓库以完全一致的版本拉下来。这个设计带来的好处是Zephyr整个生态的版本是一个整体你切到v3.7.0的manifest所有模块都会自动切到配套版本不会出现Zephyr主仓库和HAL版本不匹配的尴尬。3.2 安装west并初始化项目目录在虚拟环境激活的状态下安装west很简单pip install west然后找一个空目录初始化整个Zephyr工程。以当前主流的v3.7.0分支为例cd ~ mkdir zephyrproject cd zephyrproject west init -m https://github.com/zephyrproject-rtos/zephyr --mr v3.7.0 west updatewest init的作用是把manifest仓库和初始代码拉到本地--mr v3.7.0指定你想要的版本分支。如果你不指定--mr默认拉main分支那是开发版虽然也能用但API变动频繁不建议学习和产品开发时使用。west update是真正拉取所有子仓库的过程需要下载的数据量不小网络好坏直接影响这个步骤的时长。要注意一个容易踩的坑west init要求你所在的目录必须是空目录或者尚未被west管理过。如果你在之前的失败尝试中已经部分初始化过west会拒绝继续执行并提示目录非空。解决方式是删除旧的.west隐藏目录再重试。3.3 west zephyr-export和Python依赖为什么要单独做初始化完成后还需要执行两个补充步骤west zephyr-export pip install -r zephyr/scripts/requirements.txtwest zephyr-export做的事情很关键它把Zephyr的CMake包路径导出到用户级CMake配置目录通常是~/.cmake/packages/Zephyr这样后续你用CMake写外部应用工程时find_package(Zephyr)就能找到对应的构建定义。不做这一步你从west直接构建Zephyr内置的sample没有问题但自己新建应用工程时会找不到Zephyr的CMake模块。pip install -r zephyr/scripts/requirements.txt则是安装Zephyr构建过程中Python脚本依赖的三方库比如pyelftools用于解析ELF文件、elftools相关模块用于镜像生成。不装这个列表编译某些sample和生成hex文件时会出现ModuleNotFoundError: No module named elftools这样的错误。这两步做完代码侧的环境就完整了。3.4 网络条件不理想时怎么办国内网络环境下直接从GitHub拉取这些仓库确实时快时慢。这种情况下我没有特别推荐的“魔法”方案但有几个务实的做法一是把west update安排在网络空闲的时间段执行一次性挂在那里等它跑完二是如果公司或学校有GitHub镜像服务可以把manifest里的仓库URL整体替换为镜像地址三是实在不行就找一台网络条件好的机器把整个zephyrproject目录压缩打包后拷贝过来只要两边系统架构一致这套目录复制过去后修改一下Python虚拟环境路径就能直接用。这个笨办法我在离线内网环境验证过很多次是最省事的一种。4. Zephyr SDK安装交叉编译的关键一步4.1 SDK里装的到底是什么Zephyr SDK不是Zephyr源码而是一整套独立发布的交叉编译工具链和辅助工具包。它里面包含了针对多种目标架构的GCC交叉编译器ARM、x86、RISC-V、MIPS等、对应的binutils、libc库、以及OpenOCD、QEMU等调试仿真工具还有一部分不随系统包发布的host工具。换句话说Zephyr SDK替代了传统嵌入式开发中要分别安装的ARM GCC工具链和调试软件做到了一包覆盖。为什么Zephyr不带一套“apt install gcc-arm-none-eabi”就能编译因为Zephyr支持的架构太多各自需要的编译器版本和配置都不相同而且Zephyr编译需要针对多个目标变体比如ARMv7-M和ARMv8-M的浮点选项不同单独维护这些工具链非常低效。官方统一打包SDK是保证“所有人在同一版本工具链下构建”的最稳妥手段。4.2 下载、解压、运行的完整步骤SDK发布在GitHub的zephyrproject-rtos/sdk-ng仓库。以0.16.8版本为例x86_64架构的Ubuntu下载这个文件cd ~ wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.8/zephyr-sdk-0.16.8_linux-x86_64.tar.xz tar xf zephyr-sdk-0.16.8_linux-x86_64.tar.xz cd zephyr-sdk-0.16.8 ./setup.sh如果你用的是ARM架构的机器比如树莓派上跑Ubuntu应该下载zephyr-sdk-0.16.8_linux-aarch64.tar.xz这个包名字里带_aarch64的才是ARM平台版本别下错了。setup.sh执行时会问你Do you want to install host tools? [Y/n]这里要输入y或直接回车。host tools包括ccache、dtc、ninja等工具的SDK内部版本装上之后即使系统缺少某些依赖SDK也能够自给自足完成构建对排查问题的确省心。整个安装过程需要sudo权限脚本会提示你输入管理员密码。4.3 环境变量怎么配才不容易出错SDK装好后最关键的环境变量是ZEPHYR_TOOLCHAIN_VARIANT它的值固定为zephyr用于告诉Zephyr构建系统优先使用SDK里的交叉编译器而不是系统默认的GCC。另一个变量ZEPHYR_SDK_INSTALL_DIR用于指定SDK的安装路径如果你把SDK解压到了家目录下且目录名保持zephyr-sdk-0.16.8这种官方格式Zephyr构建系统其实能自动探测到它不用手动设置。为了显式控制我更推荐在~/.bashrc里加上export ZEPHYR_TOOLCHAIN_VARIANTzephyr export ZEPHYR_SDK_INSTALL_DIR$HOME/zephyr-sdk-0.16.8修改完记得执行source ~/.bashrc使配置生效。这里有个细节如果以后升级SDK版本一定要同步更新ZEPHYR_SDK_INSTALL_DIR指向新目录否则构建系统会固执地去找旧SDK然后报一个看起来莫名其妙找不到工具链的错。4.4 多版本SDK共存和清理策略Zephyr的版本节奏大约是几个月一个主版本偶尔会需要同时保留两套SDK比如你在维护一个基于Zephyr 3.6的老项目和基于3.7的新项目。SDK的目录设计天然支持多版本共存每个版本独立放在一个目录里你通过环境变量切换即可。我不建议覆盖安装不同版本的SDK到同一个目录最好保持“一个版本一个文件夹”。如果以后想清理直接rm -rf对应SDK目录再删掉环境变量里的路径就行不需要额外的反安装。5. 从hello_world开始编译、运行、真机部署全流程5.1 在QEMU上跑通第一个程序环境全部就绪之后第一次编译建议用QEMU虚拟板省去硬件连接。Zephyr内置了qemu_x86板子定义直接在zephyrproject目录下执行cd ~/zephyrproject west build -b qemu_x86 samples/hello_world构建完成后运行west build -t run你会看到QEMU弹出一个模拟窗口或者标准输出打印串口日志屏幕上滚动出Hello World! qemu_x86这行字。第一次看到这行输出时基本上你的Zephyr环境已经全链路打通了。如果窗口没弹出来通常是SDL显示库缺失了前面提到的libsdl2-dev就是为这个场景准备的补装之后重新运行即可。west build第一次执行会自动创建build目录并把Zephyr默认配置、用户配置、syscall生成等全部串联起来日志会很长耐心等它构建完成。构建结束时你会看到生成的固件大小信息。第二次再编译同一个sample时Ninja的增量构建会快非常多这就是为什么ccache和Ninja这对组合对体验影响如此之大。5.2 深入理解构建产物和目录结构现在打开build目录你会看到大量文件。真正重要的产物在build/zephyr下面文件作用zephyr.elf带调试信息的ELF可执行文件gdbt调试用它zephyr.bin纯二进制固件镜像烧录裸机时用zephyr.hexIntel HEX格式镜像很多烧录器更习惯用这个zephyr.map链接映射文件排查内存布局和符号地址时用zephyr.dts构建时生成的设备树文本编译真实板子时调试很有用我特别建议养成看.map文件的习惯。当你后来遇到RAM溢出或者某个外设地址明明配置了却不生效时.map文件能帮你快速确认到底是什么被链接进了固件、用了多少内存。Zephyr的构建系统会在编译结束时打印RAM和ROM的占用总结这也是快速评估一个sample有多大体量的最直接方式。5.3 换native_sim直接在宿主机上跑如果你觉得QEMU还是有点“隔着”Zephyr还提供了一个更轻量的运行目标native_sim。它把Zephyr编译成一个宿主机原生可执行文件直接在Linux上跑不需要任何模拟器west build -b native_sim samples/hello_world ./build/zephyr/zephyr.exe输出会直接打印在当前终端里。这个模式最大的价值是开发和调试速度极快不需要交叉编译和启动模拟器特别适合做逻辑开发、算法验证、学习内核API。我后来用Zephyr做很多概念验证时都直接用native_sim效果好得惊人。5.4 真机部署以nRF52840 DK为例仿真跑通后真机部署才能真正体现Zephyr的优势。以Nordic的nRF52840 DK开发板为例板子自带J-Link调试器操作非常简单west build -b nrf52840dk_nrf52840 samples/blinky west flashwest flash会自动检测调试器后端并调用J-Link工具烧录固件。如果你使用ST-Link调试器比如STM32F4开发板则需要确保系统里装了OpenOCD烧录命令也是一样的west flash。Zephyr的west已经把板级调试器细节封装好了你不需要学习每种调试器的命令行。这里有一个必须提前做的事Linux下访问USB调试器需要权限。把当前用户加到dialout组sudo usermod -a -G dialout $USER然后注销重新登录否则west flash会卡在无法打开USB设备的报错上。这一步不做你会在烧录这一步浪费大量时间。5.5 menuconfig像配置Linux内核一样配置ZephyrZephyr的一个核心特性是Kconfig配置系统它的用法和Linux内核的menuconfig完全一致。构建一个sample之后你可以运行west build -t menuconfig进入图形化配置界面在这里可以开关模块、调整设备树相关的驱动配置选项。这个界面针对的是Zephyr内核和子系统层的参数不是板级硬件配置。修改保存后重新执行west build即可增量构建会只重新编译受影响的部分。学习Zephyr的过程里我建议把每个sample的prj.conf文件和menuconfig里的实际选项对照着看这能帮你快速理解“配置项→宏定义→实际代码”这条链路。6. 常见问题与排查实录我踩过的坑都在这里6.1 安装阶段的高频错误west init时报错目录非空、pip装west时提示“externally-managed-environment”、west update中途中断这三个我全部遇到过。目录非空的问题前面已经提过解决就是清理.west目录或者换全新目录重来。pip的externally-managed-environment错误是Ubuntu 22.04及以上版本对系统Python环境的保护机制你可以不用系统python3而改用venv也可以在pip命令后面加--break-system-packages参数强行安装但后者不推荐。west update如果因为网络中断而失败不要慌重新执行west update即可west会基于已经拉取的部分继续补全不会从头再来。6.2 编译阶段最典型的三个报错第一个是CMake Error: Could not find Zephyr SDK。原因几乎都是ZEPHYR_TOOLCHAIN_VARIANT没设或者SDK路径不对。按第4.3节重新检查环境变量即可。第二个是链接错误提示缺少libgcc或者-mfloat-abi相关的选项。这个问题在32位x86目标或某些ARM目标上出现一般是宿主机的gcc-multilib没装。把第2.1节里的gcc-multilib g-multilib装上基本就能解决。第三个是dtc: command not found。这是少了device-tree-compiler包。如果你已经装了但版本太旧可以尝试sudo apt install --only-upgrade device-tree-compiler。我遇到过一次比较隐蔽的情况SDK的host tools里自带了一个dtc它的路径在系统dtc之前被调用导致编译时使用的工具版本非常老解决方法是在~/.bashrc里把SDK的host tools路径从PATH中移除强制使用系统dtc。6.3 运行和烧录阶段的权限坑west flash报Permission denied或者Could not open device /dev/ttyACM099%是用户权限问题。加入dialout组后再重新登录即可。有个小技巧加入组后不需要重新启动整个系统注销再登录一次或者执行newgrp dialout就能在当前会话里生效。QEMU在虚拟机里运行慢的问题偶尔也有人遇到。我给的建议是给虚拟机分配2个以上CPU核心并且确保在VMware里开启了VT-x/AMD-V嵌套虚拟化支持QEMU的图形输出和运行速度都会有明显改善。6.4 一次性梳理的常用操作命令速查这里整理一份我自己日常最常用的west命令清单贴在笔记本上可以少翻很多文档命令用途west build -b board sample编译指定开发板的程序west build -t run运行镜像QEMUwest build -t flash烧录到真实开发板west build -t menuconfig打开Kconfig配置界面west build -p auto sample清理后重新构建配置改动后建议用west build -d build/boardA sample指定构建目录可同时保留多套构建west boards列出所有支持的开发板west flash --runner runner指定烧录后端jlink/openocd等其中west build -p auto这个参数值得单独说。当你修改了prj.conf或设备树覆盖文件后如果构建系统没有自动识别到改动加-p auto会强制它感知配置变更并从正确的状态增量构建。我遇到过几次改了prj.conf但编译结果不变的情况最后都是靠-p auto解决的。6.5 两个能显著提升效率的习惯最后分享两个我个人的使用习惯。第一个是每次进入Zephyr工作目录先激活虚拟环境然后检查west版本和ZEPHYR_BASE是否指向预期的仓库这两个命令分别是west --version和echo $ZEPHYR_BASE各一秒能省去排查半天后才发现“哦我用的不是同一个环境”的尴尬。第二个习惯是给自己的应用工程建立独立的构建目录比如用-d build/test1和-d build/test2分别保存不同配置的构建产物。因为Zephyr构建目录只要还在你就保留了整套配置现场可以随时回到之前调试的状态这个体验在做复杂实验时尤其有用。有一次我为了对比两个驱动配置同时在两个目录里保存了不同的编译结果来回切换快了非常多。Zephyr这套环境第一遍搭会觉得步骤多、概念抽象但当你把west、SDK、Kconfig这几样东西真正理解之后后续换板子、加驱动、移植代码都会顺畅很多。这篇提到的所有步骤我都按从零到跑通的过程验证过遇到报错时按“系统依赖→Python依赖→SDK→west仓库”的顺序逐层排查基本几分钟内就能定位问题。祝你在Zephyr的世界里玩得开心。
返回列表