4. Yocto/OpenSTLinux构建产测专用镜像
产测镜像与量产镜像的目标不同:量产镜像追求功能完整、用户体验好;产测镜像追求启动快、体积小、可控性强,并且必须保证上电后自动进入测试流程,不需要人工登录、不需要手动挂载、不需要手动启动脚本。OpenSTLinux 基于 Yocto Project 构建,因此定制产测镜像的本质,是在 Yocto 的配方(recipe)与镜像层(image layer)体系里,把“最小系统 + 产测应用 + 依赖库 + 自动启动服务”组合成一个可重复构建、可版本管理的镜像。
先明确本节要构建的对象。假设目标板为 STM32MP157 系列,使用 OpenSTLinux 的 openstlinux-weston 或 openstlinux-headless 作为基础发行版。产测镜像命名为 st-image-prodtst,最终产出 .wic 或 .ext4 镜像,烧录到 eMMC 或 SD 卡后,系统启动到 prodtst.service,由该服务拉起产测主程序 prodtest,主程序通过串口或网络把测试结果上报给上位机。整个过程不依赖桌面环境,因此选择 headless 发行版更合适。
镜像分层与配方组织
Yocto 构建的核心是层(layer)与配方。建议新建一个独立层 meta-prodtst,与 ST 官方层并列,避免直接修改官方层导致升级困难。层内至少包含三类配方:镜像配方、应用配方、服务配方。镜像配方通过 IMAGE_INSTALL 把应用与依赖装入根文件系统;应用配方负责编译产测程序;服务配方负责安装 systemd 单元并设置开机自启。
下面给出一个可直接参考的目录结构示例:
meta-prodtst/
├── conf/layer.conf
├── recipes-core/images/st-image-prodtst.bb
├── recipes-apps/prodtest/prodtest_1.0.bb
└── recipes-apps/prodtest/files/
├── prodtest.service
└── prodtest.conf
镜像配方 st-image-prodtst.bb 的关键内容如下,它继承 ST 的镜像基类,并显式声明要安装的包:
require recipes-st/images/st-image.inc
SUMMARY = "Production test image for STM32MP1"
LICENSE = "MIT"
IMAGE_FEATURES += "ssh-server-openssh"
IMAGE_INSTALL += "prodtest libgpiod libmodbus python3-core"
# 关闭不需要的组件,减小体积
IMAGE_INSTALL:remove = "weston weston-init"
inherit core-image
这里 IMAGE_INSTALL 中的 prodtest 是应用配方产出的包,libgpiod 用于 GPIO 控制,libmodbus 用于与测试治具通信,python3-core 用于运行部分测试脚本。移除 weston 可以显著减少根文件系统体积,同时避免桌面环境抢占启动时间。
产测应用配方与依赖
应用配方 prodtest_1.0.bb 负责把源码编译并安装到镜像中。若源码放在 files/ 下,可使用 SRC_URI = "file://...";若使用 Git 仓库,则用 SRC_URI = "git://..."。配方中通过 DEPENDS 声明编译期依赖,通过 RDEPENDS 声明运行期依赖,确保依赖库被正确打包进镜像。
SUMMARY = "Production test application"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://LICENSE;md5=..."
SRC_URI = "file://prodtest.c \
file://prodtest.service \
file://prodtest.conf"
S = "${WORKDIR}"
DEPENDS = "libgpiod libmodbus"
RDEPENDS:${PN} = "libgpiod libmodbus python3-core"
do_compile() {
${CC} ${CFLAGS} ${LDFLAGS} -o prodtest prodtest.c -lgpiod -lmodbus
}
do_install() {
install -d ${D}${bindir}
install -m 0755 prodtest ${D}${bindir}/prodtest
install -d ${D}${systemd_system_unitdir}
install -m 0644 ${WORKDIR}/prodtest.service ${D}${systemd_system_unitdir}/
install -d ${D}${sysconfdir}
install -m 0644 ${WORKDIR}/prodtest.conf ${D}${sysconfdir}/
}
inherit systemd
SYSTEMD_SERVICE:${PN} = "prodtest.service"
SYSTEMD_AUTO_ENABLE:${PN} = "enable"
其中 SYSTEMD_AUTO_ENABLE 设为 enable 是自动启动的关键,它会在镜像构建时创建指向 multi-user.target.wants 的软链接,使服务随系统启动。
自动启动服务与启动顺序
产测服务需要在外设就绪后启动,因此单元文件中应声明依赖关系。After= 表示启动顺序,Wants= 表示弱依赖。若产测程序需要网络上报,可加入 network-online.target;若需要 GPIO 就绪,可加入 sysinit.target。下面是一个可用的单元文件示例:
[Unit]
Description=Production Test Service
After=network-online.target sysinit.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/bin/prodtest --config /etc/prodtest.conf
Restart=on-failure
RestartSec=2
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
配置文件 prodtest.conf 用于区分不同工位与测试项,例如指定串口设备、治具地址、超时时间、结果上报地址等。把配置与程序分离,可以在不重新构建镜像的情况下调整测试参数,这对产线快速换型非常重要。
构建、烧录与验证
完成配方后,在构建目录中初始化环境并执行镜像构建。以 ST 官方发布的环境为例,命令如下:
DISTRO=openstlinux-headless MACHINE=stm32mp157f-dk2 source layers/meta-st/scripts/envsetup.sh
bitbake st-image-prodtst
构建完成后,镜像位于 tmp-glibc/deploy/images/stm32mp157f-dk2/ 下,通常包含 .wic、.ext4 和 .tar.xz 等格式。使用 STM32CubeProgrammer 或 dd 命令烧录到 SD 卡或 eMMC。烧录后上电,观察串口输出,应能看到 systemd 启动日志中出现 Started Production Test Service,随后产测程序开始执行。
验证时重点检查三件事:第一,服务是否自动启动,可用 systemctl status prodtest 查看;第二,依赖库是否齐全,可用 ldd /usr/bin/prodtest 检查是否有 not found;第三,测试结果是否正确上报,可在上位机侧确认收到的 PASS/FAIL 记录。若服务未启动,优先检查 SYSTEMD_AUTO_ENABLE 是否生效,以及单元文件是否被正确安装到 /lib/systemd/system/。
bitbake -e 中的关键变量,可以快速定位依赖变化。体积与启动时间优化
产测镜像不需要完整发行版的所有组件。可以通过 IMAGE_INSTALL:remove 移除文档、桌面、多余语言包;通过 PACKAGE_EXCLUDE 排除不需要的包;通过 IMAGE_FSTYPES 只保留实际使用的镜像格式。若启动时间仍然偏长,可检查 systemd 的 systemd-analyze blame 输出,把非关键服务改为按需启动。对于产测场景,通常把启动时间控制在 10 秒以内是比较合理的目标,具体取决于外设初始化耗时。
最后需要强调的是,产测镜像的“最小”不是一味删减,而是保证测试所需能力完整的前提下减少无关组件。产测应用、依赖库、自动启动服务三者缺一不可,配置与程序分离、层与官方层分离,才能让镜像在产线长期使用中保持可维护、可升级、可复现。