Windows cross-build environment
Reproducible container for building the Windows executable and its installer from Linux. The specification is docs/dev/windows.md; this directory is what it turned into, and every departure from the spec's first draft is recorded in the Dockerfile's comments.
Use
# Cross-compile the desktop application
./docker/windows/build.sh cargo build --release --target x86_64-pc-windows-gnu -p darkroom-desktop
# Lint the cfg(windows) branches, which the Linux job never sees
./docker/windows/build.sh cargo clippy --target x86_64-pc-windows-gnu -p darkroom-desktop -- -D warnings
# Build the installer from that binary
./docker/windows/build.sh docker/windows/package.sh
# Smoke-test under Wine (docs/dev/windows.md §6)
./docker/windows/build.sh wine target-windows/x86_64-pc-windows-gnu/release/darkroom-desktop.exe --version
./docker/windows/build.sh wine target-windows/installer/DarkRoom-0.12.0-x86_64-setup.exe /S
# Interactive shell
./docker/windows/build.sh
# After editing the Dockerfile
./docker/windows/build.sh --rebuild
Prefers podman, falls back to docker. The cargo registry, the target directory and the Wine
prefix persist under ~/.cache/darkroom-windows/, so a warm rebuild is minutes and the first
wineboot happens once.
What is verified here, and what is not
Measured on the first build, 2026-09-12:
| Check | Result |
|---|---|
cargo build --target x86_64-pc-windows-gnu -p darkroom-desktop |
Links. 115 MB, PE32+ … (GUI) |
| DLL imports | 26 Windows system DLLs; no libwinpthread-1.dll, libgcc_s, libstdc++ |
wine darkroom-desktop.exe --version |
darkroom-desktop 0.12.0, exit 0, 0.1 s |
makensis |
105 MB DarkRoom-<version>-x86_64-setup.exe, 64-bit stub |
wine setup.exe /S |
Installs exe + 10 models to AppData\Local\Programs\DarkRoom, writes the HKCU uninstall key; the installed exe runs |
wine uninstall.exe /S |
Removes the directory and the key |
| Start Menu shortcut | Not verifiable here. CreateShortcut is IShellLink and does nothing under a headless Wine; the directory beside it is created. Check on Windows. |
Also checked by running the application itself under Wine: its log lands in
AppData\Local\darkroom\state, and nothing is written outside AppData (FR-PLAT-WIN-1).
None of this proves a Vulkan device opens, a render completes, fonts are found, the secret store round-trips or the browser opens for sign-in. Those are a Windows machine, once per release.
In CI
.gitea/workflows/windows-image.yml builds this image and pushes it to
gitea.tourolle.paris/dtourolle/darkroom-windows, exactly as the Android image is handled — tagged
by the tree hash of docker/windows/, rebuilt when and only when a file here changes. The
windows job in build-and-test.yml then runs, inside it, the same commands listed above plus
cargo clippy --target x86_64-pc-windows-gnu -- -D warnings, and uploads the installer as an
artefact.