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
| Feature | Standard SDK | Extensible SDK |
|---|---|---|
| Toolchain | Yes | Yes |
| Debugger | Yes | Yes |
| Size | 100+ MBytes | 1+ GBytes |
| devtool | No | Yes |
| Build Images | No | Yes |
| Updateable | No | Yes |
| Sysroot(库、头文件等) | 预定义的 | 动态更新 |
| Installed Packages | No | Yes |
| Construction | Packages | Shared 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 的 包。
安装这个 SDK 还是有一些基本的软件包需求,比如 python3, file 和 xz-utils,另外,make 和 cmake 之类的构建工具也没有被打包进 SDK,而是需要自己安装,你可以安装并启动 SDK 之后用 env 命令观察这个 SDK 具体设置了些什么。
需要相比标准 SDK 更多的包,包括 diffstat, bzip2, gawk, cpio, gcc, g++, perl。