3. 获取源码:使用 repo 工具下载 Poky 和 Meta 层
好,到了真正动手的时候了。
上一章我们聊了 Yocto 的哲学和整体架构。这一章,咱们直接开干——把源码拉下来。
你可能会问:「不就是 git clone 吗?有什么好讲的?」
嗯,如果只是 clone 一个 Poky,确实简单。但实际项目里,你往往需要同时管理十几个甚至几十个 Git 仓库。这时候,repo 工具就派上用场了。
3.1 为什么需要 repo?
Yocto 项目本身由上百个独立仓库组成。Poky 只是其中一个「聚合仓库」。除此之外,还有各种 BSP(板级支持包)、软件层、工具链仓库。
手动一个一个 git clone?不现实。
repo 是 Google 为 Android 开发的一个仓库管理工具,后来被 Yocto 社区广泛采用。它的核心能力就一句话:用一个 manifest 文件,描述一堆仓库该从哪里拉、拉到哪个目录、切到哪个分支。
核心概念:repo 本身不存代码,它只是帮你批量执行 git 命令。你最终看到的,还是一个个独立的 Git 仓库。
3.2 安装 repo
安装 repo 很简单。我个人习惯把它放在 ~/bin 下:
mkdir -p ~/bin
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
chmod a+x ~/bin/repo
然后把 ~/bin 加到 PATH 里:
export PATH=$PATH:~/bin
你可以把这行加到 ~/.bashrc 或 ~/.zshrc 里,省得每次都要手动 export。
小提示:如果你在公司内网,或者网络不稳定,可以先把 repo 脚本下载到本地,然后离线使用。repo 脚本本身只有几百 KB,不依赖其他外部资源。
3.3 初始化 repo 工作区
接下来,我们创建一个工作目录,然后用 repo 初始化:
mkdir yocto-project
cd yocto-project
repo init -u https://git.yoctoproject.org/poky -b kirkstone
这里解释一下参数:
-u:指定 manifest 仓库的 URL。Poky 的 manifest 仓库里,记录了所有子仓库的地址和默认分支。-b:指定分支。我用的是 kirkstone,这是 Yocto 4.0 的长期支持版本(LTS)。
执行完 repo init 后,你会看到类似这样的输出:
...
repo has been initialized in /home/user/yocto-project
这时候,目录下会多出一个 .repo 隐藏文件夹。里面存放了 manifest 文件和 repo 的元数据。
注意:.repo 目录可能很大(几百 MB 到几 GB),因为它包含了所有仓库的 Git 对象。不要随意删除或修改里面的内容。
3.4 同步所有仓库
初始化只是拉取了 manifest 文件。真正的代码下载,需要执行:
repo sync
这个命令会按照 manifest 里的描述,把每个仓库都 clone 到本地。repo sync 支持并行下载,默认是 4 个线程。你可以用 -j 参数调整:
repo sync -j8
我建议第一次同步时用 -j4,避免网络拥堵。之后增量更新时,可以开到 -j8 甚至 -j16。
同步完成后,你会看到类似这样的目录结构:
yocto-project/
├── .repo/
│ ├── manifests/
│ ├── manifests.git/
│ ├── repo/
│ └── projects/
├── bitbake/
├── documentation/
├── meta/
├── meta-poky/
├── meta-selftest/
├── meta-skeleton/
├── meta-yocto-bsp/
├── oe-init-build-env
├── README
├── README.hardware
└── ...
每个文件夹都是一个独立的 Git 仓库。你可以进入任意一个目录,执行 git log 查看历史。
3.5 理解层(Layer)的概念
好,源码拉下来了。现在我们来聊聊 Yocto 里最核心的概念——层(Layer)。
说白了,层就是一个「功能模块」。它把相关的配方(recipes)、配置文件、补丁、类文件打包在一起。
为什么需要层?
- 模块化:不同的硬件平台、不同的软件栈,可以拆成独立的层。比如,
meta-ti负责 TI 的 AM335x 系列,meta-raspberrypi负责树莓派。 - 复用:一个层可以被多个项目共享。你不需要重复造轮子。
- 隔离:层的优先级机制,允许你覆盖(override)其他层的配方,而不需要修改原始层。
我举个例子。你在 Poky 默认的 meta 层里,有一个 busybox 的配方。但你想用自己修改过的版本。怎么办?
很简单。创建一个新的层,比如 meta-custom,在里面放一个同名的 busybox 配方,然后把 meta-custom 的优先级设得比 meta 高。BitBake 会自动选择优先级高的那个。
关键点:层不是文件夹,而是有特定结构的目录。一个合法的层,必须包含 conf/layer.conf 文件。
3.6 查看源码目录结构
我们以 Poky 为例,看看它的核心目录结构:
| 目录/文件 | 作用 |
|---|---|
bitbake/ |
BitBake 构建引擎的源码。Yocto 的核心调度器。 |
meta/ |
核心层。包含基础配方、类文件、配置文件。几乎所有项目都会用到。 |
meta-poky/ |
Poky 发行版配置层。定义了默认的发行版策略。 |
meta-yocto-bsp/ |
Yocto 官方支持的 BSP 层。包含 QEMU 和一些参考板的配置。 |
meta-skeleton/ |
骨架层。给你做参考用的,教你如何创建自己的层。 |
meta-selftest/ |
自测试层。用于 Yocto 项目的自动化测试。 |
documentation/ |
Yocto 项目的文档源码(基于 Yocto 文档工具链)。 |
oe-init-build-env |
环境初始化脚本。每次开始构建前,都要 source 这个文件。 |
我们重点看看 meta/ 层的内部结构:
meta/
├── classes/
│ ├── base.bbclass
│ ├── kernel.bbclass
│ ├── autotools.bbclass
│ └── ...
├── conf/
│ ├── layer.conf
│ ├── machine/
│ │ ├── qemuarm.conf
│ │ ├── qemux86.conf
│ │ └── ...
│ └── distro/
│ ├── poky.conf
│ └── ...
├── recipes-bsp/
├── recipes-connectivity/
├── recipes-core/
├── recipes-devtools/
├── recipes-extended/
├── recipes-graphics/
├── recipes-kernel/
└── ...
这里有几个关键目录:
classes/:存放 .bbclass 文件。这些是 BitBake 的「类」,定义了通用的构建逻辑。比如autotools.bbclass封装了 autotools 的构建流程。conf/:配置文件。包括层配置(layer.conf)、机器配置(machine/)、发行版配置(distro/)。recipes-*/:配方目录。按功能分类,比如recipes-core放核心系统组件(busybox、udev 等),recipes-kernel放内核相关。
每个配方目录下,通常包含多个版本的配方文件(.bb)和附加文件(.bbappend)。
我的习惯:拿到一个新层,我第一件事就是看 conf/layer.conf。这里面定义了层的优先级、依赖关系、以及哪些目录会被搜索。理解了 layer.conf,你就理解了这个层的「边界」。
3.7 层的关系图
为了让你更直观地理解层之间的关系,我画了一张图:
这张图展示了典型的层叠结构:
- 最底层:BitBake 引擎。它不包含任何配方,只负责解析和执行。
- 核心层:Poky 提供的
meta和meta-poky。这是所有项目的基石。 - 中间层:BSP 层和软件层。它们扩展了核心层的功能。
- 最顶层:你的自定义层。优先级最高,可以覆盖下面任何层的配方。
我曾经踩过的坑:有一次,我在自定义层里修改了 base-files 的配方,但忘记检查 layer.conf 里的优先级。结果 BitBake 一直用旧版本的配方,我排查了半天才发现是优先级设低了。记住:数字越大,优先级越高。默认是 6,我建议自定义层设到 10 以上。
3.8 小结
这一章我们做了三件事:
- 用 repo 工具下载了 Poky 和相关的 meta 层。
- 理解了层(Layer)的概念——它是 Yocto 模块化的基石。
- 查看了源码目录结构,知道了每个目录是干什么的。