-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuild.zig
More file actions
419 lines (349 loc) · 15.4 KB
/
build.zig
File metadata and controls
419 lines (349 loc) · 15.4 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
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
pub const version: std.SemanticVersion = .{
.major = 0,
.minor = 0,
.patch = 0,
.pre = "pre2",
};
pub const MakeFirm = @import("build/MakeFirm.zig");
pub const Make3dsx = @import("build/Make3dsx.zig");
pub const MakeSmdh = @import("build/MakeSmdh.zig");
pub const MakeRomFs = @import("build/MakeRomFs.zig");
pub const AssemblePsm = @import("build/AssemblePsm.zig");
pub const Link3dsx = @import("build/Link3dsx.zig");
pub const target = struct {
/// Freestanding target query, use `arm-3ds` to target the horizon (a.k.a the 3DS OS) userland instead
pub const arm11: std.Target.Query = .{
.cpu_arch = .arm,
.cpu_model = .{ .explicit = &std.Target.arm.cpu.mpcore },
.abi = .eabihf,
.os_tag = .freestanding,
};
/// Freestanding target query
pub const arm9: std.Target.Query = .{
.cpu_arch = .arm,
.cpu_model = .{ .explicit = &std.Target.arm.cpu.arm946e_s },
.abi = .eabi,
.os_tag = .freestanding,
};
};
pub fn build(b: *Build) void {
const optimize = b.standardOptimizeOption(.{});
const tools_target = b.standardTargetOptions(.{});
const juicy_zig_lib_dep = b.dependency("zig-lib", .{});
b.addNamedLazyPath("juice/zig_lib", juicy_zig_lib_dep.path("."));
b.addNamedLazyPath("horizon/ld", b.path("build/ld/arm-3ds.ld"));
b.addNamedLazyPath("horizon/test-runner/app-minimal", b.path("src/horizon/testing/application_test_runner.zig"));
const plz_dep = b.dependency("plz", .{});
const plz = plz_dep.module("plz");
// TODO: Remove this dep, deprecate and archive it.
const zalloc_dep = b.dependency("zalloc", .{});
const zalloc = zalloc_dep.module("zalloc");
// TODO: Move this one to codeberg
const zsflt_dep = b.dependency("zsflt", .{});
const zsflt = zsflt_dep.module("zsflt");
const zigimg_dep = b.dependency("zigimg", .{});
const zigimg = zigimg_dep.module("zigimg");
const config = b.addOptions();
const version_slice = queryBuildVersion(b);
config.addOption([]const u8, "version", version_slice);
const zitrus = b.addModule("zitrus", .{
.root_source_file = b.path("src/zitrus.zig"),
.imports = &.{
.{ .name = "zalloc", .module = zalloc },
.{ .name = "zsflt", .module = zsflt },
},
});
zitrus.addImport("zitrus", zitrus);
makeReleaseStep(b, version_slice, optimize, config, plz, zigimg, zitrus);
// XXX: Yes, this is really needed for each target / optimize...
const zitrus_lib = b.addLibrary(.{
.name = "zitrus",
.root_module = b.createModule(.{
.root_source_file = b.path("src/zitrus.zig"),
.target = b.resolveTargetQuery(.{
.cpu_arch = .arm,
.os_tag = .@"3ds",
}),
.imports = &.{
.{ .name = "zalloc", .module = zalloc },
.{ .name = "zsflt", .module = zsflt },
},
}),
.linkage = .static,
.zig_lib_dir = b.named_lazy_paths.get("juice/zig_lib").?,
});
zitrus_lib.root_module.addImport("zitrus", zitrus_lib.root_module);
// b.installArtifact(zitrus_lib);
const install_docs = b.addInstallDirectory(.{
.source_dir = zitrus_lib.getEmittedDocs(),
.install_dir = .prefix,
.install_subdir = "docs",
});
b.addNamedLazyPath("misc/docs", zitrus_lib.getEmittedDocs());
const docs_step = b.step("docs", "Install docs");
docs_step.dependOn(&install_docs.step);
const tools, const tools_exe = createToolsExecutable(b, config, optimize, tools_target, plz, zigimg, zitrus);
const mod_tests = b.addTest(.{
.name = "zitrus-mod-tests",
.root_module = b.createModule(.{
.root_source_file = b.path("src/zitrus.zig"),
.target = b.resolveTargetQuery(.{}),
.imports = &.{
.{ .name = "zalloc", .module = zalloc },
.{ .name = "zsflt", .module = zsflt },
},
}),
});
mod_tests.root_module.addImport("zitrus", mod_tests.root_module);
const exe_tests = b.addTest(.{ .name = "zitrus-exe-tests", .root_module = tools });
const run_mod_tests = b.addRunArtifact(mod_tests);
const run_exe_tests = b.addRunArtifact(exe_tests);
const run_tests_step = b.step("test", "Run zitrus tests");
run_tests_step.dependOn(&run_mod_tests.step);
run_tests_step.dependOn(&run_exe_tests.step);
b.installArtifact(tools_exe);
const run_tool = b.addRunArtifact(tools_exe);
if (b.args) |args| {
run_tool.addArgs(args);
}
const run_step = b.step("run", "Run zitrus tools");
run_step.dependOn(&run_tool.step);
makeTestSteps(b, zitrus, tools_exe);
makeScriptSteps(b, zitrus, plz);
}
// NOTE: This literally what zig does, almost 1:1 but we have prereleases so we have to work with that.
fn queryBuildVersion(b: *Build) []const u8 {
const maybe_version = b.option([]const u8, "version-string", "Override zitrus version");
if (maybe_version) |ver| return ver;
if (!std.process.can_spawn) {
std.log.err("Cannot retrieve version info from git, set it with version-string manually", .{});
std.process.exit(1);
}
const version_string = b.fmt("{f}", .{version});
var code: u8 = undefined;
const git_describe_untrimmed = b.runAllowFail(&.{
"git",
"-C",
b.build_root.path orelse ".",
"--git-dir",
".git",
"describe",
"--match",
"v*.*.*",
"--tags",
"--abbrev=9",
}, &code, .ignore) catch return version_string;
const git_describe = std.mem.trim(u8, git_describe_untrimmed, " \n\r");
switch (std.mem.count(u8, git_describe, "-")) {
0, 1 => {
// Tagged release or prerelease
// `[1..]` to skip the 'v' in release tags.
if (!std.mem.eql(u8, git_describe[1..], version_string)) {
std.log.err("Version '{s}' does not match git tag '{s}'", .{ version_string, git_describe });
std.process.exit(1);
}
return version_string;
},
2, 3 => |cnt| {
var it = std.mem.splitScalar(u8, git_describe, '-');
// `[1..]` to skip the 'v' in release tags.
const last_tagged = if (cnt == 2) it.next().?[1..] else b.fmt("{s}-{s}", .{ it.next().?[1..], it.next().? });
const commit_height = it.next().?;
const commit_hash = it.next().?;
const last_tagged_version = std.SemanticVersion.parse(last_tagged) catch {
std.log.err("Last tagged version '{s}' is NOT a valid semantic version ", .{last_tagged});
std.process.exit(1);
};
if (version.order(last_tagged_version) != .gt) {
std.log.err("Version '{s}' must be greater than last tagged '{s}'", .{ version_string, last_tagged });
std.process.exit(1);
}
if (commit_hash.len < 1 or commit_hash[0] != 'g') {
std.log.err("Unexpected git describe output: '{s}'", .{git_describe});
return version_string;
}
return b.fmt("{}.{}.{}-{s}.dev.{s}+{s}", .{ version.major, version.minor, version.patch, version.pre.?, commit_height, commit_hash[1..] });
},
else => {
std.log.err("Unexpected git describe output: '{s}'", .{git_describe});
return version_string;
},
}
}
const release_targets: []const std.Target.Query = &.{
// Everyone is welcome to the party!
// NOTE: Even if your platform is not included here it may be supported if zig supports it.
.{ .cpu_arch = .x86, .os_tag = .linux },
.{ .cpu_arch = .x86, .os_tag = .windows },
.{ .cpu_arch = .x86, .os_tag = .netbsd },
.{ .cpu_arch = .x86_64, .os_tag = .linux },
.{ .cpu_arch = .x86_64, .os_tag = .windows },
.{ .cpu_arch = .x86_64, .os_tag = .macos },
.{ .cpu_arch = .x86_64, .os_tag = .freebsd },
.{ .cpu_arch = .x86_64, .os_tag = .netbsd },
.{ .cpu_arch = .arm, .os_tag = .linux },
.{ .cpu_arch = .arm, .os_tag = .freebsd },
.{ .cpu_arch = .arm, .os_tag = .netbsd },
.{ .cpu_arch = .aarch64, .os_tag = .linux },
.{ .cpu_arch = .aarch64, .os_tag = .windows },
.{ .cpu_arch = .aarch64, .os_tag = .macos },
.{ .cpu_arch = .aarch64, .os_tag = .freebsd },
.{ .cpu_arch = .aarch64, .os_tag = .netbsd },
.{ .cpu_arch = .riscv64, .os_tag = .linux },
};
fn makeReleaseStep(b: *Build, version_slice: []const u8, optimize: std.builtin.OptimizeMode, config: *Build.Step.Options, plz: *Build.Module, zigimg: *Build.Module, zitrus: *Build.Module) void {
const release_step = b.step("release", "Perform a release build");
for (release_targets) |release_target| {
_, const tools = createToolsExecutable(b, config, optimize, b.resolveTargetQuery(release_target), plz, zigimg, zitrus);
tools.root_module.strip = switch (optimize) {
.Debug, .ReleaseSafe => false,
else => true,
};
const tools_output = b.addInstallArtifact(tools, .{
.dest_dir = .{
.override = .{
.custom = b.fmt("zitrus-{s}-{s}", .{ release_target.zigTriple(b.allocator) catch @panic("OOM"), version_slice }),
},
},
});
release_step.dependOn(&tools_output.step);
}
}
fn createToolsExecutable(b: *Build, config: *Build.Step.Options, optimize: std.builtin.OptimizeMode, mod_target: Build.ResolvedTarget, plz: *Build.Module, zigimg: *Build.Module, zitrus: *Build.Module) struct { *Build.Module, *Build.Step.Compile } {
const tools = b.createModule(.{
.root_source_file = b.path("tools/main.zig"),
.target = mod_target,
.optimize = optimize,
.imports = &.{
.{ .name = "zitrus", .module = zitrus },
.{ .name = "plz", .module = plz },
.{ .name = "zigimg", .module = zigimg },
},
});
tools.addOptions("zitrus-config", config);
return .{ tools, b.addExecutable(.{
.name = "zitrus",
.root_module = tools,
// XXX: self-hosted backend crashes when bitcasting a packed struct with a 0-bit field.
.use_llvm = true,
}) };
}
const Script = struct { name: []const u8, path: []const u8 };
const scripts: []const Script = &.{
.{ .name = "gen-spirv-spec", .path = "scripts/gen-spirv-spec.zig" },
.{ .name = "gen-md-docs", .path = "scripts/gen-md-docs.zig" },
};
fn makeScriptSteps(b: *Build, zitrus: *Build.Module, plz: *Build.Module) void {
inline for (scripts) |script| {
const script_exe = b.addExecutable(.{
.name = script.name,
.root_module = b.createModule(.{
.root_source_file = b.path(script.path),
.target = b.resolveTargetQuery(.{}),
.optimize = .Debug,
.imports = &.{
.{ .name = "plz", .module = plz },
.{ .name = "zitrus", .module = zitrus },
},
}),
});
const run_script_step = b.step("run-" ++ script.name, "Run " ++ script.name);
const run_script = b.addRunArtifact(script_exe);
if (b.args) |args| {
run_script.addArgs(args);
}
run_script_step.dependOn(&run_script.step);
}
}
const StandaloneTest = struct {
name: []const u8,
path: []const u8,
psm: []const []const u8 = &.{},
};
const standalone_tests: []const StandaloneTest = &.{
.{ .name = "hos", .path = "test/hos.zig" },
.{
.name = "mango",
.path = "test/mango.zig",
.psm = &.{"test/mango/render/pos.psm"},
},
};
fn makeTestSteps(b: *Build, zitrus: *Build.Module, zitrus_tools: *Build.Step.Compile) void {
const build_tests_step = b.step("build-tests", "Builds tests for running on the 3DS");
const mod_tests_3ds = b.addTest(.{
.name = "zitrus-mod-tests",
.test_runner = .{ .mode = .simple, .path = b.named_lazy_paths.get("horizon/test-runner/app-minimal").? },
.root_module = b.createModule(.{
.root_source_file = b.path("src/zitrus.zig"),
.optimize = .Debug,
.target = b.resolveTargetQuery(.{
.cpu_arch = .arm,
.os_tag = .@"3ds",
}),
.imports = &.{
.{ .name = "zalloc", .module = zitrus.import_table.get("zalloc").? },
.{ .name = "zsflt", .module = zitrus.import_table.get("zsflt").? },
},
}),
.zig_lib_dir = b.named_lazy_paths.get("juice/zig_lib").?,
});
mod_tests_3ds.setLinkerScript(b.named_lazy_paths.get("horizon/ld").?);
mod_tests_3ds.pie = true;
mod_tests_3ds.root_module.addImport("zitrus", mod_tests_3ds.root_module);
const mod_tests_3dsx = Make3dsx.initInner(b, .{
.tools_artifact = zitrus_tools,
}, .{
.name = "zitrus-tests",
.exe = mod_tests_3ds,
});
const build_mod_test_step = b.step("build-zitrus-test", "Builds 'zitrus' tests for running on the 3DS");
const install_mod_test = b.addInstallArtifact(mod_tests_3ds, .{ .dest_sub_path = "tests/zitrus.elf" });
const install_mod_3dsx_test = b.addInstallBinFile(mod_tests_3dsx.out, "tests/zitrus.3dsx");
build_mod_test_step.dependOn(&install_mod_test.step);
build_mod_test_step.dependOn(&install_mod_3dsx_test.step);
build_tests_step.dependOn(build_mod_test_step);
inline for (standalone_tests) |standalone_test| {
const tests_exe = b.addTest(.{
.name = standalone_test.name,
.test_runner = .{ .mode = .simple, .path = b.named_lazy_paths.get("horizon/test-runner/app-minimal").? },
.root_module = b.createModule(.{
.root_source_file = b.path(standalone_test.path),
.target = b.resolveTargetQuery(.{
.cpu_arch = .arm,
.os_tag = .@"3ds",
}),
.optimize = .Debug,
.imports = &.{
.{ .name = "zitrus", .module = zitrus },
},
}),
.zig_lib_dir = b.named_lazy_paths.get("juice/zig_lib").?,
});
tests_exe.pie = true;
tests_exe.setLinkerScript(b.named_lazy_paths.get("horizon/ld").?);
for (standalone_test.psm) |psm| {
const assemble: AssemblePsm = .initInner(b, .{
.tools_artifact = zitrus_tools,
}, .{
.name = psm,
.root_source_file = b.path(psm),
});
tests_exe.root_module.addAnonymousImport(std.Io.Dir.path.basename(psm), .{ .root_source_file = assemble.out });
}
const tests_3dsx = Make3dsx.initInner(b, .{
.tools_artifact = zitrus_tools,
}, .{
.name = standalone_test.name,
.exe = tests_exe,
});
const build_test_step = b.step("build-" ++ standalone_test.name ++ "-test", "Builds the '" ++ standalone_test.name ++ "' test for running on the 3DS");
const install_lib_test = b.addInstallArtifact(tests_exe, .{ .dest_sub_path = "tests/" ++ standalone_test.name ++ ".elf" });
const install_lib_3dsx_test = b.addInstallBinFile(tests_3dsx.out, "tests/" ++ standalone_test.name ++ ".3dsx");
build_test_step.dependOn(&install_lib_test.step);
build_test_step.dependOn(&install_lib_3dsx_test.step);
build_tests_step.dependOn(build_test_step);
}
}
const builtin = @import("builtin");
const std = @import("std");
const Build = std.Build;