news 2026/10/5 1:30:23

OpenBMC开发环境构建实战:从Yocto到硬件移植的完整指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
OpenBMC开发环境构建实战:从Yocto到硬件移植的完整指南

OpenBMC 的活真不是说拿来就能开工的,光是把编译环境拉起来就有不少人卡在头三天。玩过 Yocto 的朋友都知道,那套东西和你平时 nginx 直接 make 完全不是一个量级——依赖多、下载量大、编译时间长,动不动就是二三十 GB 的磁盘空间、一晚上的全量构建。这还是在网络畅通、工具链熟悉的前提下。要是再把“硬件移植”这件事加进来,比如给一块新板子加 OpenBMC 支持,那开发环境构建就更像是一场需要提前排雷的工程,而不是单纯的搭环境。

这篇文章聚焦 OpenBMC 开发里的第二步:构建一套能正常编译、能输出固件镜像、能直接用于后续硬件移植的开发环境。说清楚目录结构怎么摆、bitbake 怎么跑、新板子怎么加、踩坑怎么排。既有命令也有思路,配着实操记录讲,尽量让看的人少走点弯路。

1. 先把 OpenBMC 的工程构成和构建原理理清楚

1.1 它不是一个仓库,而是一堆仓库

OpenBMC 是 Linux Foundation 托管的开源项目,但这玩意儿不是“clone 一个仓库改一行就能跑”的项目。从代码组织方式上看,它是由一个主仓openbmc/openbmc加无数个下一级子模块组成的多层次结构。主仓里包含的更多是元数据、构建策略和各子模块的版本指针,真正的板级代码、C++ 服务(比如 phosphor 系列)、Kernel 补丁、U-Boot 源码、BIOS/BIOS 相关的 fw 接口,都是以 Git 子模块的方式嵌进来的。

这一点和 Android 的 repo 管理方式有点像。最初玩的时候,如果你只浅层 clone 主仓,进去会发现meta-phosphor、meta-aspeed、qemu这些目录内容是空的。必须先git submodule update --init --recursive把全部子模块拉下来,构建系统才看到真正的源码。

从构建系统角度,OpenBMC 用的是 Yocto Project,底层是 BitBake 和 OpenEmbedded。BitBake 是任务执行引擎,OpenEmbedded 的 meta 层负责描述“从源码到镜像”的每一个 step。OpenBMC 的本质就是若干 OE 层叠加,比如meta-phosphor放通用 BMC 功能,meta-aspeed放 ASpeed 芯片相关,meta-google、meta-facebook、meta-ibm等对应各家的板子。

理解这个结构,构建环境才不会瞎。你处理的问题分几类:主仓构建逻辑调整、某个 meta 层的新增改动、某个 C++ service 的独立编译、kernel 补丁的修改。它们处理的手段不太一样,但都在同一套 bitbake 工作流里。

1.2 为什么构建环境比代码本身更考验人

说句实在话,OpenBMC 的代码修改多数是模块化的,改一个 D-Bus 方法或者调一个 phosphor-state-manager 的行为,很多工程师能搞定。但构建环境这一关,卡住的概率反而最高。原因有三点:

第一是依赖链太长。从 host 系统的 gcc/make 到 Python 模块,到chrpath、diffstat、texi2html这些工具,任何一环缺了或者版本不对,都可能在某次 parse 阶段报错。第二是下载量大。OpenBMC 构建会拉取 Linux Kernel、U-Boot、OpenSSL、glibc 等大批量的源码包,动辄四五个 GB,网络稍不稳定就失败。第三是环境的一致性要求高。Yocto 官方支持 Ubuntu 和 Fedora 系列,但即便是 Ubuntu,不同版本对 Python、make 的版本要求也不一样,直接用错宿主环境,编译到一半才暴露问题是常有的事。

所以,构建开发环境的本质不光是“能把命令跑通”,而是搭建一个稳定、可复现、利于调试的宿主系统。这块值得花时间认真对待,省得后面移植新板子时,每次改一个 dts 都要重新痛苦挣扎一遍。

2. 搭建 OpenBMC 构建环境的前期准备

2.1 主机系统怎么选

官方一贯推荐 Ubuntu LTS,我自己在 Ubuntu 20.04 和 22.04 上都跑过,20.04 配老版本 OpenBMC 更顺滑,22.04 在编译速度上略好。如果你是纯新手,我建议直接用 Ubuntu 22.04,遇到问题社区匹配度高,依赖安装也容易。

