Files
opendance-windows/tasks/017-pe-version.md
T
zijunchiang ba988f6ca6 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 重打包即可得到
资源管理器可直接双击解压的包。
2026-09-17 04:22:57 +08:00

4.2 KiB
Raw Blame History

T-WIN-017:发布包 exe 的 PE 版本资源必须等于发布版本

  • 状态: done
  • 依赖: T-WIN-014(打包流程)
  • 文档: v1.6 §5.3 / §5.7 / §11.2
  • 契约: 不涉及(纯打包元数据)

缺陷(v0.2.1 实测)

发布包 opendance-windows-v0.2.1.zip 里的 OpenDance.exe,在 Windows 上 「右键 → 属性 → 详细信息」显示的是:

文件版本    0.1.0
产品版本    0.1.0

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

根因

export_presets.cfg 里这两个键被硬编码在 0.1.0,且没有任何环节读写或校验:

application/file_version="0.1.0"
application/product_version="0.1.0"

Godot 导出时用它们(经 rcedit)写进 exe 的 PE VERSIONINFO 资源。 它们不会跟随 project.godot 的 application/config/version 自动更新 —— 于是每次只是改 project.godot + project.yaml 发版,二进制元数据一直停在 0.1.0。

build/check-version.sh 当时只比 project.godot ↔ project.yaml,两处一致, 所以静态校验全绿、产物却是错的:漂移发生在没人看的第三个位置。

证据

$ strings -a -el opendance-windows-v0.2.1/OpenDance.exe | sed -n '3147,3151p'
FileVersion
0.1.0
ProductVersion
0.1.0

$ bash build/check-pe-version.sh <exe> 0.2.1
  PE 版本资源(…/OpenDance.exe):
    VS_FIXEDFILEINFO  FileVersion    = 0.1.0.0
    VS_FIXEDFILEINFO  ProductVersion = 0.0.0.0
    StringFileInfo    FileVersion    = 0.1.0
    StringFileInfo    ProductVersion = 0.1.0
  ✗ PE FileVersion 为 0.1.0.0,期望 0.2.1.x(Windows 属性页会显示错版本)
  ✗ 资源字符串 FileVersion 为 '0.1.0',期望 '0.2.1'
  ✗ 资源字符串 ProductVersion 为 '0.1.0',期望 '0.2.1'

(对照组:官方模板 windows_release_x86_64.exe 的 FileVersion = 4.7.2, 说明该机上的 rcedit 改写是生效的,问题纯粹出在预设的值本身。)

修复

环节 文件 做法
同步 build/sync-export-version.sh(新增) 把版本号写进 export_presets.cfg 的 application/file_version / application/product_version;缺行则补行;幂等;拒绝非 X.Y.Z
导出 build/export-windows.sh 导出前先同步;导出后用 check-pe-version.sh 直接读 exe 复核
静态防线 build/check-version.sh 新增对 export_presets.cfg 两个键的校验(不等于项目版本即失败)
产物防线 build/check-pe-version.sh(新增) 直接读 exe 的 PE 版本资源:VS_FIXEDFILEINFO(签名 0xFEEF04BD 之后 16 字节,grep -abo 取偏移约 40 ms)+ StringFileInfo(strings -el,资源管理器属性页显示的就是这两项)
打包 build/package-release.sh 打包前校验源 exe、解包后再校验包内 exe(确认打包/解包没换错文件)
一键验证 build/verify.sh 新增步骤 1/5:已导出 exe 的 PE 版本资源;未导出则跳过并提示(打包时会强制)
单元测试 tests/test_about.gd 新增 test_export_preset_version_matches_project_version:预设两个键必须等于版本号唯一来源

只校验 VS_FIXEDFILEINFO 是不够的:本机实测该结构里的 ProductVersion 恒为 0.0.0.0(rcedit 只填了字符串形式),而属性页显示的是 StringFileInfo 的文本值。因此两处都读、都对。

验收

验收项 结果
产物 exe 的 PE 版本资源 = 发布版本 ✅ check-pe-version.sh 读 v0.2.2 产物通过(FileVersion 0.2.2.0 / 字符串 0.2.2)
预设漂移能被拦住 ✅ 反向验证:把预设改回 0.1.0,check-version.sh 与 test_about.gd 均失败
打包前/解包后都校验 ✅ package-release.sh 两处 check-pe-version.sh,失败即 die
不新增外部依赖 ✅ 只用 grep -abo + od + strings(binutils),无 python/node 依赖

复现命令

cd opendance-windows
bash build/check-pe-version.sh build/windows/OpenDance.exe 0.2.2   # 产物侧
bash build/check-version.sh 0.2.2                                  # 配置侧
bash build/sync-export-version.sh 0.2.2                            # 需要修时