☰
OpenBMC开发环境从零搭建:Yocto与BitBake实战指南
2026/10/5 5:00:48 网站建设 项目流程

写博客文章这件事,说实在的,能讲清楚"OpenBMC开发环境怎么搭"的内容其实很少。不少朋友一上来就像搞STM32那样,下载个Keil、装个CMSIS包就想开干,结果面对一堆Yocto、BitBake、Layer的概念直接懵掉。我在这个系列第1篇里已经把OpenBMC是什么、它解决了什么问题大致过了一遍,这篇就纯粹聚焦在"怎么把开发环境从零搭起来"。这是一个必须迈过去的坎,因为OpenBMC不是一个普通的单仓库项目,它是一整套嵌入式Linux发行版构建体系,环境搭不好,后面的硬件移植、BMC功能开发全是空中楼阁。这篇文章适合刚接触OpenBMC、或者卡在第一次构建过不去的同学,内容会从底层原理讲到具体命令,再到我实际踩过的那些坑,一次性把环境这件事讲透。

1. 为什么OpenBMC的构建环境比普通嵌入式项目重得多

先说句得罪人的话:如果你拿单片机IDE那套思路来搭OpenBMC环境,大概率头一天就会崩溃。这还真不是OpenBMC故意折腾人,而是它的构建本质决定了复杂度。BMC本身是一个完整的Linux小系统,包含内核、文件系统、启动引导、各种系统服务,你要为不同服务器主板定制它,就相当于为那块BMC芯片编译出一个完整可运行的Linux发行版。这个工作量不是一个Makefile、一个CMake工程能扛下来的,所以OpenBMC选择了Yocto Project体系。

1.1 Yocto和BitBake:OpenBMC构建体系的底层逻辑

Yocto到底是什么,我用一句话概括:一个可以自定义嵌入式Linux发行版的构建框架。OpenBMC基于它做二次开发,所以整个构建过程就是把源码、补丁、配置文件、编译规则全部喂给BitBake,由BitBake按照依赖关系依次执行任务。

BitBake你可以理解为强化版Make。它干的事情包括:解析所有recipe(配方文件,描述"软件从哪下载、补丁怎么打、依赖什么东西、怎么编译安装")、构建依赖图、然后调度任务执行。比如你要构建最终的系统镜像,BitBake会先看镜像依赖哪些包,包依赖哪些库,库依赖哪些源码,一层一层往上推,直到把所有依赖都构建出来。

OpenBMC的源码树就是由几十个Git仓库组成的,分别对应不同的layer。layer是Yocto里组织元数据的单元,OpenBMC里常见的如meta-phosphor、meta-evb、poky等,每个layer里放着若干recipe,加上机器配置和发行版配置。BitBake在构建时会读取build目录下的bblayers.conf,把用到的layer路径都列出来,然后在所有layer里搜索recipe,构建出一棵完整的依赖树。

所以,你要搭开发环境,本质上是在宿主机上构建这套Yocto/BitBake体系,而不是像普通项目那样一个git clone + make就能完事。理解了这一点,后面的步骤就顺理成章了。

1.2 磁盘、内存和网络:容易被低估的三道门槛

很多人在环境搭建中段放弃,不是命令敲错,而是硬件资源先扛不住了。先给一个我亲测的安全线:

  • 磁盘:OpenBMC构建过程会大量下载源码包并编译,构建目录占用通常在50GB到80GB之间。加上源码本身、sstate缓存、下载缓存,建议至少预留120GB,少于80GB真的会在某个包编译到一半时突然报磁盘满。
  • 内存:16GB起步。我曾在8GB内存的机器上试过,编译并行一拉高,内存直接吃满触发OOM,BitBake进程被杀,留下的构建日志完全没法看。
  • CPU:多核非常有优势,因为BitBake会并行跑任务。4核能跑,16核能明显缩短首次构建时间。
  • 网络:源码和依赖包来自GitHub、SourceForge等众多海外源。如果你的网络环境访问这些地址不太稳定,首次构建会非常痛苦,因为任何一个fetch任务失败都可能中断构建。后面我会细说应对方案。

另外,操作系统建议直接用Ubuntu 22.04 LTS。OpenBMC官方文档的依赖验证基本都在这个版本上跑过,Debian、Fedora不是不行,只是遇到问题时你很难判断是环境问题还是OpenBMC问题,经验不足时别给自己额外加难度。

2. 宿主机选型与依赖安装:一次配齐,省得后面反复翻车

资源门槛确认自己能接受之后,就可以真正动手准备宿主机了。这一步不难,但细节很多。我见过不少人装到一半依赖不全,然后构建时报错,只能回头一个一个装包,非常消磨耐心。

