build(vcv): build Windows here in a resource-bounded container + link ws2_32

- vcv/Makefile: include arch.mk early, link -lws2_32 when ARCH_WIN (the OSC
  server uses Winsock; mingw ignores the MSVC #pragma comment lib).
- vcv/build-win.sh: bounded Docker mingw cross-build (hard CPU/mem caps, no
  extra swap, prebuilt mingw — no toolchain compile). Produces win-x64 .vcvplugin.
- DISTRIBUTION.md: reflect the no-dedicated-box reality — Linux + Windows built
  locally (supervised + bounded), macOS needs the Apple SDK (CI or a Mac).
This commit is contained in:
monkey-w1n5t0n 2026-06-28 05:16:39 +02:00
parent 892384f043
commit c86c7da5df
3 changed files with 97 additions and 13 deletions

View file

@ -15,6 +15,10 @@ official `plugin.mk` `dist` target produces it, named
`<slug>-<version>-<platform>.vcvplugin` (e.g. `MEMLNaut-0.2.0-lin-x64.vcvplugin`).
Platforms: `lin-x64`, `win-x64`, `mac-x64`, `mac-arm64`.
We have no dedicated build box, so we build **on this host**, but **resource-bounded**
so a build can never starve the live services. Build products (`build/`, `dist/`,
`plugin.so`, `*.vcvplugin`) are git-ignored — they are publish artefacts, not source.
### Linux x64 — locally (works today)
The Rack 2 SDK is installed at `$HOME/.local/share/Rack2/Rack-SDK`:
@ -25,21 +29,39 @@ RACK_DIR=$HOME/.local/share/Rack2/Rack-SDK make dist
# -> vcv/dist/MEMLNaut-<version>-lin-x64.vcvplugin
```
This is the only platform we build on the server: the host toolchain is native
Linux x64 and the SDK is already present. Build products (`build/`, `dist/`,
`plugin.so`, `*.vcvplugin`) are git-ignored — they are publish artefacts, not
source.
Native host toolchain, SDK already present — trivial, no caps needed.
### Windows / macOS — cross-built on CI (NOT on the server)
### Windows x64 — locally, resource-bounded (works today)
The other three platforms are cross-built by the official
[VCVRack/rack-plugin-toolchain](https://github.com/VCVRack/rack-plugin-toolchain),
the same Docker cross-builder the VCV Library uses. **We do not run that toolchain
on the production VPS** — its image build compiles mingw + osxcross and pulls the
Apple SDK (multi-GB, multi-hour), which would overload a host that serves live
services. macOS additionally requires the Apple SDK, which we never redistribute.
CI is the right place for all of this; for a local-only macOS build the operator
can use a Mac with the native SDK.
`vcv/build-win.sh` cross-builds Windows in a **hard-capped Docker container** using
**prebuilt mingw-w64** (no GCC/toolchain compile — it only apt-installs mingw and
compiles two `.cpp` files). The container is capped on CPU + memory with no extra
swap, so the cgroup OOM-kills the container rather than the host if it ever exceeded
the cap. In practice the host stays at full free RAM throughout.
```bash
vcv/build-win.sh # defaults: CPUS=6 MEM=8g, Rack SDK 2.6.4
CPUS=4 MEM=6g vcv/build-win.sh # tighter caps
# -> vcv/dist/MEMLNaut-<version>-win-x64.vcvplugin
```
Note: the OSC bridge server needs Winsock on Windows; `vcv/Makefile` links
`-lws2_32` when `ARCH_WIN` is set (mingw ignores the MSVC `#pragma comment(lib,…)`).
### macOS (x64 + arm64) — Apple SDK required
macOS cross-builds need Apple's **licensed macOS SDK**, which we never download or
redistribute on this host. Two routes:
1. **CI** (`.github/workflows/vcv-plugin.yml`) — the
[VCVRack/rack-plugin-toolchain](https://github.com/VCVRack/rack-plugin-toolchain)
builds mac-x64 + mac-arm64 on tagged releases (the toolchain fetches the SDK only
inside its own image build).
2. **A Mac** — build with the native SDK + `RACK_DIR` set to the macOS Rack SDK.
The full rack-plugin-toolchain image build is **not** run on this host: its Dockerfile
`COPY`s the Apple SDK and compiles osxcross, so it both needs the SDK and is multi-GB
/ multi-hour. That belongs on CI. (Linux + Windows above need none of it.)
---

View file

@ -1,5 +1,14 @@
RACK_DIR ?= $(HOME)/.local/share/Rack2/Rack-SDK
# Detect the target arch early (defines ARCH_WIN/ARCH_LIN/ARCH_MAC) so we can add
# per-platform link libs before plugin.mk wires the link rule. The OSC bridge
# server (src/osc_server.hpp) uses Winsock2 on Windows; mingw ignores the
# MSVC-only `#pragma comment(lib, "ws2_32.lib")`, so link it explicitly.
include $(RACK_DIR)/arch.mk
ifdef ARCH_WIN
LDFLAGS += -lws2_32
endif
FLAGS += -std=c++20
FLAGS += -I$(RACK_DIR)/include -I$(RACK_DIR)/dep/include
# The retired nisps-core header tree is gone; the runtime IML/MLP is vendored

53
vcv/build-win.sh Executable file
View file

@ -0,0 +1,53 @@
#!/usr/bin/env bash
#
# build-win.sh — cross-build the MEMLNaut VCV plugin for Windows x64, here, in a
# RESOURCE-BOUNDED Docker container (prebuilt mingw-w64; no GCC/toolchain compile).
#
# Why Docker + caps: this host also runs live services. The container is hard-
# capped (CPU + memory + no extra swap) so the build physically cannot starve or
# crash the host — the cgroup OOM-kills the container, not the system, if it ever
# exceeded the cap. In practice this build peaks well under the cap (it only
# apt-installs prebuilt mingw + compiles two .cpp files), and the host stays at
# full free RAM throughout. Tune CPUS / MEM below for your machine.
#
# Output: vcv/dist/MEMLNaut-<version>-win-x64.vcvplugin
# Requires: docker. Run from anywhere; paths are resolved from this script.
set -euo pipefail
CPUS="${CPUS:-6}" # cores the container may use
MEM="${MEM:-8g}" # hard memory cap (== memory-swap, so no host swap)
RACK_SDK_VERSION="${RACK_SDK_VERSION:-2.6.4}"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # vcv/
WORK="$(mktemp -d /tmp/vcv-win-build.XXXXXX)"
trap 'rm -rf "$WORK"' EXIT
echo "==> staging a clean copy of the plugin source"
cp -r "$SCRIPT_DIR/." "$WORK/"
rm -rf "$WORK/build" "$WORK/dist" "$WORK/plugin.so" 2>/dev/null || true
cat > "$WORK/_in-container.sh" <<EOF
set -euo pipefail
export DEBIAN_FRONTEND=noninteractive
apt-get update -qq
apt-get install -y -qq g++-mingw-w64-x86-64-posix make unzip wget zstd tar jq >/dev/null
cd /tmp
wget -q "https://vcvrack.com/downloads/Rack-SDK-${RACK_SDK_VERSION}-win-x64.zip"
unzip -q "Rack-SDK-${RACK_SDK_VERSION}-win-x64.zip"
cd /src
export RACK_DIR=/tmp/Rack-SDK
export CC=x86_64-w64-mingw32-gcc-posix CXX=x86_64-w64-mingw32-g++-posix
export STRIP=x86_64-w64-mingw32-strip OBJCOPY=x86_64-w64-mingw32-objcopy
make clean >/dev/null 2>&1 || true
make -j${CPUS} dist
ls -la dist/
EOF
echo "==> building Windows plugin in a bounded container (cpus=$CPUS, mem=$MEM, no extra swap)"
docker run --rm --cpus="$CPUS" --memory="$MEM" --memory-swap="$MEM" \
-v "$WORK:/src" ubuntu:24.04 bash /src/_in-container.sh
mkdir -p "$SCRIPT_DIR/dist"
cp "$WORK"/dist/*-win-x64.vcvplugin "$SCRIPT_DIR/dist/"
echo "==> done: $(ls "$SCRIPT_DIR"/dist/*-win-x64.vcvplugin)"