Files
Unlucky-Launcher/packaging/docs/artifacts-and-version.md
T
AskaEth e858664fca ci(release): M164 arm64 判定权交回编译器 + 发布名单守卫(不翻牌)
根因(拿到的真实证据,不是猜的):v0.2.2(run 42322062879 / job 128248713926)与 v0.2.3
(run 42429017002 / job 128573547829)两份 check-run 注解逐字一致 —— 失败步骤是第 6 步
`Windows ARM64 工具链体检`,第 7 步 `cargo build` 状态 skipped。也就是说 v0.2.1~v0.2.3 五轮
全红都红在一个**编译前的启发式探针**上,真正的编译器/链接器一次都没说话。该探针的结论还与它
自己打印的快照矛盾:`SDK Lib 版本→um 架构: 10.0.22621.0→um:[arm,arm64,x64,x86,]` 明明在,却
同时报 `kernel32=缺失`(同一个 `find -path` 模式在本地合成目录树上命中)。runner 实况是
Windows 11 Arm64 + Visual Studio 2026 镜像,`VC.Tools.ARM64` 与 `Windows11SDK.22621/26100`
都装好了,M142 的 `setup.exe modify` 反倒返回非 0。

改:
- release-build.yml:探针降级为「只取证」——vswhere 组件查询 + 各目录 `.lib` 计数 +
  arm64 `link.exe` 候选,一条 `::error::` 都不写、永不 exit 1;不再自动补装 VS。红绿只由
  cargo/链接/静态 CRT 导入表门禁决定。cargo build 步给 arm64 显式备齐工具链:
  `rustup target add aarch64-pc-windows-msvc`、`vcvarsall.bat arm64` 取 `LIB`/`INCLUDE`、
  vswhere 定位 arm64 `link.exe` 后导出 `CARGO_TARGET_AARCH64_PC_WINDOWS_MSVC_LINKER`
  (顺序不能反:只给链接器不给 LIB ⇒ LNK1181 kernel32.lib)。
- 新增 packaging/check_publish_slots.py(344 行,零依赖):名单 ⇄ 产物**两个方向**。
  声明了缺 GUI/CLI ⇒ `::error::` + exit 1;有产物没声明 ⇒ `::warning::` 明说未发布(M142 之后
  这个方向是静默的,裁剪步只 echo 一行 drop:)。另有源码级断言(名单每项必须存在且 mode=ci、
  运行期名单必须等于文件里那行)与 8 条 `--self-test` 注入回归。
- release-publish.yml:裁剪前插一步跑那个守卫,原来内联的齐全性循环搬进脚本(一套判据一处实现);
  重算 SHA256SUMS 的步骤只负责重算。
- release-guard.yml:PR 阶段跑守卫自测 + 源码级断言。
- 文档同步:release.yml / release-publish.yml / release-build.yml 头注释、packaging/README §12、
  §1 矩阵、§3 构建与发布、§9 支持矩阵、§7.5 arm64 取证、release-notes.md、README/README.zh-CN
  的产物矩阵与说明。口径统一为「arm64 构建取证中、未发布」,不写成已支持。

没做的(按 tower 裁决「方案乙」):`PUBLISH_SLOTS` 本轮**不加回** arm64。arm64 从未产出过 PE、
本机也证不了,写进名单就等于拿 x64 的发布去赌它(M142 移出名单正是为避免这个事故)。下一 tag 的
CI 真出包后翻一行即可,守卫与 SHA256SUMS 自动跟着扩。

验证:workflow YAML 全部可被 PyYAML 解析;所有 `run:` 块过 `bash -n`;探针步在本机(无 VS/SDK)
实跑 exit 0 并打出实况注解;守卫 `--self-test` 8 条全绿、正反两个方向都在合成 dist 上实测过;
check_release_semantics.py(含 --self-mutation)/ release_marker / make_manifest 自检全绿;
cargo metadata 正常。**arm64 产物从未被构建过、也从未在真机跑过**——本机 `rustc --target
aarch64-pc-windows-msvc` 直接撞上没有 MSVC 链接器(git-bash 的 GNU `link` 被当成 link.exe),
`cargo check --workspace --target aarch64-pc-windows-msvc` 也死在 aws-lc-sys 的 cc-rs 阶段
(GNU host 上没有该 target 的 C 编译器)。真实结论只能等下一 tag 的 CI。
2026-11-08 08:33:44 +08:00

5.5 KiB
Raw Blame History

产物矩阵与版本来源(M145 拆自 packaging/README.md)

本文承载原 packaging/README.md 的 §1、§2,节号沿用原编号(全仓 packaging/README.md §N 这类引用照旧有效, 对照表在 packaging/README.md 的索引里)。内容一字未改、只搬家:本行以上是 M145 新增的导航说明, 以下逐行取自原文件。

1. 产物矩阵