2.1 推荐的操作系统与版本

拿Linux发行版来说,Ubuntu 22.04 LTS是最稳的选择。如果你还在用18.04这种老版本,建议先升级系统再继续,否则新版OpenBMC的某些recipe会用到比较新的工具链特性,老系统的gcc和python版本可能不满足要求。Python版本也要注意,OpenBMC当前主线要求Python 3.8以上,Ubuntu 22.04默认自带的是3.10,完全够用。

如果你在WSL2里构建,我不拦你,但我得提醒几个潜在坑:WSL2的文件系统在跨Windows和Linux边界时性能很差,把openbmc源码放在Linux虚拟磁盘里会好很多;另外某些Yocto脚本对systemd有依赖,WSL2默认没有完整systemd,可能需要额外配置。真要长期做OpenBMC开发,买台工作站跑原生Linux,能省下一大堆奇怪问题。

2.2 两个常见但隐蔽的坑:root用户和文件系统

BitBake有个硬性限制:不能以root用户执行构建。这是Yocto的设计理念,防止构建过程中对宿主机造成不可控影响。好多朋友拿到服务器一看是root登录,直接source环境变量,然后BitBake瞬间报错,中文搜索半天才明白是root账户的问题。所以请务必创建一个普通用户来构建:

sudo useradd -m -s /bin/bash bmcdev sudo passwd bmcdev su - bmcdev

另一个坑是文件系统。Yocto要求源码路径必须位于大小写敏感的文件系统上,因为Linux内核源码里有很多同名但大小写不同的头文件,如果构建目录在大小写不敏感的FAT/NTFS挂载点上,报错会非常诡异,而且不是你代码的问题。绝大多数原生Linux没问题,但如果你把源码放在Windows共享目录、或者某些特殊挂载配置下,就要格外留意。

2.3 编译OpenBMC需要哪些系统依赖包

下面这组依赖是我在Ubuntu 22.04上验证过的,基本涵盖了OpenBMC构建所需的核心工具:

sudo apt update sudo apt install -y \ git python3 python3-pip python3-venv \ gcc g++ make \ libssl-dev libncurses-dev libelf-dev \ flex bison chrpath gawk \ texinfo diffstat lzop cpio \ wget xz-utils unzip zip bzip2 \ lz4 zstd

简单说下这些包的作用。gcc/g++/make是编译工具链基础;flex和bison是词法/语法分析器,内核和U-Boot编译时要用;chrpath、gawk、diffstat、texinfo是Yocto/OpenEmbedded构建时需要的辅助工具;libssl-dev提供OpenSSL头文件,kernel配置和某些recipe依赖它;lz4和zstd是压缩格式工具,镜像打包阶段会用到;cpio、xz-utils、lzop用于处理initramfs和各种压缩包。

装完之后顺手确认一下版本:

git --version python3 --version gcc --version

别小看这一步,后面很多莫名其妙的报错,其实都是某些工具版本过老或压根没装。系统准备好之后,下一步就是拉取OpenBMC源码。

3. 用repo拉取OpenBMC源码:理解manifest比敲命令更重要

看到repo这个工具,从没接触过Android或Yocto生态的人可能一脸茫然。它其实就是一个Python写的仓库管理脚本,用来同时同步管理多个Git仓库。OpenBMC整个工程由几十个Git仓库组成,如果一个个git clone,不但容易漏,版本还会对不齐。repo就是来解决这个问题的。

3.1 为什么OpenBMC要用repo管理几十个Git仓库

OpenBMC的代码组织方式是这样的:根目录下有一个manifest仓库,里面放着一个default.xml文件,这个文件列出了所有子仓库的"地址 + 版本号(通常是commit id或branch)"。repo init就是读取这个manifest,建立一个索引;repo sync则按照索引把每个仓库都clone到本地。

这种结构最大的好处是版本可固化。比如OpenBMC发布一个稳定版本,manifest会锁定每个子仓库到特定commit,你repo sync出来的代码,和别人repo sync出来的就是一模一样,不会因为某个子仓库更新导致构建结果漂移。对于需要长期维护BMC固件的团队来说,这一点至关重要。

3.2 repo的获取、初始化与目录结构

repo工具的安装很简单,Ubuntu 22.04可以直接用系统包:

sudo apt install -y repo

如果系统源里没有,也可以直接用Google发布的repo脚本:

mkdir -p ~/bin curl https://storage.googleapis.com/git-repo-downloads/repo -o ~/bin/repo chmod +x ~/bin/repo export PATH="$HOME/bin:$PATH"

