欢迎加入开源鸿蒙PC社区: https://harmonypc.csdn.net/

欢迎在PC社区平台申请新建项目:https://atomgit.com/OpenHarmonyPCDeveloper

llvmorg-22.1.0 适配鸿蒙 PC aarch64 (65025个测试全量实录)

项内容
对象lldb 0.0.1(平台任务伪版本;实际源码 llvm-project 官方发布快照 llvmorg-22.1.0)
环境HUAWEI MateBook Pro(HAD-W32)/ HarmonyOS 6.1.0 / aarch64 / Conan 2.29.1(OHOS 适配版)
仓库OpenHarmonyPCDeveloper/build_in_harmonyos(AtomGit)
PR#13409
发布lldb/0.0.1 已入制品仓

摘要

lldb 0.0.1(llvmorg-22.1.0 官方快照)适配鸿蒙 PC aarch64。核心难点不是"换个编译器再编一遍",而是构建路径:上游 lldb 假设在 monorepo 里随 3369 个 target 一起构建,本文走 standalone 路径——消费制品仓预编译的 llvm/22.1.0 与 clang/22.1.8 包,不重编 LLVM。8 个 CMake 补丁(6 个平台分支 + vendored gtest 接线 + unittest 顶层门控);上游测试全量执行 65025 次 = lit 33638(94.52% 通过)+ gtest 31387(99.91% 通过,该 31387 已含于 lit 全量树的逐用例条目内,两口径不可相加);120 个 lit 失败逐项归因至设备沙箱/上游因素(零适配缺陷,两日独立重跑字节级一致);test_package 3/3 为真实 SB API 断言;CI 11 轮 6 绿 5 红(红轮全部为基础设施原因作废,逐轮附证据行);3 对知识草稿随 PR 入仓。PR #13409 已合并入 main,lldb/0.0.1 已入制品仓。

不是"换个编译器再编一遍":lldb 是 LLVM 工具链里唯一的生产级全功能调试器,其上游假设在 monorepo 中整体构建——本文的真正挑战,是让 lldb 子项目 standalone 构建、确定性地链接"正确版本"的 LLVM、全量跑完上游测试,并对每一个失败给出诚实的归因。

声明(结论边界):

  • 设备内核级沙箱拒绝 ptrace / mkfifo / unix socket bind 等进程控制类系统调用,lldb 的"launch 目标 → 运行 → 断点命中"工作流在本设备受限;120 个 lit 失败与 28 个 gtest 失败均已归因于此及其他环境/上游因素(零适配缺陷)。本文以断点位置解析、符号解析与真实 API 断言证明"可用",不宣称"运行中命中"工作流已在本设备验证。
  • 本构建无 python 绑定(SWIG-NOTFOUND → LLDB_ENABLE_PYTHON=Auto),上游 API 套件 1342 例全部 unsupported(0 执行、0 失败),不是 100% 通过。
  • 全部结论限定于:HarmonyOS PC aarch64 真机(本设备)+ 本构建配置。

1. 背景:为什么值得做

  • 生态价值:lldb 是 LLVM 工具链中唯一的生产级调试器(clang 的调试搭档),是鸿蒙 PC 原生应用开发的 C/C++ 调试能力底座。制品仓已有 llvm/22.1.0 与 clang/22.1.8(本工程的直接依赖,均已发布)——工具链只差调试器这最后一块。
  • 先例:仓库已有 lldb/17.0.0 适配先例(monorepo 全量构建路径:llvm+clang+lldb 同源全编,3369 target,40-60min)。本次直接复用其 Conan 2.x 配方骨架、平台分支补丁模式、W3 长耗时策略与 binary 重签名模式。
  • 选型理由:本次依赖已全部入仓,17.0.0 的 monorepo 全量路径会重编整个 LLVM(重复制品仓已有工作、多耗一个多小时)→ 改走 standalone lldb 子项目路径(find_package 消费预编译 LLVM/Clang)。技术新颖性 = 新构建路径:standalone 构建边规模、双 CONFIG 版本钳制、vendored gtest 接线均为该路径独有。

2. 环境与差异前置

环境表全部值为当事机器实测(或标注来源):

项值测量来源
设备HUAWEI MateBook Pro(HAD-W32)设置页(用户确认)
系统HarmonyOS 6.1.0(HongMeng Kernel 1.12.0)设置页(用户确认)/ uname -a
架构aarch64uname -m
Conan2.29.1(OHOS 适配版,os=OHOS 为有效枚举)conan --version
主构建编译器clang 15.0.4(hnp,/data/service/hnp/bin/clang)conan profile show(compiler.version=15)
测试 harness 编译器clang 22.1.8(conan 包,经 clang shim 注入,见 3.8 坑 7)适配笔记 / 难度台账 #11
构建工具CMake + Ninja配方 generate()
上游源llvm-project-22.1.0.src.tar.xzconandata.yml;本机实测 HTTP 200 可达(2026-10-04)
SHA-25625d2e2adc4356d758405dd885fcfd6447bce82a90eb78b6b87ce0934bd077173conandata.yml(与制品仓 llvm/22.1.0 包同源,双验证)
构建规模conan create 1245 构建边(unittests OFF);本地全量树 1488 边(含 unittests)G2/W3 实测 / 难度台账 #10

差异表(先列全 8 项,第三节逐项展开;每行对应一个坑位或复用项):

