From 8fbfcf34d17e2f18521fb7e1b6238de4056637b4 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 19 Feb 2026 13:50:56 -0800 Subject: [PATCH] Maker.Step.Compile: progress towards lowering zig args --- lib/compiler/Maker.zig | 91 +++--- lib/compiler/Maker/Graph.zig | 21 ++ lib/compiler/Maker/Step.zig | 94 +----- lib/compiler/Maker/Step/Compile.zig | 491 +++++++++++++--------------- lib/compiler/Maker/Step/Run.zig | 4 +- lib/compiler/configure_runner.zig | 25 +- lib/std/Build.zig | 194 +---------- lib/std/Build/Step/Compile.zig | 4 + lib/std/zig.zig | 73 +++++ 9 files changed, 412 insertions(+), 585 deletions(-) diff --git a/lib/compiler/Maker.zig b/lib/compiler/Maker.zig index 4a1557a996..36932c2cef 100644 --- a/lib/compiler/Maker.zig +++ b/lib/compiler/Maker.zig @@ -124,7 +124,6 @@ pub fn main(init: process.Init.Minimal) !void { graph.cache.hash.addBytes(builtin.zig_version_string); var step_names: std.ArrayList([]const u8) = .empty; - var debug_log_scopes: std.ArrayList([]const u8) = .empty; var help_menu = false; var steps_menu = false; var print_configuration = false; @@ -143,10 +142,6 @@ pub fn main(init: process.Init.Minimal) !void { var fuzz: ?Fuzz.Mode = null; var debounce_interval_ms: u16 = 50; var webui_listen: ?Io.net.IpAddress = null; - var verbose = false; - var sysroot: ?[]const u8 = null; - var search_prefixes: std.ArrayList([]const u8) = .empty; - var libc_file: ?[]const u8 = null; var debug_pkg_config: bool = false; // After following the steps in https://codeberg.org/ziglang/infra/src/branch/master/libc-update/glibc.md, // this will be the directory $glibc-build-dir/install/glibcs @@ -159,7 +154,6 @@ pub fn main(init: process.Init.Minimal) !void { var enable_wasmtime = false; var enable_darling = false; var enable_rosetta = false; - var reference_trace: ?u32 = null; var run_args: ?[]const []const u8 = null; if (std.zig.EnvVar.ZIG_BUILD_ERROR_STYLE.get(&graph.environ_map)) |str| { @@ -182,8 +176,6 @@ pub fn main(init: process.Init.Minimal) !void { steps_menu = true; } else if (mem.eql(u8, arg, "--print-configuration")) { print_configuration = true; - } else if (mem.eql(u8, arg, "--verbose")) { - verbose = true; } else if (mem.eql(u8, arg, "-p") or mem.eql(u8, arg, "--prefix")) { override_install_prefix = nextArgOrFatal(args, &arg_idx); } else if (mem.eql(u8, arg, "--prefix-lib-dir")) { @@ -193,11 +185,12 @@ pub fn main(init: process.Init.Minimal) !void { } else if (mem.eql(u8, arg, "--prefix-include-dir")) { override_include_dir = nextArgOrFatal(args, &arg_idx); } else if (mem.eql(u8, arg, "--sysroot")) { - sysroot = nextArgOrFatal(args, &arg_idx); + graph.sysroot = nextArgOrFatal(args, &arg_idx); } else if (mem.eql(u8, arg, "--maxrss")) { + // TODO refactor and reuse the fuzz number parsing here const max_rss_text = nextArgOrFatal(args, &arg_idx); max_rss = std.fmt.parseIntSizeSuffix(max_rss_text, 10) catch |err| - fatal("invalid byte size: '{s}': {t}", .{ max_rss_text, err }); + fatal("invalid byte size {q}: {t}", .{ max_rss_text, err }); } else if (mem.eql(u8, arg, "--skip-oom-steps")) { skip_oom_steps = true; } else if (mem.eql(u8, arg, "--test-timeout")) { @@ -217,7 +210,7 @@ pub fn main(init: process.Init.Minimal) !void { }; const timeout_str = nextArgOrFatal(args, &arg_idx); const num_end_idx = std.mem.findLastNone(u8, timeout_str, "abcdefghijklmnopqrstuvwxyz") orelse fatal( - "invalid timeout '{s}': expected unit (ns, us, ms, s, m, h)", + "invalid timeout {q}: expected unit (ns, us, ms, s, m, h)", .{timeout_str}, ); const num_str = timeout_str[0 .. num_end_idx + 1]; @@ -227,57 +220,63 @@ pub fn main(init: process.Init.Minimal) !void { break @floatFromInt(unit_and_factor[1]); } } else fatal( - "invalid timeout '{s}': invalid unit '{s}' (expected ns, us, ms, s, m, h)", + "invalid timeout {q}: invalid unit {q} (expected ns, us, ms, s, m, h)", .{ timeout_str, unit_str }, ); const num_parsed = std.fmt.parseFloat(f64, num_str) catch |err| fatal( - "invalid timeout '{s}': invalid number '{s}' ({t})", + "invalid timeout {q}: invalid number {q} ({t})", .{ timeout_str, num_str, err }, ); test_timeout_ns = std.math.lossyCast(u64, unit_factor * num_parsed); } else if (mem.eql(u8, arg, "--search-prefix")) { - try search_prefixes.append(arena, nextArgOrFatal(args, &arg_idx)); + try graph.search_prefixes.append(arena, nextArgOrFatal(args, &arg_idx)); } else if (mem.eql(u8, arg, "--libc")) { - libc_file = nextArgOrFatal(args, &arg_idx); + graph.libc_file = nextArgOrFatal(args, &arg_idx); } else if (mem.eql(u8, arg, "--color")) { const next_arg = nextArg(args, &arg_idx) orelse - fatalWithHint("expected [auto|on|off] after '{s}'", .{arg}); + fatalWithHint("expected [auto|on|off] after {q}", .{arg}); color = std.meta.stringToEnum(Color, next_arg) orelse { - fatalWithHint("expected [auto|on|off] after '{s}', found '{s}'", .{ + fatalWithHint("expected [auto|on|off] after {q}, found {q}", .{ arg, next_arg, }); }; } else if (mem.eql(u8, arg, "--error-style")) { const next_arg = nextArg(args, &arg_idx) orelse - fatalWithHint("expected style after '{s}'", .{arg}); + fatalWithHint("expected style after {q}", .{arg}); error_style = std.meta.stringToEnum(ErrorStyle, next_arg) orelse { - fatalWithHint("expected style after '{s}', found '{s}'", .{ arg, next_arg }); + fatalWithHint("expected style after {q}, found {q}", .{ arg, next_arg }); }; } else if (mem.eql(u8, arg, "--multiline-errors")) { const next_arg = nextArg(args, &arg_idx) orelse - fatalWithHint("expected style after '{s}'", .{arg}); + fatalWithHint("expected style after {q}", .{arg}); multiline_errors = std.meta.stringToEnum(MultilineErrors, next_arg) orelse { - fatalWithHint("expected style after '{s}', found '{s}'", .{ arg, next_arg }); + fatalWithHint("expected style after {q}, found {q}", .{ arg, next_arg }); }; } else if (mem.eql(u8, arg, "--summary")) { const next_arg = nextArg(args, &arg_idx) orelse - fatalWithHint("expected [all|new|failures|line|none] after '{s}'", .{arg}); + fatalWithHint("expected [all|new|failures|line|none] after {q}", .{arg}); summary = std.meta.stringToEnum(Summary, next_arg) orelse { - fatalWithHint("expected [all|new|failures|line|none] after '{s}', found '{s}'", .{ + fatalWithHint("expected [all|new|failures|line|none] after {q}, found {q}", .{ arg, next_arg, }); }; } else if (mem.eql(u8, arg, "--seed")) { const next_arg = nextArg(args, &arg_idx) orelse - fatalWithHint("expected u32 after '{s}'", .{arg}); + fatalWithHint("expected u32 after {q}", .{arg}); graph.random_seed = std.fmt.parseUnsigned(u32, next_arg, 0) catch |err| { - fatal("unable to parse seed '{s}' as unsigned 32-bit integer: {t}", .{ next_arg, err }); + fatal("unable to parse seed {q} as unsigned 32-bit integer: {t}", .{ next_arg, err }); }; + } else if (mem.eql(u8, arg, "--build-id")) { + graph.build_id = .fast; + } else if (mem.cutPrefix(u8, arg, "--build-id=")) |style| { + graph.build_id = std.zig.BuildId.parse(style) catch |err| + fatal("unable to parse --build-id style {q}: {t}", .{ style, err }); } else if (mem.eql(u8, arg, "--debounce")) { + // TODO refactor and reuse the timeout parsing code also here const next_arg = nextArg(args, &arg_idx) orelse - fatalWithHint("expected u16 after '{s}'", .{arg}); + fatalWithHint("expected u16 after {q}", .{arg}); debounce_interval_ms = std.fmt.parseUnsigned(u16, next_arg, 0) catch |err| { - fatal("unable to parse debounce interval '{s}' as unsigned 16-bit integer: {t}\n", .{ + fatal("unable to parse debounce interval {q} as unsigned 16-bit integer: {t}", .{ next_arg, err, }); }; @@ -287,11 +286,15 @@ pub fn main(init: process.Init.Minimal) !void { const addr_str = arg["--webui=".len..]; if (std.mem.eql(u8, addr_str, "-")) fatal("web interface cannot listen on stdio", .{}); webui_listen = Io.net.IpAddress.parseLiteral(addr_str) catch |err| { - fatal("invalid web UI address '{s}': {t}", .{ addr_str, err }); + fatal("invalid web UI address {q}: {t}", .{ addr_str, err }); }; } else if (mem.eql(u8, arg, "--debug-log")) { const next_arg = nextArgOrFatal(args, &arg_idx); - try debug_log_scopes.append(arena, next_arg); + try graph.debug_log_scopes.append(arena, next_arg); + } else if (mem.eql(u8, arg, "--debug-compile-errors")) { + graph.debug_compile_errors = true; + } else if (mem.eql(u8, arg, "--debug-incremental")) { + graph.debug_incremental = true; } else if (mem.eql(u8, arg, "--debug-pkg-config")) { debug_pkg_config = true; } else if (mem.eql(u8, arg, "--debug-rt")) { @@ -301,6 +304,16 @@ pub fn main(init: process.Init.Minimal) !void { fatal("unrecognized optimization mode: {s}", .{rest}); } else if (mem.eql(u8, arg, "--libc-runtimes")) { libc_runtimes_dir = nextArgOrFatal(args, &arg_idx); + } else if (mem.eql(u8, arg, "--verbose")) { + graph.verbose = true; + } else if (mem.eql(u8, arg, "--verbose-cimport")) { + graph.verbose_cimport = true; + } else if (mem.eql(u8, arg, "--verbose-air")) { + graph.verbose_air = true; + } else if (mem.eql(u8, arg, "--verbose-cc")) { + graph.verbose_cc = true; + } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) { + graph.verbose_llvm_ir = true; } else if (mem.eql(u8, arg, "--watch")) { watch = true; } else if (mem.eql(u8, arg, "--time-report")) { @@ -372,25 +385,22 @@ pub fn main(init: process.Init.Minimal) !void { } else if (mem.eql(u8, arg, "-fno-allow-so-scripts")) { graph.allow_so_scripts = false; } else if (mem.eql(u8, arg, "-freference-trace")) { - reference_trace = 256; - } else if (mem.startsWith(u8, arg, "-freference-trace=")) { - const num = arg["-freference-trace=".len..]; - reference_trace = std.fmt.parseUnsigned(u32, num, 10) catch |err| { - std.debug.print("unable to parse reference_trace count '{s}': {t}", .{ num, err }); - process.exit(1); - }; + graph.reference_trace = 256; + } else if (mem.cutPrefix(u8, arg, "-freference-trace=")) |num| { + graph.reference_trace = std.fmt.parseUnsigned(u32, num, 10) catch |err| + fatal("unable to parse reference_trace count {q}: {t}", .{ num, err }); } else if (mem.eql(u8, arg, "-fno-reference-trace")) { - reference_trace = null; + graph.reference_trace = null; } else if (mem.cutPrefix(u8, arg, "-j")) |text| { const n = std.fmt.parseUnsigned(u32, text, 10) catch |err| - fatal("unable to parse jobs count '{s}': {t}", .{ text, err }); + fatal("unable to parse jobs count {q}: {t}", .{ text, err }); if (n < 1) fatal("number of jobs must be at least 1", .{}); threaded.setAsyncLimit(.limited(n)); } else if (mem.eql(u8, arg, "--")) { run_args = argsRest(args, arg_idx); break; } else { - fatalWithHint("unrecognized argument: '{s}'", .{arg}); + fatalWithHint("unrecognized argument: {s}", .{arg}); } } else { try step_names.append(arena, arg); @@ -1841,8 +1851,7 @@ const ScannedConfig = struct { \\ --debug-rt Debug compiler runtime libraries \\ --verbose-link Enable compiler debug output for linking \\ --verbose-air Enable compiler debug output for Zig AIR - \\ --verbose-llvm-ir[=file] Enable compiler debug output for LLVM IR - \\ --verbose-llvm-bc=[file] Enable compiler debug output for LLVM BC + \\ --verbose-llvm-ir Enable compiler debug output for LLVM IR \\ --verbose-cimport Enable compiler debug output for C imports \\ --verbose-cc Enable compiler debug output for C compilation \\ --verbose-llvm-cpu-features Enable compiler debug output for LLVM CPU features diff --git a/lib/compiler/Maker/Graph.zig b/lib/compiler/Maker/Graph.zig index ba9cad0ee1..3441a55af1 100644 --- a/lib/compiler/Maker/Graph.zig +++ b/lib/compiler/Maker/Graph.zig @@ -23,3 +23,24 @@ time_report: bool = false, /// Similar to the `Io.Terminal.Mode` returned by `Io.lockStderr`, but also /// respects the '--color' flag. stderr_mode: ?Io.Terminal.Mode = null, +reference_trace: ?u32 = null, +debug_log_scopes: std.ArrayList([]const u8) = .empty, +debug_compile_errors: bool = false, +debug_incremental: bool = false, +verbose: bool = false, +verbose_air: bool = false, +verbose_cc: bool = false, +verbose_cimport: bool = false, +verbose_link: bool = false, +verbose_llvm_cpu_features: bool = false, +verbose_llvm_ir: bool = false, +libc_file: ?[]const u8 = null, +/// What does this do? Nobody bothered to document it, and I think it's a +/// smelly option. So unless somebody deletes these passive aggressive comments +/// and replaces them with actual documentation, I'm going to delete this +/// option from the build system in a future release. In other words, this is +/// deprecated due to lack of test coverage, lack of documentation, and a hunch +/// that it's a bad option that should be avoided. +sysroot: ?[]const u8 = null, +search_prefixes: std.ArrayList([]const u8) = .empty, +build_id: ?std.zig.BuildId = null, diff --git a/lib/compiler/Maker/Step.zig b/lib/compiler/Maker/Step.zig index dbd47fe93b..0115f3a7db 100644 --- a/lib/compiler/Maker/Step.zig +++ b/lib/compiler/Maker/Step.zig @@ -298,7 +298,7 @@ pub fn captureChildProcess( // If an error occurs, it's happened in this command: assert(s.result_failed_command == null); - s.result_failed_command = try allocPrintCmd(gpa, .inherit, null, argv); + s.result_failed_command = try std.zig.allocPrintCmd(gpa, .inherit, null, argv); try handleChildProcUnsupported(s); try handleVerbose(s, .inherit, argv); @@ -354,15 +354,15 @@ pub fn evalZigProcess( argv: []const []const u8, prog_node: std.Progress.Node, watch: bool, - web_server: ?*WebServer, - gpa: Allocator, + maker: *Maker, ) !?Cache.Path { + const gpa = maker.gpa; const b = s.owner; const io = b.graph.io; // If an error occurs, it's happened in this command: assert(s.result_failed_command == null); - s.result_failed_command = try allocPrintCmd(gpa, .inherit, null, argv); + s.result_failed_command = try std.zig.allocPrintCmd(gpa, .inherit, null, argv); if (s.getZigProcess()) |zp| update: { assert(watch); @@ -374,7 +374,7 @@ pub fn evalZigProcess( zp.deinit(io); gpa.destroy(zp); } else zp.saveState(prog_node); - const result = zigProcessUpdate(s, zp, watch, web_server, gpa) catch |err| switch (err) { + const result = zigProcessUpdate(s, zp, watch, maker) catch |err| switch (err) { error.BrokenPipe, error.EndOfStream => |reason| { std.log.info("{s} restart required: {t}", .{ argv[0], reason }); // Process restart required. @@ -431,7 +431,7 @@ pub fn evalZigProcess( const result = result: { defer if (watch) zp.saveState(prog_node); - break :result try zigProcessUpdate(s, zp, watch, web_server, gpa); + break :result try zigProcessUpdate(s, zp, watch, maker); }; if (!watch) { @@ -485,7 +485,8 @@ pub fn installDir(s: *Step, dest_path: []const u8) !Io.Dir.CreatePathStatus { return s.fail("unable to create dir '{s}': {t}", .{ dest_path, err }); } -fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool, web_server: ?*WebServer, gpa: Allocator) !?Path { +fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool, maker: *Maker) !?Path { + const gpa = maker.gpa; const b = s.owner; const arena = b.allocator; const io = b.graph.io; @@ -586,7 +587,7 @@ fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool, web_server: ?*WebSer } } }, - .time_report => if (web_server) |ws| { + .time_report => if (maker.web_server) |ws| { const TimeReport = std.zig.Server.Message.TimeReport; const tr: *align(1) const TimeReport = @ptrCast(body[0..@sizeOf(TimeReport)]); ws.updateTimeReportCompile(.{ @@ -641,11 +642,11 @@ pub fn handleVerbose( opt_env: ?*const std.process.Environ.Map, argv: []const []const u8, ) error{OutOfMemory}!void { - if (!s.verbose) return; const graph = s.graph; + if (!graph.verbose) return; // Intention of verbose is to print all sub-process command lines to // stderr before spawning them. - const text = try allocPrintCmd(arena, cwd, if (opt_env) |env| .{ + const text = try std.zig.allocPrintCmd(arena, cwd, if (opt_env) |env| .{ .child = env, .parent = &graph.environ_map, } else null, argv); @@ -843,79 +844,6 @@ fn addWatchInputFromPath(step: *Step, path: Cache.Path, basename: []const u8) !v try gop.value_ptr.append(gpa, basename); } -pub fn allocPrintCmd( - gpa: Allocator, - cwd: std.process.Child.Cwd, - opt_env: ?struct { - child: *const std.process.Environ.Map, - parent: *const std.process.Environ.Map, - }, - argv: []const []const u8, -) Allocator.Error![]u8 { - const shell = struct { - fn escape(writer: *Io.Writer, string: []const u8, is_argv0: bool) !void { - for (string) |c| { - if (switch (c) { - else => true, - '%', '+'...':', '@'...'Z', '_', 'a'...'z' => false, - '=' => is_argv0, - }) break; - } else return writer.writeAll(string); - - try writer.writeByte('"'); - for (string) |c| { - if (switch (c) { - std.ascii.control_code.nul => break, - '!', '"', '$', '\\', '`' => true, - else => !std.ascii.isPrint(c), - }) try writer.writeByte('\\'); - switch (c) { - std.ascii.control_code.nul => unreachable, - std.ascii.control_code.bel => try writer.writeByte('a'), - std.ascii.control_code.bs => try writer.writeByte('b'), - std.ascii.control_code.ht => try writer.writeByte('t'), - std.ascii.control_code.lf => try writer.writeByte('n'), - std.ascii.control_code.vt => try writer.writeByte('v'), - std.ascii.control_code.ff => try writer.writeByte('f'), - std.ascii.control_code.cr => try writer.writeByte('r'), - std.ascii.control_code.esc => try writer.writeByte('E'), - ' '...'~' => try writer.writeByte(c), - else => try writer.print("{o:0>3}", .{c}), - } - } - try writer.writeByte('"'); - } - }; - - var aw: Io.Writer.Allocating = .init(gpa); - defer aw.deinit(); - const writer = &aw.writer; - switch (cwd) { - .inherit => {}, - .path => |path| writer.print("cd {s} && ", .{path}) catch return error.OutOfMemory, - .dir => @panic("TODO"), - } - if (opt_env) |env| { - var it = env.child.iterator(); - while (it.next()) |entry| { - const key = entry.key_ptr.*; - const value = entry.value_ptr.*; - if (env.parent.get(key)) |process_value| { - if (std.mem.eql(u8, value, process_value)) continue; - } - writer.print("{s}=", .{key}) catch return error.OutOfMemory; - shell.escape(writer, value, false) catch return error.OutOfMemory; - writer.writeByte(' ') catch return error.OutOfMemory; - } - } - shell.escape(writer, argv[0], true) catch return error.OutOfMemory; - for (argv[1..]) |arg| { - writer.writeByte(' ') catch return error.OutOfMemory; - shell.escape(writer, arg, false) catch return error.OutOfMemory; - } - return aw.toOwnedSlice(); -} - fn oomWrap(s: *Step, result: error{OutOfMemory}!void) void { result catch { s.result_oom = true; diff --git a/lib/compiler/Maker/Step/Compile.zig b/lib/compiler/Maker/Step/Compile.zig index b0ec3fa9ea..edec00b89c 100644 --- a/lib/compiler/Maker/Step/Compile.zig +++ b/lib/compiler/Maker/Step/Compile.zig @@ -10,6 +10,7 @@ const Io = std.Io; const Sha256 = std.crypto.hash.sha2.Sha256; const assert = std.debug.assert; const mem = std.mem; +const allocPrint = std.fmt.allocPrint; const Step = @import("../Step.zig"); const Maker = @import("../../Maker.zig"); @@ -17,6 +18,8 @@ const Maker = @import("../../Maker.zig"); /// Populated during the make phase when there is a long-lived compiler process. /// Managed by the build runner, not user build script. zig_process: ?*Step.ZigProcess = null, +/// Persisted to reuse memory on subsequent make. +zig_args: std.ArrayList([]const u8) = .empty, pub fn make( compile: *Compile, @@ -24,14 +27,15 @@ pub fn make( maker: *Maker, progress_node: std.Progress.Node, ) Step.ExtendedMakeError!void { - if (true) @panic("TODO implement compile.make()"); const graph = maker.graph; const step = maker.stepByIndex(step_index); - const zig_args = try getZigArgs(compile, maker, false); + compile.zig_args.clearRetainingCapacity(); + if (true) @panic("TODO implement compile.make()"); + try lowerZigArgs(compile, step_index, maker, &compile.zig_args, false); const process_arena = graph.arena; // TODO don't leak into the process_arena const maybe_output_dir = step.evalZigProcess( - zig_args, + compile.zig_args.items, progress_node, (graph.incremental == true) and (maker.watch or maker.web_server != null), maker, @@ -47,7 +51,7 @@ pub fn make( // Update generated files if (maybe_output_dir) |output_dir| { if (compile.emit_directory) |lp| { - lp.path = try std.fmt.allocPrint(process_arena, "{f}", .{output_dir}); + lp.path = try allocPrint(process_arena, "{f}", .{output_dir}); } // zig fmt: off @@ -68,23 +72,26 @@ pub fn make( { try doAtomicSymLinks( step, - compile.getEmittedBin().getPath2(step.owner, step), + compile.getEmittedBin().getPath2(step), compile.major_only_filename.?, compile.name_only_filename.?, ); } } -fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 { - const step = &compile.step; - const b = step.owner; +fn lowerZigArgs( + compile: *Compile, + step_index: Configuration.Step.Index, + maker: *Maker, + zig_args: *std.ArrayList([]const u8), + fuzz: bool, +) Allocator.Error!void { + const step = maker.stepByIndex(step_index); const graph = maker.graph; const arena = graph.arena; // TODO don't leak into the process arena + const gpa = maker.gpa; - var zig_args = std.array_list.Managed([]const u8).init(arena); - defer zig_args.deinit(); - - try zig_args.append(graph.zig_exe); + try zig_args.append(gpa, graph.zig_exe); const cmd = switch (compile.kind) { .lib => "build-lib", @@ -93,10 +100,10 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 { .@"test" => "test", .test_obj => "test-obj", }; - try zig_args.append(cmd); + try zig_args.append(gpa, cmd); - if (b.reference_trace) |some| { - try zig_args.append(try std.fmt.allocPrint(arena, "-freference-trace={d}", .{some})); + if (graph.reference_trace) |some| { + try zig_args.append(gpa, try allocPrint(arena, "-freference-trace={d}", .{some})); } try addFlag(&zig_args, "allow-so-scripts", compile.allow_so_scripts orelse graph.allow_so_scripts); @@ -105,33 +112,31 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 { try addFlag(&zig_args, "new-linker", compile.use_new_linker); if (compile.root_module.resolved_target.?.query.ofmt) |ofmt| { - try zig_args.append(try std.fmt.allocPrint(arena, "-ofmt={s}", .{@tagName(ofmt)})); + try zig_args.append(gpa, try allocPrint(arena, "-ofmt={t}", .{ofmt})); } switch (compile.entry) { .default => {}, - .disabled => try zig_args.append("-fno-entry"), - .enabled => try zig_args.append("-fentry"), + .disabled => try zig_args.append(gpa, "-fno-entry"), + .enabled => try zig_args.append(gpa, "-fentry"), .symbol_name => |entry_name| { - try zig_args.append(try std.fmt.allocPrint(arena, "-fentry={s}", .{entry_name})); + try zig_args.append(gpa, try allocPrint(arena, "-fentry={s}", .{entry_name})); }, } { for (compile.force_undefined_symbols.keys()) |symbol_name| { - try zig_args.append("--force_undefined"); - try zig_args.append(symbol_name.*); + try zig_args.append(gpa, "--force_undefined"); + try zig_args.append(gpa, symbol_name.*); } } if (compile.stack_size) |stack_size| { - try zig_args.append("--stack"); - try zig_args.append(try std.fmt.allocPrint(arena, "{}", .{stack_size})); + try zig_args.append(gpa, "--stack"); + try zig_args.append(gpa, try allocPrint(arena, "{}", .{stack_size})); } - if (fuzz) { - try zig_args.append("-ffuzz"); - } + try addBool(gpa, zig_args, fuzz, "-ffuzz"); { // Stores system libraries that have already been seen for at least one @@ -181,14 +186,14 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 { switch (link_object) { .static_path => |static_path| { if (my_responsibility) { - try zig_args.append(static_path.getPath2(mod.owner, step)); + try zig_args.append(gpa, static_path.getPath2(step)); total_linker_objects += 1; } }, .system_lib => |system_lib| { const system_lib_gop = try seen_system_libs.getOrPut(arena, system_lib.name); if (system_lib_gop.found_existing) { - try zig_args.appendSlice(system_lib_gop.value_ptr.*); + try zig_args.appendSlice(gpa, system_lib_gop.value_ptr.*); continue; } else { system_lib_gop.value_ptr.* = &.{}; @@ -203,16 +208,16 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 { { switch (system_lib.search_strategy) { .no_fallback => switch (system_lib.preferred_link_mode) { - .dynamic => try zig_args.append("-search_dylibs_only"), - .static => try zig_args.append("-search_static_only"), + .dynamic => try zig_args.append(gpa, "-search_dylibs_only"), + .static => try zig_args.append(gpa, "-search_static_only"), }, .paths_first => switch (system_lib.preferred_link_mode) { - .dynamic => try zig_args.append("-search_paths_first"), - .static => try zig_args.append("-search_paths_first_static"), + .dynamic => try zig_args.append(gpa, "-search_paths_first"), + .static => try zig_args.append(gpa, "-search_paths_first_static"), }, .mode_first => switch (system_lib.preferred_link_mode) { - .dynamic => try zig_args.append("-search_dylibs_first"), - .static => try zig_args.append("-search_static_first"), + .dynamic => try zig_args.append(gpa, "-search_dylibs_first"), + .static => try zig_args.append(gpa, "-search_static_first"), }, } prev_search_strategy = system_lib.search_strategy; @@ -225,11 +230,11 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 { break :prefix "-l"; }; switch (system_lib.use_pkg_config) { - .no => try zig_args.append(b.fmt("{s}{s}", .{ prefix, system_lib.name })), + .no => try zig_args.append(gpa, try allocPrint(arena, "{s}{s}", .{ prefix, system_lib.name })), .yes, .force => { if (compile.runPkgConfig(maker, system_lib.name)) |result| { - try zig_args.appendSlice(result.cflags); - try zig_args.appendSlice(result.libs); + try zig_args.appendSlice(gpa, result.cflags); + try zig_args.appendSlice(gpa, result.libs); try seen_system_libs.put(arena, system_lib.name, result.cflags); } else |err| switch (err) { error.PkgConfigInvalidOutput, @@ -241,7 +246,7 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 { .yes => { // pkg-config failed, so fall back to linking the library // by name directly. - try zig_args.append(b.fmt("{s}{s}", .{ + try zig_args.append(gpa, try allocPrint(arena, "{s}{s}", .{ prefix, system_lib.name, })); @@ -265,7 +270,7 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 { const included_in_lib_or_obj = !my_responsibility and (dep_compile.kind == .lib or dep_compile.kind == .obj or dep_compile.kind == .test_obj); if (!already_linked and !included_in_lib_or_obj) { - try zig_args.append(other.getEmittedBin().getPath2(b, step)); + try zig_args.append(gpa, other.getEmittedBin().getPath2(step)); total_linker_objects += 1; } }, @@ -286,15 +291,15 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 { else try other.getGeneratedFilePath("generated_bin", &compile.step); - try zig_args.append(full_path_lib); + try zig_args.append(gpa, full_path_lib); total_linker_objects += 1; if (other.linkage == .dynamic and compile.rootModuleTarget().os.tag != .windows) { if (Dir.path.dirname(full_path_lib)) |dirname| { - try zig_args.append("-rpath"); - try zig_args.append(dirname); + try zig_args.append(gpa, "-rpath"); + try zig_args.append(gpa, dirname); } } }, @@ -304,11 +309,11 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 { if (!my_responsibility) break :l; if (prev_has_cflags) { - try zig_args.append("-cflags"); - try zig_args.append("--"); + try zig_args.append(gpa, "-cflags"); + try zig_args.append(gpa, "--"); prev_has_cflags = false; } - try zig_args.append(asm_file.getPath2(mod.owner, step)); + try zig_args.append(gpa, asm_file.getPath2(mod.owner, step)); total_linker_objects += 1; }, @@ -316,24 +321,24 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 { if (!my_responsibility) break :l; if (prev_has_cflags or c_source_file.flags.len != 0) { - try zig_args.append("-cflags"); + try zig_args.append(gpa, "-cflags"); for (c_source_file.flags) |arg| { - try zig_args.append(arg); + try zig_args.append(gpa, arg); } - try zig_args.append("--"); + try zig_args.append(gpa, "--"); } prev_has_cflags = (c_source_file.flags.len != 0); if (c_source_file.language) |lang| { - try zig_args.append("-x"); - try zig_args.append(lang.internalIdentifier()); + try zig_args.append(gpa, "-x"); + try zig_args.append(gpa, lang.internalIdentifier()); } - try zig_args.append(c_source_file.file.getPath2(mod.owner, step)); + try zig_args.append(gpa, c_source_file.file.getPath2(mod.owner, step)); if (c_source_file.language != null) { - try zig_args.append("-x"); - try zig_args.append("none"); + try zig_args.append(gpa, "-x"); + try zig_args.append(gpa, "none"); } total_linker_objects += 1; }, @@ -342,27 +347,27 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 { if (!my_responsibility) break :l; if (prev_has_cflags or c_source_files.flags.len != 0) { - try zig_args.append("-cflags"); + try zig_args.append(gpa, "-cflags"); for (c_source_files.flags) |arg| { - try zig_args.append(arg); + try zig_args.append(gpa, arg); } - try zig_args.append("--"); + try zig_args.append(gpa, "--"); } prev_has_cflags = (c_source_files.flags.len != 0); if (c_source_files.language) |lang| { - try zig_args.append("-x"); - try zig_args.append(lang.internalIdentifier()); + try zig_args.append(gpa, "-x"); + try zig_args.append(gpa, lang.internalIdentifier()); } const root_path = c_source_files.root.getPath2(mod.owner, step); for (c_source_files.files) |file| { - try zig_args.append(b.pathJoin(&.{ root_path, file })); + try zig_args.append(gpa, try Dir.path.join(arena, &.{ root_path, file })); } if (c_source_files.language != null) { - try zig_args.append("-x"); - try zig_args.append("none"); + try zig_args.append(gpa, "-x"); + try zig_args.append(gpa, "none"); } total_linker_objects += c_source_files.files.len; @@ -373,23 +378,23 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 { if (rc_source_file.flags.len == 0 and rc_source_file.include_paths.len == 0) { if (prev_has_rcflags) { - try zig_args.append("-rcflags"); - try zig_args.append("--"); + try zig_args.append(gpa, "-rcflags"); + try zig_args.append(gpa, "--"); prev_has_rcflags = false; } } else { - try zig_args.append("-rcflags"); + try zig_args.append(gpa, "-rcflags"); for (rc_source_file.flags) |arg| { - try zig_args.append(arg); + try zig_args.append(gpa, arg); } for (rc_source_file.include_paths) |include_path| { - try zig_args.append("/I"); - try zig_args.append(include_path.getPath2(mod.owner, step)); + try zig_args.append(gpa, "/I"); + try zig_args.append(gpa, include_path.getPath2(mod.owner, step)); } - try zig_args.append("--"); + try zig_args.append(gpa, "--"); prev_has_rcflags = true; } - try zig_args.append(rc_source_file.file.getPath2(mod.owner, step)); + try zig_args.append(gpa, rc_source_file.file.getPath2(mod.owner, step)); total_linker_objects += 1; }, } @@ -412,7 +417,7 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 { if (std.mem.eql(u8, import_cli_name, name)) { zig_args.appendAssumeCapacity(import_cli_name); } else { - zig_args.appendAssumeCapacity(b.fmt("{s}={s}", .{ name, import_cli_name })); + zig_args.appendAssumeCapacity(try allocPrint(arena, "{s}={s}", .{ name, import_cli_name })); } } @@ -425,9 +430,9 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 { // files must have a module parent. if (mod.root_source_file) |lp| { const src = lp.getPath2(mod.owner, step); - try zig_args.append(b.fmt("-M{s}={s}", .{ module_cli_name, src })); + try zig_args.append(gpa, try allocPrint(arena, "-M{s}={s}", .{ module_cli_name, src })); } else if (moduleNeedsCliArg(mod)) { - try zig_args.append(b.fmt("-M{s}", .{module_cli_name})); + try zig_args.append(gpa, try allocPrint(arena, "-M{s}", .{module_cli_name})); } } } @@ -439,276 +444,249 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 { for (frameworks.keys(), frameworks.values()) |name, info| { if (info.needed) { - try zig_args.append("-needed_framework"); + try zig_args.append(gpa, "-needed_framework"); } else if (info.weak) { - try zig_args.append("-weak_framework"); + try zig_args.append(gpa, "-weak_framework"); } else { - try zig_args.append("-framework"); + try zig_args.append(gpa, "-framework"); } - try zig_args.append(name); + try zig_args.append(gpa, name); } if (compile.is_linking_libcpp) { - try zig_args.append("-lc++"); + try zig_args.append(gpa, "-lc++"); } if (compile.is_linking_libc) { - try zig_args.append("-lc"); + try zig_args.append(gpa, "-lc"); } } if (compile.win32_manifest) |manifest_file| { - try zig_args.append(manifest_file.getPath2(b, step)); + try zig_args.append(gpa, manifest_file.getPath2(step)); } if (compile.win32_module_definition) |module_file| { - try zig_args.append(module_file.getPath2(b, step)); + try zig_args.append(gpa, module_file.getPath2(step)); } if (compile.image_base) |image_base| { - try zig_args.append("--image-base"); - try zig_args.append(b.fmt("0x{x}", .{image_base})); + try zig_args.appendSlice(gpa, &.{ + "--image-base", try allocPrint(arena, "0x{x}", .{image_base}), + }); } for (compile.filters) |filter| { - try zig_args.append("--test-filter"); - try zig_args.append(filter); + try zig_args.appendSlice(gpa, &.{ "--test-filter", filter }); } if (compile.test_runner) |test_runner| { - try zig_args.append("--test-runner"); - try zig_args.append(test_runner.path.getPath2(b, step)); + try zig_args.appendSlice(gpa, &.{ "--test-runner", test_runner.path.getPath2(step) }); } - for (b.debug_log_scopes) |log_scope| { - try zig_args.append("--debug-log"); - try zig_args.append(log_scope); + for (graph.debug_log_scopes) |log_scope| { + try zig_args.appendSlice(gpa, &.{ "--debug-log", log_scope }); } - if (b.debug_compile_errors) { - try zig_args.append("--debug-compile-errors"); - } + try addBool(gpa, zig_args, graph.debug_compile_errors, "--debug-compile-errors"); + try addBool(gpa, zig_args, graph.debug_incremental, "--debug-incremental"); + try addBool(gpa, zig_args, graph.verbose_cimport, "--verbose-cimport"); + try addBool(gpa, zig_args, graph.verbose_air, "--verbose-air"); + try addBool(gpa, zig_args, graph.verbose_llvm_ir, "--verbose-llvm-ir"); + try addBool(gpa, zig_args, graph.verbose_link or compile.verbose_link, "--verbose-link"); + try addBool(gpa, zig_args, graph.verbose_cc or compile.verbose_cc, "--verbose-cc"); + try addBool(gpa, zig_args, graph.verbose_llvm_cpu_features, "--verbose-llvm-cpu-features"); + try addBool(gpa, zig_args, graph.time_report, "--time-report"); - if (b.debug_incremental) { - try zig_args.append("--debug-incremental"); - } - - if (b.verbose_cimport) try zig_args.append("--verbose-cimport"); - if (b.verbose_air) try zig_args.append("--verbose-air"); - if (b.verbose_llvm_ir) |path| try zig_args.append(b.fmt("--verbose-llvm-ir={s}", .{path})); - if (b.verbose_llvm_bc) |path| try zig_args.append(b.fmt("--verbose-llvm-bc={s}", .{path})); - if (b.verbose_link or compile.verbose_link) try zig_args.append("--verbose-link"); - if (b.verbose_cc or compile.verbose_cc) try zig_args.append("--verbose-cc"); - if (b.verbose_llvm_cpu_features) try zig_args.append("--verbose-llvm-cpu-features"); - if (graph.time_report) try zig_args.append("--time-report"); - - if (compile.generated_asm != null) try zig_args.append("-femit-asm"); - if (compile.generated_bin == null) try zig_args.append("-fno-emit-bin"); - if (compile.generated_docs != null) try zig_args.append("-femit-docs"); - if (compile.generated_implib != null) try zig_args.append("-femit-implib"); - if (compile.generated_llvm_bc != null) try zig_args.append("-femit-llvm-bc"); - if (compile.generated_llvm_ir != null) try zig_args.append("-femit-llvm-ir"); - if (compile.generated_h != null) try zig_args.append("-femit-h"); + if (compile.generated_asm != null) try zig_args.append(gpa, "-femit-asm"); + if (compile.generated_bin == null) try zig_args.append(gpa, "-fno-emit-bin"); + if (compile.generated_docs != null) try zig_args.append(gpa, "-femit-docs"); + if (compile.generated_implib != null) try zig_args.append(gpa, "-femit-implib"); + if (compile.generated_llvm_bc != null) try zig_args.append(gpa, "-femit-llvm-bc"); + if (compile.generated_llvm_ir != null) try zig_args.append(gpa, "-femit-llvm-ir"); + if (compile.generated_h != null) try zig_args.append(gpa, "-femit-h"); try addFlag(&zig_args, "formatted-panics", compile.formatted_panics); switch (compile.compress_debug_sections) { .none => {}, - .zlib => try zig_args.append("--compress-debug-sections=zlib"), - .zstd => try zig_args.append("--compress-debug-sections=zstd"), + .zlib => try zig_args.append(gpa, "--compress-debug-sections=zlib"), + .zstd => try zig_args.append(gpa, "--compress-debug-sections=zstd"), } if (compile.link_eh_frame_hdr) { - try zig_args.append("--eh-frame-hdr"); + try zig_args.append(gpa, "--eh-frame-hdr"); } if (compile.link_emit_relocs) { - try zig_args.append("--emit-relocs"); + try zig_args.append(gpa, "--emit-relocs"); } if (compile.link_function_sections) { - try zig_args.append("-ffunction-sections"); + try zig_args.append(gpa, "-ffunction-sections"); } if (compile.link_data_sections) { - try zig_args.append("-fdata-sections"); + try zig_args.append(gpa, "-fdata-sections"); } if (compile.link_gc_sections) |x| { - try zig_args.append(if (x) "--gc-sections" else "--no-gc-sections"); + try zig_args.append(gpa, if (x) "--gc-sections" else "--no-gc-sections"); } if (!compile.linker_dynamicbase) { - try zig_args.append("--no-dynamicbase"); + try zig_args.append(gpa, "--no-dynamicbase"); } if (compile.linker_allow_shlib_undefined) |x| { - try zig_args.append(if (x) "-fallow-shlib-undefined" else "-fno-allow-shlib-undefined"); - } - if (compile.link_z_notext) { - try zig_args.append("-z"); - try zig_args.append("notext"); - } - if (!compile.link_z_relro) { - try zig_args.append("-z"); - try zig_args.append("norelro"); - } - if (compile.link_z_lazy) { - try zig_args.append("-z"); - try zig_args.append("lazy"); - } - if (compile.link_z_common_page_size) |size| { - try zig_args.append("-z"); - try zig_args.append(b.fmt("common-page-size={d}", .{size})); - } - if (compile.link_z_max_page_size) |size| { - try zig_args.append("-z"); - try zig_args.append(b.fmt("max-page-size={d}", .{size})); - } - if (compile.link_z_defs) { - try zig_args.append("-z"); - try zig_args.append("defs"); + try zig_args.append(gpa, if (x) "-fallow-shlib-undefined" else "-fno-allow-shlib-undefined"); } + if (compile.link_z_notext) try zig_args.appendSlice(gpa, &.{ "-z", "notext" }); + if (!compile.link_z_relro) try zig_args.appendSlice(gpa, &.{ "-z", "norelro" }); + if (compile.link_z_lazy) try zig_args.appendSlice(gpa, &.{ "-z", "lazy" }); + if (compile.link_z_common_page_size) |size| try zig_args.appendSlice(gpa, &.{ + "-z", + try allocPrint(arena, "common-page-size={d}", .{size}), + }); + if (compile.link_z_max_page_size) |size| try zig_args.appendSlice(gpa, &.{ + "-z", + try allocPrint(arena, "max-page-size={d}", .{size}), + }); + if (compile.link_z_defs) try zig_args.appendSlice(gpa, &.{ "-z", "defs" }); if (compile.libc_file) |libc_file| { - try zig_args.append("--libc"); - try zig_args.append(libc_file.getPath2(b, step)); - } else if (b.libc_file) |libc_file| { - try zig_args.append("--libc"); - try zig_args.append(libc_file); + try zig_args.appendSlice(gpa, &.{ "--libc", libc_file.getPath2(step) }); + } else if (graph.libc_file) |libc_file| { + try zig_args.appendSlice(gpa, &.{ "--libc", libc_file }); } - try zig_args.append("--cache-dir"); - try zig_args.append(b.cache_root.path orelse "."); + try zig_args.append(gpa, "--cache-dir"); + try zig_args.append(gpa, graph.cache_root.path orelse "."); - try zig_args.append("--global-cache-dir"); - try zig_args.append(graph.global_cache_root.path orelse "."); + try zig_args.append(gpa, "--global-cache-dir"); + try zig_args.append(gpa, graph.global_cache_root.path orelse "."); if (graph.debug_compiler_runtime_libs) |mode| - try zig_args.append(b.fmt("--debug-rt={t}", .{mode})); + try zig_args.append(gpa, try allocPrint(arena, "--debug-rt={t}", .{mode})); - try zig_args.append("--name"); - try zig_args.append(compile.name); + try zig_args.append(gpa, "--name"); + try zig_args.append(gpa, compile.name); if (compile.linkage) |some| switch (some) { - .dynamic => try zig_args.append("-dynamic"), - .static => try zig_args.append("-static"), + .dynamic => try zig_args.append(gpa, "-dynamic"), + .static => try zig_args.append(gpa, "-static"), }; if (compile.kind == .lib and compile.linkage != null and compile.linkage.? == .dynamic) { if (compile.version) |version| { - try zig_args.append("--version"); - try zig_args.append(b.fmt("{f}", .{version})); + try zig_args.append(gpa, "--version"); + try zig_args.append(gpa, try allocPrint(arena, "{f}", .{version})); } if (compile.rootModuleTarget().os.tag.isDarwin()) { - const install_name = compile.install_name orelse b.fmt("@rpath/{s}{s}{s}", .{ + const install_name = compile.install_name orelse try allocPrint(arena, "@rpath/{s}{s}{s}", .{ compile.rootModuleTarget().libPrefix(), compile.name, compile.rootModuleTarget().dynamicLibSuffix(), }); - try zig_args.append("-install_name"); - try zig_args.append(install_name); + try zig_args.append(gpa, "-install_name"); + try zig_args.append(gpa, install_name); } } if (compile.entitlements) |entitlements| { - try zig_args.appendSlice(&[_][]const u8{ "--entitlements", entitlements }); + try zig_args.appendSlice(gpa, &[_][]const u8{ "--entitlements", entitlements }); } if (compile.pagezero_size) |pagezero_size| { - const size = try std.fmt.allocPrint(arena, "{x}", .{pagezero_size}); - try zig_args.appendSlice(&[_][]const u8{ "-pagezero_size", size }); + const size = try allocPrint(arena, "{x}", .{pagezero_size}); + try zig_args.appendSlice(gpa, &[_][]const u8{ "-pagezero_size", size }); } if (compile.headerpad_size) |headerpad_size| { - const size = try std.fmt.allocPrint(arena, "{x}", .{headerpad_size}); - try zig_args.appendSlice(&[_][]const u8{ "-headerpad", size }); + const size = try allocPrint(arena, "{x}", .{headerpad_size}); + try zig_args.appendSlice(gpa, &[_][]const u8{ "-headerpad", size }); } if (compile.headerpad_max_install_names) { - try zig_args.append("-headerpad_max_install_names"); + try zig_args.append(gpa, "-headerpad_max_install_names"); } if (compile.dead_strip_dylibs) { - try zig_args.append("-dead_strip_dylibs"); + try zig_args.append(gpa, "-dead_strip_dylibs"); } if (compile.force_load_objc) { - try zig_args.append("-ObjC"); + try zig_args.append(gpa, "-ObjC"); } if (compile.discard_local_symbols) { - try zig_args.append("--discard-all"); + try zig_args.append(gpa, "--discard-all"); } try addFlag(&zig_args, "compiler-rt", compile.bundle_compiler_rt); try addFlag(&zig_args, "ubsan-rt", compile.bundle_ubsan_rt); try addFlag(&zig_args, "dll-export-fns", compile.dll_export_fns); if (compile.rdynamic) { - try zig_args.append("-rdynamic"); + try zig_args.append(gpa, "-rdynamic"); } if (compile.import_memory) { - try zig_args.append("--import-memory"); + try zig_args.append(gpa, "--import-memory"); } if (compile.export_memory) { - try zig_args.append("--export-memory"); + try zig_args.append(gpa, "--export-memory"); } if (compile.import_symbols) { - try zig_args.append("--import-symbols"); + try zig_args.append(gpa, "--import-symbols"); } if (compile.import_table) { - try zig_args.append("--import-table"); + try zig_args.append(gpa, "--import-table"); } if (compile.export_table) { - try zig_args.append("--export-table"); + try zig_args.append(gpa, "--export-table"); } if (compile.initial_memory) |initial_memory| { - try zig_args.append(b.fmt("--initial-memory={d}", .{initial_memory})); + try zig_args.append(gpa, try allocPrint(arena, "--initial-memory={d}", .{initial_memory})); } if (compile.max_memory) |max_memory| { - try zig_args.append(b.fmt("--max-memory={d}", .{max_memory})); + try zig_args.append(gpa, try allocPrint(arena, "--max-memory={d}", .{max_memory})); } if (compile.shared_memory) { - try zig_args.append("--shared-memory"); + try zig_args.append(gpa, "--shared-memory"); } if (compile.global_base) |global_base| { - try zig_args.append(b.fmt("--global-base={d}", .{global_base})); + try zig_args.append(gpa, try allocPrint(arena, "--global-base={d}", .{global_base})); } if (compile.wasi_exec_model) |model| { - try zig_args.append(b.fmt("-mexec-model={s}", .{@tagName(model)})); + try zig_args.append(gpa, try allocPrint(arena, "-mexec-model={t}", .{model})); } if (compile.linker_script) |linker_script| { - try zig_args.append("--script"); - try zig_args.append(linker_script.getPath2(b, step)); + try zig_args.append(gpa, "--script"); + try zig_args.append(gpa, linker_script.getPath2(step)); } if (compile.version_script) |version_script| { - try zig_args.append("--version-script"); - try zig_args.append(version_script.getPath2(b, step)); + try zig_args.append(gpa, "--version-script"); + try zig_args.append(gpa, version_script.getPath2(step)); } if (compile.linker_allow_undefined_version) |x| { - try zig_args.append(if (x) "--undefined-version" else "--no-undefined-version"); + try zig_args.append(gpa, if (x) "--undefined-version" else "--no-undefined-version"); } if (compile.linker_enable_new_dtags) |enabled| { - try zig_args.append(if (enabled) "--enable-new-dtags" else "--disable-new-dtags"); + try zig_args.append(gpa, if (enabled) "--enable-new-dtags" else "--disable-new-dtags"); } if (compile.kind == .@"test") { if (compile.exec_cmd_args) |exec_cmd_args| { for (exec_cmd_args) |cmd_arg| { if (cmd_arg) |arg| { - try zig_args.append("--test-cmd"); - try zig_args.append(arg); + try zig_args.append(gpa, "--test-cmd"); + try zig_args.append(gpa, arg); } else { - try zig_args.append("--test-cmd-bin"); + try zig_args.append(gpa, "--test-cmd-bin"); } } } } - if (b.sysroot) |sysroot| { - try zig_args.appendSlice(&[_][]const u8{ "--sysroot", sysroot }); - } + if (graph.sysroot) |sysroot| try zig_args.appendSlice(gpa, &.{ "--sysroot", sysroot }); // -I and -L arguments that appear after the last --mod argument apply to all modules. const cwd: Io.Dir = .cwd(); const io = graph.io; - for (b.search_prefixes.items) |search_prefix| { + for (graph.search_prefixes.items) |search_prefix| { var prefix_dir = cwd.openDir(io, search_prefix, .{}) catch |err| { - return step.fail("unable to open prefix directory '{s}': {s}", .{ - search_prefix, @errorName(err), - }); + return step.fail("unable to open prefix directory '{s}': {t}", .{ search_prefix, err }); }; defer prefix_dir.close(io); @@ -717,58 +695,53 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 { // CLI parsing code, when the linker sees an -L directory that does not exist. if (prefix_dir.access(io, "lib", .{})) |_| { - try zig_args.appendSlice(&.{ - "-L", b.pathJoin(&.{ search_prefix, "lib" }), + try zig_args.appendSlice(gpa, &.{ + "-L", try Dir.path.join(arena, &.{ search_prefix, "lib" }), }); } else |err| switch (err) { error.FileNotFound => {}, - else => |e| return step.fail("unable to access '{s}/lib' directory: {s}", .{ - search_prefix, @errorName(e), - }), + else => |e| return step.fail("unable to access '{s}/lib' directory: {t}", .{ search_prefix, e }), } if (prefix_dir.access(io, "include", .{})) |_| { - try zig_args.appendSlice(&.{ - "-I", b.pathJoin(&.{ search_prefix, "include" }), + try zig_args.appendSlice(gpa, &.{ + "-I", try Dir.path.join(arena, &.{ search_prefix, "include" }), }); } else |err| switch (err) { error.FileNotFound => {}, - else => |e| return step.fail("unable to access '{s}/include' directory: {s}", .{ - search_prefix, @errorName(e), - }), + else => |e| return step.fail("unable to access '{s}/include' directory: {t}", .{ search_prefix, e }), } } if (compile.rc_includes != .any) { - try zig_args.append("-rcincludes"); - try zig_args.append(@tagName(compile.rc_includes)); + try zig_args.appendSlice(gpa, &.{ "-rcincludes", @tagName(compile.rc_includes) }); } try addFlag(&zig_args, "each-lib-rpath", compile.each_lib_rpath); - if (compile.build_id orelse b.build_id) |build_id| { - try zig_args.append(switch (build_id) { - .hexstring => |hs| b.fmt("--build-id=0x{x}", .{hs.toSlice()}), - .none, .fast, .uuid, .sha1, .md5 => b.fmt("--build-id={s}", .{@tagName(build_id)}), + if (compile.build_id orelse graph.build_id) |build_id| { + try zig_args.append(gpa, switch (build_id) { + .hexstring => |hs| try allocPrint(arena, "--build-id=0x{x}", .{hs.toSlice()}), + .none, .fast, .uuid, .sha1, .md5 => try allocPrint(arena, "--build-id={t}", .{build_id}), }); } const opt_zig_lib_dir = if (compile.zig_lib_dir) |dir| - dir.getPath2(b, step) + dir.getPath2(step) else if (graph.zig_lib_directory.path) |_| - b.fmt("{f}", .{graph.zig_lib_directory}) + try allocPrint(arena, "{f}", .{graph.zig_lib_directory}) else null; if (opt_zig_lib_dir) |zig_lib_dir| { - try zig_args.append("--zig-lib-dir"); - try zig_args.append(zig_lib_dir); + try zig_args.append(gpa, "--zig-lib-dir"); + try zig_args.append(gpa, zig_lib_dir); } try addFlag(&zig_args, "PIE", compile.pie); if (compile.lto) |lto| { - try zig_args.append(switch (lto) { + try zig_args.append(gpa, switch (lto) { .full => "-flto=full", .thin => "-flto=thin", .none => "-fno-lto", @@ -778,21 +751,20 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 { try addFlag(&zig_args, "sanitize-coverage-trace-pc-guard", compile.sanitize_coverage_trace_pc_guard); if (compile.subsystem) |subsystem| { - try zig_args.append("--subsystem"); - try zig_args.append(@tagName(subsystem)); + try zig_args.appendSlice(gpa, &.{ "--subsystem", @tagName(subsystem) }); } if (compile.mingw_unicode_entry_point) { - try zig_args.append("-municode"); + try zig_args.append(gpa, "-municode"); } - if (compile.error_limit) |err_limit| try zig_args.appendSlice(&.{ - "--error-limit", b.fmt("{d}", .{err_limit}), + if (compile.error_limit) |err_limit| try zig_args.appendSlice(gpa, &.{ + "--error-limit", try allocPrint(arena, "{d}", .{err_limit}), }); try addFlag(&zig_args, "incremental", graph.incremental); - try zig_args.append("--listen=-"); + try zig_args.append(gpa, "--listen=-"); // Windows has an argument length limit of 32,766 characters, macOS 262,144 and Linux // 2,097,152. If our args exceed 30 KiB, we instead write them to a "response file" and @@ -803,7 +775,7 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 { args_length += arg.len + 1; // +1 to account for null terminator } if (args_length >= 30 * 1024) { - try b.cache_root.handle.createDirPath(io, "args"); + try graph.cache_root.handle.createDirPath(io, "args"); const args_to_escape = zig_args.items[2..]; var escaped_args = try std.array_list.Managed([]const u8).initCapacity(arena, args_to_escape.len); @@ -836,21 +808,21 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 { _ = try std.fmt.bufPrint(&args_hex_hash, "{x}", .{&args_hash}); const args_file = "args" ++ Dir.path.sep_str ++ args_hex_hash; - if (b.cache_root.handle.access(io, args_file, .{})) |_| { + if (graph.cache_root.handle.access(io, args_file, .{})) |_| { // The args file is already present from a previous run. } else |err| switch (err) { error.FileNotFound => { - var af = b.cache_root.handle.createFileAtomic(io, args_file, .{ + var af = graph.cache_root.handle.createFileAtomic(io, args_file, .{ .replace = false, .make_path = true, }) catch |e| return step.fail("failed creating tmp args file {f}{s}: {t}", .{ - b.cache_root, args_file, e, + graph.cache_root, args_file, e, }); defer af.deinit(io); af.file.writeStreamingAll(io, args) catch |e| { return step.fail("failed writing args data to tmp file {f}{s}: {t}", .{ - b.cache_root, args_file, e, + graph.cache_root, args_file, e, }); }; // Note we can't clean up this file, not even after build @@ -861,7 +833,7 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 { // The args file was created by another concurrent build process. }, else => |other_err| return step.fail("failed linking tmp file {f}{s}: {t}", .{ - b.cache_root, args_file, other_err, + graph.cache_root, args_file, other_err, }), }; }, @@ -870,32 +842,34 @@ fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 { const resolved_args_file = try mem.concat(arena, u8, &.{ "@", - try b.cache_root.join(arena, &.{args_file}), + try graph.cache_root.join(arena, &.{args_file}), }); zig_args.shrinkRetainingCapacity(2); - try zig_args.append(resolved_args_file); + try zig_args.append(gpa, resolved_args_file); } return try zig_args.toOwnedSlice(); } -pub fn rebuildInFuzzMode(c: *Compile, maker: *Maker, progress_node: std.Progress.Node) !Path { +pub fn rebuildInFuzzMode(compile: *Compile, maker: *Maker, progress_node: std.Progress.Node) !Path { const gpa = maker.graph.gpa; - c.step.result_error_msgs.clearRetainingCapacity(); - c.step.result_stderr = ""; + compile.step.result_error_msgs.clearRetainingCapacity(); + compile.step.result_stderr = ""; - c.step.result_error_bundle.deinit(gpa); - c.step.result_error_bundle = std.zig.ErrorBundle.empty; + compile.step.result_error_bundle.deinit(gpa); + compile.step.result_error_bundle = std.zig.ErrorBundle.empty; - if (c.step.result_failed_command) |cmd| { + if (compile.step.result_failed_command) |cmd| { gpa.free(cmd); - c.step.result_failed_command = null; + compile.step.result_failed_command = null; } - const zig_args = try getZigArgs(c, maker, true); - const maybe_output_bin_path = try c.step.evalZigProcess(zig_args, progress_node, false, null, gpa); + const zig_args = &compile.zig_args; + zig_args.clearRetainingCapacity(); + try lowerZigArgs(compile, maker, zig_args, true); + const maybe_output_bin_path = try compile.step.evalZigProcess(zig_args.items, progress_node, false, maker); return maybe_output_bin_path.?; } @@ -906,24 +880,24 @@ pub fn doAtomicSymLinks( filename_major_only: []const u8, filename_name_only: []const u8, ) !void { - const b = step.owner; const graph = maker.graph; + const arena = graph.arena; // TODO don't leak into process arena const io = graph.io; const out_dir = Dir.path.dirname(output_path) orelse "."; const out_basename = Dir.path.basename(output_path); // sym link for libfoo.so.1 to libfoo.so.1.2.3 - const major_only_path = b.pathJoin(&.{ out_dir, filename_major_only }); + const major_only_path = try Dir.path.join(arena, &.{ out_dir, filename_major_only }); const cwd: Io.Dir = .cwd(); cwd.symLinkAtomic(io, out_basename, major_only_path, .{}) catch |err| { - return step.fail("unable to symlink {s} -> {s}: {s}", .{ - major_only_path, out_basename, @errorName(err), + return step.fail("unable to symlink {s} -> {s}: {t}", .{ + major_only_path, out_basename, err, }); }; // sym link for libfoo.so to libfoo.so.1 - const name_only_path = b.pathJoin(&.{ out_dir, filename_name_only }); + const name_only_path = try Dir.path.join(arena, &.{ out_dir, filename_name_only }); cwd.symLinkAtomic(io, filename_major_only, name_only_path, .{}) catch |err| { - return step.fail("Unable to symlink {s} -> {s}: {s}", .{ - name_only_path, filename_major_only, @errorName(err), + return step.fail("unable to symlink {s} -> {s}: {t}", .{ + name_only_path, filename_major_only, err, }); }; } @@ -982,14 +956,13 @@ fn getPkgConfigList(b: *std.Build) ![]const PkgConfigPkg { } } -fn addFlag(args: *std.array_list.Managed([]const u8), comptime name: []const u8, opt: ?bool) !void { +fn addBool(gpa: Allocator, args: *std.ArrayList([]const u8), arg: []const u8, opt: bool) !void { + if (opt) try args.append(gpa, arg); +} + +fn addFlag(gpa: Allocator, args: *std.ArrayList([]const u8), comptime name: []const u8, opt: ?bool) !void { const cond = opt orelse return; - try args.ensureUnusedCapacity(1); - if (cond) { - args.appendAssumeCapacity("-f" ++ name); - } else { - args.appendAssumeCapacity("-fno-" ++ name); - } + try args.append(gpa, if (cond) "-f" ++ name else "-fno-" ++ name); } const PkgConfigResult = struct { @@ -1262,7 +1235,7 @@ const CliNamedModules = struct { try compile.modules.putNoClobber(arena, mod, {}); break; } - name = try std.fmt.allocPrint(arena, "{s}{d}", .{ orig_name, n }); + name = try allocPrint(arena, "{s}{d}", .{ orig_name, n }); n += 1; } } diff --git a/lib/compiler/Maker/Step/Run.zig b/lib/compiler/Maker/Step/Run.zig index 17b8f29b90..e19ef9aff8 100644 --- a/lib/compiler/Maker/Step/Run.zig +++ b/lib/compiler/Maker/Step/Run.zig @@ -1091,7 +1091,7 @@ fn runCommand( const cwd: process.Child.Cwd = if (run.cwd) |lazy_cwd| .{ .path = lazy_cwd.getPath2(b, step) } else .inherit; try step.handleChildProcUnsupported(); - try Step.handleVerbose2(step.owner, cwd, run.environ_map, argv); + try Step.handleVerbose(step.owner, cwd, run.environ_map, argv); const allow_skip = switch (run.stdio) { .check, .zig_test => run.skip_foreign_checks, @@ -1241,7 +1241,7 @@ fn runCommand( gpa.free(step.result_failed_command.?); step.result_failed_command = null; - try Step.handleVerbose2(step.owner, cwd, run.environ_map, interp_argv.items); + try Step.handleVerbose(step.owner, cwd, run.environ_map, interp_argv.items); break :term spawnChildAndCollect(run, maker, progress_node, interp_argv.items, &environ_map, has_side_effects, fuzz_context) catch |e| { if (!run.failing_to_execute_foreign_is_an_error) return error.MakeSkipped; diff --git a/lib/compiler/configure_runner.zig b/lib/compiler/configure_runner.zig index 54113594f6..392f0a42c5 100644 --- a/lib/compiler/configure_runner.zig +++ b/lib/compiler/configure_runner.zig @@ -148,39 +148,30 @@ pub fn main(init: process.Init.Minimal) !void { graph.release_mode = .any; } else if (mem.cutPrefix(u8, arg, "--release=")) |text| { graph.release_mode = std.meta.stringToEnum(std.Build.ReleaseMode, text) orelse { - fatalWithHint("expected [off|any|fast|safe|small] in '{s}', found '{s}'", .{ + fatalWithHint("expected [off|any|fast|safe|small] in {q}, found {q}", .{ arg, text, }); }; } else if (mem.eql(u8, arg, "--color")) { const next_arg = nextArg(args, &arg_idx) orelse - fatalWithHint("expected [auto|on|off] after '{s}'", .{arg}); + fatalWithHint("expected [auto|on|off] after {q}", .{arg}); color = std.meta.stringToEnum(Color, next_arg) orelse { - fatalWithHint("expected [auto|on|off] after '{s}', found '{s}'", .{ + fatalWithHint("expected [auto|on|off] after {q}, found {q}", .{ arg, next_arg, }); }; } else if (mem.eql(u8, arg, "--error-style")) { const next_arg = nextArg(args, &arg_idx) orelse - fatalWithHint("expected style after '{s}'", .{arg}); + fatalWithHint("expected style after {q}", .{arg}); error_style = std.meta.stringToEnum(ErrorStyle, next_arg) orelse { - fatalWithHint("expected style after '{s}', found '{s}'", .{ arg, next_arg }); + fatalWithHint("expected style after {q}, found {q}", .{ arg, next_arg }); }; } else if (mem.eql(u8, arg, "--multiline-errors")) { const next_arg = nextArg(args, &arg_idx) orelse - fatalWithHint("expected style after '{s}'", .{arg}); + fatalWithHint("expected style after {q}", .{arg}); multiline_errors = std.meta.stringToEnum(MultilineErrors, next_arg) orelse { - fatalWithHint("expected style after '{s}', found '{s}'", .{ arg, next_arg }); + fatalWithHint("expected style after {q}, found {q}", .{ arg, next_arg }); }; - } else if (mem.eql(u8, arg, "--build-id")) { - builder.build_id = .fast; - } else if (mem.cutPrefix(u8, arg, "--build-id=")) |style| { - builder.build_id = std.zig.BuildId.parse(style) catch |err| - fatal("unable to parse --build-id style '{s}': {t}", .{ style, err }); - } else if (mem.eql(u8, arg, "--debug-compile-errors")) { - builder.debug_compile_errors = true; - } else if (mem.eql(u8, arg, "--debug-incremental")) { - builder.debug_incremental = true; } else if (mem.eql(u8, arg, "--system")) { // The usage text shows another argument after this parameter // but it is handled by the parent process. The build runner @@ -189,7 +180,7 @@ pub fn main(init: process.Init.Minimal) !void { } else if (mem.eql(u8, arg, "--have-run-args")) { graph.have_run_args = true; } else { - fatalWithHint("unrecognized argument: '{s}'", .{arg}); + fatalWithHint("unrecognized argument: {q}", .{arg}); } } diff --git a/lib/std/Build.zig b/lib/std/Build.zig index a152448a8a..a35f9473bc 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -31,14 +31,6 @@ allocator: Allocator, user_input_options: UserInputOptionsMap, available_options_map: AvailableOptionsMap, available_options_list: std.array_list.Managed(AvailableOption), -verbose: bool, -verbose_link: bool, -verbose_cc: bool, -verbose_air: bool, -verbose_llvm_ir: ?[]const u8, -verbose_llvm_bc: ?[]const u8, -verbose_cimport: bool, -verbose_llvm_cpu_features: bool, invalid_user_input: bool, default_step: *Step, top_level_steps: std.StringArrayHashMapUnmanaged(*Step.TopLevel), @@ -47,8 +39,6 @@ install_prefix: []const u8, build_root: Cache.Directory, cache_root: Cache.Directory, debug_log_scopes: []const []const u8 = &.{}, -debug_compile_errors: bool = false, -debug_incremental: bool = false, /// Number of stack frames captured when a `StackTrace` is recorded for debug purposes, /// in particular at `Step` creation. /// Set to 0 to disable stack collection. @@ -76,8 +66,6 @@ pkg_hash: []const u8, /// A mapping from dependency names to package hashes. available_deps: AvailableDeps, -build_id: ?std.zig.BuildId = null, - pub const ReleaseMode = enum { off, any, @@ -225,14 +213,6 @@ pub fn create( .graph = graph, .build_root = build_root, .cache_root = cache_root, - .verbose = false, - .verbose_link = false, - .verbose_cc = false, - .verbose_air = false, - .verbose_llvm_ir = null, - .verbose_llvm_bc = null, - .verbose_cimport = false, - .verbose_llvm_cpu_features = false, .invalid_user_input = false, .allocator = arena, .user_input_options = UserInputOptionsMap.init(arena), @@ -301,23 +281,12 @@ fn createChild( .user_input_options = user_input_options, .available_options_map = AvailableOptionsMap.init(allocator), .available_options_list = std.array_list.Managed(AvailableOption).init(allocator), - .verbose = parent.verbose, - .verbose_link = parent.verbose_link, - .verbose_cc = parent.verbose_cc, - .verbose_air = parent.verbose_air, - .verbose_llvm_ir = parent.verbose_llvm_ir, - .verbose_llvm_bc = parent.verbose_llvm_bc, - .verbose_cimport = parent.verbose_cimport, - .verbose_llvm_cpu_features = parent.verbose_llvm_cpu_features, .invalid_user_input = false, .default_step = undefined, .top_level_steps = .{}, - .sysroot = parent.sysroot, .build_root = build_root, .cache_root = parent.cache_root, .debug_log_scopes = parent.debug_log_scopes, - .debug_compile_errors = parent.debug_compile_errors, - .debug_incremental = parent.debug_incremental, .enable_darling = parent.enable_darling, .enable_qemu = parent.enable_qemu, .enable_rosetta = parent.enable_rosetta, @@ -1125,7 +1094,7 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw if (std.zig.BuildId.parse(s)) |build_id| { return build_id; } else |err| { - log.err("unable to parse option '-D{s}': {s}", .{ name, @errorName(err) }); + log.err("unable to parse option '-D{s}': {t}", .{ name, err }); b.markInvalidUserInput(); return null; } @@ -1594,8 +1563,9 @@ pub fn addCheckFile( } pub fn truncateFile(b: *Build, dest_path: []const u8) (Io.Dir.CreateDirError || Io.Dir.StatFileError)!void { - const io = b.graph.io; - if (b.verbose) log.info("truncate {s}", .{dest_path}); + const graph = b.graph; + const io = graph.io; + if (graph.verbose) log.info("truncate {s}", .{dest_path}); const cwd = Io.Dir.cwd(); var src_file = cwd.createFile(io, dest_path, .{}) catch |err| switch (err) { error.FileNotFound => blk: { @@ -1705,9 +1675,13 @@ pub fn runAllowFail( const graph = b.graph; const io = graph.io; + const arena = graph.arena; const max_output_size = 400 * 1024; - try Step.handleVerbose2(b, .inherit, &graph.environ_map, argv); + if (graph.verbose) { + const text = std.zig.allocPrintCmd(arena, .inherit, null, argv); + std.log.scoped(.verbose).info("{s}", .{text}); + } var child = try std.process.spawn(io, .{ .argv = argv, @@ -1718,10 +1692,10 @@ pub fn runAllowFail( }); var stdout_reader = child.stdout.?.readerStreaming(io, &.{}); - const stdout = stdout_reader.interface.allocRemaining(b.allocator, .limited(max_output_size)) catch { + const stdout = stdout_reader.interface.allocRemaining(arena, .limited(max_output_size)) catch { return error.ReadFailure; }; - errdefer b.allocator.free(stdout); + errdefer arena.free(stdout); const term = try child.wait(io); switch (term) { @@ -2089,34 +2063,6 @@ pub fn runBuild(b: *Build, build_zig: anytype) anyerror!void { pub const GeneratedFile = struct { /// The step that generates the file. step: *Step, - /// The path to the generated file. Must be either absolute or relative to the build runner cwd. - /// This value must be set in the `fn make()` of the `step` and must not be `null` afterwards. - path: ?[]const u8 = null, - - /// Deprecated, see `getPath3`. - pub fn getPath(gen: GeneratedFile) []const u8 { - return gen.step.owner.pathFromCwd(gen.path orelse std.debug.panic( - "getPath() was called on a GeneratedFile that wasn't built yet. Is there a missing Step dependency on step '{s}'?", - .{gen.step.name}, - )); - } - - /// Deprecated, see `getPath3`. - pub fn getPath2(gen: GeneratedFile, src_builder: *Build, asking_step: ?*Step) []const u8 { - return getPath3(gen, src_builder, asking_step) catch |err| switch (err) { - error.Canceled => std.process.exit(1), - }; - } - - pub fn getPath3(gen: GeneratedFile, src_builder: *Build, asking_step: ?*Step) Io.Cancelable![]const u8 { - return gen.path orelse { - const graph = gen.step.owner.graph; - const io = graph.io; - const stderr = try io.lockStderr(&.{}, graph.stderr_mode); - dumpBadGetPathHelp(gen.step, stderr.terminal(), src_builder, asking_step) catch {}; - @panic("misconfigured build script"); - }; - } }; // dirnameAllowEmpty is a variant of fs.path.dirname @@ -2290,94 +2236,6 @@ pub const LazyPath = union(enum) { } } - /// Deprecated, see `getPath4`. - pub fn getPath(lazy_path: LazyPath, src_builder: *Build) []const u8 { - return getPath2(lazy_path, src_builder, null); - } - - /// Deprecated, see `getPath4`. - pub fn getPath2(lazy_path: LazyPath, src_builder: *Build, asking_step: ?*Step) []const u8 { - const p = getPath3(lazy_path, src_builder, asking_step); - return src_builder.pathResolve(&.{ p.root_dir.path orelse ".", p.sub_path }); - } - - /// Deprecated, see `getPath4`. - pub fn getPath3(lazy_path: LazyPath, src_builder: *Build, asking_step: ?*Step) Cache.Path { - return getPath4(lazy_path, src_builder, asking_step) catch |err| switch (err) { - error.Canceled => std.process.exit(1), - }; - } - - /// Intended to be used during the make phase only. - /// - /// `asking_step` is only used for debugging purposes; it's the step being - /// run that is asking for the path. - pub fn getPath4(lazy_path: LazyPath, src_builder: *Build, asking_step: ?*Step) Io.Cancelable!Cache.Path { - switch (lazy_path) { - .src_path => |sp| return .{ - .root_dir = sp.owner.build_root, - .sub_path = sp.sub_path, - }, - .cwd_relative => |sub_path| return .{ - .root_dir = Cache.Directory.cwd(), - .sub_path = sub_path, - }, - .generated => |gen| { - // TODO make gen.file.path not be absolute and use that as the - // basis for not traversing up too many directories. - - const graph = src_builder.graph; - - var file_path: Cache.Path = .{ - .root_dir = Cache.Directory.cwd(), - .sub_path = gen.file.path orelse { - const io = graph.io; - const stderr = try io.lockStderr(&.{}, graph.stderr_mode); - dumpBadGetPathHelp(gen.file.step, stderr.terminal(), src_builder, asking_step) catch {}; - io.unlockStderr(); - @panic("misconfigured build script"); - }, - }; - - if (gen.up > 0) { - const cache_root_path = src_builder.cache_root.path orelse - (src_builder.cache_root.join(src_builder.allocator, &.{"."}) catch @panic("OOM")); - - for (0..gen.up) |_| { - if (mem.eql(u8, file_path.sub_path, cache_root_path)) { - // If we hit the cache root and there's still more to go, - // the script attempted to go too far. - dumpBadDirnameHelp(gen.file.step, asking_step, - \\dirname() attempted to traverse outside the cache root. - \\This is not allowed. - \\ - , .{}) catch {}; - @panic("misconfigured build script"); - } - - // path is absolute. - // dirname will return null only if we're at root. - // Typically, we'll stop well before that at the cache root. - file_path.sub_path = fs.path.dirname(file_path.sub_path) orelse { - dumpBadDirnameHelp(gen.file.step, asking_step, - \\dirname() reached root. - \\No more directories left to go up. - \\ - , .{}) catch {}; - @panic("misconfigured build script"); - }; - } - } - - return file_path.join(src_builder.allocator, gen.sub_path) catch @panic("OOM"); - }, - .dependency => |dep| return .{ - .root_dir = dep.dependency.builder.build_root, - .sub_path = dep.sub_path, - }, - } - } - pub fn basename(lazy_path: LazyPath, src_builder: *Build, asking_step: ?*Step) []const u8 { return fs.path.basename(switch (lazy_path) { .src_path => |sp| sp.sub_path, @@ -2451,36 +2309,6 @@ fn dumpBadDirnameHelp( stderr.setColor(.reset) catch {}; } -/// In this function the stderr mutex has already been locked. -pub fn dumpBadGetPathHelp(s: *Step, t: Io.Terminal, src_builder: *Build, asking_step: ?*Step) anyerror!void { - const w = t.writer; - try w.print( - \\getPath() was called on a GeneratedFile that wasn't built yet. - \\ source package path: {s} - \\ Is there a missing Step dependency on step '{s}'? - \\ - , .{ - src_builder.build_root.path orelse ".", - s.name, - }); - - t.setColor(.red) catch {}; - try w.writeAll(" The step was created by this stack trace:\n"); - t.setColor(.reset) catch {}; - - s.dump(t); - if (asking_step) |as| { - t.setColor(.red) catch {}; - try w.print(" The step '{s}' that is missing a dependency on the above step was created by this stack trace:\n", .{as.name}); - t.setColor(.reset) catch {}; - - as.dump(t); - } - t.setColor(.red) catch {}; - try w.writeAll(" Proceeding to panic.\n"); - t.setColor(.reset) catch {}; -} - pub const InstallDir = union(enum) { prefix: void, lib: void, diff --git a/lib/std/Build/Step/Compile.zig b/lib/std/Build/Step/Compile.zig index a4769b1302..2e751abe24 100644 --- a/lib/std/Build/Step/Compile.zig +++ b/lib/std/Build/Step/Compile.zig @@ -87,9 +87,13 @@ libc_file: ?LazyPath = null, each_lib_rpath: ?bool = null, /// On ELF targets, this will emit a link section called ".note.gnu.build-id" /// which can be used to coordinate a stripped binary with its debug symbols. +/// /// As an example, the bloaty project refuses to work unless its inputs have /// build ids, in order to prevent accidental mismatches. +/// /// The default is to not include this section because it slows down linking. +/// +/// This option overrides the CLI argument passed to `zig build`. build_id: ?std.zig.BuildId = null, /// Create a .eh_frame_hdr section and a PT_GNU_EH_FRAME segment in the ELF diff --git a/lib/std/zig.zig b/lib/std/zig.zig index 1f250db0cc..c9d6cdfa28 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -983,6 +983,79 @@ pub const EmitArtifact = enum { } }; +pub fn allocPrintCmd( + gpa: Allocator, + cwd: std.process.Child.Cwd, + opt_env: ?struct { + child: *const std.process.Environ.Map, + parent: *const std.process.Environ.Map, + }, + argv: []const []const u8, +) Allocator.Error![]u8 { + const shell = struct { + fn escape(writer: *Io.Writer, string: []const u8, is_argv0: bool) !void { + for (string) |c| { + if (switch (c) { + else => true, + '%', '+'...':', '@'...'Z', '_', 'a'...'z' => false, + '=' => is_argv0, + }) break; + } else return writer.writeAll(string); + + try writer.writeByte('"'); + for (string) |c| { + if (switch (c) { + std.ascii.control_code.nul => break, + '!', '"', '$', '\\', '`' => true, + else => !std.ascii.isPrint(c), + }) try writer.writeByte('\\'); + switch (c) { + std.ascii.control_code.nul => unreachable, + std.ascii.control_code.bel => try writer.writeByte('a'), + std.ascii.control_code.bs => try writer.writeByte('b'), + std.ascii.control_code.ht => try writer.writeByte('t'), + std.ascii.control_code.lf => try writer.writeByte('n'), + std.ascii.control_code.vt => try writer.writeByte('v'), + std.ascii.control_code.ff => try writer.writeByte('f'), + std.ascii.control_code.cr => try writer.writeByte('r'), + std.ascii.control_code.esc => try writer.writeByte('E'), + ' '...'~' => try writer.writeByte(c), + else => try writer.print("{o:0>3}", .{c}), + } + } + try writer.writeByte('"'); + } + }; + + var aw: Io.Writer.Allocating = .init(gpa); + defer aw.deinit(); + const writer = &aw.writer; + switch (cwd) { + .inherit => {}, + .path => |path| writer.print("cd {s} && ", .{path}) catch return error.OutOfMemory, + .dir => @panic("TODO"), + } + if (opt_env) |env| { + var it = env.child.iterator(); + while (it.next()) |entry| { + const key = entry.key_ptr.*; + const value = entry.value_ptr.*; + if (env.parent.get(key)) |process_value| { + if (std.mem.eql(u8, value, process_value)) continue; + } + writer.print("{s}=", .{key}) catch return error.OutOfMemory; + shell.escape(writer, value, false) catch return error.OutOfMemory; + writer.writeByte(' ') catch return error.OutOfMemory; + } + } + shell.escape(writer, argv[0], true) catch return error.OutOfMemory; + for (argv[1..]) |arg| { + writer.writeByte(' ') catch return error.OutOfMemory; + shell.escape(writer, arg, false) catch return error.OutOfMemory; + } + return aw.toOwnedSlice(); +} + test { _ = Ast; _ = AstRlAnnotate;