Building the Universal VST3 Bundle
macOS ships on two architectures. A plugin bundle holds one universal binary so that hosts of either architecture load the same file.
zig build vst3
That step, in build.zig, does four things.
1. Compiles the plugin twice. Once for aarch64-macos and once for
x86_64-macos, via b.resolveTargetQuery. Zig cross-compiles both from
whichever machine you are on, so no second toolchain is needed.
const arches = [_]std.Target.Cpu.Arch{ .aarch64, .x86_64 };
const suffixes = [_][]const u8{ "arm64", "x86" };
inline for (arches, suffixes) |arch, suffix| {
const arch_target = b.resolveTargetQuery(.{ .cpu_arch = arch, .os_tag = .macos });
// ... build danzig_<suffix> and DanzigGain_<suffix>
lipo.addArtifactArg(plugin);
}
2. Merges them with lipo. b.addSystemCommand(&.{ "lipo", "-create" })
collects both artifacts and writes one fat Mach-O into the build cache. The
output path is a build-graph node, so the merge reruns only when an input
changes.
3. Lays out the bundle. b.addWriteFiles() builds the directory:
DanzigGain.vst3/
Contents/
Info.plist generated from a template in build.zig
PkgInfo the 8 bytes "BNDL????"
MacOS/
DanzigGain the universal binary, no file extension
The executable carries no extension. That is a bundle requirement, and it is why the lipo output is copied rather than installed under its library name.
4. Installs into zig-out/. The result is
zig-out/DanzigGain.vst3.
Then:
zig build install-vst3
removes any existing copy and copies the bundle to
$HOME/Library/Audio/Plug-Ins/VST3/DanzigGain.vst3, which is where macOS hosts
scan.
The bundle is kept behind its own step rather than the default install because it doubles the compile work and only applies to macOS.
Sizes, from a ReleaseFast build:
| Artifact | Size |
|---|---|
zig-out/DanzigGain.vst3/Contents/MacOS/DanzigGain | 84 KB (universal) |
zig-out/lib/libDanzigGain.dylib | 52 KB (arm64) |
zig-out/lib/libDanzigMinimal.dylib | 52 KB (arm64) |
zig-out/bin/danzig-minimal | 168 KB |
The same artifacts in the default Debug build run about 1 to 2 MB each.