chore: move build output under build/ and scripts into scripts/
Layout: - scripts/ holds the four build scripts plus the new clean.sh - cmake/ holds mingw64-toolchain.cmake - the scripts default to build/linux, build/macos, build/windows, build/harness - docs/ holds the audit documents, with the round 1 task list archived Cleanup: - scripts/clean.sh removes generated output, with --dry-run, --staging, --legacy and --all, and refuses tracked, protected or outside paths - the Windows VST3 manifest now comes from cmake/moduleinfo.json.in, so its version, vendor and class IDs follow cmake/Plugin.cmake instead of a hand-written heredoc that could drift - deleted the unused Source/GUI/Slider, which no code constructed - fixed the hidden double processBlock overload: three warning lines to zero - unslopped the build scripts, the two .cjs helpers and the CMake comments - .gitignore covers the upstream JUCE Projucer and DemoRunner binaries Verified: five scripts pass bash -n; the harness passes CTest with zero warning lines; the Linux VST3 and Standalone link; the Windows cross-build passes its x86-64, runtime-import and entry-point checks; each configure exposes only its own targets; and a full build leaves Source/ and third_party/JUCE unchanged. The generated manifest is identical to the previous hand-written one.
This commit is contained in:
1 parent
e4cea300db
commit
facd5c5b5e
25 files changed
+438
-313
No files matched your search
@@ -6,7 +6,7 @@ const { execFileSync } = require('child_process');
|
||||
const dir = process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
||||
const BAKED = "/usr/lib/node_modules/@nanonets/graft/dist/claude";
|
||||
|
||||
// The dist/claude dir of @nanonets/graft resolved from a base whose node_modules is searched.
|
||||
// dist/claude inside @nanonets/graft, resolved from a directory npm searches.
|
||||
function fromPkg(base) {
|
||||
try {
|
||||
const pkg = require.resolve('@nanonets/graft/package.json', { paths: [base] });
|
||||
@@ -14,7 +14,7 @@ function fromPkg(base) {
|
||||
} catch { return null; }
|
||||
}
|
||||
|
||||
// The global node_modules dir per npm (handles Homebrew/Windows/volta). Queried on demand.
|
||||
// The global node_modules directory, as npm reports it. Queried only when needed.
|
||||
function globalRoot() {
|
||||
try {
|
||||
const root = execFileSync('npm', ['root', '-g'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], shell: process.platform === 'win32' }).trim();
|
||||
@@ -22,14 +22,14 @@ function globalRoot() {
|
||||
} catch { return null; /* npm unavailable */ }
|
||||
}
|
||||
|
||||
// The version of the package a dist/claude dir belongs to, or null if unreadable.
|
||||
// The version of the package that owns a dist/claude directory, or null.
|
||||
function versionOf(distClaude) {
|
||||
try {
|
||||
return JSON.parse(fs.readFileSync(path.join(distClaude, '..', '..', 'package.json'), 'utf8')).version || null;
|
||||
} catch { return null; }
|
||||
}
|
||||
|
||||
// Numeric-dotted compare of the release part; an unreadable version loses to any known one.
|
||||
// Compares dotted version numbers. An unreadable version counts as older.
|
||||
function newer(a, b) {
|
||||
if (!a) return false;
|
||||
if (!b) return true;
|
||||
@@ -42,7 +42,7 @@ function newer(a, b) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The highest-versioned dir in `dirs` that actually contains `name`, or null.
|
||||
// The highest-versioned entry in `dirs` that contains `name`, or null.
|
||||
function best(dirs, name) {
|
||||
let bestDir = null, bestVer = null;
|
||||
for (const d of dirs) {
|
||||
@@ -54,14 +54,14 @@ function best(dirs, name) {
|
||||
}
|
||||
|
||||
function entry(name) {
|
||||
// Cheap candidates first, and only shell out to npm when every one of them misses.
|
||||
// Check the cheap candidates first, and run npm only if none of them match.
|
||||
const cheap = [BAKED, fromPkg(dir), fromPkg(path.join(path.dirname(process.execPath), '..', 'lib'))];
|
||||
const hit = best(cheap, name);
|
||||
if (hit) return path.join(hit, name);
|
||||
const gr = globalRoot();
|
||||
const global = gr && path.join(gr, '@nanonets', 'graft', 'dist', 'claude');
|
||||
if (global && fs.existsSync(path.join(global, name))) return path.join(global, name);
|
||||
return path.join(dir, 'dist', 'claude', name); // last-ditch; import will no-op if absent
|
||||
return path.join(dir, 'dist', 'claude', name); // fallback; the import does nothing when the file is absent
|
||||
}
|
||||
|
||||
import(pathToFileURL(entry("hooks.js")).href).then((m) => m.main(process.argv[2])).catch(() => { /* graft unavailable, no-op */ });
|
||||
import(pathToFileURL(entry("hooks.js")).href).then((m) => m.main(process.argv[2])).catch(() => { /* graft is unavailable: do nothing */ });
|
||||
@@ -6,7 +6,7 @@ const { execFileSync } = require('child_process');
|
||||
const dir = process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
||||
const BAKED = "/usr/lib/node_modules/@nanonets/graft/dist/claude";
|
||||
|
||||
// The dist/claude dir of @nanonets/graft resolved from a base whose node_modules is searched.
|
||||
// dist/claude inside @nanonets/graft, resolved from a directory npm searches.
|
||||
function fromPkg(base) {
|
||||
try {
|
||||
const pkg = require.resolve('@nanonets/graft/package.json', { paths: [base] });
|
||||
@@ -14,7 +14,7 @@ function fromPkg(base) {
|
||||
} catch { return null; }
|
||||
}
|
||||
|
||||
// The global node_modules dir per npm (handles Homebrew/Windows/volta). Queried on demand.
|
||||
// The global node_modules directory, as npm reports it. Queried only when needed.
|
||||
function globalRoot() {
|
||||
try {
|
||||
const root = execFileSync('npm', ['root', '-g'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], shell: process.platform === 'win32' }).trim();
|
||||
@@ -22,14 +22,14 @@ function globalRoot() {
|
||||
} catch { return null; /* npm unavailable */ }
|
||||
}
|
||||
|
||||
// The version of the package a dist/claude dir belongs to, or null if unreadable.
|
||||
// The version of the package that owns a dist/claude directory, or null.
|
||||
function versionOf(distClaude) {
|
||||
try {
|
||||
return JSON.parse(fs.readFileSync(path.join(distClaude, '..', '..', 'package.json'), 'utf8')).version || null;
|
||||
} catch { return null; }
|
||||
}
|
||||
|
||||
// Numeric-dotted compare of the release part; an unreadable version loses to any known one.
|
||||
// Compares dotted version numbers. An unreadable version counts as older.
|
||||
function newer(a, b) {
|
||||
if (!a) return false;
|
||||
if (!b) return true;
|
||||
@@ -42,7 +42,7 @@ function newer(a, b) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The highest-versioned dir in `dirs` that actually contains `name`, or null.
|
||||
// The highest-versioned entry in `dirs` that contains `name`, or null.
|
||||
function best(dirs, name) {
|
||||
let bestDir = null, bestVer = null;
|
||||
for (const d of dirs) {
|
||||
@@ -54,14 +54,14 @@ function best(dirs, name) {
|
||||
}
|
||||
|
||||
function entry(name) {
|
||||
// Cheap candidates first, and only shell out to npm when every one of them misses.
|
||||
// Check the cheap candidates first, and run npm only if none of them match.
|
||||
const cheap = [BAKED, fromPkg(dir), fromPkg(path.join(path.dirname(process.execPath), '..', 'lib'))];
|
||||
const hit = best(cheap, name);
|
||||
if (hit) return path.join(hit, name);
|
||||
const gr = globalRoot();
|
||||
const global = gr && path.join(gr, '@nanonets', 'graft', 'dist', 'claude');
|
||||
if (global && fs.existsSync(path.join(global, name))) return path.join(global, name);
|
||||
return path.join(dir, 'dist', 'claude', name); // last-ditch; import will no-op if absent
|
||||
return path.join(dir, 'dist', 'claude', name); // fallback; the import does nothing when the file is absent
|
||||
}
|
||||
|
||||
import(pathToFileURL(entry("statusline.js")).href).then((m) => m.main()).catch(() => { /* graft unavailable, no-op */ });
|
||||
import(pathToFileURL(entry("statusline.js")).href).then((m) => m.main()).catch(() => { /* graft is unavailable: do nothing */ });
|
||||
+10
-4
@@ -1,9 +1,10 @@
|
||||
# CMake build directories
|
||||
# Build output. /build/ holds the default trees; the other two patterns cover a
|
||||
# BUILD_DIR override and the trees that earlier script versions left at the root.
|
||||
/build/
|
||||
/build_*/
|
||||
/cmake-build-*/
|
||||
|
||||
# Windows output staging
|
||||
# Windows distribution staging
|
||||
/SerumAlt_Windows/
|
||||
|
||||
# CMake generated files
|
||||
@@ -12,10 +13,15 @@ compile_commands.json
|
||||
|
||||
# IDE and OS files
|
||||
.vscode/
|
||||
.idea/
|
||||
.idea
|
||||
*.user
|
||||
.DS_Store
|
||||
.cache/
|
||||
|
||||
# graft's local graph cache — regenerable, not committed (run `graft build`).
|
||||
# Upstream JUCE release binaries. They ship with the vendored copy and are not
|
||||
# built here; committing them would add 22 MB of Linux executables.
|
||||
/third_party/JUCE/DemoRunner
|
||||
/third_party/JUCE/Projucer
|
||||
|
||||
# graft's local graph cache, regenerable and not committed (run `graft build`).
|
||||
/graft/
|
||||
@@ -62,11 +62,12 @@ safety fixes practical, without adding a generic framework.
|
||||
Read README.md's Building section before changing scripts, dependencies, or CMake.
|
||||
It is the maintained source for prerequisites, options and artifact paths.
|
||||
|
||||
- Linux production: `./build_linux.sh`.
|
||||
- macOS production, on a Mac: `./build_macos.sh`.
|
||||
- Windows x64 VST3, cross-compiled on Linux: `./build_windows.sh`.
|
||||
- Native QA build and execution: `./build_harness.sh --run`.
|
||||
- Shell syntax: `for script in build_*.sh; do bash -n "$script"; done`.
|
||||
- Linux production: `./scripts/build_linux.sh`.
|
||||
- macOS production, on a Mac: `./scripts/build_macos.sh`.
|
||||
- Windows x64 VST3, cross-compiled on Linux: `./scripts/build_windows.sh`.
|
||||
- Native QA build and execution: `./scripts/build_harness.sh --run`.
|
||||
- Shell syntax: `for script in scripts/*.sh; do bash -n "$script"; done`.
|
||||
- Build output removal: `./scripts/clean.sh --dry-run`, then the flags you need.
|
||||
|
||||
Production scripts explicitly enable `SERUMALT_BUILD_PLUGIN` and disable
|
||||
`SERUMALT_BUILD_TESTS`. The harness script does the reverse in a separate directory.
|
||||
@@ -74,10 +75,11 @@ Building `SerumAltTest` alone does not execute it; `--run` invokes CTest.
|
||||
When changing CMake, verify production has no `SerumAltTest` target and the
|
||||
harness-only build has no `SerumAlt`, VST3, AU, or Standalone target.
|
||||
|
||||
Keep existing build trees and local changes intact. Use a new `BUILD_DIR` for
|
||||
clean-build verification. Use a fresh Windows `OUTPUT_DIR` for distribution checks,
|
||||
since staging does not remove extra files. Never edit generated CMakeCache.txt files.
|
||||
The checked-in MinGW toolchain is the single source of cross-compiler configuration.
|
||||
Keep existing build trees and local changes intact. Each script defaults to a
|
||||
directory under `build/`; use a new `BUILD_DIR` for clean-build verification. Use a
|
||||
fresh Windows `OUTPUT_DIR` for distribution checks, since staging does not remove
|
||||
extra files. Never edit generated CMakeCache.txt files. The checked-in
|
||||
`cmake/mingw64-toolchain.cmake` is the single source of cross-compiler configuration.
|
||||
|
||||
## Current source layout
|
||||
|
||||
@@ -95,7 +97,7 @@ The lowercase `Source/engine`, `modulation`, `params`, `plugin`, and `synth`
|
||||
directories currently hold guidance, not relocated implementations. Consult their
|
||||
`AGENTS.md` files when editing the related root-level sources. Consult the matching
|
||||
`AGENTS.md` when editing an existing implementation subdirectory.
|
||||
`AUDIT_REPORT.md` is a historical audit and proposed refactor, not a pending
|
||||
`docs/AUDIT_REPORT.md` is a historical audit and proposed refactor, not a pending
|
||||
instruction to move files. Update the explicit source list and includes only when
|
||||
an actual source move is part of the requested task.
|
||||
|
||||
|
||||
@@ -2,9 +2,6 @@ cmake_minimum_required(VERSION 3.22)
|
||||
|
||||
project(SerumAlt VERSION 1.0.0 LANGUAGES CXX)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# C++ standard
|
||||
# ---------------------------------------------------------------------------
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
@@ -16,9 +13,6 @@ if(NOT SERUMALT_BUILD_PLUGIN AND NOT SERUMALT_BUILD_TESTS)
|
||||
message(FATAL_ERROR "Enable SERUMALT_BUILD_PLUGIN or SERUMALT_BUILD_TESTS")
|
||||
endif()
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# JUCE
|
||||
# ---------------------------------------------------------------------------
|
||||
if(NOT DEFINED JUCE_ROOT)
|
||||
set(JUCE_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/third_party/JUCE")
|
||||
endif()
|
||||
@@ -54,7 +48,6 @@ set(SERUMALT_SOURCES
|
||||
Source/EffectUnits/Reverb.cpp
|
||||
Source/GUI/Knob.cpp
|
||||
Source/GUI/KnobLookAndFeel.cpp
|
||||
Source/GUI/Slider.cpp
|
||||
Source/GUI/ToggleButton.cpp
|
||||
Source/GUI/Display.cpp
|
||||
Source/GUI/WaveformDisplay.cpp
|
||||
|
||||
@@ -74,14 +74,15 @@ keeps its previous settings if an edit is still in progress.
|
||||
|
||||
## Building
|
||||
|
||||
Each script configures and builds its own directory. Production builds disable the
|
||||
QA harness explicitly; the harness script creates no plugin or standalone targets.
|
||||
JUCE 7.0.12 is vendored under `third_party/JUCE` and is not downloaded by the scripts.
|
||||
The scripts live in `scripts/`. Each configures and builds its own directory under
|
||||
`build/`. Production builds disable the QA harness explicitly; the harness script
|
||||
creates no plugin or standalone targets. JUCE 7.0.12 is vendored under
|
||||
`third_party/JUCE` and is not downloaded by the scripts.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
All scripts require Bash, CMake 3.22+, Ninja, and C/C++17 compilers. The harness
|
||||
also uses CTest, included with CMake, when invoked with `--run`.
|
||||
The build scripts require Bash, CMake 3.22+, Ninja, and C/C++17 compilers. The
|
||||
harness script also uses CTest, included with CMake, when invoked with `--run`.
|
||||
|
||||
On Linux, install GCC or Clang, `pkg-config`, and the ALSA, FreeType, X11 and OpenGL
|
||||
development libraries. For Debian/Ubuntu:
|
||||
@@ -120,40 +121,42 @@ sudo apt install gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 binutils-mingw-w64-x8
|
||||
|
||||
On Arch/CachyOS, use `sudo pacman -S --needed mingw-w64-gcc` instead. Keep the
|
||||
native Linux tools and libraries installed: JUCE builds `juceaide` for the host
|
||||
before compiling the Windows plugin. The checked-in `mingw64-toolchain.cmake`
|
||||
before compiling the Windows plugin. The checked-in `cmake/mingw64-toolchain.cmake`
|
||||
selects the `x86_64-w64-mingw32-*` tools and isolates target library searches.
|
||||
|
||||
### Production builds
|
||||
|
||||
| Host | Command | Build directory | Formats |
|
||||
| --- | --- | --- | --- |
|
||||
| Linux | `./build_linux.sh` | `build_linux/` | VST3, Standalone |
|
||||
| macOS | `./build_macos.sh` | `build_macos/` | VST3, AU, Standalone |
|
||||
| Linux targeting Windows x64 | `./build_windows.sh` | `build_windows/` | VST3 only |
|
||||
| Linux | `./scripts/build_linux.sh` | `build/linux/` | VST3, Standalone |
|
||||
| macOS | `./scripts/build_macos.sh` | `build/macos/` | VST3, AU, Standalone |
|
||||
| Linux targeting Windows x64 | `./scripts/build_windows.sh` | `build/windows/` | VST3 only |
|
||||
|
||||
Default Release artifacts:
|
||||
|
||||
- Linux: `build_linux/SerumAlt_artefacts/Release/VST3/SerumAlt.vst3` and
|
||||
`build_linux/SerumAlt_artefacts/Release/Standalone/SerumAlt`.
|
||||
- macOS: `build_macos/SerumAlt_artefacts/Release/VST3/SerumAlt.vst3`,
|
||||
`build_macos/SerumAlt_artefacts/Release/AU/SerumAlt.component`, and
|
||||
`build_macos/SerumAlt_artefacts/Release/Standalone/SerumAlt.app`.
|
||||
- Windows: `build_windows/SerumAlt_artefacts/Release/VST3/SerumAlt.vst3`, also
|
||||
- Linux: `build/linux/SerumAlt_artefacts/Release/VST3/SerumAlt.vst3` and
|
||||
`build/linux/SerumAlt_artefacts/Release/Standalone/SerumAlt`.
|
||||
- macOS: `build/macos/SerumAlt_artefacts/Release/VST3/SerumAlt.vst3`,
|
||||
`build/macos/SerumAlt_artefacts/Release/AU/SerumAlt.component`, and
|
||||
`build/macos/SerumAlt_artefacts/Release/Standalone/SerumAlt.app`.
|
||||
- Windows: `build/windows/SerumAlt_artefacts/Release/VST3/SerumAlt.vst3`, also
|
||||
copied to `SerumAlt_Windows/SerumAlt.vst3`.
|
||||
|
||||
The Windows script reuses the toolchain file without rewriting it. It injects
|
||||
`moduleinfo.json` because the cross-compiled JUCE manifest helper cannot run on
|
||||
Linux. Keep this manifest's metadata in sync with `CMakeLists.txt`,
|
||||
`cmake/Plugin.cmake`, and the vendored VST3 SDK. MinGW links its C++ and threading
|
||||
runtimes statically via `-static-libgcc -static-libstdc++ -static`. Before staging,
|
||||
the script verifies the linked module is x86-64, imports none of those MinGW
|
||||
runtimes, and exports the VST3 entry points, so a module that a stock Windows host
|
||||
could not load fails the build instead of being staged silently.
|
||||
The Windows script reuses the toolchain file without rewriting it. A cross-build
|
||||
cannot run JUCE's manifest helper, because that helper is a host tool, so the
|
||||
script copies the `moduleinfo.json` that CMake writes from
|
||||
`cmake/moduleinfo.json.in`. The plugin name, version, vendor, class IDs and VST3
|
||||
SDK version come from variables in `cmake/Plugin.cmake`, so a version bump reaches
|
||||
the manifest on its own. MinGW links its C++ and threading runtimes statically via
|
||||
`-static-libgcc -static-libstdc++ -static`. Before staging, the script verifies the
|
||||
linked module is x86-64, imports none of those MinGW runtimes, and exports the VST3
|
||||
entry points, so a module that a stock Windows host could not load fails the build
|
||||
instead of being staged silently.
|
||||
|
||||
macOS builds target the host architecture by default. To request a universal binary:
|
||||
|
||||
```bash
|
||||
CMAKE_OSX_ARCHITECTURES='arm64;x86_64' ./build_macos.sh
|
||||
CMAKE_OSX_ARCHITECTURES='arm64;x86_64' ./scripts/build_macos.sh
|
||||
```
|
||||
|
||||
`CMAKE_OSX_DEPLOYMENT_TARGET` can also be passed to that script. Architecture and
|
||||
@@ -166,22 +169,22 @@ and do not install plugins into a DAW's plugin directories.
|
||||
On Linux or macOS, build the console harness without production targets:
|
||||
|
||||
```bash
|
||||
./build_harness.sh
|
||||
./scripts/build_harness.sh
|
||||
```
|
||||
|
||||
Build and run the checks:
|
||||
|
||||
```bash
|
||||
./build_harness.sh --run
|
||||
./scripts/build_harness.sh --run
|
||||
```
|
||||
|
||||
Or rerun an already-built Release harness:
|
||||
|
||||
```bash
|
||||
ctest --test-dir build_harness --build-config Release --output-on-failure --no-tests=error
|
||||
ctest --test-dir build/harness --build-config Release --output-on-failure --no-tests=error
|
||||
```
|
||||
|
||||
The executable is `build_harness/SerumAltTest_artefacts/Release/SerumAltTest`.
|
||||
The executable is `build/harness/SerumAltTest_artefacts/Release/SerumAltTest`.
|
||||
It renders the initial state and every factory preset, checks for non-finite
|
||||
samples and aggregate non-silence, and exercises the RAVE toggle. A failed check
|
||||
returns a nonzero exit status. This is a processor integration smoke test, not a
|
||||
@@ -204,8 +207,8 @@ library. It is built and run natively, not as a Windows cross-compiled executabl
|
||||
For example:
|
||||
|
||||
```bash
|
||||
BUILD_TYPE=Debug BUILD_DIR=build_harness_debug ./build_harness.sh --run
|
||||
CMAKE_BUILD_PARALLEL_LEVEL=4 ./build_linux.sh
|
||||
BUILD_TYPE=Debug BUILD_DIR=build/harness_debug ./scripts/build_harness.sh --run
|
||||
CMAKE_BUILD_PARALLEL_LEVEL=4 ./scripts/build_linux.sh
|
||||
```
|
||||
|
||||
`CMakeLists.txt` owns the shared source list and target configuration.
|
||||
@@ -216,9 +219,9 @@ For direct CMake use, `SERUMALT_BUILD_PLUGIN` defaults to `ON` and
|
||||
`SERUMALT_BUILD_TESTS` defaults to `OFF`. A harness-only configure is:
|
||||
|
||||
```bash
|
||||
cmake -S . -B build_harness -G Ninja -DCMAKE_BUILD_TYPE=Release \
|
||||
cmake -S . -B build/harness -G Ninja -DCMAKE_BUILD_TYPE=Release \
|
||||
-DSERUMALT_BUILD_PLUGIN=OFF -DSERUMALT_BUILD_TESTS=ON
|
||||
cmake --build build_harness --target SerumAltTest
|
||||
cmake --build build/harness --target SerumAltTest
|
||||
```
|
||||
|
||||
An existing CMake cache retains its old option values; changing the defaults does
|
||||
@@ -229,12 +232,11 @@ when configuring directly with CMake.
|
||||
### Fresh builds
|
||||
|
||||
The scripts reuse their build directories without deleting files, resetting Git,
|
||||
or installing packages. Generated `build/`, `build_*/`, and `SerumAlt_Windows/`
|
||||
directories are git-ignored. Leave existing builds intact and select an unused
|
||||
build directory for a fresh configure:
|
||||
or installing packages. `build/` and `SerumAlt_Windows/` are git-ignored. Leave
|
||||
existing builds intact and select an unused build directory for a fresh configure:
|
||||
|
||||
```bash
|
||||
BUILD_DIR=build_linux_fresh ./build_linux.sh
|
||||
BUILD_DIR=build/linux_fresh ./scripts/build_linux.sh
|
||||
```
|
||||
|
||||
Windows staging updates generated files without deleting extra files already in
|
||||
@@ -242,9 +244,27 @@ the destination. For a clean distribution bundle, choose unused build and output
|
||||
paths together:
|
||||
|
||||
```bash
|
||||
BUILD_DIR=build_windows_fresh OUTPUT_DIR=build_windows_fresh/staged ./build_windows.sh
|
||||
BUILD_DIR=build/windows_fresh OUTPUT_DIR=build/windows_fresh/staged ./scripts/build_windows.sh
|
||||
```
|
||||
|
||||
### Cleaning
|
||||
|
||||
`scripts/clean.sh` removes generated output. A plain run removes the build trees
|
||||
under `build/`; `--staging` adds `SerumAlt_Windows/`, `--legacy` adds the
|
||||
`build_*` and `cmake-build-*` trees that earlier versions of the scripts left in
|
||||
the repository root, and `--all` is both. `--dry-run` prints every path with its
|
||||
size and removes nothing.
|
||||
|
||||
```bash
|
||||
./scripts/clean.sh --dry-run --all
|
||||
./scripts/clean.sh --all
|
||||
```
|
||||
|
||||
The script never removes a tracked file, anything under `Source/`, `third_party/`
|
||||
or `.git`, or a path outside the repository. It refuses to run when `BUILD_DIR` or
|
||||
`OUTPUT_DIR` names a directory outside the repository, because such a directory
|
||||
belongs to another checkout.
|
||||
|
||||
## License
|
||||
|
||||
JUCE is licensed separately (see `third_party/JUCE/LICENSE.md`). This project is
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
- Related editor implementation: `../PluginEditor.h`, `../PluginEditor.cpp`
|
||||
- Knob.h, Knob.cpp
|
||||
- Slider.h, Slider.cpp
|
||||
- KnobLookAndFeel.h, KnobLookAndFeel.cpp
|
||||
- ToggleButton.h, ToggleButton.cpp
|
||||
- Display.h, Display.cpp
|
||||
- Panel.h, Panel.cpp
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
#include "Slider.h"
|
||||
|
||||
namespace serum
|
||||
{
|
||||
|
||||
Slider::Slider (const juce::String& name, std::function<juce::String (float)> fmt)
|
||||
: Knob (name, std::move (fmt))
|
||||
{
|
||||
setSliderStyle (juce::Slider::LinearHorizontal);
|
||||
setTextBoxStyle (juce::Slider::NoTextBox, false, 0, 0);
|
||||
}
|
||||
|
||||
} // namespace serum
|
||||
@@ -1,18 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "Knob.h"
|
||||
|
||||
namespace serum
|
||||
{
|
||||
|
||||
// ===========================================================================
|
||||
// Horizontal slider (same formatting machinery as Knob).
|
||||
// ===========================================================================
|
||||
class Slider : public Knob
|
||||
{
|
||||
public:
|
||||
explicit Slider (const juce::String& name,
|
||||
std::function<juce::String (float)> formatter = {});
|
||||
};
|
||||
|
||||
} // namespace serum
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <JuceHeader.h>
|
||||
#include "PluginProcessor.h"
|
||||
#include "GUI/Knob.h"
|
||||
#include "GUI/Slider.h"
|
||||
#include "GUI/ToggleButton.h"
|
||||
#include "GUI/Display.h"
|
||||
#include "GUI/Panel.h"
|
||||
|
||||
@@ -22,6 +22,8 @@ public:
|
||||
void prepareToPlay (double sampleRate, int samplesPerBlock) override;
|
||||
void releaseResources() override;
|
||||
void processBlock (juce::AudioBuffer<float>&, juce::MidiBuffer&) override;
|
||||
// Keeps the base class double-precision overload visible, so it is not hidden.
|
||||
using juce::AudioProcessor::processBlock;
|
||||
|
||||
juce::AudioProcessorEditor* createEditor() override;
|
||||
bool hasEditor() const override { return true; }
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
## IF-THEN
|
||||
|
||||
- IF a check fails THEN increment the failure count and print the preset name.
|
||||
- Build and run natively from the repository root with `./build_harness.sh --run`. Building the `SerumAltTest` target alone does not run checks.
|
||||
- Build and run natively from the repository root with `./scripts/build_harness.sh --run`. Building the `SerumAltTest` target alone does not run checks.
|
||||
- The harness-only configuration sets `SERUMALT_BUILD_PLUGIN=OFF` and `SERUMALT_BUILD_TESTS=ON`. Production scripts disable the harness.
|
||||
- The harness links the real processor and editor sources but creates no plugin bundles. Keep that build separation when adding checks.
|
||||
|
||||
|
||||
@@ -1,167 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# ---------------------------------------------------------------------------
|
||||
# build_windows.sh, cross-compile SerumAlt VST3 for Windows using MinGW-w64
|
||||
# ---------------------------------------------------------------------------
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
cd "$SCRIPT_DIR"
|
||||
|
||||
TOOLCHAIN_FILE="$SCRIPT_DIR/mingw64-toolchain.cmake"
|
||||
BUILD_DIR="${BUILD_DIR:-$SCRIPT_DIR/build_windows}"
|
||||
BUILD_TYPE="${BUILD_TYPE:-Release}"
|
||||
OUTPUT_DIR="${OUTPUT_DIR:-$SCRIPT_DIR/SerumAlt_Windows}"
|
||||
PLUGIN_NAME="SerumAlt"
|
||||
export CMAKE_BUILD_PARALLEL_LEVEL="${CMAKE_BUILD_PARALLEL_LEVEL:-2}"
|
||||
|
||||
if [[ "$(uname -s)" != Linux ]]; then
|
||||
echo "ERROR: build_windows.sh cross-compiles from Linux using MinGW-w64." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 1. Check for the host tools and MinGW-w64 cross-compiler.
|
||||
for tool in cmake ninja pkg-config "${CC:-cc}" "${CXX:-c++}" \
|
||||
x86_64-w64-mingw32-gcc x86_64-w64-mingw32-g++ \
|
||||
x86_64-w64-mingw32-windres x86_64-w64-mingw32-ar \
|
||||
x86_64-w64-mingw32-ranlib x86_64-w64-mingw32-strip \
|
||||
x86_64-w64-mingw32-objdump; do
|
||||
if ! command -v "$tool" >/dev/null 2>&1; then
|
||||
echo "ERROR: $tool not found. See README.md prerequisites." >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Found: $(command -v x86_64-w64-mingw32-g++)"
|
||||
|
||||
# 2. Use the checked-in CMake toolchain file without overwriting it.
|
||||
if [[ ! -f "$TOOLCHAIN_FILE" ]]; then
|
||||
echo "ERROR: Toolchain file not found: $TOOLCHAIN_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "Using toolchain file: $TOOLCHAIN_FILE"
|
||||
|
||||
# 3. Configure with CMake + Ninja (VST3-only cross build, no test harness).
|
||||
echo "Configuring Windows VST3 in $BUILD_DIR ($BUILD_TYPE)..."
|
||||
cmake -S "$SCRIPT_DIR" -B "$BUILD_DIR" -G Ninja \
|
||||
-DCMAKE_BUILD_TYPE="$BUILD_TYPE" \
|
||||
-DCMAKE_TOOLCHAIN_FILE="$TOOLCHAIN_FILE" \
|
||||
-DSERUMALT_BUILD_PLUGIN=ON \
|
||||
-DSERUMALT_BUILD_TESTS=OFF
|
||||
|
||||
# 4. Build the VST3 target.
|
||||
echo "Building Windows VST3..."
|
||||
cmake --build "$BUILD_DIR" --config "$BUILD_TYPE" --target SerumAlt_VST3
|
||||
|
||||
# 5. Verify the linked module can load on a stock Windows host.
|
||||
# The MinGW C++/threading runtimes are not part of this bundle and do not exist
|
||||
# on a stock Windows machine, so a module that still imports one of them fails
|
||||
# to load and the host then omits the plugin from its scan list. The static
|
||||
# -runtime link options in cmake/Plugin.cmake are meant to prevent that; check
|
||||
# it here so a stale build tree or a dropped flag fails the build loudly
|
||||
# instead of shipping a bundle that appears nowhere in the host.
|
||||
VST3_BUNDLE="$BUILD_DIR/${PLUGIN_NAME}_artefacts/$BUILD_TYPE/VST3/$PLUGIN_NAME.vst3"
|
||||
VST3_BINARY="$VST3_BUNDLE/Contents/x86_64-win/$PLUGIN_NAME.vst3"
|
||||
if [[ ! -f "$VST3_BINARY" ]]; then
|
||||
echo "ERROR: cross-build produced no module at $VST3_BINARY" >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! x86_64-w64-mingw32-objdump -f "$VST3_BINARY" | grep -q 'i386:x86-64'; then
|
||||
echo "ERROR: $VST3_BINARY is not an x86-64 module" >&2
|
||||
exit 1
|
||||
fi
|
||||
VST3_DUMP="$(x86_64-w64-mingw32-objdump -p "$VST3_BINARY")"
|
||||
for runtime in libgcc_s_seh-1.dll libstdc++-6.dll libwinpthread-1.dll; do
|
||||
if grep -qF "DLL Name: $runtime" <<<"$VST3_DUMP"; then
|
||||
echo "ERROR: $VST3_BINARY still imports $runtime." >&2
|
||||
echo " A stock Windows host cannot resolve it and will not list the" >&2
|
||||
echo " plugin. Restore the static-runtime link options in" >&2
|
||||
echo " cmake/Plugin.cmake and rebuild with a fresh BUILD_DIR." >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
# JUCE implements only these three module entry points on Windows; bundleEntry and
|
||||
# bundleExit are macOS-only, and the VST3 SDK's Windows loader requires only
|
||||
# GetPluginFactory, treating InitDll/ExitDll as optional.
|
||||
for entry in GetPluginFactory InitDll ExitDll; do
|
||||
if ! grep -qE "[[:space:]]${entry}\$" <<<"$VST3_DUMP"; then
|
||||
echo "ERROR: $VST3_BINARY does not export $entry" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# 6. Inject the VST3 moduleinfo.json.
|
||||
# The automatic manifest step is disabled when cross-compiling (see
|
||||
# cmake/Plugin.cmake), because JUCE's manifest helper is a host tool that would
|
||||
# otherwise be built as a Windows executable. The moduleinfo content is
|
||||
# deterministic for this Windows plugin. It depends on the plugin's
|
||||
# name, manufacturer/plugin codes, and version, so we write the same metadata
|
||||
# that the native Windows helper generates. Keep it in sync with the metadata
|
||||
# in CMakeLists.txt and cmake/Plugin.cmake, including the vendored VST3 SDK version.
|
||||
echo "Writing Windows VST3 manifest..."
|
||||
mkdir -p "$VST3_BUNDLE/Contents/Resources"
|
||||
cat > "$VST3_BUNDLE/Contents/Resources/moduleinfo.json" <<'EOF'
|
||||
{
|
||||
"Name": "SerumAlt",
|
||||
"Version": "1.0.0",
|
||||
"Factory Info": {
|
||||
"Vendor": "SerumAlt Audio",
|
||||
"URL": "",
|
||||
"E-Mail": "",
|
||||
"Flags": {
|
||||
"Unicode": true,
|
||||
"Classes Discardable": false,
|
||||
"Component Non Discardable": false
|
||||
}
|
||||
},
|
||||
"Classes": [
|
||||
{
|
||||
"CID": "ABCDEF019182FAEB53616C7453657261",
|
||||
"Category": "Audio Module Class",
|
||||
"Name": "SerumAlt",
|
||||
"Vendor": "SerumAlt Audio",
|
||||
"Version": "1.0.0",
|
||||
"SDKVersion": "VST 3.7.8",
|
||||
"Sub Categories": [
|
||||
"Instrument",
|
||||
"Synth"
|
||||
],
|
||||
"Class Flags": 2,
|
||||
"Cardinality": 2147483647,
|
||||
"Snapshots": []
|
||||
},
|
||||
{
|
||||
"CID": "ABCDEF011234ABCD53616C7453657261",
|
||||
"Category": "Component Controller Class",
|
||||
"Name": "SerumAlt",
|
||||
"Vendor": "SerumAlt Audio",
|
||||
"Version": "1.0.0",
|
||||
"SDKVersion": "VST 3.7.8",
|
||||
"Sub Categories": [
|
||||
"Instrument",
|
||||
"Synth"
|
||||
],
|
||||
"Class Flags": 2,
|
||||
"Cardinality": 2147483647,
|
||||
"Snapshots": []
|
||||
},
|
||||
{
|
||||
"CID": "ABCDEF01C0DEF00D53616C7453657261",
|
||||
"Category": "Plugin Compatibility Class",
|
||||
"Name": "SerumAlt",
|
||||
"Vendor": "SerumAlt Audio",
|
||||
"Version": "1.0.0",
|
||||
"SDKVersion": "VST 3.7.8",
|
||||
"Class Flags": 0,
|
||||
"Cardinality": 2147483647,
|
||||
"Snapshots": []
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
|
||||
# 7. Copy the resulting .vst3 bundle to SerumAlt_Windows/ without deleting files.
|
||||
echo "Staging Windows VST3 in $OUTPUT_DIR..."
|
||||
cmake -E copy_directory "$VST3_BUNDLE" "$OUTPUT_DIR/$PLUGIN_NAME.vst3"
|
||||
|
||||
echo
|
||||
echo "Done. Windows VST3 plugin at: $OUTPUT_DIR/$PLUGIN_NAME.vst3"
|
||||
+1
-3
@@ -1,6 +1,4 @@
|
||||
# ---------------------------------------------------------------------------
|
||||
# Headless QA harness (console app that drives the processor and checks output)
|
||||
# ---------------------------------------------------------------------------
|
||||
# Headless QA harness: a console app that drives the processor and checks output.
|
||||
juce_add_console_app(SerumAltTest)
|
||||
serumalt_configure_target(SerumAltTest)
|
||||
target_sources(SerumAltTest PRIVATE Source/Tests/TestMain.cpp)
|
||||
|
||||
+32
-19
@@ -1,14 +1,32 @@
|
||||
# ---------------------------------------------------------------------------
|
||||
# Plugin target
|
||||
# ---------------------------------------------------------------------------
|
||||
# JUCE 7.0.12 builds its VST3 manifest helper (juce_vst3_helper) with the same
|
||||
# toolchain as the plugin itself. When cross-compiling, that produces a Windows
|
||||
# .exe which cannot run on the Linux build host, so we disable the automatic
|
||||
# manifest step and inject a Windows moduleinfo.json afterwards
|
||||
# (see build_windows.sh). Native builds keep the automatic step.
|
||||
# Plugin target.
|
||||
|
||||
# Plugin metadata. It lives here once because juce_add_plugin and the cross-build
|
||||
# VST3 manifest in cmake/moduleinfo.json.in both need the same values.
|
||||
set(SERUMALT_COMPANY_NAME "SerumAlt Audio")
|
||||
set(SERUMALT_MANUFACTURER_CODE Salt)
|
||||
set(SERUMALT_PLUGIN_CODE Sera)
|
||||
set(SERUMALT_VST3_SDK_VERSION "VST 3.7.8") # ships with the vendored JUCE 7.0.12
|
||||
|
||||
# VST3 class IDs. Each is a fixed prefix, a per-class constant and the
|
||||
# manufacturer and plugin codes as ASCII hex, built the same way JUCE builds
|
||||
# them in juce_audio_plugin_client_VST3.cpp.
|
||||
string(HEX "${SERUMALT_MANUFACTURER_CODE}${SERUMALT_PLUGIN_CODE}" serumaltCodeHex)
|
||||
string(TOUPPER "${serumaltCodeHex}" serumaltCodeHex)
|
||||
set(SERUMALT_CID_AUDIO_MODULE "ABCDEF019182FAEB${serumaltCodeHex}")
|
||||
set(SERUMALT_CID_CONTROLLER "ABCDEF011234ABCD${serumaltCodeHex}")
|
||||
set(SERUMALT_CID_COMPATIBILITY "ABCDEF01C0DEF00D${serumaltCodeHex}")
|
||||
|
||||
# JUCE builds its VST3 manifest helper with the target toolchain, so during a
|
||||
# Windows cross-build that helper is a Windows .exe and cannot run on the Linux
|
||||
# host. Disable the automatic step and write the manifest from the template
|
||||
# instead. Native builds keep JUCE's automatic step.
|
||||
set(SERUMALT_VST3_AUTO_MANIFEST TRUE)
|
||||
if(CMAKE_CROSSCOMPILING)
|
||||
set(SERUMALT_VST3_AUTO_MANIFEST FALSE)
|
||||
configure_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/moduleinfo.json.in"
|
||||
"${CMAKE_BINARY_DIR}/moduleinfo.json"
|
||||
@ONLY)
|
||||
endif()
|
||||
|
||||
set(SERUMALT_FORMATS VST3)
|
||||
@@ -21,14 +39,14 @@ endif()
|
||||
|
||||
juce_add_plugin(SerumAlt
|
||||
VERSION ${PROJECT_VERSION}
|
||||
COMPANY_NAME "SerumAlt Audio"
|
||||
COMPANY_NAME "${SERUMALT_COMPANY_NAME}"
|
||||
IS_SYNTH TRUE
|
||||
NEEDS_MIDI_INPUT TRUE
|
||||
NEEDS_MIDI_OUTPUT FALSE
|
||||
IS_MIDI_EFFECT FALSE
|
||||
EDITOR_WANTS_KEYBOARD_FOCUS FALSE
|
||||
PLUGIN_MANUFACTURER_CODE Salt
|
||||
PLUGIN_CODE Sera
|
||||
PLUGIN_MANUFACTURER_CODE ${SERUMALT_MANUFACTURER_CODE}
|
||||
PLUGIN_CODE ${SERUMALT_PLUGIN_CODE}
|
||||
BUNDLE_ID com.serumalt.SerumAlt
|
||||
FORMATS ${SERUMALT_FORMATS}
|
||||
PRODUCT_NAME "SerumAlt"
|
||||
@@ -36,14 +54,9 @@ juce_add_plugin(SerumAlt
|
||||
|
||||
serumalt_configure_target(SerumAlt)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# MinGW cross-build: static C++/threading runtime
|
||||
# ---------------------------------------------------------------------------
|
||||
# When cross-compiling for Windows with MinGW, link libgcc / libstdc++ /
|
||||
# winpthread statically so the VST3 DLL is self-contained. Otherwise the DLL
|
||||
# imports libgcc_s_seh-1.dll, libstdc++-6.dll and libwinpthread-1.dll, none of
|
||||
# which ship with the bundle (or exist on a stock Windows host), so the host's
|
||||
# scan would fail to load the plugin. Native (Linux) builds are unaffected.
|
||||
# A MinGW cross-build must link libgcc, libstdc++ and winpthread statically.
|
||||
# A stock Windows host has none of those DLLs, so a dynamic link produces a
|
||||
# module that fails to load and disappears from the host's plugin list.
|
||||
if(MINGW)
|
||||
target_link_options(SerumAlt_VST3 PRIVATE
|
||||
-static-libgcc
|
||||
|
||||
File renamed without changes.
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"Name": "@PROJECT_NAME@",
|
||||
"Version": "@PROJECT_VERSION@",
|
||||
"Factory Info": {
|
||||
"Vendor": "@SERUMALT_COMPANY_NAME@",
|
||||
"URL": "",
|
||||
"E-Mail": "",
|
||||
"Flags": {
|
||||
"Unicode": true,
|
||||
"Classes Discardable": false,
|
||||
"Component Non Discardable": false
|
||||
}
|
||||
},
|
||||
"Classes": [
|
||||
{
|
||||
"CID": "@SERUMALT_CID_AUDIO_MODULE@",
|
||||
"Category": "Audio Module Class",
|
||||
"Name": "@PROJECT_NAME@",
|
||||
"Vendor": "@SERUMALT_COMPANY_NAME@",
|
||||
"Version": "@PROJECT_VERSION@",
|
||||
"SDKVersion": "@SERUMALT_VST3_SDK_VERSION@",
|
||||
"Sub Categories": [
|
||||
"Instrument",
|
||||
"Synth"
|
||||
],
|
||||
"Class Flags": 2,
|
||||
"Cardinality": 2147483647,
|
||||
"Snapshots": []
|
||||
},
|
||||
{
|
||||
"CID": "@SERUMALT_CID_CONTROLLER@",
|
||||
"Category": "Component Controller Class",
|
||||
"Name": "@PROJECT_NAME@",
|
||||
"Vendor": "@SERUMALT_COMPANY_NAME@",
|
||||
"Version": "@PROJECT_VERSION@",
|
||||
"SDKVersion": "@SERUMALT_VST3_SDK_VERSION@",
|
||||
"Sub Categories": [
|
||||
"Instrument",
|
||||
"Synth"
|
||||
],
|
||||
"Class Flags": 2,
|
||||
"Cardinality": 2147483647,
|
||||
"Snapshots": []
|
||||
},
|
||||
{
|
||||
"CID": "@SERUMALT_CID_COMPATIBILITY@",
|
||||
"Category": "Plugin Compatibility Class",
|
||||
"Name": "@PROJECT_NAME@",
|
||||
"Vendor": "@SERUMALT_COMPANY_NAME@",
|
||||
"Version": "@PROJECT_VERSION@",
|
||||
"SDKVersion": "@SERUMALT_VST3_SDK_VERSION@",
|
||||
"Class Flags": 0,
|
||||
"Cardinality": 2147483647,
|
||||
"Snapshots": []
|
||||
}
|
||||
]
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -1,10 +1,11 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build the headless QA harness. Pass --run to execute it through CTest.
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
cd "$SCRIPT_DIR"
|
||||
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
BUILD_DIR="${BUILD_DIR:-$SCRIPT_DIR/build_harness}"
|
||||
BUILD_DIR="${BUILD_DIR:-$REPO_ROOT/build/harness}"
|
||||
BUILD_TYPE="${BUILD_TYPE:-Release}"
|
||||
export CMAKE_BUILD_PARALLEL_LEVEL="${CMAKE_BUILD_PARALLEL_LEVEL:-2}"
|
||||
|
||||
@@ -17,7 +18,7 @@ TOOLS=(cmake ninja "${CC:-cc}" "${CXX:-c++}")
|
||||
case "$(uname -s)" in
|
||||
Linux) TOOLS+=(pkg-config) ;;
|
||||
Darwin) TOOLS+=(xcrun) ;;
|
||||
*) echo "ERROR: build_harness.sh requires a native Linux or macOS host." >&2; exit 1 ;;
|
||||
*) echo "ERROR: scripts/build_harness.sh requires a Linux or macOS host." >&2; exit 1 ;;
|
||||
esac
|
||||
if [[ $# -eq 1 ]]; then
|
||||
TOOLS+=(ctest)
|
||||
@@ -33,8 +34,8 @@ if [[ "$(uname -s)" == Darwin ]]; then
|
||||
xcrun --sdk macosx --show-sdk-path
|
||||
fi
|
||||
|
||||
echo "Configuring the native QA harness only in $BUILD_DIR ($BUILD_TYPE)..."
|
||||
cmake -S "$SCRIPT_DIR" -B "$BUILD_DIR" -G Ninja \
|
||||
echo "Configuring the native QA harness in $BUILD_DIR ($BUILD_TYPE)..."
|
||||
cmake -S "$REPO_ROOT" -B "$BUILD_DIR" -G Ninja \
|
||||
-DCMAKE_BUILD_TYPE="$BUILD_TYPE" \
|
||||
-DSERUMALT_BUILD_PLUGIN=OFF \
|
||||
-DSERUMALT_BUILD_TESTS=ON
|
||||
@@ -1,15 +1,16 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build the Linux production plugin: VST3 and Standalone.
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
cd "$SCRIPT_DIR"
|
||||
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
BUILD_DIR="${BUILD_DIR:-$SCRIPT_DIR/build_linux}"
|
||||
BUILD_DIR="${BUILD_DIR:-$REPO_ROOT/build/linux}"
|
||||
BUILD_TYPE="${BUILD_TYPE:-Release}"
|
||||
export CMAKE_BUILD_PARALLEL_LEVEL="${CMAKE_BUILD_PARALLEL_LEVEL:-2}"
|
||||
|
||||
if [[ "$(uname -s)" != Linux ]]; then
|
||||
echo "ERROR: build_linux.sh requires a Linux host." >&2
|
||||
echo "ERROR: scripts/build_linux.sh requires a Linux host." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -21,7 +22,7 @@ for tool in cmake ninja pkg-config "${CC:-cc}" "${CXX:-c++}"; do
|
||||
done
|
||||
|
||||
echo "Configuring Linux production targets in $BUILD_DIR ($BUILD_TYPE)..."
|
||||
cmake -S "$SCRIPT_DIR" -B "$BUILD_DIR" -G Ninja \
|
||||
cmake -S "$REPO_ROOT" -B "$BUILD_DIR" -G Ninja \
|
||||
-DCMAKE_BUILD_TYPE="$BUILD_TYPE" \
|
||||
-DSERUMALT_BUILD_PLUGIN=ON \
|
||||
-DSERUMALT_BUILD_TESTS=OFF
|
||||
@@ -1,15 +1,16 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build the macOS production plugin: VST3, AU and Standalone.
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
cd "$SCRIPT_DIR"
|
||||
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
BUILD_DIR="${BUILD_DIR:-$SCRIPT_DIR/build_macos}"
|
||||
BUILD_DIR="${BUILD_DIR:-$REPO_ROOT/build/macos}"
|
||||
BUILD_TYPE="${BUILD_TYPE:-Release}"
|
||||
export CMAKE_BUILD_PARALLEL_LEVEL="${CMAKE_BUILD_PARALLEL_LEVEL:-2}"
|
||||
|
||||
if [[ "$(uname -s)" != Darwin ]]; then
|
||||
echo "ERROR: build_macos.sh requires macOS and the Apple SDK." >&2
|
||||
echo "ERROR: scripts/build_macos.sh requires macOS and the Apple SDK." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -30,7 +31,7 @@ if [[ -n "${CMAKE_OSX_DEPLOYMENT_TARGET:-}" ]]; then
|
||||
fi
|
||||
|
||||
echo "Configuring macOS production targets in $BUILD_DIR ($BUILD_TYPE)..."
|
||||
cmake -S "$SCRIPT_DIR" -B "$BUILD_DIR" -G Ninja \
|
||||
cmake -S "$REPO_ROOT" -B "$BUILD_DIR" -G Ninja \
|
||||
"${OSX_OPTIONS[@]}" \
|
||||
-DSERUMALT_BUILD_PLUGIN=ON \
|
||||
-DSERUMALT_BUILD_TESTS=OFF
|
||||
Executable
+93
@@ -0,0 +1,93 @@
|
||||
#!/usr/bin/env bash
|
||||
# Cross-compile the Windows x64 VST3 from Linux with MinGW-w64.
|
||||
set -euo pipefail
|
||||
|
||||
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
TOOLCHAIN_FILE="$REPO_ROOT/cmake/mingw64-toolchain.cmake"
|
||||
BUILD_DIR="${BUILD_DIR:-$REPO_ROOT/build/windows}"
|
||||
BUILD_TYPE="${BUILD_TYPE:-Release}"
|
||||
OUTPUT_DIR="${OUTPUT_DIR:-$REPO_ROOT/SerumAlt_Windows}"
|
||||
PLUGIN_NAME="SerumAlt"
|
||||
export CMAKE_BUILD_PARALLEL_LEVEL="${CMAKE_BUILD_PARALLEL_LEVEL:-2}"
|
||||
|
||||
if [[ "$(uname -s)" != Linux ]]; then
|
||||
echo "ERROR: scripts/build_windows.sh cross-compiles from Linux with MinGW-w64." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for tool in cmake ninja pkg-config "${CC:-cc}" "${CXX:-c++}" \
|
||||
x86_64-w64-mingw32-gcc x86_64-w64-mingw32-g++ \
|
||||
x86_64-w64-mingw32-windres x86_64-w64-mingw32-ar \
|
||||
x86_64-w64-mingw32-ranlib x86_64-w64-mingw32-strip \
|
||||
x86_64-w64-mingw32-objdump; do
|
||||
if ! command -v "$tool" >/dev/null 2>&1; then
|
||||
echo "ERROR: $tool not found. See README.md prerequisites." >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ ! -f "$TOOLCHAIN_FILE" ]]; then
|
||||
echo "ERROR: toolchain file not found: $TOOLCHAIN_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Configuring Windows VST3 in $BUILD_DIR ($BUILD_TYPE)..."
|
||||
cmake -S "$REPO_ROOT" -B "$BUILD_DIR" -G Ninja \
|
||||
-DCMAKE_BUILD_TYPE="$BUILD_TYPE" \
|
||||
-DCMAKE_TOOLCHAIN_FILE="$TOOLCHAIN_FILE" \
|
||||
-DSERUMALT_BUILD_PLUGIN=ON \
|
||||
-DSERUMALT_BUILD_TESTS=OFF
|
||||
|
||||
echo "Building Windows VST3..."
|
||||
cmake --build "$BUILD_DIR" --config "$BUILD_TYPE" --target SerumAlt_VST3
|
||||
|
||||
# A stock Windows host has neither the MinGW C++ runtime nor the MinGW threading
|
||||
# runtime, so a module that imports one fails to load and the host drops it from
|
||||
# its plugin list. cmake/Plugin.cmake links both statically; these checks fail the
|
||||
# build when that link option is missing from a cached or a fresh build tree.
|
||||
VST3_BUNDLE="$BUILD_DIR/${PLUGIN_NAME}_artefacts/$BUILD_TYPE/VST3/$PLUGIN_NAME.vst3"
|
||||
VST3_BINARY="$VST3_BUNDLE/Contents/x86_64-win/$PLUGIN_NAME.vst3"
|
||||
if [[ ! -f "$VST3_BINARY" ]]; then
|
||||
echo "ERROR: cross-build produced no module at $VST3_BINARY" >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! x86_64-w64-mingw32-objdump -f "$VST3_BINARY" | grep -q 'i386:x86-64'; then
|
||||
echo "ERROR: $VST3_BINARY is not an x86-64 module" >&2
|
||||
exit 1
|
||||
fi
|
||||
VST3_DUMP="$(x86_64-w64-mingw32-objdump -p "$VST3_BINARY")"
|
||||
for runtime in libgcc_s_seh-1.dll libstdc++-6.dll libwinpthread-1.dll; do
|
||||
if grep -qF "DLL Name: $runtime" <<<"$VST3_DUMP"; then
|
||||
echo "ERROR: $VST3_BINARY still imports $runtime." >&2
|
||||
echo " Restore the static-runtime link options in cmake/Plugin.cmake" >&2
|
||||
echo " and rebuild with a fresh BUILD_DIR." >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
# JUCE defines only these entry points on Windows. bundleEntry and bundleExit are
|
||||
# macOS-only, and the VST3 SDK loader requires GetPluginFactory while treating
|
||||
# InitDll and ExitDll as optional.
|
||||
for entry in GetPluginFactory InitDll ExitDll; do
|
||||
if ! grep -qE "[[:space:]]${entry}\$" <<<"$VST3_DUMP"; then
|
||||
echo "ERROR: $VST3_BINARY does not export $entry" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# JUCE's manifest helper is a host tool, so a cross-build disables it and CMake
|
||||
# writes moduleinfo.json from cmake/moduleinfo.json.in instead.
|
||||
MANIFEST="$BUILD_DIR/moduleinfo.json"
|
||||
if [[ ! -f "$MANIFEST" ]]; then
|
||||
echo "ERROR: CMake wrote no manifest at $MANIFEST" >&2
|
||||
exit 1
|
||||
fi
|
||||
mkdir -p "$VST3_BUNDLE/Contents/Resources"
|
||||
cmake -E copy "$MANIFEST" "$VST3_BUNDLE/Contents/Resources/moduleinfo.json"
|
||||
|
||||
echo "Staging Windows VST3 in $OUTPUT_DIR..."
|
||||
cmake -E copy_directory "$VST3_BUNDLE" "$OUTPUT_DIR/$PLUGIN_NAME.vst3"
|
||||
|
||||
echo
|
||||
echo "Done. Windows VST3 plugin at: $OUTPUT_DIR/$PLUGIN_NAME.vst3"
|
||||
Executable
+137
@@ -0,0 +1,137 @@
|
||||
#!/usr/bin/env bash
|
||||
# Remove generated build output from this checkout.
|
||||
#
|
||||
# Targets are limited to directories this project generates. Nothing tracked by
|
||||
# git is removed, and Source/, third_party/, .git and the other project
|
||||
# directories are refused even if they are named as a target.
|
||||
set -euo pipefail
|
||||
|
||||
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage: scripts/clean.sh [options]
|
||||
|
||||
Removes generated build output. With no options it removes the build trees
|
||||
under build/.
|
||||
|
||||
Options:
|
||||
--staging also remove the staged Windows bundle, SerumAlt_Windows/
|
||||
--legacy also remove build trees left in the repository root by earlier
|
||||
versions of the build scripts (build_*, cmake-build-*)
|
||||
--all --staging and --legacy together
|
||||
--dry-run print every path and its size, and remove nothing
|
||||
-h, --help print this text
|
||||
EOF
|
||||
}
|
||||
|
||||
DRY_RUN=false
|
||||
STAGING=false
|
||||
LEGACY=false
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--dry-run) DRY_RUN=true ;;
|
||||
--staging) STAGING=true ;;
|
||||
--legacy) LEGACY=true ;;
|
||||
--all) STAGING=true; LEGACY=true ;;
|
||||
-h|--help) usage; exit 0 ;;
|
||||
*) echo "ERROR: unknown option: $arg" >&2; usage >&2; exit 2 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if ! command -v git >/dev/null 2>&1; then
|
||||
echo "ERROR: git is required to confirm that no tracked file is removed." >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
# A build directory outside the repository belongs to some other checkout, and
|
||||
# this script has no business deciding whether it is disposable.
|
||||
for var in BUILD_DIR OUTPUT_DIR; do
|
||||
value="${!var:-}"
|
||||
[ -n "$value" ] || continue
|
||||
case "$value" in
|
||||
/*) abs="$value" ;;
|
||||
*) abs="$REPO_ROOT/$value" ;;
|
||||
esac
|
||||
abs="$(realpath -m -- "$abs" 2>/dev/null || printf '%s' "$abs")"
|
||||
case "$abs" in
|
||||
"$REPO_ROOT"/*) ;;
|
||||
*)
|
||||
echo "ERROR: $var=$value resolves outside $REPO_ROOT." >&2
|
||||
echo " Unset $var to clean this repository." >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
PROTECTED=(Source third_party .git scripts cmake docs graft)
|
||||
|
||||
refused=0
|
||||
removed=0
|
||||
|
||||
remove_target() {
|
||||
local path="$1"
|
||||
[ -e "$path" ] || return 0
|
||||
|
||||
local abs rel size
|
||||
abs="$(realpath -m -- "$path")"
|
||||
rel="${abs#"$REPO_ROOT"/}"
|
||||
|
||||
case "$abs" in
|
||||
"$REPO_ROOT"/*) ;;
|
||||
*)
|
||||
echo "refusing, outside the repository: $abs" >&2
|
||||
refused=$((refused + 1))
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
local deny
|
||||
for deny in "${PROTECTED[@]}"; do
|
||||
if [ "$rel" = "$deny" ] || [ "${rel#"$deny"/}" != "$rel" ]; then
|
||||
echo "refusing, protected path: $rel" >&2
|
||||
refused=$((refused + 1))
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -n "$(git ls-files -- "$rel")" ]; then
|
||||
echo "refusing, tracked by git: $rel" >&2
|
||||
refused=$((refused + 1))
|
||||
return 1
|
||||
fi
|
||||
|
||||
size="$(du -sh -- "$rel" 2>/dev/null | cut -f1)"
|
||||
if [ "$DRY_RUN" = true ]; then
|
||||
printf 'would remove %6s %s\n' "${size:-?}" "$rel"
|
||||
else
|
||||
rm -rf -- "$abs"
|
||||
printf 'removed %6s %s\n' "${size:-?}" "$rel"
|
||||
fi
|
||||
removed=$((removed + 1))
|
||||
}
|
||||
|
||||
TARGETS=("$REPO_ROOT/build")
|
||||
if [ "$STAGING" = true ]; then
|
||||
TARGETS+=("$REPO_ROOT/SerumAlt_Windows")
|
||||
fi
|
||||
if [ "$LEGACY" = true ]; then
|
||||
shopt -s nullglob
|
||||
for dir in "$REPO_ROOT"/build_* "$REPO_ROOT"/cmake-build-*; do
|
||||
TARGETS+=("$dir")
|
||||
done
|
||||
shopt -u nullglob
|
||||
fi
|
||||
|
||||
for target in "${TARGETS[@]}"; do
|
||||
remove_target "$target" || true
|
||||
done
|
||||
|
||||
if [ "$removed" -eq 0 ] && [ "$refused" -eq 0 ]; then
|
||||
echo "Nothing to remove."
|
||||
elif [ "$DRY_RUN" = true ]; then
|
||||
echo "Dry run: $removed path(s) listed, nothing removed."
|
||||
fi
|
||||
|
||||
[ "$refused" -eq 0 ]
|
||||
Reference in new issue
Block a user