-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuild.zig
More file actions
315 lines (280 loc) · 12.3 KB
/
Copy pathbuild.zig
File metadata and controls
315 lines (280 loc) · 12.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
const std = @import("std");
const VERSION = "0.1.0";
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
// Danzig library (static)
const danzig_lib = b.addLibrary(.{
.name = "danzig",
.root_module = b.createModule(.{
.root_source_file = b.path("src/root.zig"),
.target = target,
.optimize = optimize,
}),
.linkage = .static,
});
// Danzig module for import by other targets
const danzig_module = b.addModule("danzig", .{
.root_source_file = b.path("src/root.zig"),
});
// Danzig gain VST3 plugin (shared, embeds danzig)
const danzig_gain = b.addLibrary(.{
.name = "DanzigGain",
.root_module = b.createModule(.{
.root_source_file = b.path("examples/danzig-gain/root.zig"),
.target = target,
.optimize = optimize,
}),
.linkage = .dynamic,
});
danzig_gain.root_module.addImport("danzig", danzig_module);
danzig_gain.root_module.linkLibrary(danzig_lib);
// Install to zig-out/lib/
b.installArtifact(danzig_gain);
// Integration harness. Links the plugin itself so it can call the exported
// GetPluginFactory entry point and drive it through the raw VST3 C ABI.
const danzig_test = b.addExecutable(.{
.name = "danzig_test",
.root_module = b.createModule(.{
.root_source_file = b.path("examples/danzig-test/root.zig"),
.target = target,
.optimize = optimize,
}),
});
danzig_test.root_module.addImport("danzig", danzig_module);
danzig_test.root_module.linkLibrary(danzig_lib);
danzig_test.root_module.linkLibrary(danzig_gain);
b.installArtifact(danzig_test);
// Minimal plugin template. Built twice from one source: as the shared
// library a host would load, and as an executable so the DSP can be run
// and checked without a host.
const danzig_minimal = b.addLibrary(.{
.name = "DanzigMinimal",
.root_module = b.createModule(.{
.root_source_file = b.path("examples/danzig-minimal/root.zig"),
.target = target,
.optimize = optimize,
}),
.linkage = .dynamic,
});
danzig_minimal.root_module.addImport("danzig", danzig_module);
danzig_minimal.root_module.linkLibrary(danzig_lib);
b.installArtifact(danzig_minimal);
const danzig_minimal_demo = b.addExecutable(.{
.name = "danzig-minimal",
.root_module = b.createModule(.{
.root_source_file = b.path("examples/danzig-minimal/root.zig"),
.target = target,
.optimize = optimize,
}),
});
danzig_minimal_demo.root_module.addImport("danzig", danzig_module);
danzig_minimal_demo.root_module.linkLibrary(danzig_lib);
b.installArtifact(danzig_minimal_demo);
const run_minimal = b.addRunArtifact(danzig_minimal_demo);
const run_minimal_step = b.step("run-minimal", "Run the minimal plugin template offline");
run_minimal_step.dependOn(&run_minimal.step);
// Two demo executables still call std APIs that Zig 0.16 removed:
// std.process.argsAlloc and std.fs.cwd. Porting them means threading an
// std.Io.Threaded handle through demo code, which buys nothing for the
// library itself, so they are skipped on 0.16 until that is worth doing.
// The library, the VST3 plugin and the whole test suite build there.
const demos_supported = @import("builtin").zig_version.minor < 16;
if (demos_supported) {
// Standalone audio processor
const danzig_gain_standalone = b.addExecutable(.{
.name = "danzig-gain-standalone",
.root_module = b.createModule(.{
.root_source_file = b.path("examples/danzig-gain-standalone/root.zig"),
.target = target,
.optimize = optimize,
}),
});
danzig_gain_standalone.root_module.addImport("danzig", danzig_module);
danzig_gain_standalone.root_module.linkLibrary(danzig_lib);
b.installArtifact(danzig_gain_standalone);
const run_standalone = b.addRunArtifact(danzig_gain_standalone);
const run_standalone_step = b.step("run-standalone", "Run the standalone audio processor");
run_standalone_step.dependOn(&run_standalone.step);
// Web UI server
const danzig_webui = b.addExecutable(.{
.name = "danzig-webui",
.root_module = b.createModule(.{
.root_source_file = b.path("examples/danzig-webui/root.zig"),
.target = target,
.optimize = optimize,
}),
});
danzig_webui.root_module.addImport("danzig", danzig_module);
danzig_webui.root_module.linkLibrary(danzig_lib);
b.installArtifact(danzig_webui);
}
// --- Universal VST3 bundle (macOS) ---------------------------------------
//
// A VST3 plugin ships as a bundle holding one universal binary, so hosts of
// either architecture load the same file. Built per-arch and merged with
// lipo. Kept behind the `vst3` step rather than the default install,
// because it doubles compile work and only applies to macOS.
if (target.result.os.tag == .macos) {
addVst3Bundle(b, optimize, danzig_module);
}
// --- GUI example (macOS) -------------------------------------------------
//
// Needs the webview dependency, so it is only wired up when that has been
// fetched. Links CoreAudio for device IO and WebKit via webview.
// webview-zig's own build.zig.zon still carries a pre-0.16 hash format that
// Zig 0.16 rejects, so the GUI example cannot be built there until upstream
// updates. Everything else in danzig works on 0.16.
const webview_supported = @import("builtin").zig_version.minor < 16;
if (target.result.os.tag == .macos and webview_supported) {
if (b.lazyDependency("webview", .{ .target = target, .optimize = optimize })) |webview_dep| {
addGuiExample(b, target, optimize, danzig_module, danzig_lib, webview_dep);
}
}
// Unit tests — pure Zig, no artifact or host required
const unit_tests = b.addTest(.{
.root_module = b.createModule(.{
.root_source_file = b.path("src/tests.zig"),
.target = target,
.optimize = optimize,
}),
});
const run_unit_tests = b.addRunArtifact(unit_tests);
const unit_test_step = b.step("test-unit", "Run unit tests only");
unit_test_step.dependOn(&run_unit_tests.step);
// Integration tests — drives the built plugin through the raw VST3 C ABI
const run_test = b.addRunArtifact(danzig_test);
const integration_test_step = b.step("test-integration", "Run VST3 ABI integration tests only");
integration_test_step.dependOn(&run_test.step);
// Test step
const test_step = b.step("test", "Run tests");
test_step.dependOn(&run_unit_tests.step);
test_step.dependOn(&run_test.step);
}
/// Build DanzigGain for both macOS architectures, merge them into one
/// universal binary, and lay out the .vst3 bundle around it.
fn addVst3Bundle(
b: *std.Build,
optimize: std.builtin.OptimizeMode,
danzig_module: *std.Build.Module,
) void {
const arches = [_]std.Target.Cpu.Arch{ .aarch64, .x86_64 };
const suffixes = [_][]const u8{ "arm64", "x86" };
const lipo = b.addSystemCommand(&.{ "lipo", "-create" });
inline for (arches, suffixes) |arch, suffix| {
const arch_target = b.resolveTargetQuery(.{ .cpu_arch = arch, .os_tag = .macos });
const lib = b.addLibrary(.{
.name = "danzig_" ++ suffix,
.root_module = b.createModule(.{
.root_source_file = b.path("src/root.zig"),
.target = arch_target,
.optimize = optimize,
}),
.linkage = .static,
});
const plugin = b.addLibrary(.{
.name = "DanzigGain_" ++ suffix,
.root_module = b.createModule(.{
.root_source_file = b.path("examples/danzig-gain/root.zig"),
.target = arch_target,
.optimize = optimize,
}),
.linkage = .dynamic,
});
plugin.root_module.addImport("danzig", danzig_module);
plugin.root_module.linkLibrary(lib);
b.installArtifact(plugin);
lipo.addArtifactArg(plugin);
}
lipo.addArg("-output");
const universal = lipo.addOutputFileArg("DanzigGain");
// VST3 bundles carry no file extension on the executable itself.
const bundle = b.addWriteFiles();
_ = bundle.add("Contents/Info.plist", infoPlist(b));
_ = bundle.add("Contents/PkgInfo", "BNDL????");
_ = bundle.addCopyFile(universal, "Contents/MacOS/DanzigGain");
const install_bundle = b.addInstallDirectory(.{
.source_dir = bundle.getDirectory(),
.install_dir = .prefix,
.install_subdir = "DanzigGain.vst3",
});
const vst3_step = b.step("vst3", "Build and package the universal VST3 bundle");
vst3_step.dependOn(&install_bundle.step);
// Hosts scan ~/Library/Audio/Plug-Ins/VST3 on macOS.
const install_cmd = b.addSystemCommand(&.{ "sh", "-c", "rm -rf \"$HOME/Library/Audio/Plug-Ins/VST3/DanzigGain.vst3\" && " ++
"mkdir -p \"$HOME/Library/Audio/Plug-Ins/VST3\" && " ++
"cp -R \"$1\" \"$HOME/Library/Audio/Plug-Ins/VST3/DanzigGain.vst3\"", "sh" });
install_cmd.addDirectoryArg(bundle.getDirectory());
const install_vst3_step = b.step("install-vst3", "Install the VST3 bundle to ~/Library/Audio/Plug-Ins/VST3/");
install_vst3_step.dependOn(&install_cmd.step);
}
/// Standalone GUI host: a webview front end driving the gain processor over
/// CoreAudio.
fn addGuiExample(
b: *std.Build,
target: std.Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
danzig_module: *std.Build.Module,
danzig_lib: *std.Build.Step.Compile,
webview_dep: *std.Build.Dependency,
) void {
const coreaudio_module = b.addModule("coreaudio", .{
.root_source_file = b.path("examples/danzig-gain-ui/coreaudio.zig"),
});
const gui = b.addExecutable(.{
.name = "danzig-gain-ui",
.root_module = b.createModule(.{
.root_source_file = b.path("examples/danzig-gain-ui/root.zig"),
.target = target,
.optimize = optimize,
}),
});
gui.root_module.addImport("danzig", danzig_module);
gui.root_module.addImport("coreaudio", coreaudio_module);
gui.root_module.addImport("webview", webview_dep.module("webview"));
// The Zig bindings are declarations only; the implementation is webview's
// C++ core, which the dependency exposes as a static library.
gui.root_module.linkLibrary(webview_dep.artifact("webviewStatic"));
// The UI is embedded rather than read at runtime, so the binary is
// self-contained.
gui.root_module.addAnonymousImport("ui_html", .{ .root_source_file = b.path("ui/index.html") });
gui.root_module.linkLibrary(danzig_lib);
gui.root_module.linkFramework("CoreAudio", .{});
gui.root_module.linkFramework("CoreFoundation", .{});
b.installArtifact(gui);
const run_gui = b.addRunArtifact(gui);
const run_gui_step = b.step("run-gui", "Run the standalone GUI app");
run_gui_step.dependOn(&run_gui.step);
}
fn infoPlist(b: *std.Build) []const u8 {
const template =
\\<?xml version="1.0" encoding="UTF-8"?>
\\<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
\\<plist version="1.0">
\\<dict>
\\ <key>CFBundleExecutable</key>
\\ <string>DanzigGain</string>
\\ <key>CFBundleIdentifier</key>
\\ <string>com.danzig.DanzigGain</string>
\\ <key>CFBundleName</key>
\\ <string>DanzigGain</string>
\\ <key>CFBundleDisplayName</key>
\\ <string>Danzig Gain</string>
\\ <key>CFBundlePackageType</key>
\\ <string>BNDL</string>
\\ <key>CFBundleSignature</key>
\\ <string>????</string>
\\ <key>CFBundleVersion</key>
\\ <string>{s}</string>
\\ <key>CFBundleShortVersionString</key>
\\ <string>{s}</string>
\\ <key>CFBundleInfoDictionaryVersion</key>
\\ <string>6.0</string>
\\ <key>CSResourcesFileMapped</key>
\\ <true/>
\\</dict>
\\</plist>
\\
;
return b.fmt(template, .{ VERSION, VERSION });
}