15 使用 Multiconfig 为多个目标构建镜像

可以用一条 bitbake 命令,为不同目标构建多个镜像或软件包,每个镜像或 软件包采用不同配置。这种多配置构建也称为 "multiconfig",本节沿用这一术语。

本节介绍如何设置多配置构建,以及如何处理不同 multiconfig 之间的跨构建依赖。

15 设置并运行多配置构建

进行多配置构建时,必须在 Build Directory 或层的配置目录中,使用 并列的 configuration file 分别定义每个目标的配置,并遵循规定的 文件层级。此外,还必须在 build/conf/local.conf 中启用 多配置构建。

按以下步骤设置和执行:

  • 创建独立配置文件: 为每个构建目标,即每个 multiconfig,创建一个 Configuration File。配置内容取决于具体实现,通常会定义 MACHINE 和 BitBake 构建使用的临时目录 TMPDIR。

    备注

    能否共享 TMPDIR,取决于配置之间的相同点和差异。只要其他配置 一致,多个 MACHINE 目标可以共享同一个 TMPDIR;不同 DISTRO 设置则需要独立的 TMPDIR。

    例如,同一个 MACHINE "qemux86" 分别使用 "poky" 和 "poky-lsb" 两个发行版构建时,必须使用两个不同的 TMPDIR。

    一般而言,强烈建议不同 multiconfig 使用独立 TMPDIR。

    配置文件必须放在当前 Build Directory 的 conf/multiconfig 子目录中,或者 Layer 的 conf/multiconfig 目录中。下例为 "x86" 和 "arm" 两个 multiconfig 定义配置文件:

    ../_images/multiconfig_files.png

    与其他配置文件类似,使用通常的 BBPATH 搜索路径定位 multiconfig 文件。

    以下 qemux86.conf configuration file 展示了 qemux86 目标所需的最少语句,临时构建目录为 tmp-qemux86:

    MACHINE = "qemux86"
    TMPDIR .= "-${BB_CURRENT_MC}"
    

    BitBake 将 BB_CURRENT_MC 展开为当前使用的 multiconfig 名称。 将其追加到 TMPDIR,可以使 TMPDIR 定义的任何变化自动 影响各 multiconfig 的临时目录。

  • 向本地配置文件添加 BitBake 多配置变量: 在 build/conf/local.conf 中使用 BBMULTICONFIG 指定各 multiconfig。延续上图示例,需要指定两个配置文件以启用 "x86" 和 "arm":

    BBMULTICONFIG = "x86 arm"
    

    备注

    默认配置始终存在,名称为 "",即空字符串,由 build/conf/local.conf 中的变量定义。因此,上例实际 是在 "" 之外增加了 "arm" 和 "x86" 两种配置。

  • 启动 BitBake: 使用以下命令形式启动多配置构建:

    $ bitbake [mc:multiconfigname:]target [[[mc:multiconfigname:]target] ... ]
    

    本节示例的命令如下:

    $ bitbake mc:x86:core-image-minimal mc:arm:core-image-sato mc::core-image-base
    

    该命令构建:

    • 通过 x86.conf 配置的 core-image-minimal 镜像

    • 通过 arm.conf 配置的 core-image-sato 镜像

    • 通过 build/conf/local.conf 配置的 core-image-base

备注

Yocto Project 6.1(Blacksail)发行版的多配置构建支持不包含共享 状态(sstate)优化。因此,如果某个对象在两个不同 TMPDIR 等 位置使用两次,构建只会在开始时使用已有共享状态缓存,否则就从头构建该对象。

15 启用多配置构建依赖

多配置构建中,不同目标之间有时存在依赖。例如,为 "x86" multiconfig 构建 core-image-sato 镜像前,需要先生成 "arm" multiconfig 的根文件系统。 其本质是 core-image-sato 配方的 do_image 任务依赖 core-image-minimal 配方的 do_rootfs 任务完成。

要启用这种依赖,必须在配方中按以下格式声明:

task_or_package[mcdepends] = "mc:from_multiconfig:to_multiconfig:recipe_name:task_on_which_to_depend"

以前述场景为例,需要向构建 core-image-sato 的配方添加:

do_image[mcdepends] = "mc:x86:arm:core-image-minimal:do_rootfs"

本例的 from_multiconfig 是 "x86",to_multiconfig 是 "arm"。配方的 do_image 依赖 "arm" multiconfig 中 core-image-minimal 配方的 do_rootfs。

设置依赖后,可如下构建 "x86" multiconfig:

$ bitbake mc:x86:core-image-sato

此命令执行创建 "x86" 的 core-image-sato 镜像所需的全部任务。由于上述 依赖,BitBake 也会执行 "arm" 构建,直到完成 do_rootfs。

