🤖 roboto_origin_03 Wiki
首页 / 固件 / Deb 包本地编译与依赖管理

RDK X5 镜像工程采用本地源码编译 + 远程仓库下载的混合模式管理 Deb 包。本地编译覆盖内核、驱动、BSP 配置及算法运行时等核心组件,远程下载则补充显示服务器等第三方预编译包。本文深入解析 Deb 包编译流水线的架构设计、依赖解析策略、并行构建机制,以及镜像打包阶段的集成逻辑,帮助开发者掌握如何扩展自定义包、调试依赖冲突与优化构建效率。

Sources: build.sh

架构总览与数据流

Deb 包编译并非孤立阶段,而是嵌入在从源码到镜像的完整链路之中。内核编译输出的 Imagedtbkernel_headers 是多个本地 Deb 包的输入原材料;根文件系统 samplefs 解压后的 sysroot 又为交叉编译用户态库提供头文件与链接环境。理解这一数据流向,是定位构建失败根源的前提。

flowchart TD
    subgraph 输入层
        K[kernel编译输出<br/>deploy/kernel/]
        S[samplefs tar.gz<br/>解压为 deploy/rootfs]
        SRC[source/ 下各仓库源码]
    end

    subgraph 编译层
        MK[mk_debs.sh<br/>本地Deb包编译]
        DL[download_deb_pkgs.sh<br/>远程Deb包下载]
    end

    subgraph 输出层
        LD[deploy/deb_pkgs/<br/>本地构建产物]
        RD[deb_packages/<br/>远程下载产物]
    end

    subgraph 集成层
        PK[pack_image.sh<br/>chroot dpkg安装]
        IMG[最终镜像 .img]
    end

    K -->|Image/dtb/modules| MK
    S -->|sysroot交叉编译| MK
    SRC --> MK
    MK --> LD
    DL --> RD
    LD --> PK
    RD --> PK
    PK --> IMG

整个构建入口由 build.shdebs 子命令触发,该阶段会自动校验 sysroot 可用性,随后调用 mk_debs.sh 执行本地包编译。若执行 pack 阶段且未指定 -l(Local build)标志,则会额外触发 download_deb_pkgs.sh 拉取远程包,最终在 pack_image.sh 中完成合并安装。

Sources: build.sh, pack_image.sh

mk_debs.sh:本地包编译引擎

mk_debs.sh 是本地 Deb 包编译的核心脚本,采用声明式包列表 + 命令式 case 分发的设计模式,通过一组通用元数据生成函数与针对每个包的定制化内容拷贝/编译逻辑,完成从源码到 .deb 产物的转换。

控制文件与元数据生成

每个 Deb 包必须包含符合 Debian 规范的 DEBIAN/control 以及 md5sumschangelog.Debian.gzcopyright 等控制文件。脚本通过以下通用函数统一生成:

最终通过 fakeroot dpkg -b "${deb_dst_dir}" "${deb_dst_dir}".deb 完成打包,确保文件权限与所有权被正确记录 mk_debs.sh

包内容组装模式

make_debian_deb() 函数是包编译的主干,其输入为源码目录名(src_name),内部通过大型 case 语句分发处理。通用流程为:读取源码目录下 VERSION 文件拼接时间戳生成版本号;从 source/<pkg_name>/debian 拷贝骨架文件到临时构建目录;执行各包特有的二进制编译或文件拷贝;最后调用元数据函数完成打包。

hobot-boot 为例,其处理逻辑具有代表性:首先校验 deploy/kernel/ 目录存在(依赖前置的内核编译阶段),然后生成控制文件并将 Depends 设为 hobot-dtb,接着注入 Git Commit 与 Kernel Commit 信息,再调用 mkimage 生成 boot.scr,最后将内核 ImageImage-rtmodules 拷贝至构建目录 mk_debs.sh。类似地,hobot-kernel-headers 直接将 deploy/kernel/kernel_headers/ 的内容整体封装 mk_debs.sh,而 hobot-spdev 则需要在源码目录内执行 ./build.sh 完成交叉编译后,收集 .so.h.whl 产物 mk_debs.sh

双平台差异化处理

脚本通过全局变量 RDK_SOC_NAME(由 .rdk_config 定义)支持 X3 与 X5 双平台。差异处理体现在两个层面:

  1. 包列表差异:定义了 deb_pkg_list_x5deb_pkg_list_x3 两个数组。X5 特有的包如 hobot-spdevhobot-multimedia-samples;X3 则对应 x3-hobot-spdevx3-hobot-multimedia-samplesmk_debs.sh
  2. 内容裁剪差异:部分包(如 hobot-configshobot-utils)的控制文件与配置文件中包含 === X3_START === / === X3_END ====== X5_START === / === X5_END === 标记块,脚本通过 sed 按平台删除无关区块,实现同一份源码仓库适配双平台 mk_debs.sh

