Files
salman 5110ea4827 Build the Windows installer with electron-builder (NSIS)
The Squirrel path (electron-forge maker-squirrel -> electron-winstaller)
required Wine and Mono, plus a 64-bit Wine prefix, to cross-build on Linux.
electron-builder's NSIS target uses its own native tooling, so the same
cross-build now needs no Wine and no Mono, matching how muSRFlow is packaged.

- package.json: add an electron-builder 'build' block (win/nsis, extraResources
  for the engine and the flat rootfs, files allow-list, nsis options) and point
  package:win/make:win at 'electron-builder --win nsis'; drop maker-squirrel.
- packaging/wsl2/require-rootfs.js: fail the Windows build when the rootfs is
  missing (electron-builder has no config-time abort hook).
- forge.config.js: drop the Squirrel maker and the Windows rootfs guard; forge
  now builds Linux/macOS only.
- README/CHANGELOG: document the NSIS build and that no Wine/Mono is needed.

Verified locally: TRIMSP-NL-Workbench-Setup.exe (NSIS, 186 MB) builds with no
Wine/Mono; resources/bin/trimspNL and resources/trimspNL-runtime-rootfs.tar.gz
land where wsl-runtime.js looks; guard fails on a missing rootfs.
2026-10-20 13:35:17 +02:00
..
2026-10-20 09:31:25 +02:00

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-builder (NSIS). The build.win.extraResources entries in package.json copy the rootfs archive flat into resources/ and the engine to resources/bin/, matching what wsl-runtime.js looks for. Linux/macOS packaging still uses electron-forge (forge.config.js); the two tools coexist.

Build the NSIS 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 — packaging/wsl2/require-rootfs.js fails if packaging/wsl2/out/ is empty, so the .exe can never silently ship without its engine. Build from Linux/WSL or Windows after building the rootfs first (Windows cannot compile the Fortran engine or run the rootfs builder).

The installer is written to dist/ as TRIMSP-NL-Workbench-Setup.exe.

Build-host prerequisites

  • Building the .exe on Windows: nothing extra.
  • Building the .exe on Linux (cross-build): nothing extra either. electron-builder's NSIS target uses its own native tooling, so no Wine and no Mono are required (unlike the former Squirrel path).

Verifying the shipped .exe

The app 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:

  1. The import succeeded and the engine runs in the distribution:

    wsl -d trimspNL-runtime -- /opt/trimsp-runtime/bin/trimspNL
    

    Expected: the Usage: trimspNL <run_basename> [ranlux|pcg32|xoshiro] banner.

  2. 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*_.rge and _Seq_Results.dat appear in that folder, proving both the path translation and the wsl.exe spawn work without a local display.

  3. 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. Adjust BASE_IMAGE if the engine is rebuilt against a different baseline.
  • wsl.exe availability is assumed; older Windows builds without WSL2 must install it (wsl --install) first.
  • The macOS runtime is not built.
  • Cross-building the .exe from Linux needs no extra tooling (electron-builder NSIS); Windows builds need none either.