让配方依赖另一个构建的根文件系统,可能看起来用途不大。可以将 core-image-sato 中的语句改为:

do_image[mcdepends] = "mc:x86:arm:core-image-minimal:do_image"

这时,由于 "x86" 构建的依赖,BitBake 必须创建 "arm" 的 core-image-minimal 镜像。

因为 "x86" 和 "arm" 都已启用并具有独立配置文件,BitBake 会将各构建产物 放在相应临时构建目录,即 TMPDIR 中。

15 推荐实践

  • 除 bitbake.conf 的默认值外,TMPDIR 只由用户在 build/conf/local.conf 中设置。这意味着 不应 在 机器或发行版 configuration file 中以任何方式修改它。

  • multiconfig 应指定 TMPDIR,并通过 BB_CURRENT_MC 追加 multiconfig 名称。

  • 将某个 multiconfig 构建输出转移到另一个配置的配方,应使用 do_task[mcdepends] 触发组件构建,再在 do_install 和 do_deploy 中,依据 TMPDIR 确定部署产物位置并转移 到当前配置。

    do_install 和 do_deploy 应类似如下:

    do_install() {
        install -m 0644 ${TMPDIR}-<multiconfig>/tmp/deploy/images/<machine>/somefile ${D}/some/path
    }
    
    do_deploy() {
        install -m 0644 ${TMPDIR}-<multiconfig>/tmp/deploy/images/<machine>/somefile ${DEPLOYDIR}/somefile
    }
    

    上例中:

  • 不依赖标准 C 库等默认依赖的固件配方,可以将 INHIBIT_DEFAULT_DEPS 设为 1。

15 常见用例:同时构建裸机固件和 Linux

一种常见用法是将默认配置用于常规 Linux 构建,另用一个或多个 multiconfig 构建裸机固件等特殊组件。它也适用于微控制器与运行 Linux 的主处理器协同 工作的场景。本节说明如何通过多配置构建实现这些需求。

15 为裸机固件添加 multiconfig 配置文件和配方

如 设置并运行多配置构建 所述,每个 multiconfig 都需要独立 Configuration File。此外,本例 为裸机固件构建配置定义独立 TMPDIR。

例如,新建 conf/multiconfig/baremetal-firmware.conf,内容如下:

TMPDIR .= "-${BB_CURRENT_MC}"
TCLIBC = "newlib"

此文件配置独立的 TMPDIR,保存使用 newlib 工具链编译的二进制文件,见 TCLIBC。

备注

本例的 multiconfig 配置文件未覆盖默认 MACHINE,所以裸机二进制 文件的架构相同。如果固件运行在完全不同的架构上,则必须覆盖 MACHINE。

然后创建 my-firmware.bb 配方,定义裸机固件的构建方式。配方应提供足够 信息,让 OpenEmbedded build system 正确使用工具链编译固件。具体 构建任务因固件而异,但配方应定义 deploy 任务,将输出 部署到 DEPLOYDIR。下文假定输出文件名为 my-firmware.elf。

15 构建固件

可以用以下 BitBake 命令构建固件:

$ bitbake mc:baremetal-firmware:my-firmware

不过,我们希望启动常规 Linux 构建时自动构建 my-firmware。

Linux 构建中的配方可以通过 mcdepend 触发 my-firmware 构建。例如, Linux 构建需要组装一种使用该配方输出的“特殊”固件,称为 my-parent-firmware.bb。在其中指定依赖:

do_compile[mcdepends] = "mc::baremetal-firmware:my-firmware:do_deploy"

这样就能确保 my-parent-firmware 的 do_compile 被触发时, my-firmware 的 do_deploy 已成功完成。

15 使用 my-firmware 的输出

my-firmware 配方部署 my-firmware.elf 后,需要使用该输出。可以根据 Yocto Project 默认变量作出一组约定,以找到二进制文件进行打包。

首先在 my-parent-firmware.bb 中设置:

FIRMWARE_FILE ??= "${TMPDIR}-baremetal-firmware/deploy/images/<machine>/my-firmware.elf"
FIRMWARE_FILE[vardepsexclude] += "TMPDIR"

第一条赋值保存 my-firmware.bb 构建并部署的固件路径;第二条将 TMPDIR 排除在 FIRMWARE_FILE 的依赖之外。这意味着修改 TMPDIR,例如更换构建主机,不会使 共享状态缓存 失效。

<machine> 应替换为 baremetal-firmware 配置中构建所用的 MACHINE。

随后向 my-parent-firmware 添加 do_install 任务:

do_install() {
    install -Dm 0644 ${FIRMWARE_FILE} ${D}/lib/firmware/my-firmware.elf
}

这样便可将固件二进制文件转移并打包到 Linux 配置及根文件系统中。