槽位 本版发布 产物文件名 形态 归档内容
windows-x64 ✅ 发布 unlucky-launcher_<ver>_windows_x64.exe 裸 exe(双击即用) exe 单文件;三份合规文本作为并列 Release 资产
windows-arm64 ❌ 不发布(构建取证中) unlucky-launcher_<ver>_windows_arm64.exe 裸 exe(同 x64 策略) 同上;CI 在原生 windows-11-arm(Windows 11 Arm64 + VS2026 镜像)上构建,M164 起编译前体检只取证、不再判定红绿(此前五轮全红其实全红在那个误判的体检步),红了不挡 x64 发布(M142,见 §3)
linux-x64 ❌ 不构建(未验证) unlucky-launcher_<ver>_linux_x64.tar.gz 单二进制归档 unlucky-launcher + LICENSE + NOTICE + README.md
linux-arm64 ❌ 不构建(未验证) unlucky-launcher_<ver>_linux_arm64.tar.gz 单二进制归档(原生 ARM64 runner 构建) 同上
macos-arm64 ❌ 不构建(未验证) unlucky-launcher_<ver>_macos_arm64.tar.gz 单二进制归档 同上
macos-x64 ❌ 不构建(未验证) unlucky-launcher_<ver>_macos_x64.tar.gz 单二进制归档 同上
每槽位 随所属槽位 ull_<ver>_<平台>_<架构>[.exe] 裸 CLI 文件(独立资产,不进 tar.gz) 零 UI 依赖的 ull 本体,进同一份 SHA256SUMS.txt
全平台 仅已发布资产 SHA256SUMS.txt 校验清单 每行 <sha256>␠␠<文件名>(sha256sum -c 可直吃)
全平台 仅已发布资产 manifest.json 更新清单(D50,见 README.md §13) 渠道 + 版本 + 各平台产物(target/format/url/size/sha256);生成器 make_manifest.py

约定细节:

  • 「不构建」= CI 默认根本不跑(M139):那四档未验证,产物不给用户、构建配额也不花;要整表六槽位取证走 gh workflow run release.yml -f all_slots=true(§3)。发布白名单只有 windows-x64(M142:arm64 照构建、不发布)。 (M164)名单 ⇄ 产物两个方向都有守卫 packaging/check_publish_slots.py:声明了缺产物 ⇒ 红;有产物但没声明 ⇒ ::warning:: 明说「未发布、会被裁掉」——arm64 真出包之后把键加回名单是一行改动,守卫与 SHA256SUMS.txt 自动跟着扩。
  • 产物命名:<名字>_<版本号>_<平台>_<架构>,下划线分段、不带实现细节字样(不出现 iced);真相源是 make_artifacts.py::asset_stem()。
  • "单文件"指可执行文件本身零运行时依赖(无 WebView、无 JRE、无 sidecar、无 DLL 旁挂);归档里的三份合规文本是许可义务、不是运行时依赖,Windows 因为"一个 exe 装不下文本", 把 LICENSE / NOTICE / README.md 作为 Release 的并列资产分发,条款同样随下载走。
  • 归档解压后是一个顶层目录 unlucky-launcher_<ver>_<平台>_<架构>/,用户不会解压出一堆散文件。
  • ull 是并列的裸资产,不塞进 tar.gz:headless 用户要的就是「下一个小文件直接跑」;归档里放 LICENSE/NOTICE/README.md 是许可义务,而这三份本来就作为并列 Release 资产分发,裸 ull 不缺条款。
  • unlucky-launcher 本体也认全部 CLI 子命令(M82),ull 不是第二个界面,而是不链接图形栈的同一套命令(差异见 §4 与 §7.4),两者不是重复品。 M118:GUI 的构建产物名是 unlucky-launcher-iced(crates/app 已被 workspace exclude,不再产出 unlucky-launcher);对外文件名仍是 unlucky-launcher,改名在 make_artifacts.py 落盘时(LAUNCHER_BIN 找产物 / LAUNCHER_ASSET 定对外名),所以下载链接 / SHA256SUMS / 本文矩阵不变。
  • <ver> 不带前导 v(tag 是 v0.2.2,文件名是 0.2.2)——由脚本统一裁剪。
  • UNIX 归档内 mtime/uid/gid 归零、权限固定(二进制 0755、文本 0644), 同源构建的 sha256 不受打包时刻影响。
  • 架构不靠猜:脚本打包前回读二进制的可执行文件头(PE 机器码 / ELF e_machine / Mach-O cputype),与槽位声明的架构不符即失败——不会出现"名字是 arm64、内容还是 x64"的假产物。

2. 版本来源(唯一真相源)

版本号只有一个来源:Cargo.toml 的 [workspace.package] version。

  • <ver> 由 make_artifacts.py 通过 cargo metadata --no-deps 读出(不是正则扒文件), 任何一个 workspace member 版本不一致时直接失败。
  • 带 tag 构建时(CI)额外传 --version "$TAG":脚本裁剪 v 后与 Cargo.toml 交叉校验, 不一致即失败——避免出现 tag 说 0.2.2、产物里写 0.2.1 的发布事故。
  • ull --version 必报同一版本(脚本打包前跑一次冒烟 ull --version 断言版本串在其中), 这是 env!("CARGO_PKG_VERSION") 的实际输出,不是估算。
  • 发布流程:先改 Cargo.toml 版本 + 提交 → git tag v<ver> → 推送 tag 触发流水线。