CANN 门禁流水线"包安装失败"分层定位实战:以 ops-cv PR 1310 案例拆解 CMake 新旧宏注册冲突
【免费下载链接】infrastructure本仓库用于托管CANN社区基础设施团队的公开信息,包括不限于:会议日程,成员信息,服务文档和配置等信息项目地址: https://gitcode.com/cann/infrastructure
本文以 CANN 社区 infrastructure 仓库中已验证的排障案例 case_cv1310_pkg.md 为主体,完整还原一次 ops-cv PR 门禁流水线"包安装失败"(pkg_install_fail)的分层定位过程:从 PR 评论逐层下钻到构建日志、用证据链证明"构建成功但 .run 安装自检失败"的真因是 CMake 新旧宏注册冲突,并沉淀出可复用的三级定界与排除项方法论。读完后,你可以掌握针对 CI"构建成功+安装失败"类故障的端到端定位流程——包括末尾回溯、目标缺失反查、对照组验证和同因聚合。
案例背景:一次看起来"可能是配置问题"的 PR 门禁失败
案例对象是cann/ops-cv仓库的 PR 1310「add ROIAlign operator」——在 A5(ascend950,arch35)上新增 ROIAlign 算子。关键事实:
- 最新一次 run#1134 FAILED,PR 被打上
ci-pipeline-failed+api-check-failed标签; - 提交者的疑问很典型:"是不是安装的 xml 没有配置好?"——即怀疑是安装包元数据配置问题,而非代码问题。
这一疑问恰好是"包安装失败"类故障最易误导的方向:报错发生在安装自检环节,直觉上会往安装器配置上猜。而案例的最终结论是:安装器的必需库校验行为是正确的,包里真的缺库,根因在 PR 的 CMake 构建配置。整个定位过程分为"分层下钻"与"日志证据链"两段,下面按原案例脉络完整展开。
五层下钻:从 PR 评论到构建日志
该案例遵循 pipeline-layered-localizer 技能定义的 L0→L5 分层模型(PR → Run → Stage → Job → Step → 日志),路径如下(引自原案例):
L0 PR 评论 → 最后一次 /compile(16:37) → run 043f81e6 L1 run#1134 FAILED 3.0min L2 stage: compile FAILED(46 job 中仅 8 失败:4×A5 编译矩阵全挂, x86/arm/experimental/monitor 全过) L3 job: Compile_A5_x86 等外层报 Sub-pipeline execution failed; 内层 Compile [JOB_a5_compile_0] 报 步骤compile_acc执行失败 → 下日志 L4 step: compile_acc FAILED(3min 处) L5 日志: cc5ef259…(内层job).zip → 3_compile_acc.log各层判据在技能的分层判据明细(layer_criteria.md)中有系统定义,其中两点值得强调:
- L2 判据的"矩阵筛选"价值:46 个 job 中只有 4 个 A5 编译矩阵 job(x86/arm × 默认/ubuntu24)失败,x86/arm/experimental/monitor 全部通过。按判据库的逻辑,"只有特定芯片矩阵挂"意味着问题在 ascend950 专属构建路径(soc 筛选、专属宏),而非公共编译问题。这条判据直接把排查范围从"整个 CI"收窄到"A5 专属的 ops-cv 构建配置"。
- 外层/内层 job 成对出现:
Compile_A5_x86(外层 job)报的是Sub-pipeline execution failed(子流水线引用),真正的构建日志挂在 identifier 带_0的内层 job(JOB_a5_compile_0)上。这是 GitCode Actions 流水线的结构性特点,直接下外层 job 的日志会一无所获(详见 api_endpoints.md 中"run 详情 vs jobs API"一节)。
另外注意 L0 层"以最后一次运行为准"的原则:PR 评论中可能有多次/compile重试历史,定位对象是最后一次 run,前几次仅作对照。/compile命令与ci-pipeline-failed标签的语义源头见社区 robot使用指南;L2~L4 检查项分类与任务状态语义见 CI工程检查项概览。
L5 日志证据链:六步还原"构建成功+安装失败"
以下六步是原案例的核心内容,证据链环环相扣,按原始顺序完整继承。
第 1 步:构建与打包其实成功
3_compile_acc.log开头显示构建命令与打包结果:
[LOG_DO] bash scripts/ci/compile_a5_pkg.sh pr_filelist.txt -j16 [compile_a5_pkg] executing build_cmd: bash build.sh --pkg --ops=roi_align --soc=ascend950 ... Self-extractable archive "cann-ops-cv-custom-linux.x86_64.run" successfully created..run自解包安装包创建成功,说明编译和 CPack 打包阶段没有报错。再看 ccache(CloudCache)统计:miss: 0(全命中)——编译没有实际压力,排除"编译本身出问题"的假设。构建命令的判读规则(--ops=<x>表示只构建指定算子的 PR 增量构建)在日志特征模式库 log_patterns.md 的"构建命令头"一节有说明。
第 2 步:失败点在 .run 安装自检
失败并非发生在编译,而是 CI 的冒烟安装环节——用刚打出的包做安装自检:
./build_out/cann-ops-cv-custom-linux.x86_64.run --install-path=/tmp [ops_custom] [INFO] validate shared libraries before installation [ops_custom] [ERROR] Required shared library 'libcust_opmaster_rt2.0.so' was not found in package path. [ops_custom] [ERROR] Shared library validation failed. execute pkg error ::error::ASSERT FAILED: Build ops-cv (expected=0, actual=1)这里有一个关键的方法论点("末尾回溯原则",果不是因):execute pkg error和::error::ASSERT FAILED: Build ops-cv都是收尾/汇总信号,真正根因在它们上方的[ops_custom] [ERROR]段——缺的是libcust_opmaster_rt2.0.so。log_patterns.md 明确将execute pkg error标为 generic 类别,ASSERT FAILED同理;判据库 classification_rules.md 中"包安装卸载验证失败(pkg_install_fail)"小类的核心判据正是\[ops_custom\] \[ERROR\] Required shared library '(\S+)' was not found,且注明配套反查动作:Built target 缺失 + already compiled / don't need tiling → cmake 注册类代码问题。
第 3 步:包清单确认缺库(CPack 段)
缺哪个库不能只听安装器的报错,要用包清单坐实。扫描日志中 CPack 打包阶段的文件清单(./packages/...逐文件行)确认:
- 包内仅有
op_proto/lib/linux/x86_64/libcust_opsproto_rt2.0.so(proto 定义库); - 没有
libcust_opmaster_rt2.0.so(tiling/ophost 宿主库)。
按模式库"常见库的语义":有 tiling 的算子,libcust_opmaster_rt2.0.so是包内必需项——ROIAlign 是带 tiling 的算子,所以这个库缺失是真实的包完整性问题,而非安装器"多嘴"。
第 4 步:编译产物反查(目标缺失)
用"目标缺失反查法"(先搜Built target <X>,无果则反查 target 创建条件与跳过消息,该方法完整定义在 log_patterns.md §2):日志中Building CXX object的完整列表显示——
roi_align_def.cpp(gen 库)、roi_align_infershape.cpp(ophost_cv_infer_obj)都编译了;roi_align_tiling.cpp从未出现在编译列表中,无 cust_opmaster target。
即:不是编译失败,而是 tiling 源文件根本没被 CMake 收集,导致下游 target 从未创建。
第 5 步:cmake 语义消息定根因(铁证)
日志中一行看似不起眼的 cmake 输出成为定根因的铁证:
-- already compiled roi_align, skip在判据库中,already compiled (\S+), skip是代码问题高价值子类:算子被先执行的宏注册,后续宏被去重跳过——新旧宏共存冲突的直接证据。结合 PR 改动面(L5→PR files 关联分析),完整根因链为:
- PR 在
objdetect/roi_align/CMakeLists.txt顶层新增新宏add_all_modules_sources(... TILING_DIR arch35 DISABLE_IN_OPP TRUE)(能正确收集 arch35 子目录下的 tiling 源); - 但未删除遗留的
op_host/CMakeLists.txt,其中仍是旧宏add_modules_sources(OPTYPE roi_align ACLNNTYPE aclnn_exclude)——旧宏的 tiling glob 只扫op_host/*_tiling*.cpp顶层,不含 arch35 子目录; - 顶层 CMakeLists 的 foreach 先执行
add_subdirectory(op_host)→ 旧宏先跑:infershape 编译了、arch35 tiling 源没被收集、roi_align 被标记进 COMPILED_OPS; - 轮到新宏时,cmake 去重逻辑输出
already compiled roi_align, skip直接跳过 → tiling 源永不编译; - 无 tiling_obj → 无 cust_opmaster target → 打包条件
if (TARGET cust_opmaster)为假 → 库不入包 →.run安装自检失败。
这条链说明了一个微妙之处:.run包"创建成功"(第 1 步)与"包内容不完整"并不矛盾——打包条件静默为假时,CMake 不会报错,缺库要到安装自检这一关才暴露。
第 6 步:对照验证
仅靠单一 PR 的日志还不够"立得住",原案例做了对照组验证:CI 通过的 A5 算子(d_io_u_grad/g_io_u_grad/extract_glimpse_v2/roi_align_grad)目录结构相同、全部没有op_host/CMakeLists.txt,只由顶层新宏注册——本 PR 是其中唯一带遗留文件的。结构差异与故障现象精确对应,排除了"其他共性原因"。
结论与三级定界输出
案例的最终结论:不是安装 xml 配置问题(用户最初的猜测),根因是 CMake 新旧宏注册冲突;修复方案只需一行改动——删除objdetect/roi_align/op_host/CMakeLists.txt,让新宏全权接管。
在技能的三级定界体系(代码/工程/环境 → 该谁修)中,本案例归代码问题 / pkg_install_fail:classification_rules.md 中将其明确列为"PR 变更导致,提交者修",并特别注明这类"构建成功但 .run 安装自检失败"应归代码问题而非环境/平台。原案例给出的定界输出示例("三级定界 + 排除项"格式,与 report_template.md 的报告模板一致)如下:
## 定界结论 - 失败类型: 代码问题 / 包安装卸载验证失败(pkg_install_fail) - 根因: PR 新增顶层新宏 add_all_modules_sources(TILING_DIR arch35), 但遗留 op_host/CMakeLists.txt 的旧宏 add_modules_sources 先执行并 将 roi_align 标记已编译("already compiled roi_align, skip"), tiling 源未编译 → cust_opmaster target 未生成 → 库未入包 - 影响 Job: 4 个 A5 编译矩阵(x86/arm × 默认/ubuntu24),根因组 #1(同因) - 处置建议: 通知 PR 提交者删除 objdetect/roi_align/op_host/CMakeLists.txt - 排除项: - 非环境问题: ccache miss=0(无重编压力)、其余 46 job 同机通过 - 非工程问题: 同 workflow 其他 PR 运行正常、依赖下载步骤 COMPLETED注意"影响 Job"一栏:4 个 A5 job 虽然各自 FAILED,但错误模式/算子相同,按技能的"根因聚合"原则归入同一根因组 #1,报告只展开一次。定界结论中"处置出口"(该联系谁)可对照 基础设施支撑矩阵 落位。
方法论沉淀:从单个案例到可复用判据
原案例最后总结了 8 条方法论,全部被技能体系吸收为通用判据,这里逐条对应说明:
ASSERT FAILED/execute pkg error是收尾信号(generic),真正根因在其上方的 [ERROR] 段——对应模式库"末尾回溯跳过信号"表:见到ASSERT FAILED: Build <repo>、execute pkg error、N FAILED TEST、gmake *** Error 2(make 级联)、ls: cannot access 'build_out/'(后置检查)一律跳过继续向前,回溯到第一个"具体错误"(文件:行号/算子名/缺失库名)才停。- "构建成功+安装失败"组合 → 直接跳到包清单比对,别在编译错误上浪费时间——这正是流程C(包安装失败专项)的起手式:日志定位
[ops_custom] ERROR→ 包清单确认缺失库 → 仓库 cmake 分析打包条件(if TARGET X)→ target 生成链反查 → cmake 消息佐证 → 对照通过案例定界。 already compiled X, skip出现 + 产物缺失 = 注册冲突类根因,是所有 cmake 语义消息中价值最高的信号之一(同族信号还有don't need add tiling sources、skipped, not in ascend_op_name list等,均收录于 log_patterns.md §2)。- 目标缺失反查法:日志搜
Built target <X>无果 → 查 target 创建条件(cmake/symbol.cmake)→ 查跳过消息,三步定位"谁把 target 吞了"。 - 对照组方法:找同仓库结构相同且 CI 通过的算子,比目录/宏用法差异——本案例第 6 步即其应用。
- "只有特定芯片矩阵挂"(本例仅 A5)→ 优先查该芯片专属路径(soc 筛选/专属宏),这是 L2 层收窄范围的核心判据。
- 多 Job 同因聚合:4 个 A5 job 归入同一根因组,报告只展开一次;同时坚持"全部分析,不要只报第一个"。
- 排除项用数据说话:
miss=0、"其余 46 job 同机通过"、"依赖下载步骤 COMPLETED"——每条排除项都挂可验证证据,定界结论才立得住。report_template.md 中还给出了 Failed_Reason 的好坏对照:好格式是[编译错误]: objdetect/roi_align/op_host/arch35/roi_align_tiling.cpp 编译被跳过(already compiled roi_align, skip),导致 libcust_opmaster_rt2.0.so 未入包;坏格式是只写[ERROR] UT build/test failed这类汇总行。
技能体系上下文:案例如何被沉淀与复用
本案例文件本身是 pipeline-layered-localizer 技能的 references 之一(该目录由 .agent/README.md 统一说明:将门禁 CI 看护方法论沉淀为可复用 AI 技能,供 CannBot 及各代理按需加载,也供开发者作为排障手册查阅)。在技能的"已验证案例"清单中,本案例与慢 run 案例(ops-transformer PR 11316)并列,标注为:
ops-cv PR 1310 run#1134 | 包安装失败 |代码问题(PR 构建配置)| CMake 新旧宏注册冲突致 opmaster 缺库 | 关键证据:already compiled skip + 包清单缺 .so;排除项:ccache miss=0、其余 46 job 通过 → 非环境/工程问题
支撑该案例定位流程的关键设施还包括:
- 只读 API 取数:v5 端点查 PR 详情/评论/改动文件,v8 端点查 runs/jobs 并
download_log下载失败 job 的日志 zip(zip 内按步骤分文件,首要分析3_compile_acc.log;只有 FAILED job 有日志归档),端点细节与"已知坑"见 api_endpoints.md; - 三级定界判据库:代码→工程→环境按序首次命中生效,
pkg_install_fail小类及其配套反查链完整定义于 classification_rules.md; - 日志特征模式库:失败锚点、cmake 语义消息、ccache 统计、包清单比对的正则与判读规则集中于 log_patterns.md,文末还附了一段解包日志、提取失败锚点/缓存统计/Built target 时间线的 Python 示例代码。
技能判据与社区文档同源:L0 判据(/compile命令、标签语义)源自 robot使用指南,L2~L4 判据(检查项分类、任务状态)源自 CI工程检查项概览,定界后的处置出口(该联系谁)指向 基础设施支撑矩阵。
实操清单:遇到"构建成功+安装失败"时的标准动作
综合原案例与方法论,可提炼为一份可执行清单(适用前提:GitCode Actions 上 cann 组织 ops 仓库的 PR 门禁,日志结构为3_compile_acc.log类):
- 下钻到正确日志:以最后一次 run 为准;下 identifier 带
_0的内层 job 日志,而非外层 sub_pipeline job; - 末尾回溯:从日志末尾往前找,跳过
ASSERT FAILED、execute pkg error、Error 2级联等汇总/连锁信号,停在第一个具体错误行; - 缺库坐实:用 CPack 包清单(
./packages/...行)确认安装器报缺的库确实不在包里,避免误判安装器校验逻辑; - 目标缺失反查:搜
Built target <对应 target>,无果则查该 target 的创建条件与跳过消息,重点识别already compiled X, skip; - PR 改动面关联:拉 PR files diff,确认失败算子的 CMakeLists/注册文件是否在改动列表,并与"同仓库已通过的同类算子"对照目录结构与宏用法;
- 聚合与排除:同因 job 归入一个根因组只报一次;定界结论附排除项(缓存统计、同机其余 job、依赖下载状态),每条挂数据。
案例从"是不是 xml 没配好"的猜测出发,最终用一条-- already compiled roi_align, skip日志行加包清单比对完成了定界与定责,修复代价仅一行删除。这正是"结论必须挂日志原文证据、区分根因与连锁失败"两条纪律的完整示范。
【免费下载链接】infrastructure本仓库用于托管CANN社区基础设施团队的公开信息,包括不限于:会议日程,成员信息,服务文档和配置等信息项目地址: https://gitcode.com/cann/infrastructure
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考