然后设置Git用户信息,否则后面的提交相关操作会报错:

git config --global user.name "Your Name" git config --global user.email "your.email@example.com"

接下来初始化并同步OpenBMC源码:

mkdir -p ~/openbmc cd ~/openbmc repo init -u https://github.com/openbmc/openbmc.git -b master repo sync -j8

-j8表示并行下载8个仓库,如果你的网络带宽够大,可以调到-j16。同步完成后,你会看到目录里除了拥有所有manifest指定的子仓库,还有几个重要入口文件,其中包括oe-init-build-env,这是后面构建环境初始化的脚本,它实际是个符号链接,指向poky仓库里的对应脚本。

3.3 首次repo sync的体验与失败补救

首次同步下载量不小,具体看网络环境,从几分钟到几十分钟都可能。我遇到最多的问题是中途某个仓库fetch失败。这种情况不用从头再来,重新执行一次repo sync即可,它会跳过已经完成的仓库,只拉取剩余的,断点续传体验还算不错。

如果某些仓库反复失败,可以用repo sync -f强制继续,或者用repo sync --no-tags跳过tag拉取减少网络压力。另外,如果你所在网络环境访问GitHub确实不稳定,优先检查是否能调整网络配置让连通性变好,或者让熟悉网络的人配一个稳定的访问通道,但这不是OpenBMC本身能解决的问题。团队开发时,更推荐的做法是把源码仓库镜像到内网Git服务器,大家从内网同步,速度和稳定性都会好很多,这也是我目前实际采用的方式。

4. 初始化bitbake构建环境:从source到第一个镜像

源码就位之后,就可以进入构建环节了。这里说的"构建环境初始化"和前面装系统依赖是两码事,它是指准备好BitBake运行所需的全部环境变量和配置文件。

4.1 oe-init-build-env执行后发生了什么

进入源码根目录,执行:

source oe-init-build-env

注意是source,不是直接执行脚本,因为要设置当前shell的环境变量。执行之后,终端会进入build目录(如果不存在会自动创建),并提示环境设置成功。这个脚本主要做了几件事:

  • 把BitBake和各类工具脚本的路径加入PATH
  • 设置若干与Yocto相关的环境变量
  • 如果build/conf下还没有local.conf和bblayers.conf,会从默认模板复制生成

打开build/conf/local.conf看一看,会发现里面全是注释和默认配置。这是整个构建的最核心配置文件,机器类型、并行度、下载目录、缓存目录全在这里定义。

4.2 选择MACHINE:决定你为哪块板子构建

OpenBMC里MACHINE这个概念对应的是具体的BMC硬件平台,而BMC通常集成在服务器主板上,所以MACHINE一般以服务器型号命名。比如IBM的witherspoon对应Power9服务器,Facebook的fby35对应其某一代整机柜硬件,ASPEED的ast2600-dcscm对应基于ASPEED 2600的评估板。

查看OpenBMC支持哪些MACHINE,可以这样:

bitbake-layers show-recipes "*-machine-*"

或者更直接一点,看meta-*各layer里的conf/machine目录。

选好你的板子之后,编辑build/conf/local.conf,把MACHINE改掉:

sed -i 's/^MACHINE ?=.*/MACHINE = "witherspoon"/' conf/local.conf

不推荐用命令行临时指定MACHINE,因为每次执行bitbake都要重复带参数,而且其他工具(比如runqemu)也会读local.conf里的配置。直接固化到文件里最省心。

这里顺便说一下,OpenBMC不同版本对镜像目标(image)的命名有差异,常见的是obmc-phosphor-image。它是完整系统镜像,包含了内核、文件系统、初始化脚本以及所有BMC服务。如果你只改了个服务想快速验证,也可以只构建单个包(比如bitbake bmcweb),但完整镜像才是最终要烧录到硬件上的。

4.3 首次构建obmc-phosphor-image的完整流程

配置好MACHINE之后,执行:

bitbake obmc-phosphor-image

这就是整个环境搭建里最考验耐心的一步。首次构建需要解析所有recipe、下载源码包、交叉编译内核与上百个软件包,在我的机器上(16核32GB内存,网络良好)大概要四五个小时,配置差一点通宵也是常事。

构建过程中,终端会滚动大量输出。有几种日志你需要知道去哪看:

  • 当次构建的cooker日志:build/tmp/log/cooker/[MACHINE]/console-latest.log
  • 每个recipe的具体任务日志:build/tmp/work/[MACHINE]/.../temp/log.do_compile

