当前位置:首页>Linux>从零构建 Linux|10 构建系统镜像

从零构建 Linux|10 构建系统镜像

  • 2026-09-10 05:34:26
从零构建 Linux|10 构建系统镜像

系列第 10 篇|Demo:在 WSL2 里 bitbake,分别产出虚机与真机镜像提醒:第一次构建可能要数小时;两机型都编会更久,属正常现象

第 8~9 篇的配置与定制已经就绪。本篇做的事情很单纯,但通常最耗时间:

在 WSL2 Ubuntu 中分别进入两个 build 目录,先做出 qemux86-64,再做出 genericx86-64,并确认两套产物分别在哪里。

这些产物将在第 11 篇分别用于 runqemu 与 U 盘双系统。再次强调:这是 x86_64 虚机/真机镜像,不是玄铁板卡烧写包。

构建前再检查一遍

开始前花两分钟确认,能少熬几个失败的小时:

检查项
要求
环境
当前在 WSL2 的 Ubuntu 里。工程路径优先在 ~/...,不要放在 /mnt/c/...
磁盘
剩余空间尽量 ≥ 50GB;两机型都编时更多更稳妥
网络
能访问源码下载地址;有代理则先配置好
两个 build 目录
第 8 篇已初始化 build-qemux86-64 与 build-genericx86-64,各自 MACHINE 已写对
hello
在对应环境中 bitbake -s | grep hello 能看到
目标名字
本篇构建 core-image-base

如果你是合上电脑很久后再回来,按目标机型重新进入环境:

cd ~/yocto/pokysource oe-init-build-env build-qemux86-64# 或source oe-init-build-env build-genericx86-64

推荐顺序:先虚机,再真机

第一步:构建 qemux86-64

cd ~/yocto/pokysource oe-init-build-env build-qemux86-64# 可选确认bitbake -e | grep "^MACHINE="# 期望:MACHINE="qemux86-64"bitbake core-image-base

成功后,产物在(相对当前 build 目录):

ls tmp/deploy/images/qemux86-64/

完整路径类似:

~/yocto/poky/build-qemux86-64/tmp/deploy/images/qemux86-64/

这一套主要供第 11 篇 runqemu 使用。

第二步:在另一目录构建 genericx86-64

不必改虚机目录里的配置。另进真机 build:

cd ~/yocto/pokysource oe-init-build-env build-genericx86-64bitbake -e | grep "^MACHINE="# 期望:MACHINE="genericx86-64"# 确认 IMAGE_FSTYPES 仍含 wic / hddimg / tar.bz2(见第 8~9 篇)bitbake core-image-base

成功后:

ls tmp/deploy/images/genericx86-64/

完整路径类似:

~/yocto/poky/build-genericx86-64/tmp/deploy/images/genericx86-64/

这一套主要供第 11 篇写 U 盘与双系统使用。

两机型会不会「白做两遍」?

第 8 篇模板已把 DL_DIR、SSTATE_DIR 指到 poky 下同一共享目录(downloads/、sstate-cache/)。先编完虚机再编真机时,共用模块一般不必重复下载、也不必从零再编。

即使共享缓存,内核、机器相关打包仍会按 MACHINE 分别做——这很正常。别急着删整个 build 目录「图个干净」,除非你明确知道自己在做什么。

执行构建:这一条命令背后在忙什么?

bitbake core-image-base

终端会刷很久,看起来像「卡住了」。其实 BitBake 在按依赖图并行跑几百个菜谱。第 7 篇给过总链路;这里拆成两层看:整镜像在干什么,以及其中一个最重的包(Linux 内核)具体怎么编。

整镜像:从目标名到可启动盒子

读 conf / 扫 layer  → 解析 core-image-base 的依赖图(内核、busybox、hello、工具链……)  → 查 sstate:能复用的任务直接跳过  → 缺的源码进 DL_DIR(downloads/)  → 按任务链编每个包  → 组装 rootfs(用户态)  → 把内核放进启动分区,打成 wic / hddimg / tar.bz2  → 拷到 tmp/deploy/images/<machine>/

对应到屏幕上常见的几类输出:

你看到的
实际在做
Parsing recipes...
读 .bb / .conf,算出要编哪些包
Checking sstate...
 / Setscene
看共享缓存里有没有现成结果
do_fetch
下载源码或校验已有 tarball
do_compile
真正编译(内核、gcc、glibc 最耗时)
do_rootfs
 / do_image_*
组文件系统、打镜像

hello 只是依赖图里很小的一环。第一次构建真正耗时的,通常是交叉工具链和 linux-yocto。