Sources: mk_debs.sh, .rdk_config

并行构建与失败熔断

当不带参数调用 mk_debs.sh 时,脚本会启用基于 Bash 后台作业的并行构建引擎。核心逻辑如下:

若需单独调试某个包,可执行 ./mk_debs.sh <pkg_name>,此时走串行单包路径,日志直接输出到终端 mk_debs.sh

包依赖图谱与管理策略

本地 Deb 包之间的依赖关系通过 DEBIAN/controlDepends 字段显式声明。这种设计使得 pack_image.sh 在安装阶段可以按拓扑顺序处理,也为开发者提供了清晰的升级与兼容性边界。

本地包依赖矩阵(X5 平台)

下表列出 X5 平台各本地包的依赖声明与实际含义:

包名 Depends 声明 依赖含义与用途
hobot-dtb 设备树包,处于依赖链根部,不依赖其他本地包
hobot-boot hobot-dtb 内核镜像包需要设备树配合启动
hobot-kernel-headers hobot-boot 头文件版本需与运行内核严格匹配
hobot-configs hobot-boot, udisks2 系统配置依赖内核启动与磁盘管理
hobot-utils hobot-boot 工具集依赖内核接口
hobot-display hobot-boot, hobot-dtb 显示 overlay 需内核与设备树支持
hobot-io hobot-boot GPIO/DTB 工具依赖内核
hobot-io-samples hobot-io IO 示例依赖基础 IO 包
hobot-multimedia hobot-boot 多媒体库依赖内核驱动
hobot-multimedia-dev hobot-multimedia 开发头文件依赖运行时库
hobot-camera hobot-boot 摄像头 sensor 驱动依赖内核
hobot-dnn hobot-boot BPU 运行时依赖内核 BPU 驱动
hobot-spdev hobot-multimedia, hobot-camera, hobot-dnn 高级开发接口聚合多媒体、摄像头与算法能力
hobot-multimedia-samples hobot-multimedia-dev, hobot-multimedia 示例需头文件与运行时库
hobot-audio-config hobot-boot, hobot-dtb 音频配置与 overlay 需内核和设备树
hobot-miniboot Bootloader 更新包,独立升级
hobot-wifi Wi-Fi 固件包,不依赖本地内核包

从表中可以看出,hobot-boothobot-dtb 构成了整个本地包生态的依赖根节点。任何涉及内核接口、设备树 overlay 或驱动模块的包,都必须直接或间接依赖它们。hobot-spdev 则处于依赖链的末端,聚合了多媒体、视觉与 AI 三条子链路,是应用开发者的主要入口。

Sources: mk_debs.sh

远程包与递归依赖解析

并非所有 Deb 包都值得本地源码编译。对于 xserver-xorg-core 等第三方大型包,工程通过 download_deb_pkgs.sharchive.d-robotics.cc 远程仓库下载。该脚本的核心能力在于递归依赖解析与版本锁定

  1. 下载指定 Ubuntu 发行版(如 jammy)的 Packages 索引文件。
  2. RDK_DEB_PKG_LIST 中列出的每个包,从索引中提取最新版本号、文件名、MD5 校验值与 Depends 字段。
  3. 对依赖项进行过滤:仅保留以 xserver 开头的包加入递归下载队列,本地 hobot-* 包由 mk_debs.sh 负责,不在远程解析范围内 download_deb_pkgs.sh
  4. 递归调用 get_download_pkg_list() 直到依赖闭包稳定,最后通过 sort -u 去重。
  5. 下载阶段执行版本比较:若本地已存在同名包但版本较低,自动删除旧版;下载完成后进行 MD5 校验 download_deb_pkgs.sh

这种设计有效避免了手动维护冗长的第三方包列表,同时通过 MD5 校验确保构建可复现性。

Sources: download_deb_pkgs.sh

镜像集成与 Chroot 安装

本地编译与远程下载的 Deb 包,最终需要在 pack_image.sh 中安装到 rootfs 才能进入镜像。该阶段的关键挑战在于:rootfs 此时仅是一个解压后的目录树,尚未启动,因此无法使用 apt 进行在线依赖解析。

三路合并与去重

pack_image.sh 从三个来源收集 Deb 包并拷贝至 ${ROOTFS_BUILD_DIR}/app/hobot_debs

  1. RDK_DEB_PKG_DIR(默认 deb_packages/):远程下载包。
  2. RDK_THIRD_DEB_PKG_DIR(默认 third_packages/):外部第三方包。
  3. deploy/deb_pkgs/mk_debs.sh 的本地编译输出 pack_image.sh

