3. Yocto工程与BSP层定制
在 i.MX Linux BSP 开发中,Yocto 工程并不是“一个可以直接改的源码树”,而是由多个 layer 叠加形成的构建系统。理解 layer 的职责边界,比记住某条 bitbake 命令更重要。NXP 官方 BSP 主要依赖两个关键层:meta-freescale 与 meta-imx。前者是社区维护的 Freescale/NXP 通用支持层,后者是 NXP 官方发布的 i.MX 专用 BSP 层,二者在依赖关系、配方内容和发布节奏上都有明显差异。
meta-freescale 与 meta-imx 的层结构差异
meta-freescale 属于 OpenEmbedded/Yocto 社区层,主要提供 i.MX 系列 SoC 的通用 BSP 支持,包括 U-Boot、Linux 内核、GPU/VPU 固件、imx-gpu-viv、imx-vpu 等配方的社区版本。它的更新跟随社区节奏,适合需要长期维护、可自行打补丁的产品。
meta-imx 是 NXP 官方发布的 BSP 层,通常以 release tag 形式提供,例如 rel_imx_5.15.71_2.2.0 或 rel_imx_6.1.55_2.2.0。它内部按功能拆分为多个子层,常见结构如下:
meta-imx-bsp:machine 配置、U-Boot、kernel、ATF、firmware 等核心 BSP 配方;meta-imx-sdk:SDK 工具链、交叉编译环境相关配方;meta-imx-ml:机器学习、NPU、eIQ 相关配方;meta-imx-graphics:GPU、Wayland、Weston、OpenGL ES 相关配方;meta-imx-vpu:VPU 编解码固件与库。
实际工程中,bblayers.conf 的 BBLAYERS 变量决定了哪些层参与构建。一个典型的 i.MX 8M Plus 工程会同时包含 meta-freescale、meta-imx/meta-imx-bsp、meta-imx/meta-imx-sdk 以及 meta-openembedded 下的若干子层。层顺序会影响配方优先级,后加入的层通常覆盖前面的同名配方。
machine 配置:从 SoC 到板级
machine 配置决定目标板的 CPU 架构、内核设备树、U-Boot 配置、镜像格式和启动方式。在 meta-imx-bsp/conf/machine/ 下可以看到 imx8mp-evk.conf、imx8mm-evk.conf、imx93-11x11-evk.conf 等文件。以 i.MX 8M Plus EVK 为例,关键变量包括:
# imx8mp-evk.conf 关键片段(示例)
MACHINEOVERRIDES =. "imx8mp:imx8m:"
KERNEL_DEVICETREE = "freescale/imx8mp-evk.dtb freescale/imx8mp-evk-rm67191.dtb"
UBOOT_CONFIG = "sd"
UBOOT_CONFIG[sd] = "imx8mp_evk_defconfig,sdcard"
SERIAL_CONSOLES = "115200;ttymxc1"
IMX_DEFAULT_BSP = "nxp"
如果产品基于 EVK 但更换了 PMIC、DDR 容量或以太网 PHY,不应直接修改官方 imx8mp-evk.conf,而应在本地层新建 conf/machine/myboard.conf,通过 require 继承官方配置后再覆盖差异项:
# meta-myproduct/conf/machine/myboard.conf
require conf/machine/imx8mp-evk.conf
KERNEL_DEVICETREE = "freescale/myboard.dtb"
UBOOT_CONFIG = "sd"
PREFERRED_PROVIDER_u-boot = "u-boot-imx"
PREFERRED_VERSION_u-boot-imx = "2022.04%"
这样既保留了官方 BSP 的完整定义,又只暴露产品差异,后续升级 BSP 时冲突面最小。
distro 配置:发行版策略
distro 配置决定整个发行版的构建策略,包括 init 系统、C 库、包管理格式、编译优化选项和特性开关。NXP 官方提供 fsl-imx-xwayland、fsl-imx-wayland、fsl-imx-fb 等 distro。选择哪一个,直接影响镜像中是否包含 Wayland、X11 或 Framebuffer 支持。
在 build/conf/local.conf 中通过 DISTRO 变量指定:
DISTRO = "fsl-imx-xwayland"
MACHINE = "imx8mp-evk"
若产品需要精简系统,可在本地层创建 conf/distro/myproduct.conf,继承官方 distro 后关闭不需要的特性:
require conf/distro/fsl-imx-xwayland.conf
DISTRO_FEATURES:remove = "x11 wayland"
DISTRO_FEATURES:append = " systemd"
PACKAGE_CLASSES = "package_rpm"
注意 DISTRO_FEATURES 的增删会影响大量配方的条件编译分支,修改后建议先执行 bitbake -e 检查变量展开结果,再开始完整构建。
image 配方:定义最终交付物
image 配方决定根文件系统中包含哪些包、生成什么格式的镜像。NXP 官方提供 imx-image-core、imx-image-full、core-image-base 等。产品通常需要自定义 image,例如只保留 Qt、网络工具和调试串口,去掉示例程序和文档。
# meta-myproduct/recipes-core/images/myproduct-image.bb
require recipes-core/images/core-image-base.bb
IMAGE_INSTALL:append = " \
packagegroup-core-boot \
qtbase \
qtwayland \
openssh \
ethtool \
i2c-tools \
"
IMAGE_FEATURES:append = " debug-tweaks ssh-server-openssh"
IMAGE_FSTYPES = "wic.bz2 tar.bz2"
构建命令为 bitbake myproduct-image。生成物位于 tmp/deploy/images/imx8mp-evk/ 下,可通过 wic.bz2 直接烧录到 SD 卡。判断 image 是否包含预期包,可用 bitbake -e myproduct-image | grep ^IMAGE_INSTALL= 查看最终展开值。
bbappend 与本地层创建方法
bbappend 是覆盖或追加官方配方内容的标准手段。创建本地层的基本流程如下:
- 在
sources/下新建目录meta-myproduct; - 创建
conf/layer.conf,声明层路径、优先级和兼容的 Yocto 版本; - 按配方类别建立子目录,如
recipes-kernel/linux/、recipes-bsp/u-boot/; - 在
bblayers.conf的BBLAYERS末尾加入该层路径; - 用
bitbake-layers show-layers确认层已生效。
# meta-myproduct/conf/layer.conf
BBPATH .= ":${LAYERDIR}"
BBFILES += "${LAYERDIR}/recipes-*/*/*.bb ${LAYERDIR}/recipes-*/*/*.bbappend"
BBFILE_COLLECTIONS += "myproduct"
BBFILE_PATTERN_myproduct = "^${LAYERDIR}/"
BBFILE_PRIORITY_myproduct = "20"
LAYERSERIES_COMPAT_myproduct = "kirkstone"
一个典型的内核 bbappend 用于追加设备树和配置片段:
# meta-myproduct/recipes-kernel/linux/linux-imx_%.bbappend
FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
SRC_URI += "file://myboard.dts \
file://myboard.cfg"
KERNEL_DEVICETREE:append = " freescale/myboard.dtb"
其中 FILESEXTRAPATHS:prepend 保证 file:// 引用的文件优先从本地层目录查找,而不是官方层。修改后执行 bitbake -c cleansstate linux-imx 再重新构建,避免旧缓存掩盖变更。
bitbake-layers show-appends 确认追加关系,再开始构建。
linux-imx_%.bbappend 中的 % 用于匹配任意版本。若写成 linux-imx.bbappend,在部分 Yocto 版本中不会生效。另外,SRC_URI 追加的文件必须放在与 bbappend 同级的 ${PN} 目录下,否则会报找不到文件。