Three plugins in one JUCE repository cost 540.6 CPU-seconds to build in Release. One plugin costs 160.4. You are paying three times for the same framework, and every fresh build directory and every CI job pays it again from zero. Kiln compiles each module once per configuration and reuses the result. The three-plugin build drops to 189.1 CPU-seconds. The second build directory drops to 3.0.
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 Kiln it is 1.12x.
Build CPU-seconds, macOS arm64, Apple M4 Max, Release, no LTO, cold cache per scenario. Hello-world GUI app cold: 157.8 stock, 142.1 with Kiln. One plugin in three formats: 160.4 stock, 169.3 with Kiln. Three plugins in one format: 540.6 stock, 189.1 with Kiln, a 65 percent cut. A second build directory: 141.8 stock, 3.0 with Kiln, a 98 percent cut. Flipping one config flag: 146.2 stock, 142.0 with Kiln. Two of these effects are real and three are run-to-run noise, and the page says which.
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 Kiln it is 0.6 seconds wall and 0.7 CPU-seconds.
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.
Some edits cost more with Kiln than without. Editing a widget source file inside juce_gui_basics rebuilds 8 objects against 1. Editing a juce_core header rebuilds 34 against 22. Flipping a config macro is still a full rebuild, 34 objects either way. A single target built once on one machine gains nothing beyond the configure step. The savings are in repetition: more targets, more build directories, more CI jobs.
Measured, not asserted. On the three-plugin build ccache gets 2 hits out of 150, tuned with CCACHE_BASEDIR and CCACHE_NOHASHDIR. On a second build directory it gets 15 of 98. 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.
macOS arm64 is verified on Ninja and Xcode, Debug and Release. iOS compiles, with a simulator cross-compile smoke passing on Xcode 26.2. Android arm64-v8a is verified on NDK 27.2 and android-34. Linux and Windows are untested and no numbers are claimed for them.
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. It applies to the JUCE checkout you already licence; it does not redistribute JUCE and does not change your obligations to Raw Material Software.