#差异点上游假设鸿蒙 PC 实际情况对应
1构建模式monorepo 全量构建(3369 target)standalone lldb 子项目(消费预编译 LLVM/Clang)3.0 侦察 / 3.1 依赖树
2LLVM 版本来源树内 LLVM(in-tree)制品仓双 CONFIG 包并存(llvm 22.1.0 / clang 携带 22.1.8,EXACT 钳制)3.5 坑 4
3gtest 来源in-tree vendored(monorepo 语义)22.1.0 存档顶层 third-party/unittest 需显式接线3.4 坑 3
4平台宏Linux/Darwin/Windows 分支HarmonyOS(6 个 CMake 文件需加 MATCHES 分支)8 个补丁(conandata.yml 声明)
5cmake 平台模块Platform/HarmonyOS.cmake 不存在generate() 构造 shim(复用 Platform/Linux)3.6 坑 5(四层注入同源)
6libedit系统 libedit + find moduleconan 包:CMakeDeps 目标名遮蔽 + tinfo 传播 + 网络 FS stat 假阴性3.6 坑 5
7/tmp可写只读(TMPDIR 重写)配方 build()(E002 已知陷阱)
8进程控制 syscallptrace 可用(调试器命脉)沙箱拒绝 ptrace/mkfifo/socket bind(影响 120+28 个测试用例)3.9 坑 8

3. 适配过程

3.0 侦察(动手前)

  1. W0 依赖预检:llvm/22.1.0、clang/22.1.8、libedit/20240808 逐一 conan download <pkg> -r=ohpcd --only-recipe 核查制品仓,全部已发布 → 无需自编译依赖(standalone 路径成立的前提)。
  2. 源码证据(standalone 判定):lldb/CMakeLists.txt 以 CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR 判定 → LLDB_BUILT_STANDALONE=TRUE → include(LLDBStandalone);LLDBStandalone.cmake 硬性要求 find_package(LLVM REQUIRED CONFIG) + find_package(Clang REQUIRED CONFIG) → 配方 requires 必须同时含 llvm + clang(源码级硬依赖,非可选)。
  3. 一个转折性发现:22.1.0 官方存档顶层含 vendored third-party/unittest(LLVM 打过补丁的 googletest,即 monorepo CI 用的 gtest 源)→ gtest 不需要 conan 依赖,只需接线(见 3.4 坑 3)。
  4. 版本核验:下载后核对快照 cmake/Modules/LLVMVersion.cmake → 22.1.0;tarball SHA-256 与官方存档一致(双验证)。
  5. 测试策略:上游测试三步法(清点 → 实跑(全量、不抽样)→ 回填),清点数据见 4.1。

3.1 依赖树

lldb/0.0.1(standalone 子项目,-S lldb)
├── llvm/22.1.0        制品仓预编译 — find_package(LLVM) 候选 + 构建工具(llvm-tblgen/FileCheck)
├── clang/22.1.8       制品仓预编译 — 有效运行时依赖(ClangConfig EXACT 22.1.8 钳制)+ 全套工具链(llvm-lit 等)
├── libedit/20240808   制品仓预编译 — REPL 行编辑(可选依赖,FindLibEdit)
└── third-party/unittest(vendored,随源码存档)— gtest 源,非 conan 依赖

3.2 坑 1:monorepo 存档被误判为嵌套源码根

  • 现象:init-build 的嵌套源码检测把存档内的 bolt/ 子目录当作源码根——.work 只有 1163 个文件,lldb/ 与 llvm/ 缺失,照此构建必然失败。
  • 定位:工具启发式取"第一个含 CMakeLists.txt 的嵌套目录",无法识别 llvm-project 多项目根。
  • 方案:手动 tar -xJf --strip-components=1 全量解出至 .orig/.work 双轨(168,946 文件);tarball SHA-256 25d2e2…173 与官方存档一致(双验证)。
  • 经验:monorepo 多项目存档"含 CMakeLists.txt" ≠ “是源码根”;解出后须校验顶层项目列表(llvm/clang/lldb 齐全)完整。

3.3 坑 2:语言预检把 monorepo 误判为 python

  • 现象:lang-preflight 在 monorepo 范围给出 detected=python(exit 2)——若照闸门走 env_unsupported 终态,与事实(快照 C/C++ 实际源码占 99.2%)明显冲突。
  • 定位(三层根因):① manifest 扫描先命中 pyproject.toml(LLVM 官方整仓打包清单,列 packages=[“clang”,“lldb”],不是语言信号)再命中 CMakeLists.txt;② 70% 主体测试按单语言口径计算(cpp 63% < 70%);③ 矛盾仲裁规则在份额 < 70% 时不触发。
  • 误判→ 纠正:最初倾向把"闸门说 python"当真;经源码统计复核 C/C++ 占比 99.2% 后判定误判、继续适配;改用 --src <快照>/lldb(实际适配目标)重跑 → exit 0,detected=cpp(CMakeLists.txt project(lldb),cpp 2268 文件为主体)。
  • 经验:monorepo 的语言预检应按"实际适配目标子目录"判定而非整仓;闸门信号须经源码统计复核后才可行动。