以 linux-yocto 为例:内核是怎么被编出来的

第 8 篇说过:镜像配方里往往不写linux-yocto,内核是经 MACHINE → virtual/kernel 拉进来的。bitbake core-image-base 会顺带构建它;你也可以单独跑:

bitbake virtual/kernel# 等价于当前 MACHINE 下的 linux-yocto

先对照你在裸机上编内核的习惯:

手工编内核(概念)              Yocto 里对应的任务─────────────────────────────────────────────────────git clone / 下 tarball          do_fetch解压、切到指定提交               do_unpack(linux-yocto 还有 checkout)打补丁                          do_patchmake defconfig / 合并配置       do_kernel_metadata → do_configuremake -jN(出 bzImage)          do_compilemake modules                    do_compile_kernelmodulesmake modules_install            do_install把 bzImage 拷到启动介质         do_deploy  →  镜像的 do_image_wic 再装进启动分区

linux-yocto 比 hello 多几步,是因为内核配置不是一张手写的 .config,而是由 MACHINE 默认配置 + kernel-meta 片段(第 9 篇 bbappend 里的 demo.cfg 也走这条路)拼出来的。不会弹 make menuconfig。

任务顺序可以记成:

do_fetch  → do_unpack / 检出源码  → do_patch  → do_kernel_metadata     # 按 MACHINE 收集配置片段  → do_configure           # 生成 .config(类似 olddefconfig)  → do_compile             # 编 vmlinux / bzImage,最耗 CPU  → do_compile_kernelmodules  → do_install             # 模块、头文件进暂存目录 ${D}  → do_package             # 打成 kernel-image、kernel-module-* 等包  → do_deploy              # bzImage 等放到 deploy/images/<machine>/

工作目录在当前 build 下,路径模式:

tmp/work/<arch>-poky-linux/linux-yocto/<版本>-<修订>/

例如 qemux86-64 上常见类似:

tmp/work/qemux86_64-poky-linux/linux-yocto/6.6.xx-r0/  ├── linux-qemux86_64-standard-build/   # 编译目录:.config、vmlinux  ├── image/                             # do_install 的暂存根  ├── packages-split/                    # 打出来的各个子包  └── temp/                              # 每个任务的日志        ├── log.do_configure        ├── log.do_compile        └── log.do_deploy

版本号随你钉的 PREFERRED_VERSION 变化,以实际目录名为准。想确认「现在卡在哪一步」,打开对应 temp/log.do_* 即可,不必等整镜像结束。

编完后,内核相关文件会出现在两处,职责不同:

位置
是什么
tmp/deploy/images/<machine>/bzImage
(及带 MACHINE、时间戳的副本)
给 Bootloader / QEMU 用的内核映像
rootfs 里的 /lib/modules/<uname -r>/
可加载模块;随 do_rootfs 装进用户态

镜像打包时再把它们和 rootfs 合到一起:

bzImage  ──►  wic / hddimg 的启动分区(GRUB 或 QEMU 直接加载)模块     ──►  rootfs(/lib/modules/...)hello 等 ──►  rootfs(/usr/bin/hello)              ↓         core-image-base-*.wic / *.hddimg / *.tar.bz2

这就是第 1~3 篇那条启动链在构建侧的对应关系:你等的不是「编一个 hello」,而是「编出能被 Bootloader 跳进去的内核 + 能被内核挂上的 rootfs」。

构建中可以自己看一眼

同一 build 目录同时只能跑一条 bitbake(有锁)。想先摸清内核任务,开编整镜像之前执行:

# 这个菜谱会跑哪些任务(名字即可,不必全懂)bitbake -c listtasks virtual/kernel# 只编内核、不组整镜像(第一次仍会拉工具链,但范围更小)bitbake virtual/kernel

整镜像已经在跑时,不要再开第二条 bitbake。看当前 build 的终端输出即可;若长时间停在 linux-yocto 的 do_compile,属于正常:那就是在跑内核的 make -jN。要核对细节,直接读工作目录里的 temp/log.do_compile。

时间与中断

  1. 第一次构建可能要数小时,机器越慢越久。
  2. 若中途失败或你主动打断,修好问题后再次执行同一条命令即可;BitBake 会尽量接着做,不必每次从零开始。
  3. 想先验证 hello 菜谱时,可先 bitbake hello,成功后再构建完整镜像。

产物对比:两套目录,两种用途

路径可以拆开理解:

路径段
含义
build-*/tmp/
该机型构建过程的工作区与输出区
deploy/
面向「交付」的文件
images/
镜像类产物
<machine>/
对应你的 MACHINE 名

qemux86-64 目录

