5 理解 Yocto 项目 Autobuilder

5 Autobuilder 内部的执行流程

“a-full” 和 “a-quick” 是 Autobuilder 常用的入口,可以从这里跟踪整个执行过程。 最直观的查看方式是 Autobuilder 控制台视图。

控制台顶部的每一项代表一个目标构建,这些目标并行运行。 完整构建触发大部分目标,快速构建只触发其中一部分。 每个目标的配置会在独立的 Buildbot 工作节点上执行。 配置定义位于 yocto-autobuilder-helper 仓库的 config.json 中,具体目标列在 overrides 部分。 例如,qemux86-64 的配置如下:

"qemux86-64" : {
      "MACHINE" : "qemux86-64",
      "TEMPLATE" : "arch-qemu",
      "step1" : {
            "extravars" : [
                  "IMAGE_FSTYPES:append = ' wic wic.bmap'"
                 ]
     }
},

要进一步展开,还需查看 templates 中的 arch-qemu 模板:

"arch-qemu" : {
      "BUILDINFO" : true,
      "BUILDHISTORY" : true,
      "step1" : {
            "BBTARGETS" : "core-image-sato core-image-sato-dev core-image-sato-sdk core-image-minimal core-image-minimal-dev core-image-sato:do_populate_sdk",
      "SANITYTARGETS" : "core-image-minimal:do_testimage core-image-sato:do_testimage core-image-sato-sdk:do_testimage core-image-sato:do_testsdk"
      },
      "step2" : {
            "SDKMACHINE" : "x86_64",
            "BBTARGETS" : "core-image-sato:do_populate_sdk core-image-minimal:do_populate_sdk_ext core-image-sato:do_populate_sdk_ext",
            "SANITYTARGETS" : "core-image-sato:do_testsdk core-image-minimal:do_testsdkext core-image-sato:do_testsdkext"
      },
      "step3" : {
            "BUILDHISTORY" : false,
            "EXTRACMDS" : ["${SCRIPTSDIR}/checkvnc; DISPLAY=:1 oe-selftest ${HELPERSTMACHTARGS} -j 15"],
            "ADDLAYER" : ["${BUILDDIR}/../meta-selftest"]
      }
},

结合两段配置可知,qemux86-64 构建包含三个步骤, 每步先运行 bitbake BBTARGETS,再运行 bitbake SANITYTARGETS。 所有步骤都使用 MACHINE="qemux86-64",但 SDKMACHINE 设置可能不同。 第 1 步还向 build/conf/auto.conf 添加了变量,启用 wic 镜像生成。

这里没有逐项解释所有细节,但可以看出模板机制如何在尽量减少重复配置的同时, 组合出较为复杂的构建方案。

各构建目标按便于并行化的方式设计。不同机器通常并行构建, 使用相同机器和元数据的操作则顺序执行,以尽可能提高效率。

config.json 由 Helper 仓库 scripts 目录中的脚本处理, 下一节介绍具体过程。

5 Autobuilder 目标执行概览

对于构建中的每个目标,Autobuilder 会执行多个步骤。 这些步骤定义在 yocto-autobuilder2/builders.py 中,大致如下:

  1. 运行 clobberdir。

    清理之前的构建。保留旧构建是为了便于调试失败情况。 详情见 clobberdir。

  2. 获取 yocto-autobuilder-helper。

    克隆 yocto-autobuilder-helper 仓库。 这样就不必把所有版本或项目专用代码都维护在 Buildbot 中。 所选分支与待构建版本一致,因此既能支持旧版本,也能改进新版本的行为。

  3. 写入 layerinfo.json。

    将在 Buildbot 界面中配置构建时提供的数据传给 Helper。

  4. 调用 scripts/shared-repo-unpack。

    Helper 脚本准备该构建所需全部组件的检出副本, 可能包括 BitBake、OpenEmbedded-Core (OE-Core) 及额外的层。 脚本使用 layerinfo.json 理解配置,并通过本地仓库缓存加快克隆。 详情见 Autobuilder 克隆缓存。

    这一步有两种运行模式。如果构建属于某个父构建, 所需仓库可能已经放在事先准备好的目录中。 “a-quick” 或 “a-full” 会先准备这些仓库,再启动子目标,原因有二:

    • 构建过程中上游可能发生变化,例如被强制推送。 共用预先准备的副本可以确保整个构建使用一致内容。

    • 如果 15 个工作节点同时从相同上游仓库拉取数据, 可能触发服务器资源限制,甚至被误认为网络攻击。

    准备好的目录通过 NFS 在工作节点之间共享。 如果是单独构建,没有这样的共享目录,则按需从缓存和上游克隆,作为后备方式。

  5. 调用 scripts/run-config。

    再次进入 Helper 脚本,执行该目标的主要工作。

