鸿蒙PC适配mpd 0.24.12:从交叉编译到合入实录
欢迎加入开源鸿蒙PC社区:https://harmonypc.csdn.net/
欢迎在PC社区平台申请新建项目:https://atomgit.com/OpenHarmonyPCDeveloper
鸿蒙PC适配mpd 0.24.12:从交叉编译到合入实录
| 项 | 内容 |
|---|---|
| 对象 | mpd 0.24.12(Music Player Daemon,上游官方源 musicpd.org,2026-05-15 发布) |
| 环境 | HUAWEI MateBook Pro(HAD-W32)/ HarmonyOS 6.1.0(6.1.0.117 SP68C00E100R13P3,HongMeng Kernel 1.12.0)/ aarch64 / Conan 2.29.1(OHOS 适配版) |
| 仓库 | OpenHarmonyPCDeveloper/build_in_harmonyos(AtomGit) |
| PR | #13375 |
| 发布 | mpd/0.24.12 配方已入制品仓(2026-10-03 上传;2026-10-04 conan download 实测可达) |
摘要
mpd 0.24.12 适配鸿蒙 PC aarch64:mpd(Music Player Daemon)是开源世界最老牌的独立音乐服务器之一(HTTP/JSON API + 曲库 + 解码/编码后端),上游以 meson 构建。核心难点不是"换个编译器再编一遍":OHOS libcxx-ohos(LLVM 15.0.4 基线)缺失多项 C++23 标准库 API,而上游源码无条件使用——40 个文件的源码级 portable 补丁,分 4 类(其中 1 个文件属双类修改);meson 交叉编译需自包含交叉文件(host_machine=linux/aarch64 + identity exe_wrapper + 全局 -I/-L 注入);conan 2.29 的 PkgConfigDeps .pc prefix 缺陷与 find_library 型依赖用 8 个 shim 收口。上游测试 18 个 test() 注册,本配置启用 16 个、全量实测 Ok 16 / Fail 0(其中 15 个 gtest 套件共 170 例 [OK],1 个 bzip2 shell 套件 0.20s 通过;2 个未注册因上游环境依赖缺失,非适配裁剪);test_package 消费者测试 C1-C4 共 9 条真实断言,含 null 输出 + 协议状态机的无头播放闭环(play→stop);CI 7 轮构建 4 绿 3 作废(作废轮均为基础设施原因,逐轮附证据);3 份知识草稿(E429/E430/E1003)随 PR 入仓。PR #13375 已合并入 main,mpd/0.24.12 配方已入制品仓。
mpd 0.24 起上游切换到 C++20(官方推荐 clang 14+),而源码树又无条件使用 C++23 的 make_unique_for_overwrite——OHOS 的 clang 版本号 15.0.4 能过上游要求,但其标准库基线(LLVM 15)缺的正是这批 C++23 API,任何 option 组合都会命中;而在没有音频硬件的环境下,音乐服务器"真的能播"这个核心功能如何验证,同样没有现成答案。本文给出 40 个可移植补丁、8 个 pkg-config shim 与一条 null 输出播放闭环的完整实证过程。
诚实声明(结论边界):
- 18 个上游测试套件中 2 个未注册:test_archive_iso9660(需 libiso9660 + mkisofs 程序,依赖未入制品仓)与 test_archive_zzip(需 libzzip + zip 程序,zziplib 不在本图)——上游环境依赖缺失,不是适配裁剪;点亮路径见 4.7。
- 播放闭环经 null 输出插件验证(协议→队列→解码→输出线程全链路,play→stop 状态机实测迁移);ALSA/JACK 输出仅构建期启用(enabled),未在本设备验证真实音频设备出声路径。
- JACK 符号探测
jack_set_info_function= NO,JACK 运行时行为未验证;inotify 本配置关闭。 - 全部结论限定于:HarmonyOS PC aarch64 真机(本设备)+ 本构建配置。
1. 背景:为什么值得做
- 生态价值:mpd 是开源世界最老牌的独立音乐服务器之一(源码树 NEWS 追溯至 0.5 初始发布,最早带日期条目为 2003-05-25)——守护进程 + 客户端分离架构,通过网络协议(文本命令协议 + HTTP/JSON API)暴露曲库管理、播放控制与解码/编码后端(flac/vorbis/opus/wavpack/mp3/ffmpeg 等)。它是 Linux 音频生态的事实标准组件:应用与脚本可通过其网络协议直接调度本地播放,而不依赖任何厂商私有框架。把它带到鸿蒙 PC,等于给平台补上"本地音频服务器"这一基础件。
- 版本选择:0.24 系列是上游当前维护线(源码树 NEWS:ver 0.24 发布 2025/03/11,其后持续出补丁版至 ver 0.24.12 发布 2026/05/15)。0.24 的构建要求(NEWS 逐字):
switch to C++20(GCC 12 或 clang 14+ 推荐)、require Meson 1.0、require libfmt 9 or later、remove Boost dependency,另有 ffmpeg≥4.0、alsa-lib≥1.1、libwavpack 5 等依赖底线——本配方 17 个依赖版本全部满足。0.24.12 修复 0.24.11 引入的回归:0.24.11 修复 path traversal 后误伤 lsinfo/add 的空 URI,0.24.12 放开(NEWS 逐字:allow empty URI in "lsinfo", "add" etc. (0.24.11 regression))。 - 制品仓现状:适配前 W0 预检确认制品仓无 mpd 记录(无先例可复用);依赖链 17 个 host 包 + 1 个构建工具包全部已发布(逐包
conan download核验,2026-09-27)——“依赖齐、本体空白”,适合直接做本体适配。 - 路径C 高难度定性:mpd 同时命中四类深度集成面——多媒体解码/编码(归档格式 bz2/iso9660/zzip 等 + 主流标签格式 + ffmpeg 全家桶)、音频输出(ALSA/JACK)、网络服务(HTTP/ICY/WebDAV 输入)、系统存储(sqlite 曲库);源码树又无条件使用 C++23 标准库 API,在 OHOS LLVM 15.0.4 基线工具链上构成系统性缺口——不是"改两三个平台分支"能解决的量级。
2. 环境与差异前置
环境表全部值为当事机器实测(或标注来源):
| 项 | 值 | 测量来源 |
|---|---|---|
| 设备 | HUAWEI MateBook Pro(HAD-W32) | param get const.product.model 实测 |
| 系统 | HarmonyOS 6.1.0(版本串 6.1.0.117 SP68C00E100R13P3;HongMeng Kernel 1.12.0) | param get const.product.software.version / 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 conf + 构建笔记 |
| conan profile | os=OHOS / arch=armv8 / compiler clang 15 / libcxx=libc++ / cppstd=17 / Release | ci/conan/profiles/ohos-aarch64(仓库内文件) |
| 构建工具 | meson 1.12.0 + ninja | 构建树实测 / 构建笔记 |
| 上游源 | https://www.musicpd.org/download/mpd/0.24/mpd-0.24.12.tar.xz | conandata.yml;本机 curl -I 实测 HTTP 200(2026-10-04) |
| SHA-256 | 14223ca883c35fbf711994bcf745726cecc9d898e3d3964265cf3a2c7519a360 | conandata.yml(下载时校验通过) |
两个直接影响适配形态的环境事实:
- profile 声明 cppstd=17,但 MPD 0.24 强制 C++20(meson 自报
cpp_std=c++20)——编译器"版本号"达标不保证"能力"达标,C++20/23 特性实际由标准库实现决定,这正是第 3 节 4 类源码缺口的根因。 - 本机 = 目标机(aarch64 HarmonyOS 原生环境,不是"x86 host + 远端目标"的远程交叉布局)——这决定了交叉文件的形态(host_machine=linux + identity exe_wrapper),也决定了上游测试二进制可以在真机上直接实跑(见 4.2)。
差异表(先列全 13 项,第 3 节逐项展开;每行对应一个坑位或验证边界):
| # | 差异点 | 上游假设 | 鸿蒙 PC 实际情况 | 对应 |
|---|---|---|---|---|
| 1 | C++ 标准库能力 | 现代 libc++(C++23 P2325/P2652 等可用) | libcxx-ohos 基于 LLVM 15.0.4,缺失多项 C++23 API | 3.3 坑 2(4 类补丁) |
| 2 | fmt 头文件布局 | fmt <11(core.h 暴露全量 API) | 图内解析 fmt/12.2.0,core.h 精简布局 | 3.3 坑 2(第 3 类,29 文件) |
| 3 | 构建模式 | 原生 meson 构建 | meson 交叉文件(host_machine=linux/aarch64)+ identity exe_wrapper | 3.2 坑 1 |
| 4 | pkg-config 生态 | 系统 .pc 前缀有效 | conan PkgConfigDeps .pc prefix 指向不存在的槽 + 个别模块缺失 | 3.5 坑 4(8 shim) |
| 5 | find_library 型依赖 | 系统 /usr/include 默认可见 | mad/lame/bzip2 需显式 -I/-L 注入 | 3.5 坑 4 |
| 6 | ICU 形态 | 动态或静态均可 | 纯静态包,数据符号 -licudata 必链 + meson 缓存 .pc 结果 | 3.6 坑 5 |
| 7 | cross 测试执行 | 无需 wrapper | meson 1.12 cross 构建无 exe_wrapper → 全部测试 SKIP | 3.7 坑 6 |
| 8 | CLI/配置格式 | 0.22 时代习惯(–config / 等号) | 0.24 重构:配置路径是位置参数、无等号格式 | 3.8 坑 7 |
| 9 | ELF 链接后处理 | strip/install 常规操作 | 已落盘 ELF 的 in-place 字节改动 = 不可执行(完整性封印) | 3.9 坑 8 |
| 10 | 构建缓存 | 独占 .conan2 | 多 worker 共享缓存,槽位漂移/遗留 | 3.10 坑 9 |
| 11 | 依赖版本图 | 单版本 bzip2 | host 图 1.0.8(ffmpeg 传递)与程序需求(1.0.8.2 才有 bindirs) | 3.11 坑 10 |
| 12 | conan 2.29 依赖引用 | 传递可达即可用 | package_info 使用直接依赖必须显式声明 | 3.12 坑 11 |
| 13 | 音频输出 | ALSA/JACK 设备可用 | 构建期 enabled,运行时无设备;验证走 null 输出 | 3.14 坑 13 + 4.4 C4 边界 |
3. 适配过程
3.0 侦察(动手前)
- W0 依赖预检:17 个 host 依赖 + 1 个工具依赖逐一
conan download <pkg> -r=ohpcd --only-recipe核验制品仓,全部已发布(2026-09-27)→ 无需自编译依赖。测试清点阶段另发现 TestIcu 需要 icu/76.1(制品仓已有,补入 requires,初始依赖清单外)。 - 构建系统判定:meson + ninja(源码声明
meson_version >= 1.0;0.24 主程序无 autotools/CMake 路径)。交叉三元组口径:meson 无 ohos 系统名,host_machine用 linux/aarch64。 - 测试策略:R51 三步法(清点 → 全量实跑 → 回填)。清点:
test/目录 86 个 .cxx + 8 个 .hxx + 3 个 .sh,GoogleTest 框架,18 个 test() 注册;其中 3 个受"上游环境依赖"门控(bzip2 程序 / mkisofs 程序 / zip 程序 + 对应库),轮 A 预期本配置启用 15/18。 - 语言预检误报(误判 ①):lang-preflight 初判 mixed(exit 2)——3 个 build.gradle.kts + 6 个 .java 全部位于 android/ 可选 Android 客户端目录(不在 meson 构建图内);主体 1671 个 .cpp 占 99.4% → 经源码统计复核改判 cpp 继续。教训:多客户端目录工程的主体判定要按"实际适配目标",不能按全仓文件统计。
- 开关基线:22 个 -D 开关 = 1 显式(default_library=static)+ 15 特性开关 + 6 背景 OFF(shout/ao/oss/pulse/sndfile/faad)+ inotify=false;背景 ON 清单 11 项逐项与 meson configure 自报值核对(ALSA/JACK/SQLITE/FLAC/VORBIS+VORBISENC/MAD/WAVPACK/OPUS/FFMPEG;CDIR 因 libcdio_paranoia 不在制品仓 auto→off,PORTAUDIO 在 0.24.12 无对应输出插件不被消费);auto 族按"依赖在图内默认启用、缺省关闭"处理(curl/expat/webdav/pcre/lame/ipv6 转 ON,34 项缺依赖族 off)。
3.1 依赖树
mpd/0.24.12(meson 交叉构建,host_machine=linux/aarch64)
├── alsa-lib/1.2.16.1 音频输出(OHOS 运行时无设备,构建期 enabled)
├── jack/1.9.22 JACK 输出(符号探测 NO,运行时未验证)
├── sqlite3/3.53.4 曲库
├── zlib/1.3.1.1 ffmpeg 图冲突下唯一可解版本
├── flac/1.5.0 flac 解码
├── vorbis/1.3.7 ogg/vorbis 解码+编码(vorbis+vorbisenc 双模块)
├── mad/0.16.4 mp3 解码(find_library 型,-I/-L 注入)
├── wavpack/5.9.0 wavpack 解码
├── opus/1.5.2.1 opus 解码
├── ffmpeg/6.1.6 通用解码(libavformat 60.16.101 等,.pc Version 自 SONAME 修正)
├── icu/76.1 Unicode(纯静态包,-licudata 必链)
├── fmt/12.2.0 格式化(29 文件 core.h→format.h)
├── libcurl/8.5.0 HTTP/WebDAV 输入 + test_icy_parser(shim 收口)
├── lame/4.0 mp3 编码(find_library 型)
├── bzip2/1.0.8 .bz2 档案解码(host 图版本,与 ffmpeg 传递一致)
├── gtest/1.17.0 单元测试(gmock 代码实装于本包内,shim 收口)
├── gmock/1.17.0 单元测试(shim 收口)
└── tool_requires: bzip2/1.0.8.2 bzip2 程序(test_archive_bzip2 shell 套件;1.0.8 包无 bindirs)
传递/图内(不在 requires 主清单):expat 2.8.2.1 / libpcre2-8 10.48 /
libiso9660 2.3.0 / ogg 1.1.1(libvorbis 传递)/ fontconfig·freetype·harfbuzz·libxml2·xz(ffmpeg 传递)
3.2 坑 1:交叉文件自包含(三件套 + 两个易错点)
- 现象:交叉构建需要 [binaries](编译器绝对路径——OHOS posix_spawn 无法经 PATH 解析裸命令)、[host_machine] 与代码生成器的 native file;本地探索期的机器特定配置若直接进配方,CI clean 环境不可复现。
- 定位:meson 1.12 交叉三元组口径(host_machine=linux/aarch64);源码 GenParseName.cxx 是 native:true 构建期代码生成器,需要 build machine 编译器的 native file。实测 ar 必须写入 native file——缺失时 meson 对 build machine archiver 回退 PATH 查找(llvm-ar-15/llvm-ar/ar/gar 全部 ENOENT),报 “Unknown linker(s)” 误报。
- 方案:conanfile build() 自包含生成三个文件——cross-ohos.ini([binaries] 绝对路径 + exe_wrapper + [host_machine] system=linux + [built-in options] 全局 c/cpp_args 与 c/cpp_link_args)、native-build.ini(c/cpp/ar 三件套)、mpd-exe-wrapper.sh(identity wrapper,见坑 6)。编译器路径优先取 profile conf(tools.build:compiler_executables,R33 合规),回退 HNP 绝对路径;机器环境 CFLAGS 原值(-fPIC -O2)显式保留([built-in options] 会覆盖环境 CFLAGS)。
- 经验:meson 1.12 位置参数序是
[builddir] [sourcedir](builddir 在前);遇到 “Unknown linker(s)” 先查 archiver 探测链,而不是怀疑链接器缺失。
3.3 坑 2:OHOS libcxx-ohos 的 C++23 标准库缺口(4 类 40 文件,全部 portable)
共同根因:OHOS 工具链的 libc++ 基于 LLVM 15.0.4,上游 MPD 0.24 源码无条件使用更新的标准库 API;clang 版本号 15.0.4 能过上游推荐(clang 14+),但"标准库实现"落后于"编译器版本号"。四类:
| 类 | 现象(首个命中) | 根因(标准缺口) | portable 修法 | 范围 |
|---|---|---|---|---|
| 1. span range 构造 | src/util/SpanCast.hxx:53 string_view→span 初始化无匹配构造 | 缺 C++23 P2652(span-from-range,libc++ 18 才并入);上游 guard 仅覆盖 __clang_major__ < 15,本机 clang 15.0.4 恰好落在 guard 之外 | guard 改特征宏 #if __cpp_lib_span < 202306L(1 行),两分支产生等价 span | 1 文件 |
| 2. make_unique_for_overwrite | 全树编译错(首命中 FileCommands.cxx) | 缺 C++23 P2325R3(libc++ 19 才并入);源码树无条件使用,任何 option 组合都会命中 | 统一替换 std::make_unique(语义差异仅值初始化多一次零填充;13 处使用点均写后才读,无副作用) | 10 文件 13 处(含双类文件 0024) |
| 3. fmt 头布局 | 29 文件 no member named 'format' in namespace 'fmt'(首命中 ToString.cxx) | fmt 11+ 将 <fmt/core.h> 改精简布局(format/to_string/join 移入 <fmt/format.h>);图内 fmt/12.2.0;任何平台 fmt≥11 均会命中 | #include <fmt/core.h> 统一替换 <fmt/format.h>(严格超集、幂等、fmt 9-12 全兼容) | 29 文件(含 1 个 win32 专属文件,统一替换保任意平台可构建) |
| 4. chrono time_point <=> | src/event/TimerList.hxx:22 regular_invocable<compare_three_way, time_point, time_point> = false(一次命中 6 个 TU) | 缺 std::chrono::time_point::operator<=>,默认 Compare=std::compare_three_way 不可调用 | 增加显式比较器 CompareDue(返回 strong_ordering,仅用 C++11 关系符)并传入;树逻辑以 weak_ordering 接收(strong→weak 标准隐式转换),语义完全一致 | 1 文件 |
- 文件数口径(包含关系):类别计 1+10+29+1 = 41 个"类-文件"计次,其中 0024 属双类修改文件(同时计在第 2 类与第 3 类),去重后共 40 个文件(0001–0040),与 conandata.yml 声明的补丁文件数逐一对应;notes.md 中的"41 文件"是未去重的类别计次口径。
- W0b 历史比对:历史同类适配曾用
defined(__OHOS__)平台宏(R8 违规),本次不复用——4 类修法均为特征宏/等价 API/显式比较器/头替换,零平台宏、零行为差异、任意平台可构建;历史补丁仅覆盖 make_unique_for_overwrite 10 文件中的 3 个,本次全树补全(含本配置对应 option 关闭的 4 个文件:Sidplay/io_uring/Win32/nfs,保证任意 option 组合可构建)。 - 经验:“编译器版本号达标” ≠ “标准库能力达标”——现代 C++ 工程适配旧基线标准库的工具链时,先做一次"特征宏 vs 版本宏"清点;上游 guard 用版本宏写死的,改特征宏永远是最 portable 的修法。
3.4 坑 3:meson 1.12.0 对同一 dep 的 cflags 传递不一致(alsa)
- 现象:编译错
fatal error: 'alsa/asoundlib.h' file not found(仅 input_plugins 目标)——同一 alsa_dep 对象在 libalsa/output_plugins 目标正常,唯独 input_plugins 漏掉 alsa 的 pkg-config cflags;直接pkg-config --cflags alsa输出正常(可复现)。 - 定位:meson 1.12.0 对同一 dep 对象在不同 executable 目标的 cflags 传递行为不一致(疑似 dep 对象共享/缓存问题);现象可复现,内部机制未完全定位——如实记录,不假装已定位。
- 方案:交叉文件 [built-in options] 全局注入
-I <alsa-lib include>(workaround,conanfile build() 复现;CI clean 环境同 meson 版本必现)。 - 经验:依赖问题"部分目标成功、部分失败"时,先用
pkg-config直查排除 .pc 文件本身,再怀疑构建系统的 dep 传递层;机制未定位的 workaround 在台账中写明"可复现 + 影响范围 + 同版本必现",供后续升级构建系统时复核。
3.5 坑 4:PkgConfigDeps .pc prefix 缺陷 + find_library 无 include(8 个 shim + -I/-L 注入)
- 现象(同族两个问题):
- broken .pc 三处来源:PkgConfigDeps 生成的 mad.pc/lame.pc 等 prefix 指向 recipe 槽的 p/(路径不存在,真实产物在另一 package_id 槽);gtest 包自带 4 个 .pc 硬编码原构建期 build-context 绝对路径(本机不存在);共享缓存遗留 curl 8.15.0 包的 libcurl.pc prefix 指向跨机路径。
- find_library 型依赖:MPD 对 mad/lame/bzip2 走
compiler.find_library——find_library 只给链接探测(认 -L),不给 include(上游假设系统 /usr/include 默认可见),mad.h/lame/lame.hnot found + 链接缺库。
- 定位:① conan 2.29.1 PkgConfigDeps 的 .pc prefix 解析到 recipe 槽而非 package 槽(缺陷在 conan 侧,CI clean 环境同样必现);② find_library 型依赖不携带 include 路径是上游设计,非缺陷。
- 方案:8 个 shim 收口(PKG_CONFIG_PATH 最前:
shims:generators,shim prefix 一律取 conan APIpackage_folder真实产物槽,不依赖 .pc 自带 prefix)——shim 收口对象 原因 icu-uc / icu-i18n ICU 双模块 PkgConfigDeps 只生成单一 icu.pc,MPD 按 icu-i18n/icu-uc 两模块名查询 libcurl libcurl 8.5.0 包自带 .pc prefix 跨机损坏 gtest / gtest_main / gmock / gmock_main 测试框架 4 模块 包自带 .pc prefix 损坏 + 模块缺失;gmock 代码实装在 gtest 包内(conan gmock 包为无产物标记包),shim 统一指向 gtest 包 bzip2 bzip2 1.0.8 轮 B 新增,PkgConfigDeps prefix 槽缺陷同类 find_library 族:交叉文件 c_args 全局 -I <mad/lame/bzip2 include>+ c/cpp_link_args-L <mad/lame/bzip2 lib>。 - 经验:conan + pkg-config 生态里,.pc"由谁生成"不如"prefix 指向哪"重要——shim 目录 + prefix 权威来源(conan API)可以把 N 个来源各异的 broken .pc 一次收口;shim 在配方 build() 内自包含生成,CI clean 环境等价复现。
3.6 坑 5:纯静态 ICU 包缺数据符号 + meson coredata 缓存 .pc 结果
- 现象:链接错
undefined symbol: icudt76_dat(mpd 主可执行文件 + 4 个测试链接)。 - 定位:conan icu/76.1 是纯静态包(libicuuc.a/libicui18n.a/libicudata.a);
icudt76_dat数据符号由 libicudata.a 提供,.pc Libs 只写 -licuuc 即缺 -licudata。且 meson 把 pkg-config 结果缓存进 coredata,meson reconfigure复用缓存不重查——实测踩坑:改 .pc 后连续两次 reconfigure,build.ninja 仍无 -licudata。 - 方案:shim icu-uc.pc 的 Libs 补
-licudata(顺序 -licuuc 在前、-licudata 在后)+meson setup --reconfigure --clearcache强制刷新。 - 经验:纯静态包的"数据符号"(icu 的 icudt*_dat 一类)必须显式链上;构建系统缓存了依赖探测结果(meson coredata、cmake cache)时,"改输入重跑"不生效——清缓存,并以 build.ninja 的实际内容(而不是 .pc 的内容)为验证对象。
3.7 坑 6:cross 构建测试全 SKIP(exit 77)→ identity exe_wrapper
- 现象:
meson test15 个测试全部 SKIP(exit status 77、0.00s、无输出);手动直接运行同一测试二进制 55/55 PASSED。 - 定位:meson 1.12 交叉构建语义——cross 构建产物运行测试必须经
exe_wrapper;交叉文件未定义 exe_wrapper → mtest.py_get_test_cmd返回 None →complete_skip()(源码注释:“Can not run test on cross compiled executable because there is no execute wrapper”)。 - 方案:交叉文件
[binaries] exe_wrapper = ['mpd-exe-wrapper.sh']——本机 = 目标机(aarch64 HarmonyOS 原生),wrapper 为 identity 形态:注入 LD_LIBRARY_PATH(全部有 package_folder 且 lib 目录非空的依赖 + SDK llvm 库)后exec "$@"透传。conanfile build() 生成(CI clean 环境等价;CI worker 同为目标机)。 - 经验:"测试全 SKIP 且 0.00s"是 cross 构建缺 wrapper 的强信号,不是测试失败;本机 = 目标机时,identity wrapper 是成本最低且最诚实的解法(不引入 QEMU/模拟器变量)。
3.8 坑 7:0.24 CLI/配置格式重构(上游行为变化,非平台问题)
- 现象:冒烟脚本按 0.22 时代习惯启动 mpd,立刻
'"' expected配置解析错;--decode-file报未知选项。 - 定位(源码实证 4 条):① 0.24 主程序无 --config 选项(命令行仅 kill/no-config/no-daemon/systemd/stdout/stderr/verbose/version/help),配置文件路径是位置参数(src/CommandLine.cxx 首个非选项参数);② 新配置解析器(src/config/File.cxx + Tokenizer)不接受
name = "value"(NextString 要求值紧随名字,=触发'"' expected)——mpd.conf 必须name "value"格式;③--decode-file选项已移除(0.24 无);④ 测试工具 read_tags/run_decoder 的 URI 参数直接接受绝对路径(InputStream::Open 对 IsAbsolute 走本地打开,无需 file:// 前缀),DECODER 参数必须为具体插件名(mad/ffmpeg/opus 等,无 “all”)。 - 方案:冒烟脚本 / test_package 按上述格式编写(
mpd --no-daemon <conf>;conf 无等号);R40 实质验证改用 read_tags/run_decoder 替代 --decode-file。 - 经验:大版本升级的 CLI/配置重构是"上游行为变化"不是"平台问题"——台账中单独成行(不标可移植性),测试脚本是这类变化的第一集中命中处;解析器报错(
'"' expected这类)先核对当前版本的配置文法,再怀疑平台。
3.9 坑 8:OHOS 已落盘 ELF 的 in-place 字节改动 = 不可执行(完整性封印)
- 现象(两条独立证据链,2026-09-27 本机实测,已入档 E430):
llvm-objcopy(本机 llvm-strip 的别名,无独立 llvm-strip)输出——strip --strip-all 与零选项纯重序列化皆然,4.6KB hello world 亦复现——exec 报 EACCES/EPERM;meson install对 builddir 产物剥 DT_RUNPATH 的 in-place patch(1195 字节改动、文件大小不变)→ 安装产物 stage 直接执行报 EPERM(cmp 证明 stage ≠ builddir 原件)。
共性:文件 mode 770、ELF ehdr/phdr 内部一致、SELinux context(hmdfs:s0)与可执行文件完全相同仍被拒——权限层面无任何异常,纯内核拒 exec。
- 定位:推断(标注为推断)——OHOS 内核/FS 对已落盘文件做完整性封印(与 lld 生成的
.note.ohos.ident标识段相关,与 SKILL gotchas"ELF 签名:必须签名否则不可执行"同族机制):落盘后任何 in-place 字节改动破坏封印 → exec 拒绝;全新文件写入不受影响(clang/lld 原始产物可执行,cp/shutil.copy2全新拷贝可执行)。 - 方案:package() 禁止 meson install / strip / objcopy 一切链接后重写,一律对 builddir 原始产物做全新拷贝(conan copy = 新文件写入);builddir 产物携带的 DT_RUNPATH(指向 conan build tree 目录)异地为死路径、无害,运行时库解析由 conanrunenv 的 LD_LIBRARY_PATH 承担;瘦身/签名需求走 CI sign.sh 签名链,不做本地重写。
- 经验:在 OHOS 上"链接后处理"与"产物搬运"必须严格分离——搬运只允许以"新文件写入"发生;仓库内 aegisub 先例同为 builddir 直拷(未走 meson install),本坑是第二个实证。
3.10 坑 9:共享 conan 缓存污染(多 worker 环境)
- 现象:.conan2 为本机共享,被并发任务增删/清理:缓存出现空槽、跨机 prefix 的 .pc、build-context 遗留槽(p/b/ 目录消失);曾导致 libcurl 8.5.0 解析指向已消失的槽。
- 方案:① 依赖存在性一律
conan download -r=ohpcd(W0/R36/R35 口径),不信任本地缓存的"存在";② .pc 消费一律经 SHIM 收口到实测存在的产物槽(不依赖 .pc 自带 prefix);③ PKG_CONFIG_PATH =SHIM:deps-only(排除遗留槽 .pc 干扰)。 - 经验:共享缓存机器上,“本地有包” ≠ “包可用”;"存在性判断"与"路径引用"两个动作都应走权威源(制品仓 + conan API
package_folder),不要走文件系统探测。
3.11 坑 10:bzip2 版本冲突三连坑(轮 B)
- 现象(点亮 test_archive_bzip2 时三连命中):
- 版本冲突——直接
requires("bzip2/1.0.8.2")vs ffmpeg 传递bzip2/1.0.8,conan 2 图内直接报Version conflict; ld.lld: unable to find library -lbz2——MPD 对 bzip2 走cc.find_library('bz2')(find_library 型只认 -L,交叉文件 c_link_args 此前仅 mad/lame);- bzip2/1.0.8 包为纯库(package_info 无 bindirs),而套件另需 bzip2 程序(1.0.8.2 包才声明 bindirs=bin,含 12 个程序)。
- 版本冲突——直接
- 误判(②)→ 纠正:最初按"哪个包带程序就依赖哪个包"的直觉直接 requires 1.0.8.2 → 撞上硬冲突;复核 ffmpeg 的传递声明后改为分工:host 图维持 bzip2/1.0.8(与 ffmpeg 传递一致,mpd 链 libbz2.a),程序需求单独走 tool_requires(构建上下文与 host 图版本互不冲突)。
- 方案:①
tool_requires("bzip2/1.0.8.2")仅提供程序(conan 2 直接/传递同包不同版本 = 硬冲突,无隐式升级;build/host 双上下文天然隔离);② 交叉文件 c_args 补-I <bzip2 include>、c/cpp_link_args 补-L <bzip2 lib>(meson-log 实证:补前链接测试缺 -L,补后 find_library 通过);③ bzip2.pc 作为第 8 个 shim 收口;④ 程序入 PATH = conan buildenv 自动注入 + 配方shutil.which回退注入双保险(which 未命中时读dependencies.build["bzip2"].package_folder的 bin 前置 PATH,带 None 判空守卫——与坑 11 同口径)。 - 经验:conan 2 的"同包异版本"冲突,可用 host/tool 双上下文分工化解——依赖是"库 + 程序"双形态且分属两个版本包时,库走 host、程序走 tool_requires,不强行统一版本。
3.12 坑 11:conan 2.29 直接依赖引用强制(G2 第三类失败)
- 现象:轮 B 引入 bzip2 后,G2(conan create/verify 配方复现门禁)报 bzip2 依赖引用缺失——
package_info().requires未声明bzip2::bzip2。 - 定位:ohpcd conan 2.29 的依赖引用检查要求 package_info 中实际消费的直接依赖必须在 requires 显式声明(依赖在图内传递可达不等于声明层可用)。
- 方案:package_info requires 补
"bzip2::bzip2";终态 17 个直接依赖逐一声明(与 requirements() 一一对应)。 - 经验:新增直接依赖要同步三处——
requirements()、对应 meson 开关、package_info().requires;第三处最容易被漏(主构建可能不报,验证阶段才暴露)。
3.13 坑 12:W3 “Already installed” 缓存跳过与构建等价判定
- 现象:W3 本地验证(conan create)阶段出现 “Already installed”——包被判定已在缓存中,实际构建被跳过,验证形同虚设。
- 定位:共享缓存(坑 9)中留有前一轮产物(同包名版本、同依赖图、同 profile 命中同一 package_id),conan create 缓存命中即短路——这是 conan 的缓存语义,不是配方缺陷。
- 方案:做构建等价判定——残留包须满足"同配方 revision + 同依赖图 + 同 profile"三要素才可视为等价于本轮构建,判定依据写入台账;最终由 CI clean 环境(无残留缓存)的绿轮做独立复验兜底。
- 经验:“验证被跳过"要先区分"工具缓存语义"与"验证缺失”——缓存命中必须核对三要素才能接受,且必须留一轮 clean 环境的独立验证,不能拿缓存命中当验证完成。
3.14 坑 13:无头播放协议坑(null 输出播放闭环,已入档 E1003)
- 背景:OHOS 无 ALSA/JACK 音频设备,R40 实质验证(“真的能播”)不能依赖真实出声;mpd 的 null 输出插件无条件编译(output_plugins_sources 初始值),配置
audio_output { type "null" name "X" }即得一条零新增依赖的播放链路。 - 协议坑(两条直觉误用,实测报错,2026-10-01):
play N= 播放列表索引(不是数据库 ID);启动时列表为空 →Bad song index;add <uri>用 music_directory 相对路径;把 listall 返回的0:前缀(数据库索引)传给 add →No such directory。
- 误判(③)→ 纠正:协议读取初版按 ACK 惯例严格判定(MPD 协议中带 id 的命令回
ACK <id>),实测 MPD 0.24.12 的add(无 id 命令)返回OK→ 脚本判全部失败;终态改为以ERROR为唯一失败信号(不强制 ACK/OK,跨版本兼容)。教训:协议断言必须以前置的"实测应答采样"为准,不能从协议文档惯例直接推断。 - 方案:test_package C4 固化(详见 4.4)——python3 wave 生成 3s wav(440Hz、44100Hz mono)→ 独立配置(port 6602 + 独立 music_dir/db/log,0.24 无等号格式)→
mpd --no-daemon <conf>→ python3 socket 客户端:recv greeting → listall → add 相对路径 → play 0 → 每 0.3s 轮询 status(40 次 = 12s 窗口)→ saw_play 与 saw_stop 均为真才通过(play→stop 闭环证明);失败输出 mpd 日志 tail。 - 实测结果:2026-10-01 本机,3s 样本(440Hz wav)完整走完:协议观测到
state=play(time 0→3)→state=stop(play→stop 闭环),脚本输出ok: C4 playback end-to-end。 - 经验:无音频输出的守护进程可用"协议状态机迁移"作为唯一可观测信号;两个前提——样本时长足够(≥3s,0.5s wav 可能采不到 play 状态)、断言双向(play 与 stop 都要观测到,"从未进入 play"与"播了停不下来"都算失败)。
4. 验证(分层,口径不可相加)
4.0 口径声明
本文四个口径相互独立,不可相加:
- 上游 meson 套件:16(本配置注册数,上游共 18);
- gtest 用例:170(15 个 gtest 套件的 [OK] 行;第 16 个套件 bzip2 为 shell 型,不产 gtest 行)——⊂ 口径 1;
- 消费者 test_package 断言:9(C1-C4 = 1+3+3+2)——鸿蒙特有验证,独立于 1/2;
- CI 构建轮次:7(4 绿 / 3 作废)——过程口径,不是测试通过率。
"16/16 Ok"指口径 1(套件通过率),"170/170"指口径 2(用例通过率),"9/9"指口径 3。
4.1 上游测试(R51 三步法)
第一步 清点(构建前,2026-09-27):
| 项 | 值 |
|---|---|
| test() 注册总数 | 18(纯净源码树静态清点,test/meson.build,GoogleTest 框架) |
| 本配置注册 | 16(轮 B) |
| 未注册 2 个 | test_archive_iso9660(注册条件 = libiso9660 + mkisofs 程序;轮 A 实测 libiso9660 图内可解析、构建机缺 mkisofs 程序,终报口径记为"libiso9660 未发布",两种口径结论一致:上游环境依赖缺失)/ test_archive_zzip(需 libzzip + zip 程序,zziplib 不在本图)——上游环境依赖,非适配裁剪 |
| 轮 B 点亮 | test_archive_bzip2(轮 A 未注册:无 bzip2 库 + 程序;轮 B 以 host bzip2/1.0.8 + tool bzip2/1.0.8.2 点亮,见 3.11 坑 10) |
第二步 实跑(2026-10-01 真机,host=target 原生执行):
meson test -v -j4 -t 10 # 轮 B 配方构建树
# → Ok: 16 / Fail: 0(100%)
对归档证据文件(test-evidence.md,686 行 meson test -v 原文,未删节,随 PR 入仓)逐行计数核验:170 [ OK ] = 170 [ RUN ],15 个 [ PASSED ] 套件汇总行;TestUtil 为最大单套件(55 用例);bzip2 shell 套件 OK 0.20s(其 bzip2 程序由 tool_requires bzip2/1.0.8.2 注入 PATH)。
第三步 回填:配方 build() 内置 meson test -j4 -t 10(失败即 fail build,真门禁),CI clean 环境等价复现;全量输出与 16 套件逐条声明分别归档于 test-evidence.md 与 test_package/MANIFEST.yml。

