Skip to content

build: 新增 Windows CI 并对齐触发条件(消除 push/PR 重复运行) - #74

Merged
wt159 merged 12 commits into
masterfrom
ci/windows-coverage
Nov 7, 2026
Merged

wt159 merged 12 commits into
masterfrom
ci/windows-coverage

Conversation

@wt159

@wt159 wt159 commented Nov 7, 2026

Copy link
Copy Markdown
Owner

做了什么

两件事,都属于「工程配置」类的风险收口。

1. 新增 Windows CI

项目主力是 Windows + MinGW,但此前 .github/workflows/ 只有 sdk-coverage.yml(Linux)。
2026-11-06 那个 seek 差异是 Linux 侧先撞出来的 —— 反方向同样成立,Windows 独有的问题
现在没有任何 CI 能接住。

.github/workflows/sdk-windows.yml:

  • windows-latest + 仓库已有的 scripts/setup_windows_env.ps1(CMake 3.31.6 / Qt 5.14.2 /
    MinGW 7.3.0)。不另写一套安装逻辑,避免 CI 与本地环境漂移。
  • 编译后跑 ctest -R sdk_ 的 11 组,并用 -ts=MediaCoverage -s 打印覆盖度矩阵的
    declared / measured,与 Linux 侧同名步骤对齐,供两端逐项核对(见 doc/format-support.md)。
  • SDL_AUDIODRIVER=dummy,与 Linux 一致。

成本处理:3rdparty 在 Windows 上只能源码构建(Boost / FFmpeg / SDL2 / FLAC / Ogg /
Vorbis / zlib / g3log / g3sinks),首次 40~90 分钟。所以:

  • 整个 sdk/3rdparty/dist/windows_x86_64_gcc_debug 走缓存,键只取第三方构建输入
    (3rdparty 的 CMakeLists / build_option / toolchain / ffmpeg 与 boost 构建脚本),
    业务代码改动不会让缓存失效;
  • 缓存命中时走 -SkipThirdParty,单次约 10~15 分钟;
  • 冷缓存构建完立刻删掉 sdk/3rdparty/build,避免打满 runner 磁盘;
  • 用 actions/cache/save 显式回写,这样「构建成功但后面的测试红」也不会让 90 分钟白跑。

一个必须踩准的点:全程用脚本装好的 CMake 3.31.6 绝对路径。runner 自带的 CMake 若是 4.x,
会对 cmake_minimum_required(3.5) 直接报错。

2. 消除 push / PR 重复运行

on.push 原先没有分支过滤,导致「分支提交」和「同一份 commit 的 PR」各跑一遍完整
sdk-coverage(14 分钟 × 2)。改成 push 只对 master 生效,分支验证交给
pull_request,另加 workflow_dispatch 供单独验证某个分支。

已验证:推 ci/windows-coverage 分支后 gh run list 里没有出现任何新 run —— 之前这里是必然多一轮的。
本 PR 自己就是证据:只有 pull_request 触发的那一轮。

验证情况

  • 两个 workflow 的 YAML 都能正常解析,push.branches 均为 [master],均带 workflow_dispatch。
  • 文件沿用仓库 CRLF。
  • Windows 任务本身还在跑首轮:冷缓存要构建全部第三方库,预计 40~90 分钟。这一轮的价值是
    把 dist 灌进缓存并暴露 runner 上的环境差异;如果红了我会在本 PR 继续修到绿,不合绿不合并。

影响面

  • 业务代码零改动。
  • 新增了一个 PR 检查项(sdk-windows),首轮之后再跑约 10~15 分钟。
  • sdk-coverage 的行为不变,只是不再被分支 push 重复触发。

wt159 added 12 commits November 7, 2026 12:04
- 新增 .github/workflows/sdk-windows.yml:windows-latest + 仓库已有的
  scripts/setup_windows_env.ps1(CMake 3.31.6 + Qt 5.14.2 + MinGW 7.3.0),
  编译后跑 ctest -R sdk_ 11 组,并像 Linux 侧一样用 -ts=MediaCoverage -s
  打印覆盖度矩阵的 declared / measured,供两端逐项核对。
- 3rdparty 在 Windows 上只能源码构建(Boost / FFmpeg / SDL2 / FLAC / Ogg /
  Vorbis / zlib / g3log / g3sinks),首次 40~90 分钟,因此把 dist 目录整体
  缓存,键只取第三方构建输入;缓存命中走 -SkipThirdParty,单次 10~15 分钟。
  冷缓存时构建完立即删掉 3rdparty/build,避免打满 runner 磁盘。
- 全程用脚本装好的 CMake 3.31.6 绝对路径:runner 自带 CMake 若是 4.x,
  会对 cmake_minimum_required(3.5) 直接报错。
- sdk-coverage.yml 的 push 触发收窄到 master,加 workflow_dispatch。
  原先分支提交与 PR 各跑一遍同一份 commit,白等两轮 14 分钟。
- shell 对未加引号的 `-Name=Value` 令牌不做变量展开,所以
  `-DCMAKE_BUILD_TYPE=$BuildType` 原样传给 cmake,CMAKE_BUILD_TYPE 的字面值就是
  "$BuildType"。toolchain 再把它小写化成 $buildtype,dist 目录于是变成
  windows_x86_64_gcc_$buildtype。
- `$` 在 mingw32-make 里是变量前缀,include 路径里的 `$buildtype` 被展开成空,
  g3sinks 编译时找不到 boost/filesystem.hpp;同时根工程会去找一个不存在的
  dist 目录。Windows CI 首轮(run 42336893127)就是卡在这里。
- 两处 cmake 调用都改成整体加引号。toolchain 那一行原本就是引号形式,所以它一直是对的,
  这也是只有 build type 出问题的原因。
