diff --git a/build.zig b/build.zig index 9fddd1b..2b66c73 100644 --- a/build.zig +++ b/build.zig @@ -29,10 +29,14 @@ pub fn build(b: *std.build.Builder) !void { b.option(bool, "allocation_info", "Enable use of debugging allocator and info logging.") orelse false, ); + exe.addPackage(.{ .name = "known-folders", .path = "src/known-folders/known-folders.zig" }); + exe.setTarget(target); exe.setBuildMode(mode); exe.install(); + b.installFile("src/special/build_runner.zig", "bin/build_runner.zig"); + const run_cmd = exe.run(); run_cmd.step.dependOn(b.getInstallStep()); diff --git a/src/main.zig b/src/main.zig index 76a1dc3..2199560 100644 --- a/src/main.zig +++ b/src/main.zig @@ -870,7 +870,7 @@ pub fn main() anyerror!void { defer std.json.parseFree(Config, config, config_parse_options); config_read: { - const known_folders = @import("known-folders/known-folders.zig"); + const known_folders = @import("known-folders"); const res = try known_folders.getPath(allocator, .local_configuration); if (res) |local_config_path| { defer allocator.free(local_config_path); diff --git a/src/special/build_runner.zig b/src/special/build_runner.zig new file mode 100644 index 0000000..4ec7ee2 --- /dev/null +++ b/src/special/build_runner.zig @@ -0,0 +1,89 @@ +const root = @import("build.zig"); +const std = @import("std"); +const io = std.io; +const fmt = std.fmt; +const Builder = std.build.Builder; +const Pkg = std.build.Pkg; +const LibExeObjStep = std.build.LibExeObjStep; +const ArrayList = std.ArrayList; +///! This is a modified build runner to extract information out of build.zig +///! Modified from std.special.build_runner + +// We use a custom Allocator to intercept the creation of steps +const InterceptAllocator = struct { + base_allocator: *std.mem.Allocator, + allocator: std.mem.Allocator, + steps: std.ArrayListUnmanaged(*LibExeObjStep), + + fn init(base_allocator: *std.mem.Allocator) InterceptAllocator { + return .{ + .base_allocator = base_allocator, + .allocator = .{ + .reallocFn = realloc, + .shrinkFn = shrink, + }, + .steps = .{}, + }; + } + + // TODO: Check LibExeObjStep has a unique size. + fn realloc(allocator: *std.mem.Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 { + const self = @fieldParentPtr(InterceptAllocator, "allocator", allocator); + var data = try self.base_allocator.reallocFn(self.base_allocator, old_mem, old_align, new_size, new_align); + if (old_mem.len == 0 and new_size == @sizeOf(LibExeObjStep)) { + try self.steps.append(self.base_allocator, @ptrCast(*LibExeObjStep, @alignCast(@alignOf(LibExeObjStep), data.ptr))); + } + return data; + } + + fn shrink(allocator: *std.mem.Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 { + const self = @fieldParentPtr(InterceptAllocator, "allocator", allocator); + return self.base_allocator.shrinkFn(self.base_allocator, old_mem, old_align, new_size, new_align); + } + + fn deinit(self: *InterceptAllocator) void { + self.steps.deinit(self.base_allocator); + } +}; + +pub fn main() !void { + var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); + defer arena.deinit(); + + var intercept = InterceptAllocator.init(&arena.allocator); + defer intercept.deinit(); + const allocator = &intercept.allocator; + + const builder = try Builder.create(allocator, "", "", ""); + defer builder.destroy(); + + try runBuild(builder); + + const stdout_stream = io.getStdOut().outStream(); + + // TODO: We currently add packages from every step., + // Should we error out or keep one step or something similar? + // We also flatten them, we should probably keep the nested structure. + for (intercept.steps.items) |step| { + for (step.packages.items) |pkg| { + try processPackage(stdout_stream, pkg); + } + } +} + +fn processPackage(out_stream: var, pkg: Pkg) anyerror!void { + try out_stream.print("{}\x00{}\n", .{ pkg.name, pkg.path }); + if (pkg.dependencies) |dependencies| { + for (dependencies) |dep| { + try processPackage(out_stream, dep); + } + } +} + +fn runBuild(builder: *Builder) anyerror!void { + switch (@typeInfo(@TypeOf(root.build).ReturnType)) { + .Void => root.build(builder), + .ErrorUnion => try root.build(builder), + else => @compileError("expected return type of build to be 'void' or '!void'"), + } +}