缺陷(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 重打包即可得到
资源管理器可直接双击解压的包。
136 lines
5.2 KiB
Bash
Executable File
136 lines
5.2 KiB
Bash
Executable File
#!/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 同目录)。"
|