- AGENTS.md 的 NOTES 补上两个 CI 工作流的触发约定与 Windows 缓存说明。

本机用 -SkipQt -SkipThirdParty 复跑:`-- CMAKE_BUILD_TYPE: Debug`、
`3RDPARTY_DIST_DIR: .../dist/windows_x86_64_gcc_debug`,脚本正常收尾;
build/CMakeCache.txt 里的 $BuildType 也已纠正为 Debug。
- 根因:FileSource 用 std::ifstream 打开文件,路径经 toNativeString 从 UTF-8 转成
  ANSI(CP_ACP)。这一步是有损的,CP_ACP 表示不了的字符会被替换成 '?':
  中文系统(936)能表示中文所以本地一直好的,英文系统(1252)表示不了,于是
  "Ringtones-耳聆网.ogg" 变成 "Ringtones-?????.ogg",文件打不开。
  2026-11-07 新增的 Windows CI(en-US runner)首轮就是这么红的:21 个素材里
  所有中文名的全部 REQUIRE(fixture.exists(...)) 失败,ASCII 名的都通过。
- 修法:Windows 分支改用 _wfopen + FILE*,路径用 toWideString 转宽字符,
  与系统代码页无关;POSIX 分支仍是 std::ifstream,语义不变。
  readAt / getSize / initCheck / 析构按平台各自实现,对外契约没动。
- Utf8Path.h 新增 toWideString;toNativeString 保留但加了醒目注释说明它是有损的、
  不应再用于打开文件。
- 新增回归用例 `Non-ANSI filename opens through the wide path`:文件名用 emoji
  (U+1F600),它在 CP936 和 CP1252 里都没有映射,所以旧实现无论在哪国语言环境下都会
  失败,不需要靠 runner 的语种才能复现。
- FileSource.h 仍无条件包含 <fstream>:有测试文件依赖它顺带带来的 <ostream>。
  测试文件另需 #undef ERROR,因为 Utf8Path.h 在 Windows 上会带上 <windows.h>。

本机验证(ACP=936):
- 探针用真实 FileSource 打开 emoji 文件名 —— 修复后 initCheck=0 / size=4 / readAt=4;
  临时换回旧的 toNativeString + fopen 写法则 initCheck=-19 / size=-1 / readAt=-19。
- 新增用例在旧实现下 7 条断言挂 5 条,恢复后全绿。
- UnitTests 507 例 / 50167 断言 / 0 failed / skipped=0;ctest -R sdk_ 11/11(211.37s)。
- if 里不含任何状态检查函数时,Actions 会自动套一层 success(),
  于是「测试红」会让 Save 3rdparty dist cache 连带跳过,
  而这正是它要救的场景(run 42341337832:构建成功、缓存没写回)
- 显式加 !cancelled(),只要第三方库构建成功就回写
- aqtinstall.log 落进 .gitignore,避免 CI 上污染 git status
- if 里不含状态检查函数时 Actions 会自动套 success(),缓存回写要显式 !cancelled()
- Windows 上非 ASCII 文件名按 _wfopen + toWideString 打开,toNativeString 有损
- 直接起 UnitTests.exe 时只补了 3rdparty 的 bin,缺 Qt 与 MinGW 运行时;
  本地 A/B 实测:只补 3rdparty → 127 且零输出,三处都补 → 15 行矩阵数值齐全
- pipefail 下 grep 无匹配也返回 1,与 exe 起不来在日志里分不开,
  故先把 rc 与完整输出落盘再筛
- 该步骤纯观测,改 continue-on-error,环境问题不阻塞 PR
- 数组 splat 会把 -SkipThirdParty 按位置塞进第一个未绑定参数,
  实测 \$CmakeVersion 变成 -SkipThirdParty,URL 拼坏后 404
- 改用哈希表 splat,named + switch 都按名字绑定
- 本地 scriptblock 复现两种写法,确认后者不再污染 CmakeVersion
- next / addMusicDir / seek / stop / pause 五条用例只用到一两首曲子,
  却都扫整个 music/(20 个文件头),冷 cache 的 runner 上会撞 5s 上限
- 改为 TempMediaDir + 复制 music.wav,耗时从秒级降到 0.07s 量级
- 已做过两次红验证:清空素材目录时 2+9 条变红,把 next() 打桩后仍红
- 原文被 .gitignore 排除、从未入库,worktree 删除后会永久丢失
- 归档时逐字节核对与原文一致,并加「哪些还有效」对照表(5 条坑全部仍然成立)
- SEEKING 窗口长度固定:解码线程进入后 sleep 12ms;而主循环每 5ms 采一次样,
  Windows 上这个睡眠可能落到 15.6ms 计时器粒度,12ms 窗口可以整段落在两次采样之间
- CI 上实测漏过一次:silenceFills == 0,而 seek 本身成功
- 发出 seek 后按 ~30ns 粒度紧轮询直到窗口打开并补记一次;本地 10/10 在窗口打开后
  几微秒内命中,不再依赖 sleep 的实际粒度
- 失败信息补上 seekIssued / seekCompleted,下次真红了能一眼分清「没进窗口」与「seek 没落地」
- 素材文件名诊断是排「非 ANSI 文件名打不开」时加的脚手架,问题已由宽字符路径修掉,
  并留下 test_extractor 的专门用例锁住
- 它 continue-on-error 仍会在 UI 上留一个红叉注解,绿工作流里看起来像红
- 顺带把文件头的成本数字换成实测值(冷 24m05s / 热 7m33s),coverage.log 进 .gitignore
@wt159
wt159 merged commit 72ae155 into master Nov 7, 2026
2 checks passed
@wt159
wt159 deleted the ci/windows-coverage branch November 7, 2026 08:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant