关于 jetson-promote-image
jetson-promote-image 将定制和构建产物复制到配置的 bsp_image,供后续刷写或检查。它合并 overlay 与构建清单输入,跳过相同文件,并在内核或模块变化时刷新 initramfs。
主要功能
- 01合并 overlay 与构建清单产物
- 02跳过内容相同的文件
- 03将变更的内核 Image 镜像到 rootfs
- 04内核或模块变更后刷新 initramfs
- 05检查构建新鲜度和 overlay 冲突
适用场景
- 01刷写 Jetson 前暂存 BSP 产物
- 02不刷写而更新 bsp_image 以供检查
- 03为另一台刷写主机准备镜像
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ nvidia/ skills --skill jetson-promote-image安装后在 Claude Code 中输入/jetson-promote-image确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
BENCHMARK.mdskill-card.mdskill.oms.sigevals/evals.jsonreferences/build-source-freshness-gate.mdcopy-pass-snippets.mdkernel-image-and-initramfs.md详细介绍
提升 BSP 映像
用途
将所有 Customize-* 和 Build 输出暂存到 bsp_image,使其
可用于 /jetson-flash-image。这是 Deploy 的提升阶段——
它只复制文件,不刷写,也不构建。
前置条件
- 已激活的目标平台配置,其中
source:和bsp_image:均已解析(先运行/jetson-init-source和/jetson-init-image)。 <source.root_path>/Linux_for_Tegra/已初始化为 git 仓库 (覆盖层跟踪器),且工作树干净。<bsp_image.root_path>/Linux_for_Tegra/已从 BSP tarball 解压,并已运行apply_binaries.sh。- 主机上已安装
git、yq、cmp和sudo(用于rootfs/*目标路径)。 /jetson-build-source生成的<source.root_path>/.build-manifest.yaml和.build-state.yaml(内核侧仓库有 customize-* 提交时必需)。
概述
这是 Deploy 的提升阶段——流水线概览请参阅
../../context/bsp-customization-workflow.md。
此技能会遍历以下两个通道:
| 通道 | 来源 | 载体 | 所属方 |
|---|---|---|---|
| 覆盖层跟踪器 | <source.root_path>/Linux_for_Tegra/(位于 HEAD 的 git 仓库) | 无需构建的 Customize-* 输出(例如 nvfancontrol.conf、nvpmodel.conf、手动编辑的 BPMP DTB) | Customize customize-* 技能在此提交 |
| 构建清单 | <source.root_path>/.build-manifest.yaml | 重新构建的内核 Image、树内 .ko、OOT .ko、NVIDIA DTB | Build jetson-build-source 在此写入 |
此技能会计算需要复制的文件并集,并将每个文件写入
<bsp_image.root_path>/Linux_for_Tegra/,同时采用感知差异的
相同文件跳过逻辑。当复制操作涉及内核
Image 或 rootfs/lib/modules/ 下的任何内容时,它还会通过 NVIDIA 的
tools/l4t_update_initrd.sh 重新构建 initramfs,以便刚提升的内核和模块包含在
引导加载程序实际加载的 initrd 中。运行完成后,bsp_image 会包含所有 Customize 和 Build 输出。此技能不会刷写,也
不会修改工作区。
何时调用
- 典型 Deploy 链的第一阶段:
jetson-promote-image → jetson-flash-image → jetson-validate-image。 - 独立调用:用户希望更新
bsp_image,但尚未准备好刷写时 (例如检查解析后的文件、运行读取 bsp_image 的 带外构建,或将 bsp_image 交给单独的刷写主机)。
步骤
解析激活的目标和路径
按照
../../context/target-platform-contract.md
中的契约解析激活的配置。
在以下情况下拒绝并转交:
| 条件 | 拒绝时转交至 |
|---|---|
没有激活的配置,或 active: NA | 转交至 /jetson-set-target 或 /jetson-init-target。 |
配置缺少 bsp_image: | 转交至 /jetson-init-image。 |
<bsp_image.root_path>/Linux_for_Tegra/ 不存在 | 转交至 /jetson-init-image。 |
<source.root_path>/Linux_for_Tegra/ 不存在或不是 git 仓库 | 转交至 /jetson-init-source。 |
解析路径:
<workspace>= 激活配置的target-platform/目录的父目录(在加载时发现)。<bsp_image.root_path>取自bsp_image.root_path:(若存在), 否则为<workspace>/Image。<source.root_path>取自source.root_path:(若存在),否则 为<workspace>/Source。
为本步骤后续部分绑定 Shell 变量:
LFT_SRC="<source.root_path>/Linux_for_Tegra" # overlay tracker
LFT_DST="<bsp_image.root_path>/Linux_for_Tegra"
MANIFEST="<source.root_path>/.build-manifest.yaml" # build outputs
验证两个通道
此技能要求至少有一个通道包含内容。如果覆盖层跟踪器有未提交的更改(status --porcelain
非空)、$MANIFEST 存在但无法解析为 YAML,或两个通道都为空,则拒绝执行。记录 OVERLAY_HAS_COMMITS /
OVERLAY_HEAD 和 MANIFEST_PRESENT,供后续步骤使用。
Shell 代码片段和拒绝消息请参阅
references/copy-pass-snippets.md。
验证构建源的新鲜度
如果 .build-state.yaml 显示 Source/bsp_sources/ 中有任何内核侧仓库自上次 /jetson-build-source 以来存在未提交更改,则拒绝执行;否则,复制过程可能会悄然发布过时的制品。
检测规则和 shell 片段见
references/build-source-freshness-gate.md。
记录 BUILD_FRESH=1。
提升前冲突检查(仅限 overlay)
当 overlay 跟踪远程仓库时,如果上游存在尚未拉取的提交,则拒绝执行。未配置远程仓库时(jetson-init-source 创建的默认空 git init 跟踪仓库),则优雅跳过。
manifest 通道没有 git 远程仓库的概念——此检查仅适用于 overlay。为 Summary 记录 COLLISION_CHECK。
shell 片段见
references/copy-pass-snippets.md。
枚举源(两个通道)
通道 A — overlay:以针对 $LFT_SRC 执行的 git ls-files 结果为准(当 source.repos.Linux_for_Tegra 被覆盖时,此方式可透明处理符号链接挂载,并排除未跟踪或被 .gitignore 忽略的文件)。每个条目映射为
src = $LFT_SRC/<rel> → dst = $LFT_DST/<rel>。
通道 B — manifest:从 $MANIFEST 解析 artifacts[].{src,dst}。如果磁盘上缺少任何 src,则拒绝执行(构建已中断或 manifest 已过时——请重新运行 /jetson-build-source)。
manifest 架构由
jetson-build-source v0.2.0 编写。
两个 shell 片段和 manifest YAML 架构见 references/copy-pass-snippets.md。
将差异文件复制到 bsp_image
遍历 overlay 文件和 manifest 条目的并集。对于每个 dst:如果字节完全相同,则跳过;否则执行 cp -p(对于 rootfs/* 目标,使用 sudo,因为示例 rootfs 是以 root 身份解压的)。如果写入了任何 rootfs/lib/modules/* 或 kernel/Image,则设置 INITRD_DIRTY=1——“刷新 initramfs”步骤会根据此标志决定是否执行。为 Summary 记录计数 / FIRST / LAST。
快速失败:如果任何 cp 失败,则指出失败路径并停止。bsp_image 可能只更新了一部分——修复原因后重新运行,即可通过差异感知跳过机制继续。通道顺序为先 overlay,后 manifest:如果 dst 冲突,则以 manifest 为准(新构建的制品优先于较旧的 overlay 副本)。
copy_one() 函数和两个驱动循环见 references/copy-pass-snippets.md。
内核发生变化时,将内核 Image 镜像到 rootfs
内核 Image 在 bsp_image 中有两个路径:
<LFT_DST>/kernel/Image(刷写工具读取的文件)和
<LFT_DST>/rootfs/boot/Image(rootfs 侧副本,在刷新工具运行所在的 rootfs chroot 环境中可见为 /boot/Image)。构建 manifest 只包含 kernel/Image 的 dst,因此此步骤会将 kernel/Image 镜像到 rootfs/boot/Image(差异感知;已同步时不执行任何操作),确保 chroot 中的刷新工具使用新提升的二进制文件解析内核,而不是过时的 rootfs 副本。镜像操作也会设置 INITRD_DIRTY=1,因此仅提升内核(未写入 rootfs/lib/modules/*)时仍会触发刷新。
shell 片段、此操作可避免的故障模式以及 INITRD_DIRTY 的边缘情况见 references/kernel-image-and-initramfs.md。
刷新 initramfs(内核或模块发生变化时)
每当 INITRD_DIRTY=1(由上方的差异感知复制或镜像步骤设置)时,都要从 <LFT_DST>/ 运行 tools/l4t_update_initrd.sh。该工具会 chroot 进入 rootfs/,运行 NVIDIA 的 nv-update-initrd,并写入 <LFT_DST>/bootloader/l4t_initrd.img(由刷写工具使用)和 <LFT_DST>/rootfs/boot/initrd(DUT 上的 /boot/initrd)。操作具有幂等性;耗时约 30 秒。INITRD_DIRTY=0 时跳过(仅修改 overlay)。DUT 端的变通方案(update-initramfs -u 加手动 cp)不在范围内——应在此处修复缺口,确保刷写时使用一致的镜像。
有关 shell 代码片段、拒绝处理的路径、此重建所解决的“模块遮蔽”和“vermagic 不匹配”故障模式,以及为何不处理 bootloader/initrd(另一个不同的文件),请参阅 references/kernel-image-and-initramfs.md。
摘要
报告:
- Overlay 范围:
overlay HEAD ($OVERLAY_HEAD)或“(空)”。 - Manifest 范围:
mode=<...>, bsp_version=<...>, rebuilt_at=<...>, N artifacts或“(不存在)”。 - 冲突检查:
$COLLISION_CHECK。 - 计数:
- overlay:
$COPIED_OVERLAY copied, $IDENTICAL_OVERLAY identical - manifest:
$COPIED_MANIFEST copied, $IDENTICAL_MANIFEST identical
- overlay:
- Kernel Image 镜像:
$KIMG_MIRRORED;initramfs:$INITRD_STATUS(由kernel/Image或rootfs/lib/modules/*写入触发时为copied …/rebuilt;否则为skipped …)。 - 首个 / 最后一个复制的路径(若
COPIED总数均为 0,则省略)。 - 解析后的
<source.root_path>、<bsp_image.root_path>。 - 下一步:
/jetson-flash-image(如果用户只想刷新 bsp_image 以供检查 / 静态验证,则为/jetson-validate-image)。
限制
- 两个通道,一个目标目录。 两轮操作都会写入
bsp_image/Linux_for_Tegra/。Overlay 承载 customize-* 的输出(仅 Overlay 的修改,例如 nvfancontrol.conf);清单承载重建的二进制文件(kernel/OOT/DT)。两者在设计上互不重叠:构建输出不会进入 Overlay,customize-* 对非构建文件的修改也不会进入清单。 - 构建清单是追溯到脏源代码的约定。 清单中的所有内容都来自存在未提交更改的源代码仓库(依据
jetson-build-source的“Write the build manifest”步骤追踪策略)。因此,提升清单内容是安全的:每个条目都是承载自定义内容的构件,而不是工具链差异造成的噪声。该技能不会重新推导追踪结果,而是信任清单。 - 清单条目可能在构建输出被删除后仍然存在。 如果用户在
jetson-build-source和jetson-promote-image之间清空Source/.build/或bsp_sources/的构建构件,清单将引用不存在的文件。在这种情况下,“Enumerate sources (both channels)”步骤会拒绝继续,并提示用户运行/jetson-build-source重新构建。 - 仅发生 Overlay 修改时,清单缺失没有问题。 纯 Overlay 侧的自定义修改(例如
customize-fan)不会生成构建输出,也不会写入清单——“Enumerate sources (both channels)”步骤将不执行任何操作,“Diff-aware copy into bsp_image”步骤只会提升 Overlay 文件。该技能会在摘要中显示“manifest: (absent)”,然后继续。 - 感知差异且幂等。 如果自上次提升以来,Overlay 没有新提交且清单没有变化,重新运行不会产生任何操作(所有文件都相同)。可用此方式确认 bsp_image 已同步,且不会产生副作用。
- 透明处理符号链接挂载。 当
jetson-init-source中覆盖了source.repos.Linux_for_Tegra时,规范挂载点是指向<source.root_path>/.repos/Linux_for_Tegra/<subdir>的符号链接。git -C、cp -p和cmp -s都会透明地跟随该链接——此层无需特殊处理。清单中的src路径是绝对路径,因此bsp_sources/下的符号链接不会影响清单通道。 sudo仅用于rootfs/目标路径。rootfs/下的文件由jetson-init-image使用sudo tar xpjf解压,因此具有 root 所有权和烧录工具链读取所需的特殊模式位。sudo cp -p会保留这些属性。其他所有内容(bootloader/、kernel/、kernel/dtb/、tools/等)均归用户所有,无需使用sudo。这适用于两个通道。- 通道重叠时的优先级。 如果同一个
dst同时出现在 Overlay 和清单中,则以清单为准(它在“Diff-aware copy into bsp_image”步骤的循环中靠后处理)。这符合预期语义——清单条目是最新构建的,而 Overlay 条目可能是较旧状态。不建议手动将二进制文件编辑后放入 Overlay(应由 Build 负责重建);该优先级规则可让此类错误得以恢复。 - Deploy 之外的
bsp_image为只读。 在正常流程中,此技能是唯一的写入方(符合工作流不变量)。在 Deploy 之外手动编辑<bsp_image.root_path>/Linux_for_Tegra/,如果同一路径存在于任一通道中,下次提升运行时这些修改会被静默覆盖;反之,如果没有对应条目覆盖,这些修改则不会被还原。这两种情况都会破坏差异追踪记录——切勿手动修改上游内容。 - 范围仅限 Overlay 的 HEAD(通道 A)。 指定标签/清单/提交范围的功能暂不支持(见下文)。要提升历史状态,请先运行
git -C $LFT_SRC checkout <ref>,然后重新运行。清单通道没有范围限制——它反映jetson-build-source上次运行所生成的内容。 - 部分失败时不会自动回滚。 如果
cp中途失败,bsp_image会处于中间状态。请修复根本原因(通常是权限问题或磁盘空间不足),然后重新运行——“Diff-aware copy into bsp_image”步骤会跳过已提升的文件并从中断处继续。 - Kernel
Image镜像及 initramfs 刷新。 仅当复制过程中写入了kernel/Image或rootfs/lib/modules/*时才会触发;镜像会供刷新的 chroot 使用。两者都会感知差异,纯 Overlay 修改时会跳过。bsp_image中必须存在tools/l4t_update_initrd.sh(随apply_binaries.sh提供);如果缺少该工具,将拒绝继续并引导用户运行/jetson-init-image。完整约定和失败情况请参阅references/kernel-image-and-initramfs.md。
故障排除
| 错误 | 原因 | 解决方案 |
|---|---|---|
Overlay has uncommitted changes at <LFT_SRC> | promote 前未提交 Customize-* 编辑 | 运行 git -C $LFT_SRC commit(或 stash),然后重新运行。 |
origin has N unpulled commits on <upstream> | 远程 overlay 与本地分支不一致 | 运行 git -C $LFT_SRC pull,解决冲突,然后重新运行。 |
Both overlay and manifest are empty — nothing to promote | 没有 Customize-* 提交,也没有 Build 清单 | 先运行 customize-* 技能或 /jetson-build-source。 |
Kernel-side source(s) changed since last /jetson-build-source | 新鲜度检查发现 Source/bsp_sources/ 下有尚未处理的 customize-* 编辑 | 提交待处理的编辑,运行 /jetson-build-source,然后重新运行 promote。 |
Manifest entry references missing build output: <src> | bsp_sources/ 构建输出已被删除,或清单已过期 | 重新运行 /jetson-build-source 以重新生成。 |
Build manifest at <MANIFEST> is not valid YAML | 清单被手动编辑或只写入了一部分 | 重新运行 /jetson-build-source 以重写清单。 |
cp: permission denied(在 rootfs/ 下) | 主机缺少 sudo 权限 | 使用可以运行 sudo cp 的账户执行;重新运行后会通过差异感知复制继续操作。 |
配置文件缺少 bsp_image: / source: | 工作区尚未完成引导 | 运行 /jetson-init-image 和/或 /jetson-init-source。 |
tool not found at <LFT_DST>/tools/l4t_update_initrd.sh | tools/ 已被清理,或 bsp_image 是从非 NVIDIA 的 tarball 解压而来 | 重新运行 /jetson-init-image 以恢复所需文件。 |
l4t_update_initrd.sh exited non-zero | sudo 权限不足、rootfs 损坏(缺少 lib/modules/<ver>/modules.dep)或 /tmp 空间不足 | 先针对 rootfs 运行 depmod -a -b <LFT_DST>/rootfs <ver>;检查 /tmp 的可用空间;重新运行 promote。 |
promote 后 DUT 启动时使用的是过期内核/模块,模块加载失败并提示 disagrees about version of symbol …,或者刷新运行后 initramfs 仍包含 customize 前的模块 | 镜像/刷新检查未触发(在技能之外手动编辑了 <LFT_DST> 下的文件),或 rootfs/boot/Image 与 kernel/Image 不一致,导致 chroot 中的刷新针对过期内核构建 | 运行 sudo touch <LFT_DST>/kernel/Image 后重新运行 promote,以强制触发检查;或者手动运行以下两个步骤:sudo cp -p <LFT_DST>/kernel/Image <LFT_DST>/rootfs/boot/Image && cd <LFT_DST> && sudo ./tools/l4t_update_initrd.sh。然后重新刷写。请参阅 references/kernel-image-and-initramfs.md。 |
规范状态
已锁定在 v0.2.0 中:
- 双通道范围 — overlay HEAD 和构建清单;两者
均支持差异感知,且都会复制到
<bsp_image.root_path>/Linux_for_Tegra/。 - 通道间重叠优先级 — 当
dst冲突时,以清单为准。 - 源代码仓库冲突检查 — 仅适用于 overlay;清单没有
远程概念,且不会获取
bsp_sources/下的源代码仓库 (jetson-build-source写入清单时,其状态已固定)。 - 原子性 — 失败即停止,不回滚。差异感知复制可自然支持 恢复。
- 审计记录 — 仅在 promote 时输出到 stdout。overlay 跟踪器的 git 日志是通道 A 的规范记录;清单本身是通道 B 的规范记录。
- 内核 Image 镜像 + initramfs 刷新。 两者作为配套步骤锁定。每当复制过程触及
kernel/Image,镜像步骤就会将kernel/Image→rootfs/boot/Image;每当kernel/Image或任何rootfs/lib/modules/*被提升时,刷新步骤就会运行tools/l4t_update_initrd.sh,重新构建bootloader/l4t_initrd.img和rootfs/boot/initrd。二者不可分割,因为刷新会 chroot 到rootfs/并通过/boot/Image解析内核,因此必须先运行镜像步骤。这可避免模块遮蔽和 vermagic 不匹配两种 故障模式;两者均支持差异感知,且仅修改 overlay 时都会跳过。完整约定见references/kernel-image-and-initramfs.md。
仍暂缓:
- overlay 通道的命名标签 / 提交范围。 等出现“提升版本 X”的用例时再重新考虑。
- 清单历史记录。 目前只保留最近一次构建的清单;如果用户想将 bsp_image
回退到先前的构建状态,则需要在之前的提交上重新运行
/jetson-build-source。 按构建模式或提交保存清单归档,即可无需重新构建而实现回滚。 - bsp_image 中的旁置清单。 等到在无法访问 overlay 跟踪器仓库(或工作区清单文件)的主机上执行提升时再重新考虑。
参考资料
references/kernel-image-and-initramfs.md— 内核Image镜像和l4t_update_initrd.sh刷新的完整约定:shell 代码片段、故障模式、工具语义和输出文件名。../../context/target-platform-contract.md— 目标平台约定。../../context/bsp-customization-workflow.md— 工作区编辑协议(此技能是 Deploy 的 promote 环节)。../jetson-init-source/SKILL.md— Setup;生成此技能读取的 overlay 跟踪器(通道 A),并编写source.toolchain。../jetson-build-source/SKILL.md— 构建器;写入此技能读取的.build-manifest.yaml(通道 B)。../jetson-flash-image/SKILL.md— 下一环节;将刚提升的 bsp_image 刷写到 DUT。../jetson-validate-image/SKILL.md— 最终环节;执行静态验证和目标端验证。