diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b8df0f4..c0a6807 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,21 +1,18 @@ name: Release -# 发布流水线:tag `v*` → 四平台(六槽位)矩阵**全部构建** → 单文件产物 + SHA256SUMS -# → 上传 artifact + 创建 GitHub Release(pre-release 默认开)。同一 tag 重跑幂等: -# Release 已存在时覆盖资产与说明,不再 `gh release create`(见 release job 末步); -# 重跑**不碰** pre-release 标记,该标记只在 `inputs.prerelease` 显式给出时才被断言。 +# 发布流水线:tag `v*` → **只构建两个 Windows 槽位** → 单文件产物 + SHA256SUMS → artifact + GitHub Release +# (pre-release 默认开;同 tag 重跑幂等 = 覆盖资产与说明而不 create;重跑不碰该标记,只在显式 inputs.prerelease 时才断言) # -# **构建 ≠ 发布**:六槽位一律构建取证,但只有 release job 的 `PUBLISH_SLOTS` 白名单里的槽位会进 Release -# 与 SHA256SUMS。当前只有两个 Windows 槽位 —— Linux/macOS 四档从未真构建成功过一次、也没在真机跑过, -# 未验证的产物不推给用户(开关与打开办法见该处注释)。 +# **构建 ≠ 发布**:只有 release job 的 `PUBLISH_SLOTS` 白名单里的槽位才会进 Release 与 SHA256SUMS。 +# **CI 只跑两个 Windows 槽位**(M139):Linux x64/arm64、macOS arm64/x64 四档从未真构建成功过一次、 +# 也没在真机跑过,默认**一个都不跑**(省 CI 配额、不留没意义的红叉);要整表六槽位取证走手动入口 +# `gh workflow run release.yml -f all_slots=true`(槽位表在 `plan` job 里,唯一真相源)。 # -# 契约唯一真相源:packaging/README.md(命名/目录/运行时依赖/发布白名单)。 -# 打包本体在 packaging/make_artifacts.py(本地与 CI 同一份脚本,逐字节同布局)。 -# 手动触发(workflow_dispatch)默认只跑构建不建 Release —— 用来把六槽位矩阵整体编一遍取证。 -# `inputs.prerelease` 只在 **tag ref** 上 dispatch 才可达(Actions 页面只能选分支,要跑 tag 得 -# `gh workflow run release.yml --ref v0.2.1`);分支 ref 的 dispatch 与 push 一样被 release job 的 -# `if: github.ref_type == 'tag'` 挡在发布之外,所以「dispatch 只构建不发布」与「dispatch 可关 -# pre-release」并不矛盾。 +# 契约唯一真相源:packaging/README.md(命名/目录/运行时依赖/发布白名单);打包本体在 +# packaging/make_artifacts.py(本地与 CI 同一份脚本,逐字节同布局)。`inputs.prerelease` 只在 **tag ref** +# 上 dispatch 才可达(Actions 页面只能选分支,跑 tag 得 `gh workflow run release.yml --ref v0.2.1`); +# 分支 ref 的 dispatch 与 push 一样被 release job 的 `if: github.ref_type == 'tag'` 挡在发布之外,所以 +# 「dispatch 只构建不发布」与「dispatch 能关 pre-release」并不矛盾。 on: push: @@ -23,6 +20,10 @@ on: - "v*" workflow_dispatch: inputs: + all_slots: + description: "构建全部六个槽位(含未验证的 Linux/macOS 四档);默认只跑两个 Windows" + type: boolean + default: false prerelease: description: "标记为 pre-release(仅在 tag ref 上 dispatch 时才生效)" type: boolean @@ -40,51 +41,55 @@ concurrency: cancel-in-progress: false jobs: + # M139:矩阵不写死在 `build` 里,改由本 job 按 `inputs.all_slots` 生成 —— 矩阵不能带 `if`,而 + # `jobs..strategy` 可读 `needs`,所以「默认两个 Windows / 手动整表六槽位」用 + # `fromJSON(needs.plan.outputs.matrix)` 实现。**槽位表只在下面这一处**,改槽位只改这里。 + plan: + name: 选槽位(默认两个 Windows) + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.pick.outputs.matrix }} + steps: + - name: 生成 build 矩阵(`all_slots=true` 才整表六槽位) + id: pick + shell: bash + env: + ALL_SLOTS: ${{ inputs.all_slots }} + run: | + set -euo pipefail + python3 - "$ALL_SLOTS" >> "$GITHUB_OUTPUT" <<'PY' + import json, sys + # 槽位表(唯一真相源)。mode:"ci" = 默认在 CI 里构建;"probe" = 未验证,仅 all_slots=true 时构建。 + SLOTS = [ + # Windows x64:MSVC + 静态 CRT(+crt-static)→ exe 不依赖 VC++ 可再发行包,双击即用的单文件。 + dict(slot="windows-x64", os="windows-latest", target="", build_dir="target/release", rustflags="-C target-feature=+crt-static", mode="ci"), + # Windows arm64:在 windows-latest(x64 宿主)**交叉编译**到 aarch64-pc-windows-msvc,产物在 + # target//release(故 build_dir 参数化);不用原生 windows-11-arm 的理由见 README §4。 + dict(slot="windows-arm64", os="windows-latest", target="aarch64-pc-windows-msvc", + build_dir="target/aarch64-pc-windows-msvc/release", + rustflags="-C target-feature=+crt-static", mode="ci"), + # ↓ 四档**未验证,不纳入 CI**:从未真构建成功过一次、也没在真机跑过,默认一个都不编; + # `all_slots=true` 时照编(那是将来验证 Linux/macOS 的唯一入口,别删)。真机验证通过后: + # 把该行 mode 改成 "ci"(一行一改,不用重写矩阵)+ 槽位键加进 PUBLISH_SLOTS + 同步 + # packaging/README.md §1/§9 与 release-notes.md 的 published 列 —— 三处不一致即是假话。 + # Linux 固定 22.04 而非 latest:否则 glibc 地板跟着 runner 漂移(依据见 README §4)。 + dict(slot="linux-x64", os="ubuntu-22.04", target="", build_dir="target/release", rustflags="", mode="probe"), + dict(slot="linux-arm64", os="ubuntu-22.04-arm", target="", build_dir="target/release", rustflags="", mode="probe"), + # macOS:latest = arm64;Intel x64 用 macos-15-intel(macos-13 已下线)。 + dict(slot="macos-arm64", os="macos-latest", target="", build_dir="target/release", rustflags="", mode="probe"), + dict(slot="macos-x64", os="macos-15-intel", target="", build_dir="target/release", rustflags="", mode="probe"), + ] + keep = [s for s in SLOTS if s["mode"] == "ci" or sys.argv[1] == "true"] + print("matrix=" + json.dumps({"include": keep}, separators=(",", ":"))) + print("本次构建槽位:" + " ".join(s["slot"] for s in keep), file=sys.stderr) + PY + build: name: build (${{ matrix.slot }}) + needs: plan strategy: fail-fast: false - matrix: - include: - # Windows x64:MSVC + 静态 CRT(+crt-static)→ exe 不依赖 VC++ 可再发行包, - # 双击即用的单文件形态;UCRT 本身就是 Win10+ 的系统组件。 - # 产物根 target/release;自检与打包都从 matrix.build_dir 取路径(不硬编码)。 - - slot: windows-x64 - os: windows-latest - build_dir: target/release - rustflags: -C target-feature=+crt-static - # Windows arm64:在 windows-latest(x64 宿主)上**交叉编译**到 aarch64-pc-windows-msvc。 - # 不用 windows-11-arm 原生 runner(GitHub 文档 2026 已把它列为公开仓库免费 runner)的理由: - # ① 双 Windows 槽位共用同一套已验证镜像/工具链,tag 重跑行为与既有槽位一致;② M50 的 dumpbin - # 定位链取 `Hostx64/x64/dumpbin.exe`,它读 ARM64 PE 的导入表没问题,而原生 ARM 宿主上那条链 - # 还得再长一条 `Hostarm64/arm64` 分支——为一个槽位放宽刚立的门禁不值得;③ 交叉产物路径变成 - # target//release,已用 matrix.build_dir 参数化。将来改原生:os 换 windows-11-arm、 - # 去掉 target/rustflags 依赖并给 dumpbin 定位链补 Hostarm64 分支(届时再评估)。 - - slot: windows-arm64 - os: windows-latest - target: aarch64-pc-windows-msvc - build_dir: target/aarch64-pc-windows-msvc/release - rustflags: -C target-feature=+crt-static - # ↓ 下面四档(Linux x64/arm64、macOS arm64/x64)只**构建取证**、不进本次 Release(从未真构建 - # 成功过一次、也没在真机跑过);发哪几个槽位由 release job 的 `PUBLISH_SLOTS` 白名单唯一决定。 - # Linux:固定 ubuntu-22.04(glibc 2.35 地板)而不是 latest, - # 否则产物的 glibc 底线会跟着 runner 漂移(24.04 的 glibc 明显更高)。 - - slot: linux-x64 - os: ubuntu-22.04 - build_dir: target/release - # Linux arm64:公开仓库免费的原生 ARM64 runner(4C/16GB,原生构建不交叉)。用 22.04-arm - # 而非 24.04 是为了与 x64 同 glibc 地板(2.35),覆盖 Debian 12 / Ubuntu 22.04 arm64 / - # Raspberry Pi OS Bookworm(2.36);该家族标签还有 `ubuntu-24.04-arm` / `ubuntu-26.04-arm`。 - - slot: linux-arm64 - os: ubuntu-22.04-arm - build_dir: target/release - # macOS:latest = arm64;Intel x64 用 macos-15-intel(macos-13 已下线)。 - - slot: macos-arm64 - os: macos-latest - build_dir: target/release - - slot: macos-x64 - os: macos-15-intel - build_dir: target/release + matrix: ${{ fromJSON(needs.plan.outputs.matrix) }} runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 @@ -130,11 +135,9 @@ jobs: exit 1 fi - # M118(D26):**Slint 版停发** —— GUI 来源只有 `unlucky-launcher-iced`;`crates/app` 已在根 - # Cargo.toml 被 `exclude`,不参与任何 workspace 构建(它连 `--manifest-path` 都编不了)。 - # 对外产物名由 packaging/make_artifacts.py 的 `asset_stem()` 统一生成 - # `<名字>_<版本号>_<平台>_<架构>`(下划线分段、不带 `iced` 这类实现细节字样);`LAUNCHER_BIN` - # 只用来在构建产物里找文件。 + # M118(D26):**Slint 版停发** —— GUI 来源只有 `unlucky-launcher-iced`(`crates/app` 已被根 + # Cargo.toml `exclude`,不参与任何 workspace 构建)。对外产物名由 make_artifacts.py 的 + # `asset_stem()` 生成 `<名字>_<版本号>_<平台>_<架构>`;`LAUNCHER_BIN` 只用来在产物里找文件。 - name: cargo build --release --locked shell: bash env: @@ -152,9 +155,8 @@ jobs: if: runner.os == 'Windows' shell: bash env: - # 跨槽位的关键点:产物在 target//release 而不是 target/release。 - # M118:校验的是**构建产物**(iced bin 的原始文件名);对外名 `unlucky-launcher` 由 - # packaging/make_artifacts.py 在落盘时才换上,那一步之后才存在。 + # 跨槽位的关键点:产物在 target//release;校验的是**构建产物**(iced bin 原始名), + # 对外名 `unlucky-launcher` 由 make_artifacts.py 落盘时才换上,那一步之后才存在。 EXE: ${{ matrix.build_dir }}/unlucky-launcher-iced.exe run: | set -euo pipefail @@ -179,8 +181,7 @@ jobs: done fi if [ -z "$DUMPBIN" ]; then - # 镜像里的 VS 根形如 <年>/<版次>(2022/Enterprise、2022/BuildTools……), - # 固定层数的 glob 会在 <年>/<版次> 这两级踩空,所以按路径模式扫。 + # VS 根形如 <年>/<版次>(2022/Enterprise、2022/BuildTools……),固定层数的 glob 会踩空,按模式扫。 for root in "C:/Program Files/Microsoft Visual Studio" \ "C:/Program Files (x86)/Microsoft Visual Studio"; do [ -d "$root" ] || continue @@ -263,7 +264,7 @@ jobs: release: name: GitHub Release needs: build - # `always()` + `!cancelled()`:白名单外的槽位(Linux/macOS)只是构建取证,它们红了**不能连坐** + # `always()` + `!cancelled()`:白名单外的槽位(只有 `all_slots` 取证跑里才存在)红了**不能连坐** # Windows 发布。真正拦发布的是下面「发布白名单齐全性」那一步:白名单里少任何一个就 fail。 if: always() && !cancelled() && github.ref_type == 'tag' runs-on: ubuntu-latest @@ -272,11 +273,11 @@ jobs: env: # ── 发布白名单:唯一决定「哪几个槽位进 Release」的开关(空格分隔,键同 matrix.slot)── # 为什么只有两个 Windows 槽位:Linux x64/arm64、macOS arm64/x64 这四档**从未真构建成功过一次、 - # 更没在真机上跑过**,未验证的产物不推给用户;它们照跑构建,产物留在本次运行的 `dist-` - # artifact 里取证(可下载验证),不进 Release、不进 SHA256SUMS。 - # 将来某槽位真机验证通过后「打开」它只改这一行(把槽位键加进列表,如 `macos-arm64`):齐全性检查 - # 与 SHA256SUMS 自动跟着扩;同时把 packaging/README.md §1/§9 与 packaging/release-notes.md 的 - # Downloads / Support matrix 同步成「已发布」——三处不一致即是假话。 + # 更没在真机上跑过**,未验证的产物不推给用户;它们默认连构建都不跑(M139),只有 `all_slots=true` + # 的取证跑里才有产物,留在本次运行的 `dist-` artifact 里可下载验证,不进 Release/SHA256SUMS。 + # 将来某槽位真机验证通过后「打开」它需同时改三处(缺一即是假话):① `plan` 槽位表里把它的 mode + # 改成 `ci`;② 把槽位键加进这一行(齐全性检查与 SHA256SUMS 自动跟着扩);③ packaging/README.md + # §1/§9 与 packaging/release-notes.md 的 Downloads / Support matrix。 PUBLISH_SLOTS: "windows-x64 windows-arm64" steps: - uses: actions/checkout@v4 @@ -318,6 +319,8 @@ jobs: # GUI 与 CLI 两个资产——只按「槽位名出现过」判会被其中一个掩盖。档位比对用下划线形态: # 资产名自 D49 起是 `unlucky-launcher__windows_x64.exe`,旧写法 `dist/$prefix-*-$slot*` # (连字符)对现行命名永远匹配不上,已一并修正。 + # 矩阵裁到两个槽位(M139)后这条检查依然有效:它比的是**下载下来的产物**,不看矩阵大小 —— + # 白名单里的槽位没编(比如忘了改 plan 里的 mode)或编挂了,就在这里因缺产物 fail,不会永远过。 for slot in $PUBLISH_SLOTS; do stem=${slot//-/_} for prefix in unlucky-launcher ull; do diff --git a/packaging/README.md b/packaging/README.md index d5aae89..da27e62 100644 --- a/packaging/README.md +++ b/packaging/README.md @@ -10,15 +10,17 @@ |------|---------|-----------|------|---------| | `windows-x64` | ✅ 发布 | `unlucky-launcher__windows_x64.exe` | **裸 exe**(双击即用) | exe 单文件;三份合规文本作为并列 Release 资产 | | `windows-arm64` | ✅ 发布 | `unlucky-launcher__windows_arm64.exe` | **裸 exe**(同 x64 策略) | 同上;在 x64 宿主上交叉编译到 `aarch64-pc-windows-msvc` | -| `linux-x64` | ❌ 只构建取证 | `unlucky-launcher__linux_x64.tar.gz` | 单二进制归档 | `unlucky-launcher` + `LICENSE` + `NOTICE` + `README.md` | -| `linux-arm64` | ❌ 只构建取证 | `unlucky-launcher__linux_arm64.tar.gz` | 单二进制归档(原生 ARM64 runner 构建) | 同上 | -| `macos-arm64` | ❌ 只构建取证 | `unlucky-launcher__macos_arm64.tar.gz` | 单二进制归档 | 同上 | -| `macos-x64` | ❌ 只构建取证 | `unlucky-launcher__macos_x64.tar.gz` | 单二进制归档 | 同上 | +| `linux-x64` | ❌ 不构建(未验证) | `unlucky-launcher__linux_x64.tar.gz` | 单二进制归档 | `unlucky-launcher` + `LICENSE` + `NOTICE` + `README.md` | +| `linux-arm64` | ❌ 不构建(未验证) | `unlucky-launcher__linux_arm64.tar.gz` | 单二进制归档(原生 ARM64 runner 构建) | 同上 | +| `macos-arm64` | ❌ 不构建(未验证) | `unlucky-launcher__macos_arm64.tar.gz` | 单二进制归档 | 同上 | +| `macos-x64` | ❌ 不构建(未验证) | `unlucky-launcher__macos_x64.tar.gz` | 单二进制归档 | 同上 | | 每槽位 | 随所属槽位 | `ull__<平台>_<架构>[.exe]` | **裸 CLI 文件**(独立资产,不进 tar.gz) | 零 UI 依赖的 `ull` 本体,进同一份 `SHA256SUMS.txt` | | 全平台 | 仅已发布资产 | `SHA256SUMS.txt` | 校验清单 | 每行 `␠␠<文件名>`(`sha256sum -c` 可直吃) | 约定细节: +- **「不构建」= CI 默认根本不跑**(M139):那四档未验证,产物不给用户、构建配额也不花;要整表六槽位取证走 + `gh workflow run release.yml -f all_slots=true`(§3)。发布白名单仍只有两个 Windows 槽位。 - **产物命名**:`<名字>_<版本号>_<平台>_<架构>`,下划线分段、**不带实现细节字样**(不出现 `iced`);真相源是 `make_artifacts.py::asset_stem()`。 - **"单文件"指可执行文件本身零运行时依赖**(无 WebView、无 JRE、无 sidecar、无 DLL 旁挂);归档里的三份合规文本是许可义务、不是运行时依赖,Windows 因为"一个 exe 装不下文本", 把 `LICENSE` / `NOTICE` / `README.md` 作为 Release 的并列资产分发,条款同样随下载走。 @@ -74,43 +76,42 @@ python packaging/make_artifacts.py --slot windows-arm64 \ `--slot` 与宿主槽位不一致时,`ull --version` 冒烟会**自动跳过并打印原因**(arm64 产物在 x64 宿主机上根本执行不了;拿"跳过"当通过是假证据,所以跳过永远带原因)——那条路径的验证只能落在 -CI 真机上:`windows-arm64` 由 cross 构建产物 + M50 的 dumpbin 导入表门禁覆盖,`linux-arm64` -由 `ubuntu-22.04-arm` 原生 runner 上真跑冒烟覆盖。 +CI 真机上:`windows-arm64` 由 cross 构建产物 + M50 的 dumpbin 导入表门禁覆盖;`linux-arm64` 的同类 +冒烟只在 `all_slots=true` 的取证跑里出现(`ubuntu-22.04-arm` 原生 runner 上真跑 `ull --version`)。 -### CI(四平台六槽位矩阵) +### CI(默认只跑两个 Windows 槽位;`all_slots=true` 才整表六槽位) `.github/workflows/release.yml`: -- 触发:`push` tag `v*`;`workflow_dispatch` 只构建不发布(验证矩阵仍编得过)。 - `inputs.prerelease` **只在 tag ref 上 dispatch 才可达**——Actions 页面的 "Run workflow" 只能选分支, - 要跑 tag 得 `gh workflow run release.yml --ref v0.2.1`。分支 ref 的 dispatch 与 push 一样被 - `release` job 的 `if: github.ref_type == 'tag'` 挡在发布之外,所以「dispatch 只构建不发布」 - 与「dispatch 能关 pre-release」是两条互不冲突的规则。 -- 矩阵(六槽位;`matrix.build_dir` 参数化产物根,脚本不再假设产物一定在 `target/release`): - `windows-latest` x64(MSVC + `-C target-feature=+crt-static`)、`windows-latest` **交叉编译**到 - `aarch64-pc-windows-msvc`(产物在 `target/aarch64-pc-windows-msvc/release`)、`ubuntu-22.04` - (glibc 2.35 地板)、`ubuntu-22.04-arm`(原生 ARM64 runner,**与 x64 同 2.35 地板**)、`macos-latest`(arm64)、 - `macos-15-intel`(Intel x64;`macos-13` 已下线,`macos-26-intel` 为更新替位)。 +- 触发:`push` tag `v*`;`workflow_dispatch` 只构建不发布,且多一个 `all_slots` 开关(**默认 false = + 只跑两个 Windows 槽位**,true = 整表六槽位都编一遍取证)。`inputs.prerelease` **只在 tag ref 上 dispatch + 才可达**——Actions 页面的 "Run workflow" 只能选分支,要跑 tag 得 `gh workflow run release.yml --ref v0.2.1`。 + 分支 ref 的 dispatch 与 push 一样被 `release` job 的 `if: github.ref_type == 'tag'` 挡在发布之外,所以 + 「dispatch 只构建不发布」与「dispatch 能关 pre-release」是两条互不冲突的规则。 +- 矩阵**由 `plan` job 按 `all_slots` 生成**(`matrix: ${{ fromJSON(needs.plan.outputs.matrix) }}`:矩阵本身 + 不能带 `if`,而 `strategy` 可读 `needs`),槽位表只在该 job 里有一份:`windows-latest` x64(MSVC + + `-C target-feature=+crt-static`,产物在 `target/release`)与 `windows-latest` **交叉编译**到 + `aarch64-pc-windows-msvc`(产物在 `target/aarch64-pc-windows-msvc/release`)标 `mode: ci`(默认编); + `ubuntu-22.04`(glibc 2.35 地板)/ `ubuntu-22.04-arm`(原生 ARM64,同地板)/ `macos-latest` / + `macos-15-intel` 标 `mode: probe`——**未验证,默认一个都不编**,只有 `all_slots=true` 才进矩阵。 - 每个槽位 `cargo build --release --locked`(交叉槽位多两步:`rustup target add` + ARM64 库体检 ——查 VC 的 `lib/arm64/libcmt.lib`(`+crt-static` 靠它)与 SDK 的 `um/arm64/kernel32.lib`, 缺了直接给出"给 VS 加 `VC.Tools.ARM64` 或改用原生 `windows-11-arm`"的可执行提示)→ `make_artifacts.py --slot … --build-dir …` → 归档内容自检 → 上传 artifact。 -- **发布白名单(`PUBLISH_SLOTS`,唯一开关)**:六槽位一律构建取证,只有白名单里的槽位进 Release 与 - `SHA256SUMS.txt`——当前 = `windows-x64 windows-arm64`;Linux x64/arm64、macOS arm64/x64 四档**从未真构建 - 成功过一次、也没在真机跑过**,不推给用户(产物留在本次运行的 `dist-` artifact 里取证,它们红了也 - 不连坐 Windows 发布)。手动入口 `workflow_dispatch`(分支 ref)把六槽位整体编一遍、不发布;将来某槽位 - 真机验证通过,把它的键加进这一行即打开(齐全性检查与 SHA256SUMS 自动跟着扩),并同步 §1/§9 与本文件。 +- **发布白名单(`PUBLISH_SLOTS`,唯一开关)**:默认只构建两个 Windows 槽位,只有白名单里的槽位进 Release 与 + `SHA256SUMS.txt`——当前 = `windows-x64 windows-arm64`;四档未验证的(默认连构建都不跑)不推给用户。 + 将来某槽位真机验证通过:`plan` 槽位表里把它的 `mode` 从 `probe` 改成 `ci`、把键加进这一行(齐全性检查 + 与 `SHA256SUMS` 自动跟着扩)、再同步 §1/§9 与 `release-notes.md`——三处缺一即是假话。 - `release` job:下载全部 artifact → **按白名单裁剪** → 重算 `SHA256SUMS.txt` → 用 `packaging/release-notes.md` 模板渲染支持矩阵 → `gh release create`(**pre-release 默认开**:首建时 `push` 触发按 pre-release,`workflow_dispatch` 可关)。 - **同一 tag 重跑幂等**:`gh release view` 命中已存在的 Release 时改走 `gh release upload --clobber` + `gh release edit`,覆盖资产与说明而不是再 `create`(`create` 遇已存在会失败,把流水线最后一步染红)。 - **pre-release 标记只按显式输入断言**:`gh release edit` 分支在默认重跑(`push` 触发的 Re-run, `inputs.prerelease` 为空)时**不传** `--prerelease`,所以重跑**不会**翻转标记;只有 tag ref 上的 - `workflow_dispatch` 显式给了输入才断言——`prerelease=true` → `--prerelease`,`prerelease=false` → - `--prerelease=false`。要改标记两条路等价且互不打架:① 走流水线 - `gh workflow run release.yml --ref v0.2.1 -f prerelease=false`(会落到 edit 分支显式断言) - ② 直接 `gh release edit --prerelease=false`(不经流水线;后续默认重跑不碰该标记, - 不会被翻回去)。首建(`create`)仍保持「pre-release 默认开」的老契约,空输入按 `true` 处理。 + `workflow_dispatch` 显式给了输入才断言(`prerelease=true` → `--prerelease`,`false` → `--prerelease=false`)。 + 要改标记两条路等价且互不打架:① 走流水线 `gh workflow run release.yml --ref v0.2.1 -f prerelease=false` + (会落到 edit 分支显式断言)② 直接 `gh release edit --prerelease=false`(不经流水线;后续默认重跑 + 不碰该标记,不会被翻回去)。首建(`create`)仍保持「pre-release 默认开」的老契约,空输入按 `true` 处理。 Windows 为什么用 MSVC 静态 CRT 而不是本机这套 GNU 工具链:两者都属"标准工具链"(D21), 但发布产物要**不依赖 VC++ 可再发行包**,`+crt-static` 把 CRT 静态链进 exe,Win10+ 的 UCRT 本身是 @@ -149,7 +150,7 @@ Windows ARM64 原生库(Mojang/LWJGL 只发 x64/x86),实际游玩仍走系 | 依赖 | 说明 | |------|------| -| glibc ≥ 2.35 | 由 `ubuntu-22.04` 构建决定;更老的发行版请自行重建或等 musl 版 | +| glibc ≥ 2.35 | 由 `ubuntu-22.04` 构建决定(该槽位默认不编,`all_slots=true` 取证跑才有产物);更老的发行版请自行重建或等 musl 版 | | `libxkbcommon.so.0` | winit 键盘处理 | | `libfontconfig.so.1` + `libfreetype.so.6` | 文本渲染 | | `libGL.so.1` / `libEGL.so.1` | Slint 版:femtovg 的 GL 渲染;iced 版:wgpu 的 GL/EGL 后端(**推断,未实测**)。两者缺失都退到 CPU 软渲染(tiny-skia) | @@ -166,7 +167,7 @@ arm64 侧同理(同一份依赖树;历史口径里的「winit + femtovg」 ### Linux arm64(aarch64) 依赖与 x64 完全同一套(`libxkbcommon` / `fontconfig` / `libGL` / `libxcb` / `libwayland-client`), -**glibc 地板也相同**:arm64 槽位跑在原生 `ubuntu-22.04-arm` runner 上,地板 = **2.35**,与 x64 +**glibc 地板也相同**:arm64 槽位跑在原生 `ubuntu-22.04-arm` runner 上(默认矩阵不编它,只有 `all_slots=true` 取证跑才出产物),地板 = **2.35**,与 x64 用的 `ubuntu-22.04` 一致。选 22.04 而不是 24.04 就是为了这个地板——24.04 的 glibc 更高,会把 Debian 12(2.36)、Raspberry Pi OS Bookworm(2.36)这些实际在跑的 ARM 发行版挡在门外。 要抬地板(例如将来 ARM 生态整体上移)换 `release.yml` 里那个槽位的 `os` 即可,脚本与产物名都不用动; @@ -334,19 +335,19 @@ runner 上的真跑(本机连 `raw.githubusercontent.com` 都解析不了, |------|---------|------|-----------| | Windows 10/11 x64 | ✅ | 一等 | 无(UCRT 系统自带) | | Windows 11 ARM64 | ✅ | 一等(启动器产物) | 无额外库;启动器原生运行,游戏本体走系统 x64 模拟层 + x64 JDK | -| macOS 12+(arm64 / x64) | ❌ 只构建取证 | 一等(未真机验证) | 无第三方库;未签名需去 quarantine | -| Linux x64 X11 | ❌ 只构建取证 | 一等(未真机验证) | glibc 2.35+、xkbcommon、fontconfig、libGL、xcb | -| Linux x64 Wayland | ❌ 只构建取证 | 支持 | 上述 + wayland-client | -| Linux arm64 X11 | ❌ 只构建取证 | 一等(未真机验证) | glibc 2.35+(`ubuntu-22.04-arm` 原生构建,**与 x64 同地板**)、xkbcommon、fontconfig、libGL、xcb | -| Linux arm64 Wayland | ❌ 只构建取证 | 支持 | 上述 + wayland-client | +| macOS 12+(arm64 / x64) | ❌ 不构建 | 一等(未真机验证) | 无第三方库;未签名需去 quarantine | +| Linux x64 X11 | ❌ 不构建 | 一等(未真机验证) | glibc 2.35+、xkbcommon、fontconfig、libGL、xcb | +| Linux x64 Wayland | ❌ 不构建 | 支持 | 上述 + wayland-client | +| Linux arm64 X11 | ❌ 不构建 | 一等(未真机验证) | glibc 2.35+(`ubuntu-22.04-arm` 原生构建,**与 x64 同地板**)、xkbcommon、fontconfig、libGL、xcb | +| Linux arm64 Wayland | ❌ 不构建 | 支持 | 上述 + wayland-client | | Windows 8.1/8/7 | — | 不支持 | 基线已上调(D21) | | Android Termux + X11 | — | 试验级(不承诺) | 仅 CLI(源码自建),GUI 未验证,不在本发布矩阵内 | `packaging/release-notes.md` 的 "Support matrix" 表与上表逐行对应(英文版同样带 published / not published 一列,Termux 行标注 experimental)——改一边必须同步另一边,否则标题里的"一致"就是假话。 -两个 arm64 槽位都是**正式矩阵槽位**(不是 Termux 那种源码自建旁路),但**本版只有 `windows-arm64` -发布**:`linux-arm64` 由原生 runner 编、尚未真机验证,发布开关就是 `release.yml` 的 `PUBLISH_SLOTS`。 +两个 arm64 槽位都是**正式矩阵槽位**(不是 Termux 那种源码自建旁路),但本版只有 `windows-arm64` 发布;`linux-arm64` 连构建都不跑 +(默认矩阵只有两个 Windows 槽位),发布开关是 `release.yml` 的 `PUBLISH_SLOTS`,取证入口是 `all_slots=true`。 ## 10. 已知边界 / 后续 diff --git a/packaging/release-notes.md b/packaging/release-notes.md index 7a5a684..ac70b3c 100644 --- a/packaging/release-notes.md +++ b/packaging/release-notes.md @@ -14,10 +14,12 @@ Asset names are `___`, underscore separated — t | Windows 10/11 x64 | `unlucky-launcher_{{VERSION}}_windows_x64.exe` | single exe, double-click to run | | Windows 11 ARM64 | `unlucky-launcher_{{VERSION}}_windows_arm64.exe` | single exe, runs natively on ARM64 Windows | -**This release ships Windows only.** The Linux (x64 / arm64) and macOS (Apple Silicon / Intel) slots are -built by CI but are not assets of this release: they have not been verified on real machines yet, so -nothing unverified is handed out. They stay out of the download list and out of `SHA256SUMS.txt` until -that verification happens — the support matrix below marks them accordingly. +**This release ships Windows only, and CI builds Windows only.** The Linux (x64 / arm64) and macOS +(Apple Silicon / Intel) slots are not built by the release workflow at all — they have not been verified +on real machines yet, so nothing unverified is handed out and no build minutes are spent on them. They +stay out of the download list and out of `SHA256SUMS.txt` until that verification happens; a manual +workflow run can build all six slots for that purpose, but the four extra slots are never published. The +support matrix below marks those slots accordingly. The Windows assets are bare `.exe` files, so `LICENSE`, `NOTICE` and `README.md` are attached to this release next to them: the license terms travel with every download. Slots that ship an archive (Linux / @@ -45,19 +47,19 @@ Published = shipped as a download of **this** release, listed in `SHA256SUMS.txt | --- | --- | --- | --- | | Windows 10/11 x64 | **published** | first class | nothing beyond the OS (UCRT is part of Win10+) | | Windows 11 ARM64 | **published** | first class (launcher artifact) | nothing extra; the launcher runs natively, the game itself runs through the OS x64 emulation layer with an x64 JDK | -| macOS 12+ Apple Silicon | built by CI, not published | first class (unverified) | nothing; unsigned build, needs the Gatekeeper workaround | -| macOS 12+ Intel | built by CI, not published | first class (unverified) | same as above | -| Linux x64, X11 | built by CI, not published | first class (unverified) | `libxkbcommon`, `fontconfig`, `libGL` (or software renderer), `libxcb` | -| Linux x64, Wayland | built by CI, not published | supported (unverified) | `wayland-client`, `libxkbcommon`, plus the X11 set for XWayland apps | -| Linux arm64, X11 | built by CI, not published | first class (unverified) | glibc 2.35+, `libxkbcommon`, `fontconfig`, `libGL`, `libxcb` | -| Linux arm64, Wayland | built by CI, not published | supported (unverified) | the above plus `wayland-client` | +| macOS 12+ Apple Silicon | not built (unverified) | first class (unverified) | nothing; unsigned build, needs the Gatekeeper workaround | +| macOS 12+ Intel | not built (unverified) | first class (unverified) | same as above | +| Linux x64, X11 | not built (unverified) | first class (unverified) | `libxkbcommon`, `fontconfig`, `libGL` (or software renderer), `libxcb` | +| Linux x64, Wayland | not built (unverified) | supported (unverified) | `wayland-client`, `libxkbcommon`, plus the X11 set for XWayland apps | +| Linux arm64, X11 | not built (unverified) | first class (unverified) | glibc 2.35+, `libxkbcommon`, `fontconfig`, `libGL`, `libxcb` | +| Linux arm64, Wayland | not built (unverified) | supported (unverified) | the above plus `wayland-client` | | Windows 8.1/8/7 | not built | unsupported | the baseline is Windows 10 | | Android — Termux + X11 | not built (no CI slot) | experimental, not promised | CLI only and only when built from source; GUI unverified | Both arm64 rows are formal matrix slots, not the experimental Termux path: Windows ARM64 ships here and -is cross-built with the same static-CRT gate as x64; Linux arm64 builds on a native ARM64 runner and -joins this list once someone has run it on real hardware. The rows above and the matrix table in -`packaging/README.md` §9 are the same list — change one, change the other. +is cross-built with the same static-CRT gate as x64; Linux arm64 is kept as a matrix slot but is not built +by default — someone has to run it on real hardware (via a manual all-slots run) before it joins this list. +The rows above and the matrix table in `packaging/README.md` §9 are the same list — change one, change the other. ## Install