-
Notifications
You must be signed in to change notification settings - Fork 18
Expand file tree
/
Copy pathbuild.zig
More file actions
396 lines (336 loc) · 12.7 KB
/
build.zig
File metadata and controls
396 lines (336 loc) · 12.7 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
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
const std = @import("std");
const Build = std.Build;
const builtin = @import("builtin");
const zlua = @import("zlua");
const sokol = @import("sokol");
const system_sdk = @import("system-sdk");
const fs = std.fs;
const log = std.log;
var target: Build.ResolvedTarget = undefined;
var optimize: std.builtin.OptimizeMode = undefined;
const Backend = enum {
sokol,
headless,
null,
};
const ModuleImport = struct {
module: *Build.Module,
name: []const u8,
};
const BuildCollection = struct {
add_imports: []const ModuleImport,
link_libraries: []const *Build.Step.Compile,
};
pub fn build(b: *std.Build) !void {
target = b.standardTargetOptions(.{});
optimize = b.standardOptimizeOption(.{});
const backend = b.option(
Backend,
"backend",
"Backend for Delve Framework to use. sokol, headless, or null",
) orelse .sokol;
const options = b.addOptions();
options.addOption(Backend, "backend", backend);
const dep_sokol = b.dependency("sokol", .{
.target = target,
.optimize = optimize,
.with_sokol_imgui = true,
});
const dep_zlua = b.dependency("zlua", .{
.target = target,
.optimize = optimize,
.lang = .lua54,
.additional_system_headers = if (target.result.cpu.arch.isWasm()) getEmsdkSystemIncludePath(dep_sokol).getPath(b) else "",
.can_use_jmp = !target.result.cpu.arch.isWasm(),
});
const dep_zmesh = b.dependency("zmesh", .{
.target = target,
.optimize = optimize,
});
const dep_zaudio = b.dependency("zaudio", .{
.target = target,
.optimize = optimize,
});
const dep_zstbi = b.dependency("zstbi", .{
.target = target,
.optimize = optimize,
});
const dep_cimgui = b.dependency("cimgui", .{
.target = target,
.optimize = optimize,
});
const dep_stb_truetype = b.dependency("stb_truetype", .{
.target = target,
.optimize = optimize,
});
const dep_yamlz = b.dependency("ymlz", .{
.target = target,
.optimize = optimize,
});
// inject the cimgui header search path into the sokol C library compile step
dep_sokol.artifact("sokol_clib").addIncludePath(dep_cimgui.path("src"));
dep_stb_truetype.artifact("stb_truetype").addIncludePath(b.path("3rdparty/stb_truetype/libs"));
const sokol_item: ModuleImport = .{ .module = dep_sokol.module("sokol"), .name = "sokol" };
const zlua_item: ModuleImport = .{ .module = dep_zlua.module("zlua"), .name = "zlua" };
const zmesh_item: ModuleImport = .{ .module = dep_zmesh.module("root"), .name = "zmesh" };
const zstbi_item: ModuleImport = .{ .module = dep_zstbi.module("root"), .name = "zstbi" };
const zaudio_item: ModuleImport = .{ .module = dep_zaudio.module("root"), .name = "zaudio" };
const cimgui_item: ModuleImport = .{ .module = dep_cimgui.module("cimgui"), .name = "cimgui" };
const stb_truetype_item: ModuleImport = .{ .module = dep_stb_truetype.module("root"), .name = "stb_truetype" };
const ymlz_item: ModuleImport = .{ .module = dep_yamlz.module("root"), .name = "ymlz" };
const delve_module_imports = [_]ModuleImport{
sokol_item,
zlua_item,
zmesh_item,
zstbi_item,
zaudio_item,
cimgui_item,
stb_truetype_item,
ymlz_item,
};
const link_libraries = [_]*Build.Step.Compile{
dep_zmesh.artifact("zmesh"),
dep_zaudio.artifact("miniaudio"),
dep_cimgui.artifact("cimgui_clib"),
dep_stb_truetype.artifact("stb_truetype"),
};
const build_collection: BuildCollection = .{
.add_imports = &delve_module_imports,
.link_libraries = &link_libraries,
};
// Delve module
const delve_mod = b.addModule("delve", .{
.root_source_file = b.path("src/framework/delve.zig"),
.target = target,
.optimize = optimize,
});
delve_mod.addOptions("delve_options", options);
// Expose a few modules, so people can grab our dependencies instead of including their own directly
try b.modules.put("sokol", dep_sokol.module("sokol"));
try b.modules.put("zlua", dep_zlua.module("zlua"));
for (build_collection.add_imports) |build_import| {
delve_mod.addImport(build_import.name, build_import.module);
}
for (build_collection.link_libraries) |lib| {
if (target.result.cpu.arch.isWasm()) {
// ensure these libs all depend on the emcc C lib
lib.step.dependOn(&dep_sokol.artifact("sokol_clib").step);
}
delve_mod.linkLibrary(lib);
}
// For web builds, add the Emscripten system headers so C libraries can find the stdlib headers
if (target.result.cpu.arch.isWasm()) {
const emsdk_include_path = getEmsdkSystemIncludePath(dep_sokol);
b.addSearchPrefix(emsdk_include_path.getPath(b));
delve_mod.addSystemIncludePath(emsdk_include_path);
// Ensure that Lua links under EMCC
const lua_artifact = dep_zlua.artifact("lua");
lua_artifact.step.dependOn(&dep_sokol.artifact("sokol_clib").step);
lua_artifact.addSystemIncludePath(emsdk_include_path);
// add these new system includes to all the libs and modules
for (build_collection.add_imports) |build_import| {
build_import.module.addSystemIncludePath(emsdk_include_path);
}
for (build_collection.link_libraries) |lib| {
lib.addSystemIncludePath(emsdk_include_path);
}
}
const root_module = b.createModule(.{
.root_source_file = b.path("src/framework/delve.zig"),
.target = target,
.optimize = optimize,
});
root_module.addOptions("delve_options", options);
// Delve Static Library artifact
const delve_lib = b.addLibrary(.{
.name = "delve",
.root_module = root_module,
.linkage = .static,
});
b.installArtifact(delve_lib);
// collection of all examples
const examples = [_][]const u8{
"audio",
"sprites",
"sprite-animation",
"clear",
"collision",
"debugdraw",
"easing",
"fonts",
"forest",
"framepacing",
"frustums",
"imgui",
"clipboard",
"lighting",
"lua",
"meshbuilder",
"meshes",
"passes",
"quakemap",
"quakemdl",
"rays",
"skinned-meshes",
"stresstest",
};
for (examples) |example_item| {
try buildExample(b, example_item, delve_mod, delve_lib);
}
// add the build shaders run step, to update the baked in default shaders
buildShaders(b);
// TESTS
const exe_tests = b.addTest(.{
.root_module = root_module,
});
const test_step = b.step("test", "Run unit tests");
test_step.dependOn(&exe_tests.step);
}
fn buildExample(b: *std.Build, example: []const u8, delve_module: *Build.Module, delve_lib: *Build.Step.Compile) !void {
const name: []const u8 = example;
var root_source_buffer = [_]u8{undefined} ** 256;
const root_source_file = try std.fmt.bufPrint(&root_source_buffer, "src/examples/{s}.zig", .{name});
const root_module = b.createModule(.{
.root_source_file = b.path(root_source_file),
.target = target,
.optimize = optimize,
});
var app: *Build.Step.Compile = undefined;
// special case handling for native vs web build
if (target.result.cpu.arch.isWasm()) {
app = b.addLibrary(.{
.name = name,
.root_module = root_module,
.linkage = .static,
});
} else {
app = b.addExecutable(.{
.name = name,
.root_module = root_module,
});
}
app.root_module.addImport("delve", delve_module);
app.linkLibrary(delve_lib);
if (target.result.cpu.arch.isWasm()) {
const dep_sokol = b.dependency("sokol", .{
.target = target,
.optimize = optimize,
.with_sokol_imgui = true,
});
// link with emscripten
const link_step = try emscriptenLinkStep(b, app, dep_sokol);
// and add a run step
const run = emscriptenRunStep(b, example, dep_sokol);
run.step.dependOn(&link_step.step);
var option_buffer = [_]u8{undefined} ** 100;
const run_name = try std.fmt.bufPrint(&option_buffer, "run-{s}", .{name});
var description_buffer = [_]u8{undefined} ** 200;
const descr_name = try std.fmt.bufPrint(&description_buffer, "run {s}", .{name});
b.step(run_name, descr_name).dependOn(&run.step);
} else {
b.installArtifact(app);
const run = b.addRunArtifact(app);
var option_buffer = [_]u8{undefined} ** 100;
const run_name = try std.fmt.bufPrint(&option_buffer, "run-{s}", .{name});
var description_buffer = [_]u8{undefined} ** 200;
const descr_name = try std.fmt.bufPrint(&description_buffer, "run {s}", .{name});
b.step(run_name, descr_name).dependOn(&run.step);
}
}
pub fn emscriptenLinkStep(b: *Build, app: *Build.Step.Compile, dep_sokol: *Build.Dependency) !*Build.Step.InstallDir {
app.root_module.addCMacro("__EMSCRIPTEN__", "1");
const emsdk = dep_sokol.builder.dependency("emsdk", .{});
// Add the Emscripten system include path for the app too
const emsdk_include_path = emsdk.path("upstream/emscripten/cache/sysroot/include");
app.addSystemIncludePath(emsdk_include_path);
return try sokol.emLinkStep(b, .{
.lib_main = app,
.target = target,
.optimize = optimize,
.emsdk = emsdk,
.use_webgl2 = true,
.release_use_closure = false, // causing errors with miniaudio? might need to add a custom exerns file for closure
.use_emmalloc = true,
.use_filesystem = true,
.shell_file_path = dep_sokol.path("src/sokol/web/shell.html"),
.extra_args = &.{
"-sTOTAL_STACK=16MB",
"--preload-file=assets/",
"-sALLOW_MEMORY_GROWTH=1",
"-sSAFE_HEAP=0",
"-sERROR_ON_UNDEFINED_SYMBOLS=0",
},
});
}
pub fn getEmsdkSystemIncludePath(dep_sokol: *Build.Dependency) Build.LazyPath {
const dep_emsdk = dep_sokol.builder.dependency("emsdk", .{});
return dep_emsdk.path("upstream/emscripten/cache/sysroot/include");
}
pub fn emscriptenRunStep(b: *Build, name: []const u8, dep_sokol: *Build.Dependency) *Build.Step.Run {
const emsdk = dep_sokol.builder.dependency("emsdk", .{});
return sokol.emRunStep(b, .{ .name = name, .emsdk = emsdk });
}
// Adds a run step to compile shaders, expects the shader compiler in ../sokol-tools-bin/
fn buildShaders(b: *Build) void {
const sokol_tools_bin_dir = "../sokol-tools-bin/bin/";
const shaders_dir = "assets/shaders/";
const shaders_out_dir = "src/framework/graphics/shaders/";
const shaders = .{
"basic-lighting",
"default",
"default-mesh",
"emissive",
"skinned-basic-lighting",
"skinned",
};
const optional_shdc: ?[:0]const u8 = comptime switch (builtin.os.tag) {
.windows => "win32/sokol-shdc.exe",
.linux => "linux/sokol-shdc",
.macos => if (builtin.cpu.arch.isX86()) "osx/sokol-shdc" else "osx_arm64/sokol-shdc",
else => null,
};
if (optional_shdc == null) {
std.log.warn("unsupported host platform, skipping shader compiler step", .{});
return;
}
const shdc_step = b.step("shaders", "Compile shaders (needs ../sokol-tools-bin)");
const shdc_path = sokol_tools_bin_dir ++ optional_shdc.?;
const slang = "glsl300es:glsl430:wgsl:metal_macos:metal_ios:metal_sim:hlsl4";
// build the .zig versions
inline for (shaders) |shader| {
const shader_with_ext = shader ++ ".glsl";
const cmd = b.addSystemCommand(&.{
shdc_path,
"-i",
shaders_dir ++ shader_with_ext,
"-o",
shaders_out_dir ++ shader_with_ext ++ ".zig",
"-l",
slang,
"-f",
"sokol_zig",
"--reflection",
});
shdc_step.dependOn(&cmd.step);
}
// build the yaml reflection versions
inline for (shaders) |shader| {
const shader_with_ext = shader ++ ".glsl";
fs.cwd().makePath(shaders_dir ++ "built/" ++ shader) catch |err| {
log.info("Could not create path {}", .{err});
};
const cmd = b.addSystemCommand(&.{
shdc_path,
"-i",
shaders_dir ++ shader_with_ext,
"-o",
shaders_dir ++ "built/" ++ shader ++ "/" ++ shader,
"-l",
slang,
"-f",
"bare_yaml",
"--reflection",
});
shdc_step.dependOn(&cmd.step);
}
}