随后执行版本去重:按包名排序后,若存在多个版本,通过 dpkg --compare-versions 仅保留最新版,删除旧版 pack_image.sh

Chroot 下的强制安装

去重后的 Deb 包通过 install_deb_chroot() 函数安装。该函数首先读取包的 Depends 字段,然后执行:

chroot "${dst_dir}" /bin/bash -c "dpkg --ignore-depends=${depends// /} -i /app/hobot_debs/${package}"

此处使用 --ignore-depends 是一个关键工程权衡:由于 rootfs 中的 apt 数据库不完整,且部分依赖包(如本地 hobot-* 系列)可能已在同一批安装队列中,但 dpkg 无法感知队列内其他包的存在,直接安装会因依赖检查失败而中断。通过忽略依赖声明,脚本将控制权交给安装顺序与批次完整性——只要 pack_image.sh 按合理顺序遍历列表,且所有依赖包都在 /app/hobot_debs 中,安装即可成功 pack_image.sh

对于 xserver* 包,脚本还增加了条件判断:若 rootfs 中未预装 XServer(如 Server 版镜像),则跳过安装,避免引入不必要的图形栈依赖 pack_image.sh

Sources: pack_image.sh

构建触发与前置条件

Deb 包编译阶段对前置产物有硬性要求,理解这些条件有助于正确安排构建命令顺序。

内核编译输出

hobot-boothobot-kernel-headershobot-dtb 三个包直接消费 deploy/kernel/ 目录下的产物。若该目录缺失,make_debian_deb() 会立即 exit 1 并提示 "please build kernel" mk_debs.sh。因此,在调用 ./build.sh debs 之前,必须已完成 ./build.sh kernel

Sysroot 交叉编译环境

hobot-spdev 等用户态库需要通过交叉编译器构建,且链接过程依赖目标平台的系统头文件与库文件。build.shdo_debs() 函数会检查 deploy/rootfs/usr/include/string.haarch64-linux-gnu/gnu/stubs.h 是否存在;若缺失,则自动从 rootfs/samplefs_desktop_*.tar.gz 解压生成 sysroot。如果 samplefs 也未构建,脚本将报错并建议先执行 ./build.sh rootfs build.sh

源码仓库同步

mk_debs.sh 大量引用 source/ 目录下的各 Git 仓库(如 source/hobot-bootsource/hobot-spdev)。这些仓库通过 build.sh setup 阶段的 repo sync 拉取,不会在裸仓库中存在。首次构建前必须完成环境初始化。

Sources: build.sh

扩展自定义包

当需要为 RDK 平台引入新的本地 Deb 包时,可遵循以下步骤集成到现有流水线:

  1. 准备源码仓库:在 source/ 下新建仓库(如 source/my-custom-pkg),包含 debian/ 骨架目录、顶层 VERSION 文件,以及构建产物所需的 Makefile 或脚本。
  2. 注册到包列表:在 mk_debs.shdeb_pkg_list_x5deb_pkg_list_x3 数组中追加包名 mk_debs.sh
  3. 实现 case 分支:在 make_debian_deb()case 语句中新增分支,调用 gen_contrl_file 生成控制文件,注入 Depends,执行编译或拷贝逻辑,最后置 is_allowed=1
  4. 声明依赖关系:若新包依赖现有本地包,在 sed -i 's/Depends: .*$/Depends: .../' 中正确填写;若被其他包依赖,则需同步修改下游包的 Depends
  5. 验证与调试:先执行 ./mk_debs.sh my-custom-pkg 单包串行调试,通过后再执行 ./mk_debs.sh 全量并行构建验证兼容性。

若新包仅涉及配置脚本与数据文件、无需源码编译,可直接将文件按目标路径放入 source/my-custom-pkg/debian/ 目录,在 case 分支中通过 cp -a 拷贝即可,无需 Makefile。

总结

RDK X5 的 Deb 包管理体系通过本地源码编译保证核心组件的可控性与追溯性,通过远程仓库下载复用第三方大型包,再通过版本去重与 chroot 强制安装完成镜像集成mk_debs.sh 的 case 分发模式与通用元数据函数提供了良好的扩展性;并行构建与日志隔离则显著缩短了全量编译时间。对于高级开发者而言,掌握依赖链的根节点(hobot-dtbhobot-boot)、前置条件(内核产物与 sysroot)以及 pack_image.sh 中的 --ignore-depends 安装策略,是进行包级定制与故障排查的核心能力。

如需了解内核编译如何生成 Deb 包的输入产物,请参阅 双内核编译与实时内核。若需追踪 Deb 包安装完成后镜像打包的完整流程,可继续阅读 镜像打包与系统定制