首次构建如果中途失败,不要直接重新跑。先去console-latest.log里看失败任务和错误行,绝大多数问题都出在网络下载和系统依赖上,对症解决往往比盲目重跑快得多。

5. 构建产物拆解:镜像、内核与落盘验证

构建成功后,你会在build/tmp/deploy/images/[MACHINE]/目录下看到一堆产物。别急着烧录,先搞清楚每个文件是什么,不然拿错镜像刷进板子是会翻车的。

5.1 deploy目录下的各种image文件

以witherspoon为例,构建完成后这个目录里大致有以下几类文件:

文件用途说明
obmc-phosphor-image-witherspoon.static.mtd完整静态镜像(MTD格式),可以直接烧写到BMC的Flash芯片,这是用的最多的文件
obmc-phosphor-image-witherspoon.static.mtd.tar多个镜像段打包,适合用烧录器刷写NAND等分区
obmc-phosphor-image-witherspoon.tar非静态镜像的打包版本
zImage/uImage内核镜像,具体名字取决于kernel类型
u-boot.binU-Boot引导程序
*.dtb设备树二进制文件

不同MACHINE的文件名会对应变化,但核心规律是一致的。.static.mtd这种格式是OpenBMC烧写到SPI Flash的最常用格式,很多BMC刷机工具(比如flashrom)都支持直接刷这个文件。

5.2 用QEMU把镜像跑起来验证环境

手头没有真实硬件时,可以用QEMU验证构建产物。OpenBMC默认支持部分MACHINE在QEMU中运行,最常用的是qemuarm和ASPEED系列。

执行前确认已经source了构建环境,然后直接在build目录下运行:

runqemu nographic

runqemu会读取当前MACHINE,自动匹配对应的内核、设备树和镜像。如果报错提示找不到qemu-system-arm,先安装:

sudo apt install -y qemu-system-arm qemu-system-x86

启动后你会看到一个OpenBMC的登录提示,通常用户名是root,没有密码或默认密码见对应machines表。能进入shell,就说明你的构建环境已经完全打通,后面的开发工作有了一个可以用来验证的基线。这一步我建议每个人都做一遍,别直接拿真机试。真机刷机是有风险的,万一镜像不对导致BMC起不来,又得拆机用烧录器恢复,非常麻烦。

6. 日常开发必会的bitbake操作与加速技巧

环境跑通只是开始,后面修改代码、重新构建才是常态。BitBake的命令不少,但真正日常高频用的就那么几个,掌握之后效率会提升很多。

6.1 最常用的bitbake命令组合

# 查看某个软件包是否存在及当前配置 bitbake -s | grep bmcweb # 只构建单个软件包 bitbake bmcweb # 进入某个软件包的开发shell,可以查看源码目录和编译环境 bitbake -c devshell bmcweb # 清理某个包的编译输出,保留下载的源码 bitbake -c clean bmcweb # 清理编译输出、sstate缓存和源码,比较彻底 bitbake -c cleanall bmcweb # 忽略某些任务失败,尽量把其余任务跑完 bitbake -k obmc-phosphor-image

我建议重点掌握-c devshell。它会打开一个已经配置好交叉编译环境的shell,并把你带到该软件包的源码目录。很多排查问题的工作(比如临时修改编译参数、手动执行configure)在这个shell里做非常舒服。

6.2 DL_DIR、SSTATE_DIR和并行度配置

第一次构建最耗时是因为所有源码包都要从网络下载,并且所有包都要从头编译。第二次构建如果改动很小,为什么还是慢?大概率是你没有配好sstate缓存。

在local.conf里,有几个变量值得专门配置:

DL_DIR = "/home/bmcdev/openbmc-downloads" SSTATE_DIR = "/home/bmcdev/openbmc-sstate" BB_NUMBER_THREADS = "16" PARALLEL_MAKE = "-j 8"

DL_DIR是源码包下载缓存目录,默认在build/downloads。这个目录我强烈建议独立出来,因为有几十GB的源码包,如果放在build目录里,哪天清理build时不小心删掉,下一轮构建又得重新下载。

SSTATE_DIR是sstate缓存,BitBake会在这里缓存每个任务的输出。增量构建时,如果任务输入没有变化,BitBake会直接从sstate恢复结果,而不重新编译,这是Yocto增量构建快的核心原因。我的经验是给sstate目录留个50GB,开发中反复改代码验证时能省大量时间。

BB_NUMBER_THREADS控制BitBake并行任务的线程数,PARALLEL_MAKE控制每个任务内make的并行度。这两个值不是越大越好,建议根据CPU核心数和内存大小调整,16核心机器上面那组配置就挺合适。

