diff --git a/.github/workflows/vcv-plugin.yml b/.github/workflows/vcv-plugin.yml new file mode 100644 index 0000000..153110a --- /dev/null +++ b/.github/workflows/vcv-plugin.yml @@ -0,0 +1,130 @@ +name: VCV Rack plugin (cross-platform) + +# Builds the MEMLNaut Rack 2 plugin for all four supported platforms using the +# OFFICIAL VCVRack/rack-plugin-toolchain (the same Docker-based cross-builder the +# VCV Library uses). The toolchain image ships the Linux/MinGW/osxcross cross- +# compilers and the per-platform Rack SDKs, so every .vcvplugin is reproducible on +# a single Linux runner — no per-platform native runners, no Apple hardware. +# +# Outputs: one --.vcvplugin per platform, uploaded as a +# workflow artifact, and attached to a GitHub Release when triggered by a tag push +# (v*). See vcv/DISTRIBUTION.md for the publish-to-/next/vcv flow. + +on: + push: + branches: [main, feat/manifold-mission, feat/vcv-dist] + paths: + - 'vcv/**' + - '.github/workflows/vcv-plugin.yml' + tags: + - 'v*' + pull_request: + paths: + - 'vcv/**' + - '.github/workflows/vcv-plugin.yml' + workflow_dispatch: + +env: + # Pin the official toolchain to a known-good commit (Rack SDK 2.6.6, docker + # image version 19). Bump deliberately; never float on master. + TOOLCHAIN_REPO: VCVRack/rack-plugin-toolchain + TOOLCHAIN_REF: 4fd1318701624051cee54b385343f23d59b4845c + TOOLCHAIN_IMAGE_VERSION: '19' + PLUGIN_DIR_REL: vcv + +jobs: + build: + name: Build ${{ matrix.platform }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + # lin-x64 + win-x64 cross-build with gcc / mingw (no Apple SDK). + # mac-x64 + mac-arm64 use osxcross baked into the toolchain image — this + # is how plugins are cross-built for macOS WITHOUT Apple hardware. The + # license-restricted macOS SDK is fetched only inside the toolchain image + # build (never committed to this repo). + platform: [lin-x64, win-x64, mac-x64, mac-arm64] + + steps: + - name: Checkout plugin + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Checkout rack-plugin-toolchain (pinned) + uses: actions/checkout@v4 + with: + repository: ${{ env.TOOLCHAIN_REPO }} + ref: ${{ env.TOOLCHAIN_REF }} + path: toolchain + + - name: Cache toolchain Docker image + id: img-cache + uses: actions/cache@v4 + with: + path: /tmp/rack-toolchain-image + key: rack-toolchain-${{ env.TOOLCHAIN_REF }}-v${{ env.TOOLCHAIN_IMAGE_VERSION }} + + - name: Fetch per-platform Rack SDKs + working-directory: toolchain + run: make rack-sdk-all + + - name: Load or build toolchain image + working-directory: toolchain + run: | + set -euo pipefail + IMG="rack-plugin-toolchain:${TOOLCHAIN_IMAGE_VERSION}" + if [ -f /tmp/rack-toolchain-image/image.tar ]; then + echo "Loading cached toolchain image $IMG" + docker load -i /tmp/rack-toolchain-image/image.tar + else + echo "Building toolchain image $IMG (one-off; cached for later runs)" + # rack-sdk-all already ran; build the cross-toolchain image (mingw + + # osxcross). This is the heavy step — cached by TOOLCHAIN_REF. + docker build --build-arg JOBS=$(nproc) \ + --tag "$IMG" . --progress=plain + mkdir -p /tmp/rack-toolchain-image + docker save "$IMG" -o /tmp/rack-toolchain-image/image.tar + fi + + - name: Build .vcvplugin for ${{ matrix.platform }} + working-directory: toolchain + run: | + set -euo pipefail + make docker-plugin-build-${{ matrix.platform }} \ + PLUGIN_DIR="${GITHUB_WORKSPACE}/${PLUGIN_DIR_REL}" + + - name: Collect artifact + run: | + set -euo pipefail + mkdir -p out + cp toolchain/plugin-build/*.vcvplugin out/ + ls -la out + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: MEMLNaut-${{ matrix.platform }} + path: out/*.vcvplugin + if-no-files-found: error + + release: + name: Attach to release + needs: build + if: startsWith(github.ref, 'refs/tags/v') + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Download all artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + merge-multiple: true + + - name: Publish release + uses: softprops/action-gh-release@v2 + with: + files: artifacts/*.vcvplugin + generate_release_notes: true diff --git a/vcv/.gitignore b/vcv/.gitignore new file mode 100644 index 0000000..37d6a3e --- /dev/null +++ b/vcv/.gitignore @@ -0,0 +1,7 @@ +# VCV plugin build products (see BUILDING.md / DISTRIBUTION.md) +/build/ +/dist/ +/plugin.so +/plugin.dylib +/plugin.dll +*.vcvplugin diff --git a/vcv/BUILDING.md b/vcv/BUILDING.md index fb05a97..97fff09 100644 --- a/vcv/BUILDING.md +++ b/vcv/BUILDING.md @@ -1,5 +1,11 @@ # Building MEMLNaut VCV Plugin +> **Distribution & cross-platform builds:** for packaging `.vcvplugin` files, +> the cross-platform CI matrix, and publishing to `/next/vcv`, see +> [DISTRIBUTION.md](DISTRIBUTION.md). The official `make dist` target (from the +> SDK's `plugin.mk`) produces `dist/--.vcvplugin`; the +> legacy `Makefile.dist` (zip-based, hard-coded 0.1.0) is superseded by it. + ## Prerequisites - **VCV Rack 2 SDK** — download from https://vcvrack.com/manual/PluginDevelopmentTutorial or build from source diff --git a/vcv/DISTRIBUTION.md b/vcv/DISTRIBUTION.md new file mode 100644 index 0000000..f432438 --- /dev/null +++ b/vcv/DISTRIBUTION.md @@ -0,0 +1,128 @@ +# Distributing the MEMLNaut VCV Rack plugin + +How the `MEMLNaut` plugin is built for every platform and published to the public +download page at **https://meml.lnfinitemonkeys.org/next/vcv/**. + +Plugin slug: `MEMLNaut`. Version comes from `plugin.json` (`jq -r .version`). + +--- + +## 1. Build artefacts (`.vcvplugin`) + +A `.vcvplugin` is a `tar.zst` archive of a `MEMLNaut/` directory containing the +platform binary (`plugin.so` / `.dll` / `.dylib`), `plugin.json`, and `res/`. The +official `plugin.mk` `dist` target produces it, named +`--.vcvplugin` (e.g. `MEMLNaut-0.2.0-lin-x64.vcvplugin`). +Platforms: `lin-x64`, `win-x64`, `mac-x64`, `mac-arm64`. + +### Linux x64 — locally (works today) + +The Rack 2 SDK is installed at `$HOME/.local/share/Rack2/Rack-SDK`: + +```bash +cd vcv +RACK_DIR=$HOME/.local/share/Rack2/Rack-SDK make dist +# -> vcv/dist/MEMLNaut--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. + +### Windows / macOS — cross-built on CI (NOT on the server) + +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. + +--- + +## 2. CI: `.github/workflows/vcv-plugin.yml` + +Builds all four platforms on `ubuntu-latest` runners via the pinned toolchain +(`TOOLCHAIN_REF`, currently Rack SDK 2.6.6 / toolchain image v19). Triggers on: + +- pushes touching `vcv/**` (smoke-build the matrix), +- pull requests touching `vcv/**`, +- tag pushes `v*` (build **and** attach to a GitHub Release), +- manual `workflow_dispatch`. + +Per matrix platform the job: checks out the plugin + pinned toolchain, fetches the +per-platform Rack SDKs (`make rack-sdk-all`), builds/loads the cached toolchain +Docker image, then runs `make docker-plugin-build- +PLUGIN_DIR=$GITHUB_WORKSPACE/vcv`. The resulting `.vcvplugin` is uploaded as a +workflow artifact. On a `v*` tag the `release` job downloads all four and attaches +them to the release via `softprops/action-gh-release`. + +The heavy toolchain image is cached by `TOOLCHAIN_REF`, so only the first run on a +new pin pays the build cost. + +### Cutting a release + +```bash +# bump version in vcv/plugin.json, commit, then: +git tag v0.2.0 +git push origin v0.2.0 +``` + +CI builds lin-x64 / win-x64 / mac-x64 / mac-arm64 and attaches the four +`.vcvplugin` files to the GitHub release for `v0.2.0`. + +### Bumping the toolchain + +Edit `TOOLCHAIN_REF` (and `TOOLCHAIN_IMAGE_VERSION` if the image version changes) +in `.github/workflows/vcv-plugin.yml`. Pin to a commit — never float on `master`. + +--- + +## 3. Publishing to `/next/vcv` + +The download page lives in the live a-immersive docroot at +`/home/w1n5t0n/deployments/meml-aimmersive/next/vcv/`. It is **purely additive** — +a new subdir alongside `/next/animations`, disturbing nothing else. + +Files: + +- `index.html` — the download page (Manifold design tokens: dark, JetBrains Mono, + `--accent #ff6a00`). Lists each platform with a download link, the version, VCV + install instructions, and which platforms are available now vs built by CI. +- `a-immersive.html` — a byte-identical copy of `index.html`. nginx for + `meml.lnfinitemonkeys.org` sets `index a-immersive.html`, so `/next/vcv/` + resolves via this alias (same trick `/next/animations` uses). No nginx change is + needed for a new subdir. +- `MEMLNaut--.vcvplugin` — the artefact(s). + +### Adding CI release artifacts to `/next/vcv` + +After a `v*` release builds on CI, copy the new `.vcvplugin` files into the publish +dir and refresh the cards/links in both HTML copies: + +```bash +# from a checkout, with the release tag's artifacts downloaded e.g. via: +# gh release download v0.2.0 -p '*.vcvplugin' -D /tmp/vcvrel +PUB=/home/w1n5t0n/deployments/meml-aimmersive/next/vcv +cp /tmp/vcvrel/*.vcvplugin "$PUB"/ +# then edit $PUB/index.html: flip the win/mac cards from "built by CI" +# (.dl.disabled) to live download links, and copy index.html -> a-immersive.html: +cp "$PUB/index.html" "$PUB/a-immersive.html" +``` + +Bumping the version means updating the `v0.2.0` strings and the filenames in the +two HTML copies. Keep `index.html` and `a-immersive.html` identical. + +### Verify + +```bash +curl -sk -o /dev/null -w '%{http_code}\n' https://meml.lnfinitemonkeys.org/next/vcv/ +curl -sk -o /dev/null -w '%{http_code}\n' \ + https://meml.lnfinitemonkeys.org/next/vcv/MEMLNaut-0.2.0-lin-x64.vcvplugin +``` + +Both should return `200`. Don't disturb `/next/`, `/next/animations/`, or the live +a-immersive at `/`.