3.4 坑 3:gtest 来源三次失败 → vendored 树(路径C 转折点)

  • 现象("裸 googletest"路线,连续三败):
    1. fatal error: 'gmock/gmock-matchers.h' file not found → 补 include 后 invalid operands to binary expression ('std::stringstream' and 'const llvm::StringRef'):gtest 1.17 的 testing::Message::operator<< 无 SFINAE 保护,LLVM 类型(StringRef/Twine/SmallString)只有 raw_ostream 重载、无 std::ostream<<;
    2. llvm_gtest 别名指向裸 gtest → DAP 链接时 gmock 符号 undefined;
    3. 裸 gmock ElementsAreMatcher 要求 RangeVector::value_type(自研容器缺失)。
  • 误判→ 纠正:最初前提是".src 存档不含 third-party 子模块"——llvm/third-party 确实不存在,但存档顶层含 vendored third-party/unittest。前提只错一半,整条裸树路线却建立在错误前提上。
  • 方案(0004 重写):set(LLVM_HAS_GTEST ON) + 源码树优先 add_subdirectory(<源码>/third-party/unittest)(带包内 LLVM_THIRD_PARTY_DIR 兜底,对 standalone 消费者为静默 no-op)→ wrapper 构建合并后的 llvm_gtest/llvm_gtest_main 目标(内建 printable raw_ostream 流式桥)→ ①②③ 一次全消;同时移除 tool_requires googletest(少一个依赖面)。再经单 TU 双实验(RangeMapTest/RangeTest + 原版 RangeMap.h + vendored gmock)证明 vendored gmock 不需要 value_type → RangeMap.h 回退原版(字节一致验证),补丁集 10 → 8。
  • 经验:monorepo 子项目 standalone 构建,“消费存档内同源 vendored 依赖"优于"引入外部同名依赖”(monorepo-faithful);前提被部分证伪时,应枚举存档目录结构而不是按名字推断。
  • 入档:本案已入档知识草稿 DRAFT-lldb001-gtest117-llvm-streaming-container-matcher(错误签名 invalid operands to binary expression ('std::stringstream' and 'const llvm::StringRef'),含两条独立根因 + vendored 方案 + fallback 对比),条目见第五节。

3.5 坑 4:双 LLVM CONFIG 包并存——用三层证据链钉死 EXACT 钳制

  • 现象:显式传 -DLLVM_DIR=<llvm 包>/lib/cmake/llvm 不被 find_package 采纳,实际加载的是 clang 包携带的 LLVM 22.1.8 config。
  • 定位(三层证据链):
    1. ClangConfig.cmake:10-12(clang 包)硬编码 find_package(LLVM 22.1.8 EXACT REQUIRED CONFIG HINTS <clang 包>/lib/cmake/llvm) → find_package(Clang)(LLDBStandalone:10)之后,有效 LLVM 确定性地钳制为 22.1.8(llvm 包的 22.1.0 config 被 EXACT 拒绝),后续全部 target 定义基于钳制值 → 最终链接不依赖哪个候选先命中;
    2. 首次 find_package(LLVM)(LLDBStandalone:9)命中受网络 FS stat 间歇假阴性影响(fresh 目录探测 5/5 命中 llvm 包,真实上下文冷搜索 2 次中 1 次命中 clang 包 = FS 抖动证据);
    3. CMake 3.24+ 的 pkgRedirects 重定向库固化首次命中(find 内的 set(LLVM_DIR …) 覆盖任何 -D),且本机 FS 上 rm 可能静默失败(重定向文件时间戳证明"删除"未生效)。
  • 方案:不需要 pin——配方 requires 保留 llvm/22.1.0(候选 + 构建工具)+ clang/22.1.8(有效运行时依赖);本地验证构建的 22.1.8 链接 = 最终配方链接的精确复现(parity 自动成立);22.1.x 点发布间 ABI 稳定。
  • 经验:同名不同版本包并存时,先找上游"确定性钳制点"(EXACT),让确定性机制做保证而不是 -D 注入;“pin 不 pin"的决策前先建三层证据链(静态源码 + 动态探测 + 缓存机制)——本案的结论恰是"不需要 pin”。

3.6 坑 5:libedit 三层——find 模块假阴性 → 目标名遮蔽 → tinfo 传播(G2 两次连败)

  • 现象 1(G2 首次失败):Target "lldbHost" links to: LibEdit::LibEdit but the target was not found。
  • 现象 2(G2_5 二次失败):ld.lld: error: unable to find library -ltinfo。
  • 定位 1:预编译包的 LLVMConfig 自动把自身 lib/cmake/llvm 载入 CMAKE_MODULE_PATH,FindLibEdit.cmake find 模块本应可找到;但 find 模块文件在 pkgRedirects 网络 FS 上 stat 假阴性(间歇性:本地正常 / CI 偶现)→ 退回 config 模式,命中 CMakeDeps 的 libedit-config.cmake——其目标名 libedit::libedit 与 lldb 源码(Host/CMakeLists.txt:180)硬引用的 LibEdit::LibEdit 不匹配。
  • 定位 2(双路径差异):libedit 配方的 SYSTEM_LIBS 声明了 tinfo(libedit 自己的构建期依赖)→ CMakeDeps 将其注入 INTERFACE_LINK_LIBRARIES → 消费者链接行出现裸 -ltinfo;CI 干净环境 sysroot 无 libtinfo。本地原生构建走 FindLibEdit 模块(设备无系统 libedit → libedit off)所以未复现——conan 上下文首次暴露。
  • 方案(generate() 四层确定性注入):
    1. 显式 LibEdit_INCLUDE_DIRS / LibEdit_LIBRARIES cache 变量(find 模块预设跳过搜索,FS 免疫);
    2. 向 libedit-config.cmake 追加桥接别名 LibEdit::LibEdit → libedit::libedit(config 兜底);
    3. CMAKE_MODULE_PATH 双份拷贝(平台 shim 目录 + monorepo 源码树模块目录,stat 冗余);
    4. 移除 libedit-*-data.cmake 中 set(libedit_SYSTEM_LIBS_* …) 声明里的 tinfo——合法性:libedit.so 是共享库,其 NEEDED 的 libtinfo.so.6 由运行时动态链接器解析(设备 /usr/lib/libtinfo.so.6 实测存在),消费者链接期不需要 -ltinfo。
  • 经验:「本地过、CI 偶挂」先怀疑 FS/网络路径差异 + CMakeDeps 与 find 模块的双路径目标名差异;依赖包 SYSTEM_LIBS 传播"构建期专用"库时,在消费者 generate() 后处理中清除。
  • 入档:本案已入档知识草稿 DRAFT-lldb001-libedit-cmakedeps-name-shadowing(错误签名 Target "lldbHost" links to: LibEdit::LibEdit but the target was not found,含四层注入方案 + 跨包 fallback 对比),条目见第五节。

