Files
opendance-windows/build/export-windows.sh
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

136 lines
5.2 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# ============================================================
# OpenDance Studio —— Windows 客户端导出(在 Linux 上执行)
#
# 文档 §5.3 方案 A:Godot 4 支持在 Linux 上导出 Windows 可执行文件。
#
# 前置:
# 1. Godot 4 可执行文件(GODOT_BIN 指定,或已在 PATH 中)
# 2. 已安装对应版本的 export templates
# 下载:https://github.com/godotengine/godot/releases
# Godot_v<版本>-stable_export_templates.tpz
# 安装:解压后把 templates/* 放到
# ~/.local/share/godot/export_templates/<版本>.stable/
#
# 用法:bash build/export-windows.sh [debug|release]
# ============================================================
set -euo pipefail
PROJECT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
cd "$PROJECT_DIR"
MODE="${1:-release}"
if [ "$MODE" != "debug" ] && [ "$MODE" != "release" ]; then
echo "用法:bash build/export-windows.sh [debug|release]" >&2
exit 2
fi
# ---- 定位 Godot ----
GODOT_BIN="${GODOT_BIN:-}"
if [ -z "$GODOT_BIN" ]; then
for candidate in godot godot4 Godot; do
if command -v "$candidate" >/dev/null 2>&1; then GODOT_BIN="$candidate"; break; fi
done
fi
if [ -z "$GODOT_BIN" ]; then
echo "错误:未找到 Godot 可执行文件。请安装 Godot 4 或用 GODOT_BIN=<路径> 指定。" >&2
exit 1
fi
OUTPUT_DIR="$PROJECT_DIR/build/windows"
mkdir -p "$OUTPUT_DIR"
GODOT_VERSION="$("$GODOT_BIN" --version 2>/dev/null | head -1 || true)"
echo "[export] Godot:$GODOT_BIN($GODOT_VERSION)"
echo "[export] 项目:$PROJECT_DIR"
echo "[export] 模式:$MODE"
# ---- 导出预设必须位于项目根目录(Godot 的硬性要求)----
if [ ! -f "$PROJECT_DIR/export_presets.cfg" ]; then
if [ -f "$PROJECT_DIR/build/export_presets.cfg" ]; then
cp "$PROJECT_DIR/build/export_presets.cfg" "$PROJECT_DIR/export_presets.cfg"
echo "[export] 已从 build/ 复制导出预设到项目根目录"
else
echo "错误:缺少 export_presets.cfg(Godot 要求放在项目根目录)。" >&2
exit 1
fi
fi
# ---- 检查导出模板 ----
TEMPLATE_DIR="${HOME}/.local/share/godot/export_templates"
if [ ! -d "$TEMPLATE_DIR" ] || [ -z "$(ls -A "$TEMPLATE_DIR" 2>/dev/null)" ]; then
echo "错误:未找到导出模板($TEMPLATE_DIR 为空)。" >&2
echo " 请从 https://github.com/godotengine/godot/releases 下载" >&2
echo " Godot_v<版本>-stable_export_templates.tpz 并安装到" >&2
echo " ~/.local/share/godot/export_templates/<版本>.stable/" >&2
exit 1
fi
echo "[export] 导出模板:$(ls "$TEMPLATE_DIR" | tr '\n' ' ')"
# ---- 导出前:把版本号同步进导出预设 ----
# export_presets.cfg 的 application/file_version / product_version 决定产物 exe 的
# PE 版本资源(Windows「右键 → 属性 → 详细信息」里显示的版本),它们**不会**
# 跟随 project.godot 的 application/config/version 自动更新。不在这里同步,
# 导出的包就会带着旧版本号 —— v0.2.1 正是因此显示了 0.1.0。
echo "[export] 同步版本号到导出预设…"
bash "$PROJECT_DIR/build/sync-export-version.sh" || {
echo "错误:导出预设版本同步失败。" >&2
exit 1
}
# ---- 确保资源已导入(缺失会让导出静默产出不完整的包)----
echo "[export] 导入资源…"
"$GODOT_BIN" --headless --path "$PROJECT_DIR" --import >/dev/null 2>&1 || true
# ---- 导出 ----
echo "[export] 导出中…"
set +e
"$GODOT_BIN" --headless --path "$PROJECT_DIR" \
--export-"$MODE" "Windows Desktop" "$OUTPUT_DIR/OpenDance.exe"
EXPORT_STATUS=$?
set -e
if [ "$EXPORT_STATUS" -ne 0 ]; then
echo "[export] 导出命令返回 $EXPORT_STATUS,检查产物是否存在…"
fi
# ---- 校验产物 ----
EXE="$OUTPUT_DIR/OpenDance.exe"
PCK="$OUTPUT_DIR/OpenDance.pck"
CONSOLE="$OUTPUT_DIR/OpenDance.console.exe"
MISSING=0
[ -f "$EXE" ] || { echo "错误:未生成 $EXE" >&2; MISSING=1; }
[ -f "$PCK" ] || { echo "错误:未生成 $PCK" >&2; MISSING=1; }
[ -f "$CONSOLE" ] || echo "[export] 提示:未生成 console 包装器(非致命)"
if [ "$MISSING" -ne 0 ]; then
echo "导出失败。" >&2
exit 1
fi
# 校验 PE 头,确认确实是 Windows 可执行文件
MAGIC=$(head -c 2 "$EXE" | od -An -tx1 | tr -d ' \n')
if [ "$MAGIC" != "4d5a" ]; then
echo "错误:$EXE 不是合法的 Windows PE 文件(头 2 字节为 $MAGIC,期望 4d5a 'MZ')" >&2
exit 1
fi
# 校验 PE 版本资源 = 当前项目版本(文档 §11.2:产物元数据也必须可核对)
PROJECT_VERSION="$(sed -n 's/^config\/version="\(.*\)"$/\1/p' "$PROJECT_DIR/project.godot" | head -1)"
echo "[export] 校验产物 PE 版本资源(期望 $PROJECT_VERSION)…"
if ! bash "$PROJECT_DIR/build/check-pe-version.sh" "$EXE" "$PROJECT_VERSION"; then
echo "错误:$EXE 的 PE 版本资源与项目版本不一致。" >&2
exit 1
fi
SIZE_EXE=$(stat -c%s "$EXE")
SIZE_PCK=$(stat -c%s "$PCK")
echo ""
echo "[export] 完成:"
echo " $EXE ($((SIZE_EXE / 1024)) KiB, PE 头与版本资源校验通过)"
echo " $PCK ($((SIZE_PCK / 1024)) KiB)"
[ -f "$CONSOLE" ] && echo " $CONSOLE ($(( $(stat -c%s "$CONSOLE") / 1024 )) KiB)"
echo ""
echo "在 Windows 10/11 上运行 $EXE 即可(.pck 必须与 .exe 同目录)。"