5 Autobuilder 的实现技术

Autobuilder 包含一些针对 Yocto 项目的机制,以提高构建效率与速度。

5.3.1 clobberdir

清理文件时使用 clobberdir。 它不会立刻删除文件,而是先移到专门的位置, 随后由运行在 ionice -c 3 下的 rm 删除。 这样只有在工作节点有空闲 I/O 能力时才执行删除。 该工作由工作节点清理进程负责,见 Autobuilder 工作节点清理进程。

5 Autobuilder 克隆缓存

每次从头克隆仓库会降低构建速度,因此工作节点会预先缓存常用仓库。 克隆时先使用缓存,再按需从上游补齐较新的修订。 缓存由工作节点清理进程维护,见 Autobuilder 工作节点清理进程。

5 Autobuilder 工作节点清理进程

每个工作节点上都运行一个清理进程,主要完成两项工作: 在 I/O 空闲时后台删除文件,见 Autobuilder 目标执行概览 中的 clobberdir 步骤;以及维护克隆仓库缓存,加快后续检出。

5 共享 DL_DIR

工作节点通过 NFS 互联,从而共享 DL_DIR。 这减少了网络访问并加快构建,构建系统中的该目录本身就是按可通过 NFS 共享来设计的。

5 共享 SSTATE_DIR

工作节点通过 NFS 共享 sstate 目录。 某个节点构建出产物后,其他节点就能复用。 构建系统中的这一目录也专门支持通过 NFS 共享。

5 共享哈希等价服务器

所有工作节点使用相同的 BB_HASHSERVE 配置,连接同一个哈希等价服务器。

5.3.7 Resulttool

构建过程中运行的各类测试会将结果写入 testresults.json。 据此可以判断某次构建执行了哪些测试,以及它们的状态。 文件还可能包含失败日志、测试耗时等信息。

Resulttool 属于 OpenEmbedded-Core,用于处理这些 JSON 结果文件, 支持合并文件、显示测试报告和比较不同结果。

详情见 https://wiki.yoctoproject.org/wiki/Resulttool。

5 run-config 的目标执行过程

Autobuilder 的大部分工作发生在 scripts/run-config 中。 开始时执行一次通用初始化:

  1. 如有配置,安装 buildtools 归档。

  2. 如果启用 buildhistory,调用 buildhistory-init。

对于 config.json 中配置的每一步,依次执行:

  1. 用 bitbake-layers add-layer 加入指定的层,日志记为 stepXa。

  2. 调用 scripts/setup-config,生成该构建所需的 build/conf/auto.conf。

  3. 运行 bitbake BBTARGETS,日志记为 stepXb。

  4. 运行 bitbake SANITYTARGETS,日志记为 stepXc。

  5. 在 BitBake 构建环境中运行 EXTRACMDS,日志记为 stepXd。

  6. 在 BitBake 构建环境之外运行 EXTRAPLAINCMDS,日志记为 stepXd。

  7. 用 bitbake-layers remove-layer 移除本步最初加入的层,日志记为 stepXa。

上述步骤完成后,再执行构建后的处理:

  1. 调用 scripts/publish-artifacts,收集需要保存的构建产物。

  2. 调用 scripts/collect-results,收集需要保存的测试结果。

  3. 调用 scripts/upload-error-reports,将错误报告发送到远程服务器。

  4. 构建成功时用 clobberdir 清理 Build Directory;失败时则将目录重命名为 “build-renamed”, 以便后续调试。

5 部署 Yocto Autobuilder

部署自己的 Autobuilder 的最新说明见 yocto-autobuilder2 仓库中的 README.md。

项目希望用户能直接使用 yocto-autobuilder2 代码。 但为了定义自己的测试矩阵,通常需要较大幅度地定制 yocto-autobuilder-helper, 尤其是 config.json。

Autobuilder 支持两种定制方式:

  • 变量替换。

  • 用额外配置文件覆盖配置。

标准 config.json 至少支持路径替换。 Helper 仓库提供的 local-example.json 展示了如何从独立配置文件覆盖设置。 可以在 Autobuilder 环境中设置:

$ ABHELPER_JSON="config.json local-example.json"

也可以使用另一个位置的配置文件:

$ ABHELPER_JSON="config.json /some/location/local.json"

用户经常遇到的问题是 config.json 校验失败。 为减少无效 JSON 导致的问题,可以在提交前用 Git 的 pre-commit-hook.sh 验证文件。创建符号链接的方法如下:

$ ln -s ../../scripts/pre-commit-hook.sh .git/hooks/pre-commit