build-qemux86-64/tmp/deploy/images/qemux86-64/

主要用途:第 11 篇在同一 WSL2 环境里 runqemu。

常见文件角色:内核、rootfs 相关镜像、wic 等;具体文件名以目录中实际为准。runqemu 通常会按当前 MACHINE 自动挑选合适文件。

genericx86-64 目录

build-genericx86-64/tmp/deploy/images/genericx86-64/

主要用途:写 U 盘、双系统部署。

文件类型
作用
.wic
磁盘镜像,常直接写到 U 盘(典型名如 core-image-base-genericx86-64.rootfs.wic)
.hddimg
另一种可启动磁盘镜像格式
.bmap
描述镜像稀疏布局,配合 bmaptool 写入更快更稳
.tar.bz2
rootfs 打包归档,适合解压到硬盘分区做双系统
内核相关(如 bzImage)
多数情况下已打进 wic / hddimg;单独文件便于排查

对照启动链

虚机产物 → QEMU → kernel → rootfs → … → hello真机产物 → UEFI/BIOS → GRUB → kernel           → rootfs → … → hello

也就是说:你拿到的不是「某一个 hello 文件」而已,而是两套能被各自环境引导起来的系统材料。

为第 11 篇准备「上车行李」

路径
准备内容
路径 A(虚机)
进入 build-qemux86-64 环境,直接 runqemu 即可
路径 B(真机)
请准备拷贝到 Windows 可访问位置的文件(见下表)

真机文件清单:

  1. 首选:*.rootfs.wic(以及若存在的 *.wic.bmap)
  2. 备选:*.hddimg
  3. 强烈建议同时带上:*.rootfs.tar.bz2(双系统往硬盘分区部署时更方便)

从 WSL2 拷到 Windows,可用 /mnt/c/Users/<你的用户名>/ 下的某个文件夹,或资源管理器访问 \\wsl$。

写入工具怎么选:

环境
工具
在 WSL2 / Linux 上写 U 盘
有 bmap 时用 bmaptool;否则用 dd。务必认清设备名
在 Windows 上写 U 盘
Rufus 等图形工具(注意是否支持你的镜像后缀)

常见失败:先对号入座再深挖

现象
处理思路
报 Fetcher / 下载失败
检查网络、代理、镜像源是否可达;然后重试 bitbake
No space left on device
磁盘满了。清理或把下载 / 缓存目录放到更大的盘;必要时关注 WSL2 虚拟磁盘是否需扩容
提示缺少宿主命令 / 头文件
回到 Yocto Quick Start,在 WSL2 Ubuntu 上补齐宿主依赖包
构建极慢或怪异错误,且工程在 /mnt/c 下
把 poky 迁到 ~/ 下的 Linux 文件系统再试
找不到 hello
对应 bblayers.conf 是否加入 meta-demo;IMAGE_INSTALL 是否包含 hello
进错了 build 目录
bitbake -e | grep "^MACHINE="
 与当前要编的机型是否一致;产物是否出现在预期的 build-*/tmp/deploy/images/<machine>/
权限很奇怪 / 用 root 构建出问题
不要长期用 root 跑整个 Yocto;改回普通用户并修好目录权限

备注:官方 Quick Start(宿主依赖与兼容环境)见https://docs.yoctoproject.org/5.0/brief-yoctoprojectqs/

如果错误日志很长,先看第一处 error,不要只看最后几行翻滚输出。

本篇小结

  1. 核心命令:在对应 build 目录中 bitbake core-image-base。
  2. 推荐顺序:先 build-qemux86-64,再 build-genericx86-64。
  3. 这条命令会解析依赖、复用 sstate、编各包再组镜像;其中 linux-yocto 走 do_configure → do_compile → do_deploy,产物是 bzImage + 模块。
  4. 产物目录:各自 tmp/deploy/images/<machine>/。
  5. 虚机产物留给 runqemu;真机产物带上 wic / hddimg 与 tar.bz2,进入第 11 篇。

下一篇:先用 QEMU 跑通 hello,再把真机镜像写入 U 盘完成双系统。配置如何用 Git 托管见第 12 篇。

系列文章列表:

从零构建 Linux 系统
从零构建 Linux|01 启动流程总览
从零构建 Linux|02 Bootloader
从零构建 Linux|03 内核启动
从零构建 Linux|04 Rootfs、init 与服务
从零构建 Linux|05 包管理
从零构建 Linux|06 Yocto 是什么
从零构建 Linux|07 使用 Yocto
从零构建 Linux|08 配置自定义 Linux
从零构建 Linux|09 进一步定制系统

最新文章

随机文章