2. Yocto基础回顾

在开始编写自定义 Layer 之前,必须先把 Yocto 项目里几个高频名词的“身份”和“关系”理清楚。很多初学者会把 BitBake、OpenEmbedded、Poky 混为一谈,结果在写 layer.conf、.bb、.bbclass 时不知道文件该放哪一层、由谁解析、被谁继承。本节用一张层次关系图,把构建系统、元数据、配方、类、配置文件的职责与依赖关系一次讲透。

一、核心原理:四个概念不是并列,而是分层

Yocto 项目本质上是一套“构建框架 + 元数据集合”。其中:

  • BitBake:任务执行引擎,负责解析元数据、计算依赖、调度任务。它只认语法,不关心具体是哪个发行版。
  • OpenEmbedded:元数据规范与配方集合,定义了 .bb、.bbclass、.inc、.conf 的写法与继承机制,是“内容标准”。
  • Poky:一个参考发行版,把 BitBake、OpenEmbedded-Core(oe-core)以及若干默认配置打包在一起,是官方推荐的入门起点。
  • 元数据(Metadata):所有配置、配方、类、追加文件的总称,是 BitBake 的输入。

它们的关系可以概括为:BitBake 是引擎,OpenEmbedded 是规范,Poky 是参考实现,元数据是燃料。自定义 Layer 的本质,就是向这套元数据体系中追加自己的配方、类和配置,而不修改上游内容。

Yocto 元数据层次关系与作用 BitBake 引擎层 解析元数据 → 计算依赖 → 调度任务 → 执行 fetch / unpack / patch / configure / compile / package bitbake <recipe> 命令行入口 读取 元数据层(Metadata) 配置文件 .conf local.conf / bblayers.conf layer.conf / distro.conf 配方 .bb / .bbappend 描述“构建什么、怎么构建” SRC_URI / do_install / FILES 类 .bbclass 可复用构建逻辑 inherit autotools / cmake 包含文件 .inc 被多个配方共享的变量与函数片段,通过 require / include 引入 组合为 Poky 参考发行版 = BitBake + OpenEmbedded-Core(oe-core)+ meta-poky + meta-yocto-bsp + 默认配置 bitbake/ meta/ (oe-core) meta-poky/ meta-yocto-bsp/

二、方法流程:一次构建中元数据如何被消费

理解层次之后,再看一次典型构建的解析顺序,就能明白自定义 Layer 应该“挂”在哪里:

  1. BitBake 启动,读取 conf/bblayers.conf,得到所有参与构建的 Layer 路径。
  2. 依次加载每个 Layer 的 conf/layer.conf,把该 Layer 的 recipes-* 目录加入 BBPATH 与 BBFILES。
  3. 读取 local.conf,确定 MACHINE、DISTRO、并行度、下载目录等全局变量。
  4. 根据目标配方名,在 BBFILES 中匹配 .bb 与同名 .bbappend,按 Layer 优先级合并变量。
  5. 解析配方中的 inherit,加载对应 .bbclass,把类中的任务与变量注入当前配方。
  6. 计算任务依赖图,按 do_fetch → do_unpack → do_patch → do_configure → do_compile → do_install → do_package 顺序执行。
关键结论:自定义 Layer 不需要修改 BitBake 或 oe-core,只需提供自己的 layer.conf、配方和类,通过 bblayers.conf 注册即可参与构建。

三、案例/场景:给一个自定义 Layer 挂上配方与类

假设我们要新增 meta-myapp Layer,提供一个 hello-custom 配方,并复用自定义类 mybuild.bbclass。目录结构如下:

meta-myapp/
├── conf/
│   └── layer.conf
├── classes/
│   └── mybuild.bbclass
└── recipes-apps/
    └── hello-custom/
        ├── hello-custom_1.0.bb
        └── files/
            └── hello.c

layer.conf 负责声明 Layer 身份与搜索路径:

BBPATH .= ":${LAYERDIR}"
BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \
            ${LAYERDIR}/recipes-*/*/*.bbappend"
BBFILE_COLLECTIONS += "myapp"
BBFILE_PATTERN_myapp = "^${LAYERDIR}/"
BBFILE_PRIORITY_myapp = "10"
LAYERVERSION_myapp = "1"

配方中通过 inherit 使用类,通过 require 复用 .inc:

SUMMARY = "Custom hello application"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"

SRC_URI = "file://hello.c"

inherit mybuild

do_compile() {
    ${CC} ${CFLAGS} ${LDFLAGS} ${WORKDIR}/hello.c -o hello
}

do_install() {
    install -d ${D}${bindir}
    install -m 0755 hello ${D}${bindir}/hello
}

最后在 build/conf/bblayers.conf 中注册:

BBLAYERS ?= " \
  /opt/poky/meta \
  /opt/poky/meta-poky \
  /opt/poky/meta-yocto-bsp \
  ${TOPDIR}/../meta-myapp \
"

执行 bitbake hello-custom 后,BitBake 会先加载 meta-myapp/conf/layer.conf,再匹配到配方,继承 mybuild.bbclass,最终完成编译与打包。

四、误区与复盘:常见混淆点对照

概念 本质 常见误区 正确理解
BitBake 任务调度引擎 以为它包含配方内容 它只解析和执行,配方来自元数据
OpenEmbedded 元数据规范与配方集合 与 Poky 混为一谈 oe-core 是 Poky 的组成部分之一
Poky 参考发行版 认为必须用 Poky 才能构建 可用其他 distro 配置替换 meta-poky
.bb / .bbappend 配方与追加 在 .bbappend 中重复定义全部变量 只写差异部分,保持与上游解耦
.bbclass 可复用构建逻辑 把类当普通配置文件 通过 inherit 注入任务与变量
layer.conf Layer 注册与路径声明 忘记设置 BBFILE_PRIORITY 优先级决定同名配方覆盖顺序
复盘提醒:自定义 Layer 出问题时,优先检查三处——bblayers.conf 是否注册、layer.conf 的 BBFILES 是否匹配到配方、BBFILE_PRIORITY 是否被其他 Layer 覆盖。多数“配方找不到”或“变量不生效”都源于这三步。

把 BitBake、OpenEmbedded、Poky、元数据、配方、类、配置文件放回同一张层次图里,就能看清:引擎负责执行,规范负责约束,Poky 负责示范,元数据负责描述,而自定义 Layer 负责扩展。后续编写 Layer 时,所有文件都应落在“元数据层”的正确位置,并通过 layer.conf 与 bblayers.conf 接入构建体系。