diff --git a/build.zig b/build.zig index 208f0a0..f9d9810 100644 --- a/build.zig +++ b/build.zig @@ -12,47 +12,70 @@ const Project = struct { optimize: std.builtin.OptimizeMode, imports: ImportList, - pub fn find_demos(self: Project, b: *std.Build) !void { - const demos = b.step("demos", "Build demos"); - var dir = try std.fs.openDirAbsolute(b.path("demos/").getPath(b), .{.iterate = true}); + pub fn demos_step(self: *const Project, b: *std.Build) *std.Build.Step { + const Demos = struct { + step: std.Build.Step, + project: *const Project, - defer { - dir.close(); - } + const Self = @This(); - var entries = try dir.walk(b.allocator); + fn make(step: *std.Build.Step, _: std.Progress.Node) anyerror!void { + const demos: *const Self = @fieldParentPtr("step", step); + const absolute_path = step.owner.path("demos/").getPath(step.owner); + var dir = try std.fs.openDirAbsolute(absolute_path, .{.iterate = true}); - defer { - entries.deinit(); - } + defer { + dir.close(); + } - while (try entries.next()) |entry| { - if (entry.kind != .file or !std.mem.endsWith(u8, entry.path, ".zig")) { - continue; + var entries = try dir.walk(step.owner.allocator); + + defer { + entries.deinit(); + } + + while (try entries.next()) |entry| { + if (entry.kind != .file or !std.mem.endsWith(u8, entry.path, ".zig")) { + continue; + } + + const source_path = step.owner.pathJoin(&.{"demos", entry.basename}); + var path_buffer = [_:0]u8{0} ** 255; + + const demo = step.owner.addExecutable(.{ + .name = try std.fmt.bufPrint(&path_buffer, "{s}.out", .{std.fs.path.stem(entry.basename)}), + .root_source_file = step.owner.path(source_path), + .target = demos.project.target, + .optimize = demos.project.optimize, + }); + + for (demos.project.imports.items) |import| { + demo.root_module.addImport(import.name, import.module); + } + + step.owner.installArtifact(demo); + } + + step.state = .success; } + }; - const source_path = try sub_path(.{"demos", entry.basename}); - var path_buffer = [_:0]u8{0} ** 255; + const demos = b.allocator.create(Demos) catch { + @panic("OOM"); + }; - const demo = b.addExecutable(.{ - .name = try std.fmt.bufPrint(&path_buffer, "{s}.out", .{std.fs.path.stem(entry.basename)}), - .root_source_file = b.path(source_path.bytes()), - .target = self.target, - .optimize = self.optimize, - }); + demos.* = .{ + .step = std.Build.Step.init(.{ + .id = .custom, + .name = "demos", + .makeFn = Demos.make, + .owner = b, + }), - for (self.imports.items) |import| { - demo.root_module.addImport(import.name, import.module); - } + .project = self, + }; - demos.dependOn(&b.addInstallArtifact(demo, .{ - .dest_dir = .{ - .override = .{ - .custom = "../demos/", - }, - }, - }).step); - } + return &demos.step; } pub fn find_tests(self: Project, b: *std.Build) !void { @@ -123,15 +146,13 @@ const Project = struct { var binary_buffer = [_:0]u8{0} ** 255; const binary_name = try std.fmt.bufPrint(&binary_buffer, "{s}.spv", .{entry.path}); - const full_source_path = try sub_path(.{shaders_path, entry.path}); - const full_binary_path = try sub_path(.{shaders_path, binary_name}); const glslang_validator_args = [_][]const u8{ "glslangValidator", "-V", - full_source_path.bytes(), + b.pathJoin(&.{shaders_path, entry.path}), "-o", - full_binary_path.bytes(), + b.pathJoin(&.{shaders_path, binary_name}), }; shaders_dir.access(binary_name, .{.mode = .read_only}) catch { @@ -155,45 +176,12 @@ const Project = struct { } }; -const SubPath = struct { - buffer: [max]u8 = [_]u8{0} ** max, - unused: u8 = max, - - pub const max = 255; - - pub fn append(self: *SubPath, component: []const u8) !void { - const used = max - self.unused; - - if (used != 0 and self.buffer[used - 1] != '/') { - if (component.len > self.unused) { - return error.PathTooBig; - } - - @memcpy(self.buffer[used .. (used + component.len)], component); - - self.unused -= @intCast(component.len); - } else { - const required_len = component.len + 1; - - if (required_len > self.unused) { - return error.PathTooBig; - } - - @memcpy(self.buffer[used .. (used + component.len)], component); - - self.buffer[component.len] = '/'; - - self.unused -= @intCast(required_len); - } - } - - pub fn bytes(self: *const SubPath) [:0]const u8 { - return @ptrCast(self.buffer[0 .. max - self.unused]); - } -}; - pub fn build(b: *std.Build) !void { - var project = Project{ + const project = b.allocator.create(Project) catch { + @panic("OOM"); + }; + + project.* = .{ .imports = ImportList.init(b.allocator), .target = b.standardTargetOptions(.{}), .optimize = b.standardOptimizeOption(.{}), @@ -286,42 +274,7 @@ pub fn build(b: *std.Build) !void { gfx_module.link_libc = true; + b.step("demos", "Build demos").dependOn(project.demos_step(b)); + try project.find_tests(b); - try project.find_demos(b); -} - -fn sub_path(components: anytype) !SubPath { - var path = comptime try std.BoundedArray(u8, SubPath.max).init(0); - const Components = @TypeOf(components); - - switch (@typeInfo(Components)) { - .Struct => |@"struct"| { - if (!@"struct".is_tuple) { - @compileError("`components` must be a tuple"); - } - - const last_component_index = components.len - 1; - - inline for (components, 0 .. components.len) |component, i| { - path.appendSlice(component) catch { - return error.PathTooBig; - }; - - if (i < last_component_index and !std.mem.endsWith(u8, component, "/")) { - path.append('/') catch { - return error.PathTooBig; - }; - } - } - }, - - else => { - @compileError("`components` cannot be a " ++ @typeName(Components)); - } - } - - return .{ - .unused = SubPath.max - path.len, - .buffer = path.buffer, - }; }