llvmorg-22.1.0 适配鸿蒙 PC aarch64 (65025个测试全量实录)
欢迎加入开源鸿蒙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 |
| 架构 | aarch64 | uname -m |
| Conan | 2.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.xz | conandata.yml;本机实测 HTTP 200 可达(2026-10-04) |
| SHA-256 | 25d2e2adc4356d758405dd885fcfd6447bce82a90eb78b6b87ce0934bd077173 | conandata.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 依赖树 |
| 2 | LLVM 版本来源 | 树内 LLVM(in-tree) | 制品仓双 CONFIG 包并存(llvm 22.1.0 / clang 携带 22.1.8,EXACT 钳制) | 3.5 坑 4 |
| 3 | gtest 来源 | in-tree vendored(monorepo 语义) | 22.1.0 存档顶层 third-party/unittest 需显式接线 | 3.4 坑 3 |
| 4 | 平台宏 | Linux/Darwin/Windows 分支 | HarmonyOS(6 个 CMake 文件需加 MATCHES 分支) | 8 个补丁(conandata.yml 声明) |
| 5 | cmake 平台模块 | Platform/HarmonyOS.cmake 不存在 | generate() 构造 shim(复用 Platform/Linux) | 3.6 坑 5(四层注入同源) |
| 6 | libedit | 系统 libedit + find module | conan 包:CMakeDeps 目标名遮蔽 + tinfo 传播 + 网络 FS stat 假阴性 | 3.6 坑 5 |
| 7 | /tmp | 可写 | 只读(TMPDIR 重写) | 配方 build()(E002 已知陷阱) |
| 8 | 进程控制 syscall | ptrace 可用(调试器命脉) | 沙箱拒绝 ptrace/mkfifo/socket bind(影响 120+28 个测试用例) | 3.9 坑 8 |
3. 适配过程
3.0 侦察(动手前)
- W0 依赖预检:llvm/22.1.0、clang/22.1.8、libedit/20240808 逐一
conan download <pkg> -r=ohpcd --only-recipe核查制品仓,全部已发布 → 无需自编译依赖(standalone 路径成立的前提)。 - 源码证据(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(源码级硬依赖,非可选)。 - 一个转折性发现:22.1.0 官方存档顶层含 vendored
third-party/unittest(LLVM 打过补丁的 googletest,即 monorepo CI 用的 gtest 源)→ gtest 不需要 conan 依赖,只需接线(见 3.4 坑 3)。 - 版本核验:下载后核对快照
cmake/Modules/LLVMVersion.cmake→ 22.1.0;tarball SHA-256 与官方存档一致(双验证)。 - 测试策略:上游测试三步法(清点 → 实跑(全量、不抽样)→ 回填),清点数据见 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-25625d2e2…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"路线,连续三败):
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<<;llvm_gtest别名指向裸 gtest → DAP 链接时 gmock 符号 undefined;- 裸 gmock
ElementsAreMatcher要求RangeVector::value_type(自研容器缺失)。
- 误判→ 纠正:最初前提是"
.src存档不含 third-party 子模块"——llvm/third-party确实不存在,但存档顶层含 vendoredthird-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。 - 定位(三层证据链):
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 定义基于钳制值 → 最终链接不依赖哪个候选先命中;- 首次
find_package(LLVM)(LLDBStandalone:9)命中受网络 FS stat 间歇假阴性影响(fresh 目录探测 5/5 命中 llvm 包,真实上下文冷搜索 2 次中 1 次命中 clang 包 = FS 抖动证据); - 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() 四层确定性注入):
- 显式
LibEdit_INCLUDE_DIRS/LibEdit_LIBRARIEScache 变量(find 模块预设跳过搜索,FS 免疫); - 向 libedit-config.cmake 追加桥接别名
LibEdit::LibEdit → libedit::libedit(config 兜底); CMAKE_MODULE_PATH双份拷贝(平台 shim 目录 + monorepo 源码树模块目录,stat 冗余);- 移除 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 / pythonos.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) | 1342 | test/API(Test*.py,22.x 命名) |
| lit(Shell/CLI) | 426 .test | test/Shell(含 282 个输入文件) |
| gtest | 1713 静态注册 | lldb/unittests 31 组 / 252 cpp(含 TEST_P 参数化) |
| 合计 | lit 1768 + gtest 1713 = 3481 | unit 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 总数 | 33638 | 708+1342+31588 = 33638 | 精确一致 |
| lit pass | 31795(94.52%) | 235+0+31560 = 31795 | 一致 |
| lit fail | 120 | 92+0+28 = 120 | 一致,且 120 例失败测试集逐例字节级一致 |
| lit unsupported | 1721 | 379+1342+0 = 1721 | 一致(上游特性门控) |
| lit xfail | 2 | 2+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 逐例归因(零适配缺陷):
| # | 类别 | 数量 | 证据级别 |
|---|---|---|---|
| 1 | launch 被 PTRACE 拒绝(可见 ptrace failed: Permission denied) | 45(shell 42 + lldb-server 3) | 直接 |
| 2 | launch 下游错误(可见 process must be launched 等) | 5(shell) | 直接 |
| 3 | launch 被拒、FileCheck 窗口无错误行(最小 inferior 探针复跑 15/15) | 15(shell) | 直接 |
| 4 | launch 被拒、同族推定(同机制,未逐个探针) | 21(shell) | 推定 |
| 5 | DWO/split-DWARF 路径 + codegen 差异 | 6(shell) | 直接 |
| 6 | 用例级沙箱 EPERM(Host 8 pipe bind / Target 13 spawn / DAP 4 mkfifo) | 25(unit) | 直接 |
| 7 | CLI 注释格式 | 1(shell) | 直接 |
| 8 | scripting 设计 off(本构建无 python) | 1(shell) | 直接 |
| 9 | Apple 平台专属(Foundation.h) | 1(shell) | 直接 |
| 合计 | 120 | 99 直接 + 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)
| 用例 | 级别 | 内容 | 实测 |
|---|---|---|---|
| C1 | L1(版本断言) | SBDebugger::Initialize/Create + GetVersionString | version=lldb version 22.1.8 |
| C2 | L2(真实 API + 结果断言) | CreateTarget(自目标)+ GetNumModules / GetNumSymbols | modules=1 symbols=129 |
| C3 | L2(真实 API + 结果断言) | BreakpointCreateByName(“main”) + GetNumLocations | bp_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 | #63279 | 09-28 08:00→08:35 | 16c3bf2a | ✅ 绿 | CI-011,14400s 预算,~35min |
| 2 | #63788 | 09-28 | 1e0882fd | ✅ 绿 | |
| 3 | #63816 | 09-28 | 1e0882fd | ❌ 红(作废) | 无结果 |
| 4 | #63871 | 09-28 | 1e0882fd | ❌ 红(作废) | registry clang 包截断 97/196MB(本机强制重下验证 195,734,714B 字节级一致) |
| 5 | #63958 | 09-28 | 1e0882fd | ❌ 红(作废) | gh-proxy 源超时 |
| 6 | #63959 | 09-29 | 1e0882fd | ✅ 绿 | |
| 7 | #63995 | 09-29 | 1e0882fd | ❌ 红(作废) | registry 大包 Response ended prematurely |
| 8 | #65514 | 09-30 15:22 | 1e0882fd | ✅ 绿(当期终态) | 3600s 预算,构建步 ~25-31min |
| 9 | #66436 | 10-01 22:36 | 77984c4b | ✅ 绿 | 路径C 自检修正 commit |
| 10 | #66954 | 10-02 13:38 | 1bde8344 | ❌ 红(作废) | CI-023 死 worker(SSH bridge connection refused,全步瞬秒挂) |
| 11 | #66973 | 10-02 14:02 | 1bde8344 | ✅ 绿(终态) | 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-shadowing | Conan 上下文 LibEdit find 模块网络 FS stat 假阴性回退 CMakeDeps,目标名 libedit::libedit ≠ LibEdit::LibEdit + SYSTEM_LIBS tinfo 传播 → 四层确定性注入 | 3.6 坑 5 | 所有 Conan 上下文消费 CMakeDeps 同名库且源码硬引用 LLVM 风格目标名的配方 |
| DRAFT-lldb001-lldb-cli-ptrace-sandbox-rejection | OHOS 设备沙箱在 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 create | 1245/1245(G2/W3) |
| CI | 11 轮:6 绿 + 5 红(全部基础设施原因作废) |
| 知识沉淀 | 3 对草稿(随 PR 入仓,待 promote) |
| 构建耗时 | CI ~25-35min(无缓存)/ ~19min(有缓存) |
7.2 可复用方法(5 条)
- standalone 消费预编译 LLVM:不跟 FS 抖动对抗,找上游 EXACT 版本钳制点做确定性保证——“pin 不 pin"的决策前先建三层证据链(本案结论恰是"不需要 pin”);
- vendored 树优先:monorepo 子项目 standalone 构建,“消费存档内同源 vendored 依赖"优于"引入外部同名依赖”(monorepo-faithful,三败转一次修复);
- 双路径差异诊断:「本地过、CI 偶挂」先怀疑 FS/网络差异 + CMakeDeps/find 模块目标名差异;依赖包 SYSTEM_LIBS 传播构建期专用库时,消费者 generate() 后处理清除;
- 失败归因三级证据:可见错误行(直接)/ 探针复跑(直接)/ 同族推定(推定),分级不混写;复现矩阵 + 正控排除 harness 因素;没有正控不下上下文级结论;
- 测试证据链入仓: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 后续工作(诚实边界)
- ptrace 进程控制属设备内核级沙箱策略,"launch + 运行"调试工作流需平台侧能力开放(Issue #3564 跟踪);
- python 绑定(SWIG)缺失 → API 套件 1342 例 0 执行,补齐是测试覆盖的下一步;
- 1 条 P2 稳健性建议(tinfo 移除正则的格式无关化)+ 2 条 P3(补丁 0004 gtest 守卫解耦 / test_package 空值 guard)已记录待 follow-up。
参考链接
- PR(已合并):https://atomgit.com/OpenHarmonyPCDeveloper/build_in_harmonyos/merge_requests/13409
- Issue(随合并关闭):https://atomgit.com/OpenHarmonyPCDeveloper/build_in_harmonyos/issues/3564
- 仓库:https://atomgit.com/OpenHarmonyPCDeveloper/build_in_harmonyos
- 上游源码(2026-10-04撰文时可正常访问):https://github.com/llvm/llvm-project/releases/download/llvmorg-22.1.0/llvm-project-22.1.0.src.tar.xz
- lldb 官网:https://lldb.llvm.org/
更多推荐

所有评论(0)