图 1:上游测试复跑 Ok 16 / Fail 0
4.2 上游测试直接执行声明
本机 = 目标机(aarch64 HarmonyOS 原生):16 个上游测试二进制在目标机上真实执行(meson test 经 exe_wrapper identity 透传,见 3.7 坑 6,无 QEMU/模拟器变量),不是"x86 host 构建后回跑 host";同时未做断言级 1:1 移植——上游测试二进制本身即验证对象,gtest 套件为纯 in-process 单测,16 个套件全部可运行,0 环境受限项。
4.3 私有 API / 符号面
不适用:17 个直接依赖全部为制品仓预编译包,mpd 消费其公共 API(pkg-config + 公共头文件),无私有符号或内部头文件依赖。mpd 自身产物形态见 4.5(主可执行文件 + 2 个测试工具,default_library=static 为主)。
4.4 消费者测试 C1-C4(9 条真实断言)
test_package/test_mpd.sh(bash + python3 socket,由 test_package/conanfile.py 显式经 bash 调用;set -euo pipefail,任一断言不满足即非零退出、输出失败分支与 mpd 日志 tail,无硬编码通过):
| 用例 | 层 | 断言数 | 断言内容(逐条) | 实测关键输出 |
|---|---|---|---|---|
| C1 | L1 版本/身份 | 1 | mpd --version 输出含 0.24.12 | Music Player Daemon 0.24.12 (0.24.12) + Copyright 两行(脚本打印 head -3,断言仅版本行) |
| C2 | L2 真实 API | 3 | ① 守护进程启动后存活;② 协议握手:直连 127.0.0.1:6601 读 greeting(0.24 绑定成功无日志,端口连通即"实际监听"证明);③ 曲库导入:日志含 added + sample.wav | greeting OK MPD(banner 0.24.0 为上游 GitVersion 烘焙值,与 --version 的 0.24.12 不同,故仅断言 OK MPD 前缀);ok: C2 library import (scan added sample.wav) |
| C3 | L2 解码后端 | 3 | ① run_decoder 在包内且可执行;② run_decoder ffmpeg sample.wav(0.5s wav)退出码 0;③ 输出首行含 audio_format=(解码后端初始化并报告格式) | dec.out 首行 audio_format=… 报告 |
| C4 | L2 核心功能(播放闭环) | 2 | ① 守护进程以 null 输出配置启动存活(独立端口 6602 + 独立 music_dir/db/log);② 协议状态机:add 相对路径 → play 0 → 12s 窗口轮询中 play 与 stop 均观测到 | ok: C4 playback end-to-end (play -> stop state machine observed) |
C4 的 null 输出边界(与摘要诚实声明一致):验证的是协议→队列→解码→输出线程全链路(null 插件真实消费解码帧),不验证真实音频设备出声。
另(不计入 9 断言,属适配期手工 R40 验证,notes 留档):read_tags mad 解 mp3 → audio_format=44100:24:1、read_tags ffmpeg 解 opus → audio_format=48000:f:1、run_decoder mad/opus 解码帧正常(2026-09-28 本机实测)——mad 与 ffmpeg 两条独立解码路径均有实证。