CPU 没硬性限制,但核心数直接决定编译时间。我在自己的机器上实测过,8 核 16 线程编译witherspoon这类完整镜像,全量大概需要 3 个小时左右;16 核 32 线程能压到 1.5 到 2 小时。内存建议至少 16GB,低于这个数,并行编译任务稍微开多点就会爆内存,bitbake 直接显示MemoryError或者被 OOM-killer 杀掉。

磁盘空间是容易被低估的点。OpenBMC 构建时,build/downloads里保存所有源码包,build/tmp里放编译产物和 sstate 缓存。首次构建一个基本镜像,容易摸到 20GB;如果多编译几个目标板型,翻倍也正常。所以分区至少留 100GB 才玩得开。我当时犯过错误:根目录只有 60GB,编到一半磁盘满,整个构建目录都坏了,只能删掉tmp重新来。

2.2 系统依赖安装清单

不同 Linux 发行版装依赖的命令不同,Ubuntu/Debian 系我整理了一份比较完整的最小集,照着装就行:

sudo apt update sudo apt install -y \ git python3 python3-dev python3-venv python3-setuptools \ gcc g++ make cmake ninja-build \ gawk wget diffstat texinfo chrpath \ rsync cpio file socat iputils-ping \ libssl-dev liblz4-tool zstd \ bison flex autoconf automake libtool \ libncurses-dev libxml2-utils \ unzip zip xz-utils \ bc u-boot-tools

注意,不同 OpenBMC 版本对 host 包的要求略有差异,但上面这套基本覆盖 90% 的场景。如果 build 过程中 BitBake 提示缺了某个 host 工具,按提示补装即可。

还有个小细节:Ubuntu 20.04 自带 Python 3.8,而 22.04 是 3.10,都不影响编译 OpenBMC 的源码包,因为 Yocto 构建时用的是它自己下载到tmp/hosttools里的一套工具链,宿主机的大多数工具只用于“启动构建环境”。只有少数如git、tar、gzip这类底层工具会直接调用宿主版本,所以宿主里别装些奇奇怪怪的 alias,避免干扰。

2.3 拉取代码与子模块初始化

OpenBMC 主仓现在体积也不小,直接普通 clone 没问题,但建议加--recursive一次性把所有子模块拉下来:

git clone https://github.com/openbmc/openbmc.git --recursive

如果之前只 clone 了主仓而忘了递归子模块,可以在主仓根目录里补:

git submodule update --init --recursive --depth=1

推荐加--depth=1的原因很实际:OpenBMC 的历史提交非常多,完整拉取所有历史会占用巨大空间,而绝大多数人只需要最新状态。尤其子模块里包含 Linux Kernel 这类仓库,全历史动辄几个 GB,depth 限制能省很多时间和磁盘。

有一点要提醒:OpenBMC 子模块的分支切换和主仓版本是联动的,不要乱 checkout 某个子模块的 master 分支。如果主仓指向某个特定 commit,子模块也要保持对应 commit,否则构建时大概率会出现“recipe 找不到 source”或者编译到一半失败的情况。这也是 Yocto 体系下“可复现构建”的基础。

3. 首次构建 OpenBMC 镜像的完整实操

3.1 初始化构建目录与选择目标机型

先看代码根目录的结构。拉完代码后,你会看到一个setup脚本,它是构建环境的入口。用法很简单:

source setup <machine>

比如要构建 IBM Witherspoon 机型的镜像:

source setup witherspoon

执行完这步后,项目根目录下会生成build/witherspoon目录,并且环境变量也被设置好了,这之后才能直接跑bitbake。这个目录就是你的工作区,所有编译中间产物都在里面,换板型只需要重新执行source setup <machine>,互不影响。

如果想看当前支持哪些机器,可以直接:

