electron-winstaller's Squirrel runs as 32-bit .NET but zips the package by
ShellExecuteEx-ing the 64-bit vendor/7z.exe. A 32-bit-only Wine prefix
('#arch=win32') cannot launch a 64-bit PE, so the cross-build fails with
'ShellExecuteEx failed: Bad EXE format'. Record the WINEARCH=win64 recipe
(and the pre-existing Wine+Mono requirement) instead of leaving it as a
build-host surprise.
6.5 KiB
Windows (WSL2) engine runtime
Windows has no native TRIM.SP-NL engine; the Linux engine cannot be run directly. Instead TRIMSP-NL Workbench ships the same statically linked engine used by the Linux bundle and runs it inside a bundled WSL2 distribution.
How it works
TrimSPelec.js detects the Windows host and the bundled engine
(process.platform === "win32" and <resources>/bin/trimspNL present) and
routes the engine through wsl.exe:
wsl.exe -d trimspNL-runtime -- /opt/trimsp-runtime/bin/trimspNL <run> [rng]
Path arguments (C:\dir\file) are translated to their WSL mount form
(/mnt/c/dir/file) so the engine reads and writes the user's Windows files.
Run inputs and outputs therefore stay on the Windows side.
A user-configured engine binaries directory with a Windows-native executable is launched directly, and on non-Windows hosts the translation is inert, so the Linux build and development checkouts are unaffected.
Constants (in TrimSPelec.js): the distribution name trimspNL-runtime and the
in-distro prefix /opt/trimsp-runtime.
Building the rootfs
Requires Docker or Podman and the static engine
(npm run build:fortran, built automatically when missing).
npm run build:wsl2 # packaging/wsl2/build-wsl2.sh
Because trimspNL-static is a fully static executable (no libc/libgfortran
runtime dependencies) the rootfs is just a minimal base filesystem plus
/opt/trimsp-runtime/bin/trimspNL. The script writes /etc/wsl.conf and exports
the container filesystem to
packaging/wsl2/out/trimspNL-runtime-rootfs.tar.gz.
The script refuses to run if resources/bin/trimspNL is not statically linked.
Importing on Windows
The import is automated. On first run main.js (through wsl-runtime.js) checks
whether the trimspNL-runtime distribution is registered and, if not, imports
the bundled archive into %LOCALAPPDATA%\TrimSP\trimspNL-runtime with
wsl --import ... --version 2. The work happens in the background so the window
opens immediately; progress and failures are broadcast to the renderer on the
wslRuntimeStatus channel. A failed import resets so a later ensureWslRuntime
retries. Before running the engine the renderer awaits window.TrimSPRuntimeGate,
so the first run after startup shows a "Preparing the bundled engine runtime"
notice and proceeds once the distribution is ready; the gate is a no-op off
Windows.
The equivalent manual command, useful for debugging:
wsl --import trimspNL-runtime "$env:LOCALAPPDATA\TrimSP\trimspNL-runtime" trimspNL-runtime-rootfs.tar.gz --version 2
Verify:
wsl -d trimspNL-runtime -- /opt/trimsp-runtime/bin/trimspNL
Packaging
The Windows build ships the rootfs through electron-forge. forge.config.js
adds the archive to packagerConfig.extraResource when it exists (copied flat
into resources/), while the engine marker at resources/bin/trimspNL lets the
renderer detect the bundled runtime and route through WSL.
Build the Squirrel Setup.exe, which contains the app and the WSL2 rootfs:
npm run make:win
This runs the whole chain: it compiles the static engine, builds the rootfs, then
packages and makes the installer for win32. A Windows build requires the
rootfs — forge.config.js throws if packaging/wsl2/out/ is empty, so the
.exe can never silently ship without its engine. Build from Linux/WSL first
(Windows cannot compile the Fortran engine or run the rootfs builder).
The installer is written to out/make/squirrel.windows/x64/ as
TRIMSP-NL-Workbench-Setup.exe.
Build-host prerequisites
-
Building the
.exeon Windows: nothing extra. -
Building the
.exeon Linux (cross-build):electron-winstallerneeds both Wine and Mono installed, otherwise it fails withYou must install both Mono and Wine on non-Windows. Install e.g.wineandmono-complete(ormono-core) first.It also needs a 64-bit (WoW64) Wine prefix. Squirrel is a 32-bit .NET assembly but zips the package by
ShellExecuteEx-ing the 64-bitnode_modules/electron-winstaller/vendor/7z.exe; a 32-bit-only prefix (#arch=win32) cannot launch a 64-bit PE and the build fails withShellExecuteEx failed: Bad EXE format. Build against a WoW64 prefix without disturbing an existing one:export WINEARCH=win64 WINEPREFIX="$HOME/.wine-trimsp64" wineboot -u npm run make:win(Wine ≥ 9 supports running 32-bit apps from a
win64prefix, so a single prefix is enough.) On Windows none of this applies.
Verifying the shipped .exe
The TrimSP.exe inside the install loads the engine only through WSL, so the
same manual remote-session check below applies after installing the .exe.
Tests
npm run test:wsl-runtime # tests/wsl-runtime.test.js + tests/runtime-gate.test.js
Covers the pure main-process module (with an injected wsl.exe spawner), the
renderer-side launch translation, including inertness on Linux, and that the
scan pipeline awaits the runtime gate before launching the engine.
Manual remote-session smoke test
The engine path is a console process and never touches the display, so it cannot misroute a window the way the file dialogs could. It is still worth checking once on a real Windows host, and especially over SSH/RDP, since that is how the workbench is often driven remotely. After the first-run import, verify:
-
The import succeeded and the engine runs in the distribution:
wsl -d trimspNL-runtime -- /opt/trimsp-runtime/bin/trimspNLExpected: the
Usage: trimspNL <run_basename> [ranlux|pcg32|xoshiro]banner. -
Over a remote session (SSH/RDP, not just a local console), launch the app, set a Work Folder on a Windows drive, and click Run. Expected:
<prefix>_E*_.rgeand_Seq_Results.datappear in that folder, proving both the path translation and thewsl.exespawn work without a local display. -
The status bar first shows "Preparing the bundled engine runtime (first run only)..." and the run then proceeds, proving the runtime gate waited for the import rather than racing it.
Open items
- The rootfs is built from
almalinux:8. AdjustBASE_IMAGEif the engine is rebuilt against a different baseline. wsl.exeavailability is assumed; older Windows builds without WSL2 must install it (wsl --install) first.- The macOS runtime is not built.
- Cross-building the
.exefrom Linux additionally needs Wine, Mono and a 64-bit (WoW64) Wine prefix (see above); building on Windows needs none of these.