From 4244a8cac64482cb2d3af2b68a0d7c5cd66a5976 Mon Sep 17 00:00:00 2001 From: Auguste Rame <19855629+SuperAuguste@users.noreply.github.com> Date: Tue, 28 Feb 2023 16:10:59 -0500 Subject: [PATCH 1/2] Start work on build information dumping for IDE tooling --- lib/build_runner.zig | 13 ++++++ lib/std/Build.zig | 98 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 109 insertions(+), 2 deletions(-) diff --git a/lib/build_runner.zig b/lib/build_runner.zig index ca78ce713fbd..2826571d5a1c 100644 --- a/lib/build_runner.zig +++ b/lib/build_runner.zig @@ -182,6 +182,14 @@ pub fn main() !void { std.debug.print("Expected argument after --glibc-runtimes\n\n", .{}); return usageAndErr(builder, false, stderr_stream); }; + } else if (mem.eql(u8, arg, "--dump-build-info")) { + builder.dump_build_info = .dry; + } else if (mem.startsWith(u8, arg, "--dump-build-info=")) { + const mode = arg["--dump-build-info=".len..]; + builder.dump_build_info = std.meta.stringToEnum(@TypeOf(builder.dump_build_info), mode) orelse { + std.debug.print("invalid dump_build_info mode '{s}': must be 'off', 'dry', or 'wet'\n\n", .{mode}); + process.exit(1); + }; } else if (mem.eql(u8, arg, "--verbose-link")) { builder.verbose_link = true; } else if (mem.eql(u8, arg, "--verbose-air")) { @@ -363,6 +371,11 @@ fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi \\ --global-cache-dir [path] Override path to global Zig cache directory \\ --zig-lib-dir [arg] Override path to Zig lib directory \\ --debug-log [scope] Enable debugging the compiler + \\ --dump-build-info[=...] Dump zon-formatted module and step information to stdout + \\ off: Does not dump any build info + \\ dry: Only dumps build info, does not run any steps (default) + \\ wet: Runs build steps and then dumps build info + \\ \\ --verbose-link Enable compiler debug output for linking \\ --verbose-air Enable compiler debug output for Zig AIR \\ --verbose-llvm-ir Enable compiler debug output for LLVM IR diff --git a/lib/std/Build.zig b/lib/std/Build.zig index 26919962e341..4a99aa18a6b4 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -90,6 +90,9 @@ pkg_config_pkg_list: ?(PkgConfigError![]const PkgConfigPkg) = null, args: ?[][]const u8 = null, debug_log_scopes: []const []const u8 = &.{}, debug_compile_errors: bool = false, +/// Whether or not to dump build info in zon +/// upon construction of the build graph +dump_build_info: enum { off, dry, wet } = .off, /// Experimental. Use system Darling installation to run cross compiled macOS build artifacts. enable_darling: bool = false, @@ -112,6 +115,7 @@ host: NativeTargetInfo, dep_prefix: []const u8 = "", +dependencies: std.StringArrayHashMap(*Dependency), modules: std.StringArrayHashMap(*Module), pub const ExecError = error{ @@ -239,6 +243,7 @@ pub fn create( .install_path = undefined, .args = null, .host = host, + .dependencies = std.StringArrayHashMap(*Dependency).init(allocator), .modules = std.StringArrayHashMap(*Module).init(allocator), }; try self.top_level_steps.append(&self.install_tls); @@ -314,6 +319,7 @@ fn createChildOnly(parent: *Build, dep_name: []const u8, build_root: Cache.Direc .glibc_runtimes_dir = parent.glibc_runtimes_dir, .host = parent.host, .dep_prefix = parent.fmt("{s}{s}.", .{ parent.dep_prefix, dep_name }), + .dependencies = std.StringArrayHashMap(*Dependency).init(allocator), .modules = std.StringArrayHashMap(*Module).init(allocator), }; try child.top_level_steps.append(&child.install_tls); @@ -714,11 +720,95 @@ pub fn make(self: *Build, step_names: []const []const u8) !void { } } - for (wanted_steps.items) |s| { - try self.makeOneStep(s); + if (self.dump_build_info != .dry) { + for (wanted_steps.items) |s| { + try self.makeOneStep(s); + } + } + + if (self.dump_build_info != .off) { + const stdout_writer = std.io.getStdOut().writer(); + var buffered_writer = std.io.bufferedWriter(stdout_writer); + try self.dumpBuildInfo(buffered_writer.writer(), 0); + try buffered_writer.flush(); } } +fn indent(writer: anytype, indentation: usize) !void { + try writer.writeByteNTimes(' ', 4 * indentation); +} + +fn dumpModules(mods: std.StringArrayHashMap(*Module), writer: anytype, indentation: usize) !void { + if (mods.count() == 0) { + try writer.writeAll( + \\.{} + ); + } else { + try writer.writeAll(".{\n"); + + var module_iterator = mods.iterator(); + while (module_iterator.next()) |entry| { + try indent(writer, indentation + 1); + try writer.print(".{s} = .{{\n", .{std.zig.fmtId(entry.key_ptr.*)}); + + try indent(writer, indentation + 2); + try writer.print(".path = \"{}\",\n", .{ + std.zig.fmtEscapes( + switch (entry.value_ptr.*.source_file) { + .generated => |gen| gen.path orelse "generated", + .path => |path| path, + }, + ), + }); + + try indent(writer, indentation + 2); + try writer.print(".dependencies = ", .{}); + try dumpModules(entry.value_ptr.*.dependencies, writer, indentation + 2); + try writer.writeAll(",\n"); + + try indent(writer, indentation + 1); + try writer.writeAll("},\n"); + } + + try indent(writer, indentation); + try writer.writeAll("}"); + } +} + +pub fn dumpBuildInfo(self: *Build, writer: anytype, indentation: usize) !void { + try writer.writeAll(".{\n"); + + try indent(writer, indentation + 1); + try writer.print(".path = \"{}\",\n", .{std.zig.fmtEscapes(self.pathFromRoot("build.zig"))}); + + try indent(writer, indentation + 1); + try writer.writeAll(".dependencies = .{"); + + if (self.dependencies.count() == 0) { + try writer.writeAll("},\n"); + } else { + try writer.writeAll("\n"); + + var dep_it = self.dependencies.iterator(); + while (dep_it.next()) |entry| { + try indent(writer, indentation + 2); + try writer.print(".{s} = ", .{std.zig.fmtId(entry.key_ptr.*)}); + try entry.value_ptr.*.builder.dumpBuildInfo(writer, indentation + 2); + } + + try indent(writer, indentation + 1); + try writer.writeAll("},\n"); + } + + try indent(writer, indentation + 1); + try writer.writeAll(".modules = "); + try dumpModules(self.modules, writer, indentation + 1); + try writer.writeAll(",\n"); + + try indent(writer, indentation); + try writer.writeAll("}\n"); +} + pub fn getInstallStep(self: *Build) *Step { return &self.install_tls.step; } @@ -1537,6 +1627,9 @@ pub fn dependency(b: *Build, name: []const u8, args: anytype) *Dependency { const build_runner = @import("root"); const deps = build_runner.dependencies; + if (b.dependencies.get(name)) |dep| + return dep; + inline for (@typeInfo(deps.imports).Struct.decls) |decl| { if (mem.startsWith(u8, decl.name, b.dep_prefix) and mem.endsWith(u8, decl.name, name) and @@ -1578,6 +1671,7 @@ fn dependencyInner( const dep = b.allocator.create(Dependency) catch @panic("OOM"); dep.* = .{ .builder = sub_builder }; + b.dependencies.put(name, dep) catch @panic("unhandled error"); return dep; } From d61ee2a926f7ba293c45553a2ebc2c1bb82aa898 Mon Sep 17 00:00:00 2001 From: Auguste Rame <19855629+SuperAuguste@users.noreply.github.com> Date: Tue, 28 Feb 2023 16:15:42 -0500 Subject: [PATCH 2/2] Fix confusing usage --- lib/build_runner.zig | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/build_runner.zig b/lib/build_runner.zig index 2826571d5a1c..b5045af77c96 100644 --- a/lib/build_runner.zig +++ b/lib/build_runner.zig @@ -183,9 +183,11 @@ pub fn main() !void { return usageAndErr(builder, false, stderr_stream); }; } else if (mem.eql(u8, arg, "--dump-build-info")) { - builder.dump_build_info = .dry; - } else if (mem.startsWith(u8, arg, "--dump-build-info=")) { - const mode = arg["--dump-build-info=".len..]; + const mode = nextArg(args, &arg_idx) orelse { + std.debug.print("Expected argument after --dump-build-info\n\n", .{}); + return usageAndErr(builder, false, stderr_stream); + }; + builder.dump_build_info = std.meta.stringToEnum(@TypeOf(builder.dump_build_info), mode) orelse { std.debug.print("invalid dump_build_info mode '{s}': must be 'off', 'dry', or 'wet'\n\n", .{mode}); process.exit(1); @@ -371,9 +373,9 @@ fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi \\ --global-cache-dir [path] Override path to global Zig cache directory \\ --zig-lib-dir [arg] Override path to Zig lib directory \\ --debug-log [scope] Enable debugging the compiler - \\ --dump-build-info[=...] Dump zon-formatted module and step information to stdout - \\ off: Does not dump any build info - \\ dry: Only dumps build info, does not run any steps (default) + \\ --dump-build-info [mode] Dump zon-formatted module and step information to stdout + \\ off: Does not dump any build info (default) + \\ dry: Only dumps build info, does not run any steps \\ wet: Runs build steps and then dumps build info \\ \\ --verbose-link Enable compiler debug output for linking