6.3 添加自定义layer和recipe的快捷路径

OpenBMC开发场景里,最常见的需求是我要加一个自己写的服务,或者把一个已有软件包编译进BMC镜像。正确姿势是创建一个自定义layer,而不是去改OpenBMC自带layer。

cd ~/openbmc bitbake-layers create-layer meta-mycompany bitbake-layers add-layer meta-mycompany

create-layer会自动生成一个标准的layer骨架,里面包含conf/layer.conf和一个示例recipe。然后在你自己的layer里添加recipe,比如recipes-mine/myhello/myhello.bb,里面写清楚源码位置、依赖和安装方式。这样一个新的BMC服务就能被BitBake识别、构建并打进镜像了。

初学阶段最容易犯的错是直接把recipe塞进现有layer里。短时间内看着能用,但一旦上游更新或你同步代码,改动很容易被覆盖或冲突。自定义layer是Yocto社区推荐的隔离方式,也是OpenBMC实际项目里团队协作的基础。

7. 高频构建失败场景与排查链路

不管前面准备多充分,构建失败几乎是每个人都会遇到的事。重要的是有一套排查思路,而不是病急乱投医。我把最常见的三类失败场景和排查链路整理出来。

7.1 FetchError类报错:从日志定位到恢复

报错信息里出现"Fetcher failure"或"Unable to fetch URL"时,多半是某个源码包下载失败。这种错误需要先看日志确认是哪个recipe、哪个URL:

tail -100 tmp/log/cooker/[MACHINE]/console-latest.log

确定失败URL后,手动在浏览器或wget里访问一下,判断是URL失效、网络不稳定还是域名解析问题。代码网上游可能删除旧版本,导致某个版本hash失效,这时往往需要同步最新代码或者调整SRCREV到有效提交。如果单纯是网络抖动,清理掉残留的未完成下载文件再重试:

rm -rf tmp/downloads/<filename>* bitbake <target>

不要嫌这个动作粗暴。BitBake对下载缓存有校验,一个不完整或损坏的下载文件会导致它反复失败,删掉让BitBake重新下载反而是最快的恢复方式。

7.2 磁盘空间告急与清理姿势

构建到一半提示"No space left on device",这时候先看空间去哪了:

df -h du -sh tmp/*

如果build/tmp占了大头,优先尝试局部清理:

bitbake -c cleanall <你不需要的包>

或者把sstate缓存目录里的临时任务缓存清掉一部分。如果还是不够,只能删除整个build/tmp/work目录重新构建,但代价是之前的所有编译输出都没了,时间成本很高。所以我还是强调那句:磁盘往大里准备,120GB是舒适线,最好能用独立分区或独立目录管理。

7.3 编译错误和host工具版本冲突的排查思路

编译错误(Configure failed、Compile failed)的排查要稍微动点脑子。首先确定报错的包,再去看该包的具体编译日志:

find tmp/work -path '*<包名>*/temp/log.do_compile' -exec tail -80 {} \;

日志里能看到具体的编译命令和错误行。很多"编译错误"其实是宿主机缺少依赖导致的,比如之前提到的libssl-dev没装,OpenSSL相关头文件找不到,报错信息却是编译某个c文件失败,容易让人误判。

还有一种诡异情况是host工具版本太新,和某些老版本recipe不兼容。比如新版gcc对某些警告当错误处理,导致老代码编译失败。这种情况优先看看OpenBMC主线是否已经修复,如果主线没动,多半是当前分支和你的MACHINE不匹配,换到官方支持的组合即可。不要花太多时间自己去fix这类环境问题,性价比很低。

8. 我反复使用后总结的几点经验

环境搭了已经不止一次,几个小经验写在最后,算是给后面的人提个醒。

第一,首次构建最好挑一个空闲时间,比如周五下班前把构建挂上,周六再来验收。中间失败的概率不低,留足时间余量心里不慌。第二,local.conf里把DL_DIR和SSTATE_DIR独立出来之后,千万别再手滑删掉,这两个目录一个是源码包缓存,一个是任务缓存,删了都会让下一轮构建退回到"从零开始"的状态。第三,遇到问题先看日志再看报错,很多人只看终端最后几行红色文字就开始上网搜,效率非常低。BitBake的日志体系已经很成熟,console-latest.log和各任务的temp日志几乎能覆盖所有问题线索,学会看日志是OpenBMC开发的必修课。

环境通了,后面的路就好走了。下一篇我打算顺着这个构建环境,聊聊怎么改一个真实的BMC服务代码,并用devtool做修改验证,感兴趣的话可以先把这套环境跑起来,到时候直接上手试效果。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询