Files
DarkRoom/docker/windows/package.sh
T
dtourolle 2836ec2881 Build the Windows installer in a container, and run it under Wine
docs/windows.md specified it; this is §9 steps 1, 2 and 4 run, and the
report in §10. A Debian trixie image with rustup, the MinGW cross
compiler, NSIS and Wine; a build.sh in the shape of the Android one;
a package.sh that stages the executable and the seven models behind
the same LFS-pointer guard every other packager carries, then runs
makensis; and the .nsi itself — per-user, no elevation, an uninstaller
that leaves the library alone.

Measured: the executable links first time once the link flags were
right, imports only Windows system DLLs, prints its version under
Wine, and the installer installs and uninstalls silently under Wine
with the registry key and the models where §5.2 says. What Wine
cannot show is the Start Menu shortcut: CreateShortcut is IShellLink
and does nothing headless.

Four claims in the spec's first draft were wrong and are corrected in
place with the reasoning kept: the whole-archive winpthread flag
breaks the link and was never needed; build scripts need a host gcc;
bookworm's Wine lacks the bcryptprimitives.dll rustc's std imports,
so the image is trixie; and NSIS's default stub is 32-bit, so the
installer says amd64-unicode and needs no i386 Wine.
2026-09-12 00:54:11 +02:00

68 lines
2.7 KiB
Bash
Executable File

#!/usr/bin/env bash
# Assemble the Windows installer from a finished cross-build.
#
# ./docker/windows/build.sh docker/windows/package.sh
#
# Expects `cargo build --release --target x86_64-pc-windows-gnu -p darkroom-desktop`
# to have run in the same target directory. Produces
# DarkRoom-<version>-x86_64-setup.exe in $OUT (default: target-windows/installer).
#
# Runs inside the container, where makensis is; docs/windows.md §5 is the
# specification this implements.
set -euo pipefail
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO="$(cd "${HERE}/../.." && pwd)"
TARGET="${CARGO_TARGET_DIR:-${REPO}/target}/x86_64-pc-windows-gnu/release"
OUT="${OUT:-${CARGO_TARGET_DIR:-${REPO}/target}/installer}"
EXE="${TARGET}/darkroom-desktop.exe"
[[ -f "${EXE}" ]] || { echo "error: ${EXE} not built" >&2; exit 1; }
# The version, from the workspace rather than restated here — the same single
# source tools/set-version.sh writes and the APK packager reads.
VERSION="$(sed -n 's/^version = "\(.*\)"$/\1/p' "${REPO}/Cargo.toml" | head -1)"
[[ -n "${VERSION}" ]] || { echo "error: no version in Cargo.toml" >&2; exit 1; }
echo "==> version ${VERSION}"
# Staging: exactly what the installer carries (windows.md §5.2), and nothing
# from a previous run — a model dropped from the tree must not linger here
# and go on shipping.
STAGE="${OUT}/stage"
rm -rf "${STAGE}"
mkdir -p "${STAGE}/models"
cp "${EXE}" "${STAGE}/darkroom.exe"
# The models, with the guard every other packager carries: an LFS pointer is
# ~130 bytes and looks exactly like a model to `cp`. Shipped, it fails inside
# tract on the user's machine with a message about a broken graph rather than
# a checkout that needed `git lfs pull`. Only the weights are checked; the
# scene model's vocabulary and category descriptor are legitimately small.
for dir in face scene; do
for f in "${REPO}/models/${dir}"/*; do
case "$(basename "${f}")" in
README.md) continue ;;
esac
if [[ "${f}" == *.onnx && "$(stat -c%s "${f}")" -lt 100000 ]]; then
echo "error: $(basename "${f}") is $(stat -c%s "${f}") bytes — an LFS pointer, not a model." >&2
echo " run: git lfs pull" >&2
exit 1
fi
cp "${f}" "${STAGE}/models/"
done
done
echo "==> staged $(ls "${STAGE}/models" | wc -l) model file(s)"
INSTALLER="${OUT}/DarkRoom-${VERSION}-x86_64-setup.exe"
# NSIS wants Windows-style paths in File directives even on a POSIX host, and
# the script takes its inputs by define so nothing about the layout here is
# written into it.
makensis -V2 \
-DVERSION="${VERSION}" \
-DSTAGE="${STAGE}" \
-DOUT="${INSTALLER}" \
"${REPO}/packaging/windows/darkroom.nsi"
ls -la "${INSTALLER}"
echo "==> ${INSTALLER}"