3.7 坑 6:test_package——API 凭记忆 + stripped 目标

  • 现象:G2 conan create 首跑在 test_package 阶段失败:test_consumer.cpp 三处编译错(SBBreakpoint::GetNumEntries、SBModule::GetAddressRange 无此成员);且 C2 原目标(设备 /bin/ls)无 .symtab(stripped)→ 运行时 symbols=0 必然 FAIL。
  • 误判→ 纠正:测试源码的 API 调用凭记忆写——lldb 22.1.0 的 SB 头没有这两个成员(实为 SBBreakpoint::GetNumLocations();section 尺寸应走 GetSectionAtIndex(i).GetByteSize());选 /bin/ls 做目标时未先查符号表。
  • 方案:读安装包真实头文件(conan 缓存 include/lldb/API/*.h)定稿 API 改法;C2 目标改为测试二进制自身(/proc/self/exe + argv[0] 兜底,unstripped 天然含 main,跨设备可移植、不依赖设备预装二进制);C3 保留 section 尺寸回退(无符号场景 fallback)。
  • 经验:消费者测试的 API 以被测包真实头文件为准,不凭记忆;目标二进制选择前先 llvm-readelf -s 验证符号表。

3.8 坑 7:clang shim——conan clang 包缺 OHOS C++ 标准库头(harness 级,零测试修改)

  • 现象:lit Shell 套件测试输入编译 fatal error: 'cstdint' file not found(%clangxx_host = conan clang 22.1.8 包的 bin clang)。
  • 定位:conan clang 包 install 不含 OHOS target 的 C++ 标准库头(该包面向 CI 交叉消费,头文件跟随 llvm 包 include,llvm 包 include 亦无 OHOS target C++ stdlib 头);lit 测试输入必须编译为 OHOS target 并在宿主运行。
  • 方案(构建产物,不入 PR):clang shim 目录——conan 包 bin 全部工具符号链接 + clang/clang++ 替换为 hnp clang 15.0.4(自带 OHOS sysroot,C++ 编译实测 OK)+ 4 个 lit.site.cfg.py 覆盖 llvm_tools_dir/llvm_obj_root(构建产物,不入 PR);主构建编译器不变(本就是 hnp clang 15.0.4)。
  • 经验:测试 harness 编译器 ≠ 主构建编译器时,在 harness 层解决(shim + site cfg 覆盖),不动上游测试用例源文件——"上游测试修改 = 0"是申报红线。

3.9 坑 8:ptrace 沙箱——120F + 3 二进制 SIGSEGV 全量归因(路径C 核心)

  • 现象:lit 全量 120 fail + gtest 3 个二进制(DAP 27 / Host 36 / Target 32,共 95 例)批量 SIGSEGV;需要排除"适配缺陷"假设。
  • 定位(系统化):三类 syscall 探针全部 EPERM(lldb-server gtest ptrace failed: Permission denied ×3 / python os.mkfifo / unix socket bind)+ 普通 exec 正控 OK(拒绝的是进程控制 syscall 族,不是"不能 launch");4/4 独立复现矩阵(bash 前台 / python Popen 后台 × 裸参 / lit 同参,全部 ptrace failed: Permission denied);15 个 FileCheck-only 无错误行用例逐个最小 inferior 探针复跑 → 15/15 LAUNCH-EPERM。
  • 误判→ 纠正:09-28 报告曾宣称"SB API 1342/1342 全过 = 同库反例"——误读:本构建无 python(SWIG-NOTFOUND → LLDB_ENABLE_PYTHON=Auto),API 的 1342 例 100% unsupported(上游 REQUIRES 门控,0 执行),unsupported ≠ 通过;"沙箱按 tracer 进程上下文生效(python 路径放行)"的推断同步撤回(无正控上下文可观察——没有正控就不下上下文级策略结论)。09-30 自检修正归因表(launch 88→86、DWO 4→6),120 总数不变,两日重跑 120 例失败测试集字节级一致。
  • 方案(归因 + 反证):120 = 86 launch 关联(45 可见错误行 + 5 launch 下游 + 15 探针复跑 + 21 同族推定)+ 25 用例级沙箱 EPERM(Host 8 pipe bind / Target 13 spawn / DAP 4 mkfifo)+ 6 DWO/split-DWARF 路径 + codegen 差异 + 1 CLI 注释格式 + 1 scripting 设计 off + 1 Apple Foundation 专属;99 直接证据 + 21 同族推定(分级不混写)。反证链:LLDBCoreTests 0 fail / gtest 31359 pass / 两日字节一致 → 零适配缺陷信号。批量 SIGSEGV = 沙箱受限用例导致整进程崩溃,逐用例隔离(lit sharding)后同二进制其余 70 例全过。
  • 经验:EPERM 属内核级策略,配方侧无解(盲调不收敛);归因必须按三级证据分级(可见错误行 / 探针复跑 / 同族推定)且分级不混写;复现矩阵 + 正控排除 harness 因素;"上游测试全量实跑 + 逐例归因 + 证据入仓"是路径C 申报的可信度基础。
  • 入档:本案已入档知识草稿 DRAFT-lldb001-lldb-cli-ptrace-sandbox-rejection(错误签名 Cannot launch '<path>': ptrace failed: Permission denied,含三级证据方法论 + 正控边界),条目见第五节。

3.10 坑 9:内存竞争——ninja 构建中死亡(环境)

  • 现象:V8 构建的 ninja 进程中途死亡([1487/1488] LLDBValueObjectTests 链接点,日志无 FAILED)。
  • 定位:疑似 SIGKILL(无编译错误输出):当时 G2_5 的 conan 构建并行在跑(同层级内存占用),双大链接叠加导致设备内存压力(总内存 32GB)。
  • 方案:V9 单独重跑(G2_5 已停);配方已含 LLVM_PARALLEL_LINK_JOBS=2 防 OOM(17.0.0 CI 教训);ninja 缓存保证重试只跑未完成边。
  • 经验:同设备并行两个大构建需管理链接并发与内存峰值;“日志无 FAILED 但 ninja 死亡”= 先怀疑 OOM kill。

4. 验证(分层,禁止相加)

口径声明:各层分别统计、分别陈述,不做相加 / 改名 / 拼接。65025 = “总执行次数” = lit 33638(唯一)+ gtest 31387(复跑);该 31387 个 gtest 用例已含于 lit 全量树(unit 31588 = 31387 逐用例条目 + 201 其他)——两口径不可相加。唯一失败用例 = 120(lit 92 shell + 28 unit;其中 28 与 gtest 直跑的 28F 是同一用例集在双 runner 下的重复出现)。

4.1 上游测试全量实跑(三步法:清点 → 实跑 → 回填)

清点(22.1.0 快照实测,非静态推算):

测试类型清点说明
lit(API)1342test/API(Test*.py,22.x 命名)
lit(Shell/CLI)426 .testtest/Shell(含 282 个输入文件)
gtest1713 静态注册lldb/unittests 31 组 / 252 cpp(含 TEST_P 参数化)
合计lit 1768 + gtest 1713 = 3481unit 1 个辅助 py 不入合计

运行时展开(为什么实跑数远大于清点):Shell 426 .test → 708 条(含输入文件展开);unit = gtest 逐用例 sharding 31387 + 其他 201 = 31588;gtest 直跑 31387(1713 静态注册经参数化测试运行时实例化展开为 31387 例,LLDBCoreTests 30036 为主体)。

实跑(09-28 全量 + 09-30 三套件独立重跑,两日交叉验证):

指标09-28 全量树09-30 独立重跑结论
lit 总数33638708+1342+31588 = 33638精确一致
lit pass31795(94.52%)235+0+31560 = 31795一致
lit fail12092+0+28 = 120一致,且 120 例失败测试集逐例字节级一致
lit unsupported1721379+1342+0 = 1721一致(上游特性门控)
lit xfail22+0+0 = 2一致
gtest 全量口径31387 = 31359P(99.91%)+ 28F与 lit-unit 31588 双 runner 交叉一致

(全量树 Testing Time 28.19s,20 workers;gtest = 批量直跑 31292 [31289P + lldb-server 3F ptrace EPERM] + DAP/Host/Target 三二进制(95 例)批量 rc=-11 → 逐用例隔离 70P + 25F。归档 SUMMARY 的 TOTAL 行实测 run=31292 pass=31289 fail=0 是汇总脚本解析器的低估口径,test-evidence/README.md 已显式注记真实口径。)

120 fail 逐例归因(零适配缺陷):

#类别数量证据级别
1launch 被 PTRACE 拒绝(可见 ptrace failed: Permission denied)45(shell 42 + lldb-server 3)直接
2launch 下游错误(可见 process must be launched 等)5(shell)直接
3launch 被拒、FileCheck 窗口无错误行(最小 inferior 探针复跑 15/15)15(shell)直接
4launch 被拒、同族推定(同机制,未逐个探针)21(shell)推定
5DWO/split-DWARF 路径 + codegen 差异6(shell)直接
6用例级沙箱 EPERM(Host 8 pipe bind / Target 13 spawn / DAP 4 mkfifo)25(unit)直接
7CLI 注释格式1(shell)直接
8scripting 设计 off(本构建无 python)1(shell)直接
9Apple 平台专属(Foundation.h)1(shell)直接
合计12099 直接 + 21 推定

反证链:LLDBCoreTests 0 fail;gtest 31359 pass;两日独立重跑失败测试集逐例字节级一致 + 签名一致 → 120 例全部为环境/上游因素。上游测试用例修改 = 0;补充:test_package C1-C3;harness 级调整:clang shim + 4 个 lit.site.cfg.py 覆盖(仅构建产物,不入 PR)。

证据入仓:archives/l/lldb/0.0.1/test-evidence/(16 个文件:两日原始日志 + 逐例分类 ×2 + 15/15 探针 + gtest SUMMARY + 失败日志 ×4 + gtest 脚本 + 4/4 复现矩阵 + README;SHA-256 见 sha256sums.txt,sha256sum -c 可验证)。

4.2 断言 1:1 移植

本库属"直跑"型而非"移植"型:上游 lit/gtest 测试全部原样执行(0 源修改),不存在独立的断言移植层。1342 api 用例 100% unsupported 是构建配置边界(无 python:SWIG-NOTFOUND → LLDB_ENABLE_PYTHON=Auto,上游 REQUIRES 门控),0 执行、0 失败——不是通过声明,也不是缺陷。

4.3 私有 API

无私有 API 使用:本构建不链接 LLVM 内部 .a,消费制品仓预编译包的公开接口(find_package CONFIG 模式);消费者测试使用的 SB API 为公开 API(include/lldb/API/)。

4.4 消费者测试(test_package C1-C3,真实 SB API)

用例级别内容实测
C1L1(版本断言)SBDebugger::Initialize/Create + GetVersionStringversion=lldb version 22.1.8
C2L2(真实 API + 结果断言)CreateTarget(自目标)+ GetNumModules / GetNumSymbolsmodules=1 symbols=129
C3L2(真实 API + 结果断言)BreakpointCreateByName(“main”) + GetNumLocationsbp_locations=1(断点分支实际生效,目标显式 -g 编译)

设计要点:无 ptrace、不 spawn 进程(CI 安全);目标取测试二进制自身(/proc/self/exe,unstripped 天然含 main,跨设备可移植,不依赖设备预装二进制)。L1 级声明:C1 仅证明"可编译、可链接、可执行",不能宣称功能完成;C2/C3 为 L2 真实 API + 结果断言。

实测输出(CI/G2 一致):

test_package OK: C1 version=lldb version 22.1.8 C2 modules=1 symbols=129 C3 bp_locations=1

完整测试代码见 PR 的 archives/l/lldb/0.0.1/test_package/test_consumer.cpp(含 C3 无符号场景的 section 尺寸回退)。

在这里插入图片描述图1:鸿蒙 PC 真机 lldb 22.1.8 加载目标并解析 main 断点位置(证明产物真机可用;不能证明运行中命中,沙箱边界见 3.9)

4.5 产物核验

  • conan create:1245/1245 构建边(G2/W3,LLDB_INCLUDE_UNITTESTS=OFF——上游全量测试由本地全量构建树承担,不拖长 CI 时长);
  • 产物:6 个可执行(lldb / lldb-server / lldb-argdumper / lldb-dap / lldb-mcp / lldb-instr)+ liblldb.so.22.1.8(包内实体文件 + liblldb.so.22.1 / liblldb.so 相对符号链接)+ 公开头文件(源码树 lldb/include + 构建生成头两组:Host/Config.h 等、Version*.inc);
  • 构建耗时:CI 实测 ~25-35min(worker CI-004 / CI-011,3600s 预算;#66973 ~19min 有缓存);
  • 门禁:G3 系统同名库隔离 / G4 产物完整性 / L2 smoke / L4 安全扫描 / L5 产物基线——全部通过。

4.6 CI 与评审

完整轮次表(11 轮;红轮不删,“作废”= 基础设施故障,非配方问题):

#构建号时间head结果说明
1#6327909-28 08:00→08:3516c3bf2a✅ 绿CI-011,14400s 预算,~35min
2#6378809-281e0882fd✅ 绿
3#6381609-281e0882fd❌ 红(作废)无结果
4#6387109-281e0882fd❌ 红(作废)registry clang 包截断 97/196MB(本机强制重下验证 195,734,714B 字节级一致)
5#6395809-281e0882fd❌ 红(作废)gh-proxy 源超时
6#6395909-291e0882fd✅ 绿
7#6399509-291e0882fd❌ 红(作废)registry 大包 Response ended prematurely
8#6551409-30 15:221e0882fd✅ 绿(当期终态)3600s 预算,构建步 ~25-31min
9#6643610-01 22:3677984c4b✅ 绿路径C 自检修正 commit
10#6695410-02 13:381bde8344❌ 红(作废)CI-023 死 worker(SSH bridge connection refused,全步瞬秒挂)
11#6697310-02 14:021bde8344✅ 绿(终态)CI-004,~19min(有缓存)

评审记录(时间线):

  • 09-28 平台 AI 检视:0 阻塞 + 2 P2(readlink 未 NUL 终止 / ByLocation 误用于按名断点,均为真缺陷,修复入 04ebc5dff5 并本地复跑验证)+ 2 P3(1 条草稿命令对齐、1 条误报);
  • 09-28 人工审查(pc-pr-review 11 规则):FAIL 两条——rule5(ci/config/build_timeouts.txt 属非 archives/knowledge 目录改动,赛事严格口径披露不豁免)+ rule6(最新 commit 晚于最新 AI 检视);整改:移除超时条目(CI 实测构建步 ~25min < 3600s 默认预算,条目非必需),单 commit 1e0882fd;
  • 09-29 19:34 平台 AI 检视:“未发现问题”;
  • 10-01 / 10-02 两个 docs-only commit(自检修正 77984c4b / P2 口径修正 1bde8344)晚于上述平台检视结论;10-02 本地 AI 复检视(code_review 工具,最终态全量 42 文件)P0/P1=0——1 P2 假设性稳健(tinfo 移除正则的位置依赖:输入全部钉死 + 5 次 CI 绿,触发前提当前不成立,非阻塞,修复建议已记录)+ 2 P3,结果已发 PR 讨论区;
  • 合并记录:审批人 Clancy_Xie 批准,PR #13409 于 2026-10-03 03:53 合并入 main;关联 Issue #3564 随合并自动关闭;lldb/0.0.1 配方于合并后 ~1h19m(2026-10-03 05:12)入制品仓(2026-10-04 conan list lldb/0.0.1 -r=ohpcd 远端实测确认)。

在这里插入图片描述

图2:CI #66973 校验通过页(证明终态 CI 实际绿;不能证明本地配方质量,W3 1245/1245 正文互补)

4.7 复现速查

前置:build_in_harmonyos 仓库 clone + OHOS 适配版 conan(社区源)+ 制品仓已发布的 llvm/22.1.0、clang/22.1.8、libedit/20240808。

① 全量构建 + 消费者测试(~25-35min,CI 同口径):

cd build_in_harmonyos
conan create archives/l/lldb/0.0.1 -pr:h=ci/conan/profiles/ohos-aarch64 -pr:b=ci/conan/profiles/ohos-aarch64

期望:1245/1245 构建边全绿 + test_package 输出 test_package OK: C1 version=lldb version 22.1.8 C2 modules=1 symbols=129 C3 bp_locations=1。

② 上游证据链复跑(本地全量构建树,~5min;树需含 lldb-unittests 目标,细节见 test-evidence/README.md):

cd /storage/Users/currentUser/tmp/lldb001-build2   # 本地全量构建树
bin/llvm-lit -sv test    # 期望:33638 = 31795P / 120F / 1721U / 2X

③ 版本 / 断点解析核验(秒级,与图1 同命令):

cd /storage/Users/currentUser/tmp/lldb001-build2
LD_LIBRARY_PATH=$PWD/lib bin/lldb --version    # 期望:lldb version 22.1.8
LD_LIBRARY_PATH=$PWD/lib bin/lldb --batch -o "breakpoint set -n main" -o "breakpoint list" -- bin/lldb-argdumper
# 期望:Breakpoint 1: where = lldb-argdumper`main ... 1: name = 'main', locations = 1

口径对应:① → 4.4/4.5(1245/1245、C1-C3 实测)② → 4.1(lit 33638 / 94.52%)③ → 4.4(版本串 + 断点位置解析)。这是本文数字的完整复现命令集;两日独立重跑与 gtest 直跑细节见 test-evidence/README.md。

5. 知识沉淀

草稿编号知识(错误签名)来源坑位复用价值
DRAFT-lldb001-gtest117-llvm-streaming-container-matcher标准 gtest 1.17 头与 LLVM 22.x 不兼容:Message 流式缺 std::ostream<<(.str() 族类型)+ gmock 容器匹配器硬依赖 value_type → 消费 vendored 树3.4 坑 3所有 standalone LLVM 子项目 unittest(lldb/clang 系)
DRAFT-lldb001-libedit-cmakedeps-name-shadowingConan 上下文 LibEdit find 模块网络 FS stat 假阴性回退 CMakeDeps,目标名 libedit::libedit ≠ LibEdit::LibEdit + SYSTEM_LIBS tinfo 传播 → 四层确定性注入3.6 坑 5所有 Conan 上下文消费 CMakeDeps 同名库且源码硬引用 LLVM 风格目标名的配方
DRAFT-lldb001-lldb-cli-ptrace-sandbox-rejectionOHOS 设备沙箱在 syscall 级拒绝进程控制族(ptrace / FIFO / unix socket bind):环境因素非适配缺陷;归因须按三级证据分级3.9 坑 8所有 OHOS aarch64 设备上依赖 ptrace/attach/FIFO/子进程 spawn 的调试器与测试

状态说明:3 对草稿(kv + md,共 6 文件)已随 PR 入仓 knowledge/drafts/,待主编 promote(DRAFT 前缀编号与正式库无冲突;promote 后自动分配 E 编号并生成配套文档)。

6. FAQ

Q1:120 个 lit 失败 = 没适配成功?
不是。逐例归因表(4.1):86 例 launch 关联(设备沙箱拒绝 ptrace,其中 45 例可见错误行 + 15 例探针复跑 + 21 例同族推定)+ 25 例用例级沙箱 EPERM + 6 例 DWO/split-DWARF + 3 例其他(1 CLI 格式 / 1 scripting 设计 off / 1 Apple 专属);99 直接证据 + 21 同族推定,分级不混写。反证链:LLDBCoreTests 0 fail、gtest 31359 pass、两日独立重跑失败测试集逐例字节级一致。120 例全部为环境/上游因素,零适配缺陷。

Q2:API 1342 例 = 100% unsupported,测试是否缩水?
没有缩水,是未运行:本构建无 python(SWIG-NOTFOUND → LLDB_ENABLE_PYTHON=Auto),上游 REQUIRES 门控判定这 1342 例 unsupported(0 执行、0 失败)——不是"通过"声明。09-28 报告曾误读为"1342/1342 全过",已在 09-30 自检中撤回并修正归因(3.9 误判自曝)。补 python 绑定列入后续工作(7.4)。

Q3:65025 = 33638 + 31387,31387 不是重复计算?
65025 是"总执行次数"口径:33638 个唯一用例(lit 全量树,其中 unit 31588 已含 31387 个 gtest 用例的逐用例条目)+ 31387 次 gtest 直跑复跑(同一批用例的第二 runner,双跑交叉验证)。“唯一失败用例”= 120,两口径不可相加(第 4 节开头口径声明)。

Q4:5 轮 CI 红,是配方的问题吗?
不是,逐轮有证据行(4.6 表):#63816 无结果 / #63871 registry 截断(本机强制重下验证字节级一致)/ #63958 源超时 / #63995 大包中断 / #66954 死 worker(SSH 连接拒绝,全步瞬秒挂)。6 轮绿为同配方完整 CI。

Q5:为什么不用源码树重编 LLVM?standalone 可信吗?
制品仓已有 llvm/22.1.0 + clang/22.1.8(与本包存档同源,SHA-256 双验证),重编只是重复已有工作。有效 LLVM 版本由 ClangConfig.cmake 的 find_package(LLVM 22.1.8 EXACT REQUIRED) 确定性钳制(三层证据链,3.5 坑 4),配方刻意不 pin;1245/1245 + 65025 全量实跑是可信度背书。

Q6:test_package 3/3,能证明调试器真的可用吗?
分级证明:C1=L1(只证明可编译、可链接、可执行,不能宣称功能完成);C2/C3=L2(真实 SB API + 结果断言:symbols=129、bp_locations=1 断点实际生效)。完整"运行 + 命中"工作流受本设备 ptrace 沙箱限制(诚实声明)——这是边界而非缺陷,平台能力跟踪于 Issue #3564。

Q7:版本号为什么是 0.0.1?
0.0.1是平台任务伪版本。实际源码钉住 llvmorg-22.1.0 官方发布快照(与制品仓 llvm/22.1.0 包同源,SHA-256 25d2e2…173 双验证);0.0.1 编号只承载"本任务首次适配"语义,不代表上游版本。

7. 总结

7.1 量化盘点

维度数字
CMake 补丁8 个(6 平台分支 + 1 vendored gtest 接线 + 1 unittest 顶层门控)
难度台账13 项(其中 4 项含误判自曝与纠正)
上游测试执行65025 次(lit 33638 @94.52% + gtest 31387 @99.91%;口径见第 4 节声明)
失败归因120/120(99 直接证据 + 21 同族推定),零适配缺陷
上游测试修改0
消费者测试3/3(1 个 L1 + 2 个 L2)
conan create1245/1245(G2/W3)
CI11 轮:6 绿 + 5 红(全部基础设施原因作废)
知识沉淀3 对草稿(随 PR 入仓,待 promote)
构建耗时CI ~25-35min(无缓存)/ ~19min(有缓存)

7.2 可复用方法(5 条)

  1. standalone 消费预编译 LLVM:不跟 FS 抖动对抗,找上游 EXACT 版本钳制点做确定性保证——“pin 不 pin"的决策前先建三层证据链(本案结论恰是"不需要 pin”);
  2. vendored 树优先:monorepo 子项目 standalone 构建,“消费存档内同源 vendored 依赖"优于"引入外部同名依赖”(monorepo-faithful,三败转一次修复);
  3. 双路径差异诊断:「本地过、CI 偶挂」先怀疑 FS/网络差异 + CMakeDeps/find 模块目标名差异;依赖包 SYSTEM_LIBS 传播构建期专用库时,消费者 generate() 后处理清除;
  4. 失败归因三级证据:可见错误行(直接)/ 探针复跑(直接)/ 同族推定(推定),分级不混写;复现矩阵 + 正控排除 harness 因素;没有正控不下上下文级结论;
  5. 测试证据链入仓:SHA-256 + 两日独立重跑交叉验证 + 逐例签名文件,解决"本地 reports/ 无法入仓"的证据悬空。

7.3 流程 checklist(通用)

  • W0 依赖预检(逐项 conan download --only-recipe,禁用 conan list 判 binary)
  • 源码版本钉住:下载后核对版本行 + SHA-256 双验证
  • 语言预检按"实际适配目标子目录"判定(monorepo)
  • 动手前枚举存档目录结构(发现 vendored 依赖)
  • 双包并存先找 EXACT 钳制点
  • 消费者测试 API 以被测包真实头文件为准
  • 上游测试三步法:清点 → 实跑(全量、不抽样)→ 回填
  • 失败归因三级证据 + 复现矩阵 + 正控
  • 证据链入仓(SHA-256 + 两日重跑)
  • CI 红轮不删,基础设施故障标"作废"附证据行
  • 提交前数字口径自查(包含关系 / 双计 / 注册数 vs 执行数)

7.4 后续工作(诚实边界)

  1. ptrace 进程控制属设备内核级沙箱策略,"launch + 运行"调试工作流需平台侧能力开放(Issue #3564 跟踪);
  2. python 绑定(SWIG)缺失 → API 套件 1342 例 0 执行,补齐是测试覆盖的下一步;
  3. 1 条 P2 稳健性建议(tinfo 移除正则的格式无关化)+ 2 条 P3(补丁 0004 gtest 守卫解耦 / test_package 空值 guard)已记录待 follow-up。

参考链接

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