图 2:适配产物 mpd --version 真机运行
4.5 产物验证
| 项 | 值 | 来源 |
|---|---|---|
| 包内容 | bin/mpd(主可执行文件)+ bin/read_tags + bin/run_decoder(测试工具)+ licenses/(COPYING/LICENCE,GPL-2.0-or-later) | conanfile package() 终态 |
| mpd 可执行文件大小 | 37,857,984 字节(~37.9MB,构建树实测) | 2026-10-04 ls -la |
| 产物搬运方式 | 对 builddir 原始产物的全新拷贝(禁用 meson install/strip/objcopy,见 3.9 坑 8) | conanfile 注释 + E430 |
| 构建规模 | 737 个编译目标(轮 A 实测;轮 B 增加 bzip2 档案插件目标),本地 ninja 构建 ~13 min | PR 正文 |
| CI 构建时长 | #67013 全程 7 min 27 s(14:00:42 building → 14:08:09 passed,含 clone+构建+测试) | PR 评论时间戳 |
| 命令声明 | 软件级 commands.json(type=tool, binary=true, ref mpd/0.24.12),CI L0k 通过 | archives/m/mpd/commands.json |
| 签名 | CI sign.sh GPG 签名链(合并后发布流水线,不在本地做链接后重写) | ci/artifacts/sign.sh |
4.6 CI 与评审
CI 7 轮完整表(全部轮次的证据行来自 PR #13375 评论,无删节):
| 轮 | build | head | worker | 结果 | 备注 |
|---|---|---|---|---|---|
| 1 | #64395 | 0ad5ec04 | CI-038 | 作废(基础设施) | 09-29 12:02,fork failed: out of memory(worker OOM) |
| 2 | #64397 | 0ad5ec04 | CI-021 | 作废(基础设施) | 09-29 12:03,OOM |
| 3 | #64398 | 0ad5ec04 | CI-021 | 作废(基础设施) | 09-29 12:04,OOM |
| 4 | #64408 | 0ad5ec04 | CI-006 | ✅ 通过 | 09-29 12:09 → 12:50 |
| 5 | #64449 | 0ad5ec04 | CI-006 | ✅ 通过 | 09-29 12:51 → 13:12 |
| 6 | #66995 | 148c173e | CI-023 | 作废(基础设施) | 10-02 13:54,SSH bridge connection refused(exit -1) |
| 7 | #67013 | 148c173e | CI-019 | ✅ 通过 | 10-02 14:00:42 → 14:08:09(最终头) |
口径:作废轮不计为失败(均为基础设施原因,证据行如上);最终头 148c173ec 有独立绿轮(#67013),不是沿用旧头的绿。
评审记录:
- 平台 AI 检视:09-29 12:51"AI 代码检视已完成,未发现问题"(对 0ad5ec04);此后 3 次因基础设施失败跳过(09-29 21:11 / 09-30 14:58 / 09-30 20:19,共享盘拥堵/工具超时)——对最终头 148c173ec 的平台 AI 检视未成功,如实记录。
- 真人评审:Septest(Jiuxi.)rule 评审 09-29 12:15(rule6 AI 检视未覆盖最新提交 / rule7 CI 未通过 → 后续轮次满足);Clancy_Xie 行级意见(feedback 运行时文件不应入 PR → 0ad5ec04f 移除 129 行,保 PR 原子性)。
- 本地 AI 检视 2 轮(独立子任务执行,两轮报告均在 PR 讨论区留痕):轮 1(对 8cb8b5975)4 项发现——修 3(P1:bzip2 tool_requires 路径的 package_folder=None 守卫回归,E429 同类;P2:read_reply partial-read 竞态致状态偶发漏采;P3:add 应答判定改 ERROR 唯一失败信号)+ 弃 1(误报,附理由)→ 形成 148c173ec;轮 2(对 148c173ec)2×P3 非阻断(说明性回复,无代码改动)。
合并记录:PR #13375 于 2026-10-02 23:24 合并入 main(merged_by Clancy_Xie,approval_reviewer 已 approved;PR 属性 squash_merge=true;close_related_issue=true → 关联 Issue #3527 自动关闭,已核验为 closed)。合并后约 36 分钟,发布流水线将配方上传制品仓(见元信息表"发布"行)。

图 3:PR #13375 已合并入 main
4.7 复现速查
三条命令(① 为 CI 规范调用,与 ci/conan/build_and_test.sh 同形;②③ 为本文章节引用的本机实测命令):
# ① 配方全量重建 + 上游测试 + 消费者测试 C1-C4(构建期约 13 min,CI 口径见 4.5)
conan create archives/m/mpd/0.24.12 \
-pr:h=ci/conan/profiles/ohos-aarch64 \
-pr:b=ci/conan/profiles/ohos-aarch64 \
--build=missing
# 期望:构建成功 + meson test Ok: 16 / Fail: 0 + "PASS: all C1-C4 checks passed"
# ② 上游测试套件复跑(用既有构建树,不重新编译;bzip2 程序入 PATH)
BZBIN=$(ls ~/.conan2/p/bzip2*/p/bin/bzip2 | head -1); export PATH="$(dirname "$BZBIN"):$PATH"
meson test -C ~/.conan2/p/b/mpd8f22b09807afb/b/build-release/meson-build -j4 -t 10
# 期望:Ok: 16 / Fail: 0(见图 1)
# ③ 产物直接运行(秒级)
bash ~/.conan2/p/b/mpd8f22b09807afb/b/build-release/mpd-exe-wrapper.sh \
~/.conan2/p/b/mpd8f22b09807afb/b/build-release/meson-build/mpd --version
# 期望:Music Player Daemon 0.24.12(见图 2)
口径对应:① = 配方自包含性 + 上游 16 套件 + 消费者 9 断言(三口径一次跑完);② = 口径 1 独立复验;③ = 产物可执行性。
配方直接取用:conan download mpd/0.24.12 -r=ohpcd --only-recipe(2026-10-04 实测可达,revision 180e9359c5166e2cf71eca0042278f70)。
点亮 18/18 的路径(后续工作):先适配发布 libiso9660、zziplib 及其工具程序(mkisofs/zip)到制品仓(R36 依赖先行)→ 启用对应特性开关(-Diso9660 / -Dzzip)→ test_archive_iso9660 / test_archive_zzip 注册,预期 18/18。
5. 知识沉淀
| 编号 | 知识(一行) | 来源坑位 | 复用价值 |
|---|---|---|---|
| E429(草稿) | conan 2.29 不可见传递依赖 package_folder=None → 直接遍历抛 TypeError;使用前一律判空 | 3.12 坑 11(轮 B 在 bzip2 tool_requires 路径复发,被本地检视轮 1 P1 拦下) | 所有遍历 self.dependencies 的 conan 配方 |
| E430(草稿) | OHOS 已落盘 ELF 的任何 in-place 字节改动 = 不可执行(objcopy 重序列化 / meson install RUNPATH 剥离双证据链);package() 只允许"新文件写入" | 3.9 坑 8 | 所有含可执行文件的 OHOS 配方 |
| E1003(草稿) | MPD headless 播放闭环:null 输出 + 独立端口/目录 + 协议状态机双向断言(play→stop)+ 协议坑(play=索引 / add=相对路径 / ERROR 唯一失败信号) | 3.14 坑 13 | 无音频设备的守护进程播放/流媒体验证 |
3 份草稿随 PR #13375 入仓(knowledge/drafts/,kv+md 配套),待主编 promote 为正式条目;编号均与正式库无冲突(草稿态命名)。
另如实记录一起:适配期发生 E430 正式条目误写事件(覆盖了另一库的知识条目),当轮恢复原条目,OHOS 故事保留在草稿 E430——知识库写入本身也要如实留痕。
6. FAQ
Q1:为什么是 16/18 而不是 18/18?是不是裁剪了测试?
没有裁剪。2 个未注册套件的注册条件都是"库 + 程序"双依赖:test_archive_iso9660 需 libiso9660 + mkisofs 程序(轮 A 实测 libiso9660 图内可解析、构建机缺 mkisofs 程序;终报口径记为"libiso9660 未发布",两种口径结论一致),test_archive_zzip 需 libzzip + zip 程序(zziplib 不在本图)。属上游环境依赖缺失,非适配缺陷;点亮路径见 4.7。bzip2 套件轮 A 同样未注册,轮 B 被点亮(库走 host + 程序走 tool),证明"缺依赖→点亮"的路径可行。
Q2:null 输出播放闭环算"播放验证"吗?
算真链路验证,但边界明确:null 是 mpd 真实输出插件,播放链路(协议→队列→解码→输出线程)真实执行,3s 样本的 play→stop 状态迁移由协议观测;不验证的是真实音频设备出声(本机无 ALSA 节点)。本文在摘要诚实声明与 4.4 中写明边界,不声称"出声"。
Q3:bzip2 为什么依赖两个不同版本(host 1.0.8 + tool 1.0.8.2)?
mpd 需要 bzip2 库(链 libbz2.a)与 bzip2 程序(test_archive_bzip2 shell 套件)两种形态;制品仓 bzip2/1.0.8 为纯库,1.0.8.2 包才声明 bindirs 含程序。直接 requires 1.0.8.2 会与 ffmpeg 传递的 1.0.8 硬冲突(conan 2 无隐式升级)。解法 = host 图保持 1.0.8(库)、tool_requires 1.0.8.2(程序),build/host 双上下文天然版本隔离。详见 3.11 坑 10(含误判自曝过程)。
Q4:CI 7 轮作废 3 轮,可信吗??
7 轮全表列在 4.6,无删节;作废轮均有基础设施证据行(worker OOM ×3、SSH bridge refused ×1),与代码无关;绿轮是完整 conan create(构建+上游测试+消费者测试,与 CI 规范调用同一命令)。"作废轮不计失败"与社区 CI 对基础设施故障的通行处理一致;最终头 148c173ec 有独立绿轮(#67013)。
Q5:消费者测试 C1-C4 是空壳测试(print-only)吗?
不是。9 条断言逐条不满足即非零退出(set -euo pipefail + fail 计数 + fail 非零 exit 1),无硬编码通过;C4 通过条件 = 12s 窗口内 play 与 stop 都观测到(只见到一个也算失败);失败输出 mpd 日志 tail 便于事后定位。脚本源码在仓库(test_package/test_mpd.sh),CI 侧另有破坏性反向验证门禁确认断言有效。
Q6:40 个文件还是 41 个文件?
40。"41"是"类-文件"计次(1+10+29+1),其中 0024 是双类修改文件(fmt include 与 make_unique_for_overwrite 都改),被计了两次;去重后共 40 个文件(0001–0040),与 conandata.yml 的补丁声明逐一对应。口径见 3.3。
Q7:170 个 gtest 用例和 16 个套件能相加吗?
不能(4.0 口径声明)。170 是 15 个 gtest 套件内的 [OK] 用例数(⊂ 16 套件);第 16 个套件(bzip2)是 shell 型套件,不产 gtest 行。"16/16"是套件通过率,"170/170"是用例通过率,两者是包含关系不是并列关系。
7. 总结
7.1 量化盘点
| 维度 | 值 |
|---|---|
| 源码补丁 | 40 文件 / 4 类(0024 双类,类别计次 41) |
| 差异点 | 13(§2 差异表) |
| 坑位(含流程坑) | 13(3.2–3.14);误判 3(语言预检 / bzip2 冲突直觉 / ACK 强制)+ 构建等价判定 1(W3 缓存) |
| 直接依赖 | 17 host + 1 tool(全部制品仓预编译) |
| PkgConfig shim | 8(轮 A 7 个 + 轮 B bzip2) |
| 构建目标 | 737(轮 A 实测) |
| 上游测试 | 18 注册 / 本配置 16 启用 / 16 Ok(15 gtest 套件 170 例 + 1 bzip2 shell 套件) |
| 消费者断言 | 9(C1-C4 = 1+3+3+2) |
| 知识草稿 | 3(E429/E430/E1003,随 PR 入仓,kv+md 配套) |
| CI | 7 轮:4 绿 / 3 作废(基础设施) |
| 提交与合入 | 4 提交(52/1/8/2 文件变更),2026-10-02 23:24 合并入 main |
7.2 可复用方法(不限 mpd)
- PkgConfigDeps 缺陷收口:shim 目录 + prefix 取 conan API package_folder + PKG_CONFIG_PATH 排序 + meson coredata 清缓存验证(以 build.ninja 为验证对象)。
- find_library 型依赖三件套:交叉文件 [built-in options] 注入 -I include + -L lib + .pc shim(若经 pkg-config 查询)。
- host/tool 双上下文分工:依赖"库 + 程序"双形态且跨版本时,库走 host、程序走 tool_requires,conan 2 同包异版本硬冲突天然隔离。
- 无头播放闭环验证(E1003):null 输出 + 独立端口/目录 + 协议状态机双向断言(play 与 stop)+ 3s 样本 + 协议应答先实测后断言(ERROR 唯一失败信号)。
- CI 轮次口径:基础设施失败逐轮标作废附证据行;最终头必须独立绿轮;缓存命中验证须核对三要素(recipe/图/profile)+ clean 环境独立轮。
7.3 Checklist
- 依赖发布检查(W0:17 host + 1 tool 全部已发布)
- 语言预检(mixed 误报 → 源码统计复核改判 cpp)
- R51 上游测试三步法(18 注册 → 16 启用 → 16 Ok,全量证据入仓)
- R40 实质验证(消费者 9 断言,含播放闭环)
- conan-verify + W2/W3(含构建等价判定)
- W4 Pre-PR 独立审计(本地 AI 检视 2 轮 + 平台/真人评审闭环)
- PR 原子性(单包目录 + 知识草稿,框架文件零混入)
- CI 绿(最终头 #67013)+ 合并 + 入制品仓
- 知识沉淀(3 草稿 + notes 13 项台账)
- 18/18 点亮(被 libiso9660/zziplib 发布阻塞,路径已给)
- 真实音频设备出声路径验证(被硬件阻塞,边界已声明)
7.4 后续工作
- 适配发布 libiso9660、zziplib(+mkisofs/zip 程序)→ 18/18 点亮(4.7 路径)。
- ALSA 真实输出路径验证(需有音频节点的设备)。
- inotify 真机确认支持后 -Dinotify=auto。
- JACK 符号探测(jack_set_info_function=NO)后续跟进与运行时行为验证。
- meson 升级时复核 1.12.0 的 alsa cflags 传递问题(坑 3,机制未完全定位)。
参考链接
- PR #13375(已合并):https://atomgit.com/OpenHarmonyPCDeveloper/build_in_harmonyos/merge_requests/13375
- 关联 Issue #3527(已关闭):https://atomgit.com/OpenHarmonyPCDeveloper/build_in_harmonyos/issues/3527
- 仓库:https://atomgit.com/OpenHarmonyPCDeveloper/build_in_harmonyos
- mpd 官网(源码下载目录,截至发稿,2026-10-04 curl 实测 HTTP 200):https://www.musicpd.org
- 发布与版本要求信息:mpd 0.24.12 源码树自带 NEWS 文件(源码 tarball 内;源 URL 与 SHA-256 见 conandata.yml)
更多推荐

所有评论(0)