ls meta-*/*/conf/machine/*.conf

或者查看setup脚本里列出的 machine 列表。

这里有个新手容易懵的点:source setup之后 Bash 提示符前面会多出一串类似openbmc-env的前缀,这是正常的,说明 BitBake 环境已经激活。如果你开了多个终端,每个终端在跑 bitbake 之前都必须重新source setup,不然找不到配置环境变量。

3.2 目标镜像概念与生成固件

OpenBMC 框架里,bitbake的默认目标通常不是“镜像文件”,而是一个 image 配方。比如:

bitbake obmc-phosphor-image

这个obmc-phosphor-image是 OpenBMC 的基础系统镜像,里面包含了 Phosphor 基础服务、BMC 系统管理功能、WebUI 等。如果是硬件移植阶段,一般先编这个镜像,确保最基础的系统能跑起来,再按需追加 layer 和其他功能包。

编译完成后,镜像产物在:

build/witherspoon/tmp/deploy/images/witherspoon/

目录下常见几个文件:

  • obmc-phosphor-image-witherspoon.static.mtd:这是最终刷入 BMC 的镜像,对应的静态布局 mtd 格式。
  • obmc-phosphor-image-witherspoon.ubi:UBI 文件系统镜像。
  • u-boot.bin、u-boot.elf:U-Boot 相关。
  • fitimage-*或kernel-fit:打包了 kernel 的 FIT 镜像。

以*.mtd结尾的是刷机常用固件,很多工程师直接拿这个文件通过 ASpeed 的flashrom或者 BMC 内部分区烧写工具写入 Flash。

3.3 加速构建的几招实操

首次构建全量可能耗时很久,这里有几个实测有效的加速方法。

最有效的是开启共享状态缓存(sstate cache)。OpenBMC 默认在每个板型的 build 目录里有自己的tmp/sstate-cache,但你可以让多个板型共享一个缓存,减少重复编译。修改conf/local.conf,设置:

SSTATE_DIR ?= "/path/to/shared/sstate-cache" DL_DIR ?= "/path/to/shared/downloads"

DL_DIR是所有板型共享的源码包下载目录,SSTATE_DIR是编译状态缓存目录。这样当你在不同机器之间切换,或者给相同架构的新板子做构建时,大量编译任务可以直接命中缓存,不用重新编译。

第二个加速是增加并行度。在conf/local.conf里加:

BB_NUMBER_THREADS = "16" PARALLEL_MAKE = "-j16"

数值按 CPU 核心数调整,一般是物理核心数或线程总数。不是越大越好,我在 8 核机器上设置 16 后反而因为内存交换导致变慢,12GB 内存下建议最多等于核心数。

第三招是配置本地镜像源。如果你在国内网络环境,GitHub 和 kernel.org 下载源可能不稳定,可以换用镜像源站点,比如部分大厂内网镜像或高校镜像站。这个根据自己的环境灵活处理,核心是把DL_DIR先准备好的源码包填满,离线构建也能成功。

我自己的习惯是先跑一次bitbake obmc-phosphor-image,什么都不改,让它老老实实下载所有依赖,确认能完整编出镜像。这一步跑通,就证明宿主环境和依赖链没问题。之后再开始改代码、加板型,遇到问题就能确定是代码改动造成的,而不是环境导致的。

4. 硬件移植场景下的开发环境配置

4.1 新板子从哪里入手

OpenBMC 所谓“硬件移植”,本质上就是让 OpenBMC 的软件栈支持你手里那块新硬件。相比通用 Linux 移植,OpenBMC 的硬件抽象层次更多:有 U-Boot、有 Linux Kernel、有设备树(dts)、有各类传感器监控、有 D-Bus 服务。构建开发环境时,就要把这些都纳入到一个可编译的体系里。

最常见的起点是“叠一个自己的 meta 层”。OpenBMC 已经提供了非常多 OpenBMC 兼容板型的模板,你新做板卡时,不一定从零写所有配方,可以基于一个 CPU/SOC 最接近的已有机器来扩展。比如你的板子用 AST2600 的 BMC 芯片,那就先找到基于 ASpeed AST2600 的现有机器配置,复制一份改成自己的机器名,逐步替换设备树和外围设备信息。

大体流程是:

  1. 在某个 layer 下新建meta-<company>/meta-<board>/conf/machine/<board>.conf。
  2. 设置机器相关变量:PREFERRED_PROVIDER_virtual/kernel、KERNEL_DEVICETREE、UBOOT_MACHINE等。
  3. 添加 u-boot 的 defconfig 和 Linux kernel 的 defconfig。
  4. 修改 dts 设备树源文件,匹配新产品硬件。
  5. 继承并调整 image 配方,去掉不需要的驱动,加上需要的应用。

这套改动不是在 OpenBMC 主仓里乱来的,而是通过新 layer 去覆盖原 layer 的配方。BitBake 的 layer 优先级机制允许你用高优先级 layer 覆盖低优先级 layer 里的相同配方,所以保留 OpenBMC 官方代码不动,你的移植改动都放自己的 meta 层里,是最安全、最可维护的做法。

4.2 layer 配置与依赖关系

一个全新的层要有自己的配置文件:

meta-myboard/conf/layer.conf

里面大概长这样:

BBPATH .= ":${LAYERDIR}" BBFILES += "${LAYERDIR}/recipes-*/*/*.bb ${LAYERDIR}/recipes-*/*/*.bbappend" BBFILE_COLLECTIONS += "myboard" BBFILE_PATTERN_myboard := "^${LAYERDIR}/" BBFILE_PRIORITY_myboard = "9"

BBFILE_PRIORITY越高,遇到同名配方时优先使用你这层的版本。OpenBMC 官方层的优先级一般在 5 到 7 之间,你用 9 就能覆盖绝大多数东西。

然后在你的 machine conf 里面引用:

include conf/machine/include/ast2600.inc

官方提供的ast2600.inc里已经定义好了很多通用项:PREFERRED_VERSION 等。你只需要补上自己机器特有参数,比如 Flash 大小、U-Boot config、DTS 文件名。

开发环境这一步要特别留意TEMPLATECONF和 meta 层的组合关系。不同板型可能依赖不同的 layer,比如用到 AST2600 就必须把meta-aspeed加进bblayers.conf。如果你的板子不需要某些功能,比如依赖 BCM 或 Intel 平台的 layer,可以从bblayers.conf里删掉,减少不必要的解析和编译,构建速度也会快一点。

4.3 内核和设备树在构建环境中的配置要点

OpenBMC 里 Linux Kernel 的构建不是单独 make,而是通过 BitBake 配方触发。OpenBMC 默认的内核配方在meta-phosphor/common/recipes-kernel/linux/下面,通常叫linux-aspeed.bb或者类似名字。硬件移植时,多半要针对新板子生成新的内核 config 或 patch。

通常的操作是:

在自定义 layer 里添加一个 linux-aspeed 的 append 文件,比如:

meta-myboard/recipes-kernel/linux/linux-aspeed_%.bbappend

内容里指定你板子的设备树和 defconfig:

FILESEXTRAPATHS:prepend := "${THISDIR}/files:" SRC_URI += "file://defconfig" SRC_URI += "file://myboard.dts" KERNEL_DEVICETREE_myboard = "aspeed-bmc-myboard.dtb"

把myboard.dts放到该目录的files子目录下,然后用 bitbake 构建内核。BitBake 会把这个 dts 编译成 dtb,并打包进 FIT 镜像和最终 BMC 固件里。

这里有个常见坑:内核设备树的编译是在内核源码树里进行的,OpenBMC 又常常使用 prebuilt kernel source 或者多层叠加的补丁,如果你改了 dts 但没有强制重新编译内核,bitbake 可能认为文件没变化、还用旧缓存。排错时用:

bitbake -c cleanall linux-aspeed bitbake obmc-phosphor-image

强制重新获取、重新展开、重新编译。注意cleanall会删除下载目录里的内核源码缓存,下次构建又要重新拉取,所以一般用cleansstate比较多:

bitbake -c cleansstate linux-aspeed

这条只会清编译缓存,源码包保留,重编速度更快。

另外,OpenBMC 里很多机器直接把 kernel defconfig 内嵌在 machine conf 里,比如:

KBUILD_DEFCONFIG_myboard = "aspeed_g5_defconfig"

如果你要用自己的 config 文件,可以新增一个.config文件放到内核源码目录,或者在 append 文件里执行额外脚本。方法很多,但核心思想一致:你在自定义层里提供文件,其他行为交给 BitBake 去完成。

5. OpenBMC 构建环境排错实录

5.1 依赖与宿主环境相关报错

这类问题最多,我整理几个实录过的:

报错 1:Cannot fetch URL ...或者 download 阶段网络超时。

最常见的是下载源码包失败。检查网络、DNS、镜像源。如果用的是国内网络,GitHub 上的部分大文件容易超时,可以配置 git 低限速、或用替代源,但最稳妥的是提前把所有依赖包下载到 DL_DIR。另外子模块下载失败,可以多试几次:

git submodule sync git submodule update --init --recursive

报错 2:Please install the following missing dependencies。

当 OpenBMC 要求宿主有gawk、chrpath等,而你没有装全时,setup 脚本会在开头直接提示。按提示补装:

sudo apt install gawk wget git-core diffstat unzip texinfo gcc-multilib build-essential chrpath socat cpio python3 python3-pip python3-pexpect xz-utils debianutils iputils-ping

报错 3:bitbake: command not found。

激活环境后bitbake应该可用。如果提示不存在,多半是没source setup,或者 setup 过程中某个依赖报错导致环境变量没有完整注入。重新执行 source,确认开头没有 error。

5.2 BitBake 解析阶段的常见问题

解析阶段失败很让人崩溃,但大部分是语法或配置错误。比如 machine 名字拼写错误,bitbake 无法识别;或者 layer 依赖缺失、BBFILE_COLLECTIONS名字冲突。这类问题可以通过:

bitbake-layers show-recipes bitbake-layers show-layers

导出当前的解析状态,排查是不是某个 meta 层没加载。

还有一类典型错误是Missing metadata for machine ...。这通常是因为你写的 machine conf 文件没有落到conf/machine目录,或者 layer 没加入bblayers.conf。检查自定义层路径是否被正确添加。

5.3 编译阶段典型异常

编译阶段最常见的错误是磁盘空间不足和内存不足。磁盘不足在编译大型软件包时非常明显,报错类似于No space left on device,而且往往在tmp/work/...目录。解决方法是清理旧构建产物:

bitbake -c cleanall <target>

或者把build/tmp整个删掉重新来,前提是你有 sstate 缓存。平时建立目录软链到大分区也是个实用策略,比如:

mkdir -p /data/openbmc-build ln -s /data/openbmc-build build

将build目录放到数据盘,避开系统盘空间瓶颈。

内存不足多见于并行编译过多,bitbake 进程直接被 kill。解决:降低BB_NUMBER_THREADS和PARALLEL_MAKE,或者在local.conf限制任务内存。如果你用 8 核 16GB 内存,BB_NUMBER_THREADS = "4"是稳妥的。

5.4 缓存命中与失败重编技巧

你改了自定义 layer 里的东西,但 bitbake 认为没变化,这种问题隐蔽。原因不外乎 sstate 缓存未失效,或者本机文件时间戳问题。稳妥做法是使用-c compile/-c install强制编译某个具体阶段,而不是每次全量重新构建。

比如单独重编内核:

bitbake -c compile -f linux-aspeed bitbake -c deploy -f linux-aspeed

-f强制忽略缓存状态。硬件移植调 dts 和补丁时,这个技巧可以说每天都要用。

我把踩过的坑按类型整理成了下面这张表,方便遇到问题时快速定位。

错误类型典型提示排查重点解决方案
依赖缺失missing dependency宿主包按依赖列表补装
下载失败Cannot fetch网络/仓库配置镜像,重试子模块
磁盘不足No space left on devicebuild 目录分区清理或迁移 build 目录
内存不足OOM killedBB_NUMBER_THREADS降低并行度
解析错误ParseErrormachine/layer 配置检查 conf,运行 bitbake-layers
sstate 缓存不刷新改动未生效sstate 状态使用 cleansstate 或 -f 强制编译

6. 关于构建环境稳定复用的几个忠告

开发环境搭好以后,我强烈建议维护好两个目录:downloads和sstate-cache。前者是源码包归档,后者是编译状态缓存。在你做硬件移植、反复调整代码的那几个月,这两个目录的价值仅次于代码仓库本身。

可以把DL_DIR设成一个共享目录,比如/opt/openbmc-archive,之后所有板型、所有分支都用它;SSTATE_DIR可以每套代码对应一份,避免不同提交间的缓存污染,但同一套代码多次构建之间就可以复用。这个策略帮我节省的编译时间非常可观,至少三次以上全量构建改拼接缓存,大量公共库和工具链都能直接跳过。

最后一个忠告:不要把生产用的构建环境折腾成“测试环境”,更不要在同一个目录里既跑构建又频繁清缓存。给 OpenBMC 单独一块干净文件夹,所有 bitbake 操作都发生在激活环境里,所有临时文件都在build/tmp里解决。即使出了问题,删掉整个tmp重来也比反复排查环境变量靠谱。

我从 OpenBMC 源码构建到第一次完整刷板,前后折腾了一周多。回头再看,构建环境这一关其实没有太多捷径,就是踏踏实实把宿主环境配好、把目录规划好、把第一次全量构建跑通。后续一切硬件移植、功能裁剪、服务开发,都建立在这个“能编、能跑、能复现”的基础上。把这个地基打牢了,后面的活会顺很多。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/5 1:30:08

WPF RichTextBox MVVM双向绑定实战:附加属性方案与序列化

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/5 1:30:08

YOLOv11岩石裂隙检测与三维地质建模联合优化实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/5 1:30:08

Canny边缘检测算法详解:从原理到OpenCV实战与调参

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/5 1:28:53

小番茄目标检测数据集实战:XML转YOLO与农业场景调优

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/5 1:27:53

DCE容器云平台:企业级K8s治理底盘与工程化落地实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/5 1:27:35

Ceph块存储从选型到RBD接入:cephadm部署避坑与fio压测指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华