What is it

The Yocto Project (YP) is an open source collaboration project that helps developers create custom Linux-based systems regardless of the hardware architecture.

基本上这就是一套用来为特定硬件系统定制 Linux 发行版的工具链,一般用于嵌入式系统。

核心概念

BitBake

Yocto 项目引入的构建工具。类似于 make, cmake, bazel 等构建工具,但专门用于构建系统映像等任务。

层 是 Yocto 项目中承担 “模块” 这一角色的机制。

一般会将:

  • 一个 硬件平台 或 板级配置 所需要的所有文件。
  • 一组(往往是可重用的)逻辑上独立的文件。

组织在一个层里。 一个层往往会包含多个 配方。

配方

配方 类似于 make 的 Makefile,但相比之下 配方 除了 从源码编译到二进制 之外,同时也可以负责对软件的 源代码 的获取(支持直接利用 Git 等方式获取源代码)和解包、对 patch 的应用、配置编译环境、打包软件包 等功能。

另外,还有一些用以特殊用途的配方,比如用以制作 最终映像,向其中添加别的打包好的软件包 的 映像配方。

配方一般由一个 .bb 文件表示,并且要遵守一定的 文件名(name_version.bb) 和 目录规则。

通常指由 配方 源代码编译而成 的 产品。

工作流程

建议从 Yocto 的官方发行版 poky 开始逐步 添加/修改,得到需要的发行版,如果你没有使用 yocto 的经验,建议先构建一个 poky 的镜像,并在 qemu 中运行一下来试试手。

poky 项目的构建过程可以参考 官方文档,如果你的设备可以正常联网,请不要忘记如文档中所述地配置 mirrors(可能需要安装 python3-websockets 之类的包),否则构建将会花费长到离谱的时间。

如果你愿意使用 Docker,请使用这个 Dockerfile

从网上下载现有的层

cd poky
git clone <层的 Git URL>
# 你可能需要进入 clone 到的 repo 并切换到正确的分支
cd build
bitbake-layers add-layer ../<层名字>

然后 bitbake core-image-* 得到的镜像就是基于你加入的层的。

创建你自己的层

bitbake-layers create-layer <层名字>

然后 一个新的层就会在 poky 目录中生成。

导出 SDK

SDK 指 开发目标平台上的应用需要的交叉编译工具链 和 目标平台的头文件和库,一般如果你只需要构建一些能在固定的 目标平台(映像)上运行的二进制文件,则应该使用 SDK。

运行:

bitbake <image-name> -c populate_sdk

来制作对应镜像的 SDK。

之后可以在 poky/build/tmp/deploy/sdk 中找到一个 .sh 文件,就是打包好的 SDK。

可以在另一台计算机1上运行这个 .sh 文件,然后就可以使用这个工具链,而无需安装 poky 了。

导出 Extensible SDK (eSDK)

相比 SDK,Extensible SDK 额外打包了 devtool 命令行工具,方便用户对发行版中 现存的层 中的 配方 进行修改,如果希望创建新的层或是修改现有的层,应该使用 eSDK。

bitbake <image-name> -c populate_sdk_ext

同样可以在另一台计算机2上运行这个 .sh 文件来安装,然后就可以使用 devtool 进行对层的创建、修改,以及直接构建 image

SDK vs eSDK

FeatureStandard SDKExtensible SDK
ToolchainYesYes
DebuggerYesYes
Size100+ MBytes1+ GBytes
devtoolNoYes
Build ImagesNoYes
UpdateableNoYes
Sysroot(库、头文件等)预定义的动态更新
Installed PackagesNoYes
ConstructionPackagesShared State

简单来说,一般 SDK 只能 为固定的镜像开发二进制应用程序,而 eSDK 能对镜像进行一定程度的修改。

配方 配置文件语法和关键变量

参考 官方文档

变量

配方文件 的绝大部分都是对各种变量的值进行设置。

值得注意的是除了 A = B 这样的直接赋值,还可以:

  • 使用 A += "B" 会将 A 中的字符串、一个空格 和 "B" 拼接起来,比如:

    A = "A"
    A += "B"
    # Now A is "A B"
    
  • 要进行直接拼接而不加空格,使用 .=

    A = "A"
    A .= "B"
    # Now A is "AB"
    

    等效的,也可以使用 :append =

    A = "A"
    A:append = "B"
    # Now A is "AB"
    

函数

bitback 支持使用 shell 和 python 语法编写函数,参考 官方文档

函数 的最大用途就是 让 bb 文件可以导出任务,一般这些任务的函数名都是由 do_ 开头。

例如:

python foo() {
    bb.plain("second")
}
addtask foo after do_fetch before do_build

就创建了一个新的任务 foo, 这个任务需要在 fetch 任务之后,build 任务之前执行。

可以用 bitbake <recipe 名> -c listtasks 列出 配方中的所有任务。用 bitbake <recipe 名> -c <任务名> 执行特定任务。用 bitbake 管理任务 的 详细讲解见官方文档

继承

我们可以(且一般都需要)直接继承一些已经存在 的 配方模版,例如:

inherit cmake

会继承 cmake 模版,里面包含了一些预先定义好的任务。

在 inherit 之后写的变量和函数可以覆盖模版里的同名变量和函数。

常见的变量

全部约定名称的变量见 Bitbake 官方文档Yocto 官方文档,这里只列出一些最常见的。

SRC_URI

描述了 配方要构建的 源代码 的位置,支持从 本地文件系统、FTP、Git 仓库、一般网页 等地方自动拉取代码。

例如:

SRC_URI = "git://example.com/foo.git;branch=main;name=first \
           git://example.com/bar.git;branch=main;name=second \
           http://example.com/file.tar.gz;name=third"
SRCREV

标记要用哪个版本的代码,比如 SRCREV_first = "f1d2d2f924e986ac86fdf7b36c94bcdf32beec15" 意思就是使用上面的 foo 的对应 commit。

DEPENDS

标记这个 配方 的 构建 依赖哪些 配方 。

RDEPENDS

标记了这个 包 的 运行 依赖哪些 包。

PACKAGES

这个 配方 实际构建出 哪些包,用于和别的包的 RDEPENDS 或者 最终的 IMAGE_INSTALL 做匹配。

PN

配方名称。

PV

食谱的版本号,即 example_0.1.bb 里面这个 0.1。

PROVIDES

这个 配方 对外承诺构建出 哪些包,用于和别的包的 DEPENDS 做匹配。

WORKDIR

bitbake 构建你的 配方 时所在的 目录。

S

标记 源代码 被 下载/解压/移动 到的 目录。

有时你需要手动设置这个目录,比如如果你的 SRC_URI = "git://...,则需要写:

S = "${WORKDIR}/git"
FILES

放入 包 中的文件。

例如:FILES:${PN} += "${bindir}/mydir1 ${bindir}/mydir2/myfile"

IMAGE_INSTALL

要被直接打包进 image 的 包。

1

安装这个 SDK 还是有一些基本的软件包需求,比如 python3, filexz-utils,另外,makecmake 之类的构建工具也没有被打包进 SDK,而是需要自己安装,你可以安装并启动 SDK 之后用 env 命令观察这个 SDK 具体设置了些什么。

2

需要相比标准 SDK 更多的包,包括 diffstat, bzip2, gawk, cpio, gcc, g++, perl