fix(packaging): 发布包 exe 的 PE 版本资源必须等于发布版本(v0.2.2)

缺陷(v0.2.1 实测):把 opendance-windows-v0.2.1.zip 解开、在 Windows 上
「右键 → 属性 → 详细信息」,显示的是

    文件版本    0.1.0
    产品版本    0.1.0

而产物名、Git tag、README 全是 v0.2.1 —— 正是文档 §11.2 要禁止的
「不可核对的发布」。

根因:export_presets.cfg 的 application/file_version /
application/product_version 被硬编码在 0.1.0,而它们**不会**跟随
project.godot 的 application/config/version 自动更新;check-version.sh 当时
只比 project.godot ↔ project.yaml(两处一致),所以静态校验全绿、产物却是错的。
漂移发生在没人看的第三个位置 —— 校验位置少一个,等于没校验。

证据:
  strings -a -el OpenDance.exe  ->  FileVersion 0.1.0 / ProductVersion 0.1.0
  VS_FIXEDFILEINFO @0x67b976c   ->  FileVersion 0.1.0.0 / ProductVersion 0.0.0.0
对照组:官方模板 windows_release_x86_64.exe 的 FileVersion = 4.7.2,
说明本机 rcedit 改写是生效的,问题纯粹在预设的值本身。

修复:
  * build/sync-export-version.sh(新增):导出前把版本号写进导出预设,
    幂等、拒绝非 X.Y.Z;
  * build/check-pe-version.sh(新增):直接读 exe 的 PE 版本资源 ——
    VS_FIXEDFILEINFO(签名 0xFEEF04BD 后 16 字节,grep -abo 取偏移约 40 ms)
    与 StringFileInfo(strings -el,资源管理器属性页显示的就是它)。
    两处都查:实测固定信息里的 ProductVersion 恒为 0.0.0.0;
  * build/check-version.sh:新增导出预设两个键的校验;
  * build/export-windows.sh:导出前同步、导出后直接复核产物;
  * build/package-release.sh:打包前校验源 exe、解包后再校验包内 exe;
  * build/verify.sh:新增步骤 1/5「产物 PE 版本资源」(未导出则跳过);
  * tests/test_about.gd:新增 test_export_preset_version_matches_project_version。

反向验证:把预设 file_version 改回 0.1.0 →
  check-version.sh 退出码 1(报出两处不一致);
  无头测试 753 通过 / 1 失败,失败项正是
  「导出预设的 file_version 与版本号唯一来源一致」。

实测 v0.2.2 产物:PE FileVersion 0.2.2.0 / StringFileInfo 0.2.2,
版本号在 project.godot / project.yaml / export_presets.cfg / exe 元数据 /
产物名 / tag 六处一致。verify.sh 全绿(754 通过 / 0 失败 / 5 跳过)。

同时把 LZMA 压缩的取舍写清楚:deflate 包 38,248,818 B 仍超 IIS
30,000,000 B 上限,故 Release 资产仍是 LZMA 整包(26,628,529 B,不拆分卷);
若上限放开或改由 Web /static 分发,用 ZIP_METHOD=deflate 重打包即可得到
资源管理器可直接双击解压的包。
This commit is contained in:
2026-09-17 04:22:57 +08:00
parent 14ee5f7ec9
commit ba988f6ca6
13 changed files with 450 additions and 35 deletions
+29 -4
View File
@@ -20,15 +20,40 @@ cd "$PROJECT_DIR"
GODOT_VERSION="$(sed -n 's/^config\/version="\(.*\)"$/\1/p' project.godot | head -1)"
YAML_VERSION="$(sed -n 's/^version:[[:space:]]*//p' project.yaml | head -1)"
PRESET="$PROJECT_DIR/export_presets.cfg"
PRESET_FILE_VERSION="$(sed -n 's/^application\/file_version="\(.*\)"$/\1/p' "$PRESET" 2>/dev/null | head -1)"
PRESET_PRODUCT_VERSION="$(sed -n 's/^application\/product_version="\(.*\)"$/\1/p' "$PRESET" 2>/dev/null | head -1)"
EXPECTED="${1:-$YAML_VERSION}"
printf ' project.godot application/config/version = %s\n' "${GODOT_VERSION:-(未找到)}"
printf ' project.yaml version = %s\n' "${YAML_VERSION:-(未找到)}"
printf ' 期望版本 = %s\n' "${EXPECTED:-(未指定)}"
printf ' project.godot application/config/version = %s\n' "${GODOT_VERSION:-(未找到)}"
printf ' project.yaml version = %s\n' "${YAML_VERSION:-(未找到)}"
printf ' export_presets application/file_version = %s\n' "${PRESET_FILE_VERSION:-(未找到)}"
printf ' export_presets application/product_version= %s\n' "${PRESET_PRODUCT_VERSION:-(未找到)}"
printf ' 期望版本 = %s\n' "${EXPECTED:-(未指定)}"
FAILED=0
[ -n "$GODOT_VERSION" ] || { echo " ✗ 无法从 project.godot 解析 config/version" >&2; FAILED=1; }
[ -n "$YAML_VERSION" ] || { echo " ✗ 无法从 project.yaml 解析 version" >&2; FAILED=1; }
# 导出预设的 file_version / product_version 决定 OpenDance.exe 的 PE 版本资源,
# 即 Windows「右键 → 属性 → 详细信息」里显示的版本。它们**不会**随 project.godot
# 自动更新,曾经因此让 v0.2.1 的发布包显示 0.1.0。这里静态拦住;
# 产物那一侧再由 build/check-pe-version.sh 直接读 exe 复核。
if [ ! -f "$PRESET" ]; then
echo " ✗ 找不到 export_presets.cfg(无法校验 PE 版本资源的来源)" >&2
FAILED=1
else
for PAIR in "file_version:$PRESET_FILE_VERSION" "product_version:$PRESET_PRODUCT_VERSION"; do
KEY="${PAIR%%:*}"; VALUE="${PAIR#*:}"
if [ -z "$VALUE" ]; then
echo " ✗ export_presets.cfg 缺少 application/${KEY}(导出后 PE 版本资源会沿用旧值)" >&2
FAILED=1
elif [ -n "$GODOT_VERSION" ] && [ "$VALUE" != "$GODOT_VERSION" ]; then
echo " ✗ 导出预设 application/${KEY}=${VALUE} 与 project.godot 的 ${GODOT_VERSION} 不一致" >&2
echo " (Windows 属性页会显示 ${VALUE};跑 bash build/sync-export-version.sh 后重新导出)" >&2
FAILED=1
fi
done
fi
if [ -n "$EXPECTED" ] && [ "$GODOT_VERSION" != "$EXPECTED" ]; then
echo " ✗ project.godot 的版本与期望不一致(界面/About 会显示错版本)" >&2
FAILED=1
@@ -48,4 +73,4 @@ if [ "$FAILED" -ne 0 ]; then
exit 1
fi
echo " ✓ 版本一致:v$GODOT_VERSION(project.godot = project.yaml${EXPECTED:+ = 期望值})"
echo " ✓ 版本一致:v$GODOT_VERSION(project.godot = project.yaml = export_presets.cfg${EXPECTED:+ = 期望值})"