schmoothie - a build cache for JUCE

Three-target duplication costs 327.0 CPU-seconds upstream and 131.3 with schmoothie in the current interleaved gate. A second build directory drops from 109.0 to 2.3, and flipping a config flag drops from 94.3 to 8.2. You are paying for the same framework once per target, and every fresh build directory and CI job can pay it again from zero. schmoothie compiles each module once per configuration and reuses it.

Where the time goes

Build a JUCE project and the framework is compiled for every target in it. Measured against stock JUCE on an M4 Max, three identical plugins over one costs 3.10x in Debug, 3.36x in Release and 3.46x with LTO. With schmoothie it is 1.09x.

Measured build cost

Build CPU-seconds, wall-clock time, and objects compiled on macOS arm64, Apple M4 Max, Release, C++20, -j14, LTO off, measured against JUCE 9.0.1. Three-target duplication: 327.0 CPU-seconds and 126 objects stock, 131.3 and 69 with schmoothie. Flipping one config flag: 94.3 and 31 objects stock, 8.2 and 4 with schmoothie. A second build directory: 109.0 and 31 objects stock, 2.3 and 1 with schmoothie. Cold plugin and app builds remain effectively unchanged; the six scenarios were interleaved to control for machine drift.

Configure stops compiling things

A stock JUCE project compiles a helper binary inside your configure step, before your own first object file exists. It is serial, your core count does not help, and every fresh build directory and every CI job pays it again. Stock cold configure costs 8.4 seconds wall and 22.4 CPU-seconds. With schmoothie it is 0.6 seconds wall and 0.7 CPU-seconds.

Why the binaries can be trusted

All 23 linkable modules are built both ways and compared: same defined external symbols, every time. A real two-product VST3 and CLAP tree built both ways gives 7908 symbols per VST3 with zero differences, identical parameter surfaces, identical audio for identical input, identical state round-trips, and CPU per processBlock within 1.4 percent. AU, VST3 and Standalone bundles pass pluginval 1.0.4 at strictness 10. A mismatched build fails to compile rather than producing a binary. A shared library cross-compiled to arm64-v8a on android-34 matches 8194 symbols.

What it does not fix

One incremental case costs more: editing a header that every module reaches rebuilds 24 objects against 19. The other three are identical to a stock build. Editing your own source rebuilds 1 object either way, editing a widget source rebuilds 1 either way, and editing a widget header rebuilds 9 either way. A single target built once on one machine gains nothing beyond the configure step; the savings are in repetition.

Against ccache and unity builds

Measured, not asserted, and tuned with CCACHE_BASEDIR and CCACHE_NOHASHDIR. On the three-plugin build ccache gets 4 hits out of 130 and costs 427.6 CPU-seconds against 384.3 without it. On a second build directory it gets 0 of 63. ccache answers the question "have I compiled precisely this before", and on a JUCE tree the answer is usually no, because each target compiles the framework with its own defines and its own generated header. Unity builds have little left to give, because JUCE modules already ship as unity files. Keep ccache; it still serves your own objects and the two compose.

Where it is proved

macOS arm64 is verified on Ninja and Xcode, Debug and Release, with the full smoke suite. Android arm64-v8a is verified on NDK 27.2 and android-34. iOS compiles, with a simulator cross-compile smoke passing on Xcode 26.2. Linux and Windows jobs are written and sitting in CI and neither has completed a green run yet, so neither is a claim, and every number on this page is macOS.

What a licence includes

A drop-in CMake layer, so your existing juce_add_plugin and juce_add_gui_app calls keep working unchanged. A shared build cache a whole CI fleet can point at. A configure step that compiles nothing before your project starts. The 11-scenario benchmark harness that produced every number here, with committed baselines. The CI suite that gates every release: symbol parity across all 23 modules, plugin validation at strictness 10, and runtime parity in a host. Support, and rebases onto newer JUCE releases. schmoothie does not replace your JUCE licence or change what you owe under it. Delivery terms are settled per engagement.

Request access to schmoothie