diff --git a/lib/compiler/build_runner.zig b/lib/compiler/build_runner.zig index 91e9d20dbb668f2bbff19bf9852d2ba54863a903..f83456e93d50ed31798002c97e1ed52fb30f745f 100644 --- a/lib/compiler/build_runner.zig +++ b/lib/compiler/build_runner.zig @@ -39,7 +39,10 @@ pub fn main(init: process.Init.Minimal) !void { const args = try init.args.toSlice(arena); - var threaded: std.Io.Threaded = .init(gpa, .{}); + var threaded: std.Io.Threaded = .init(gpa, .{ + .environ = init.environ, + .argv0 = .init(init.args), + }); defer threaded.deinit(); const io = threaded.io(); diff --git a/lib/compiler/test_runner.zig b/lib/compiler/test_runner.zig index 9219c0040b9c0f9bb189e674e82b3496a9177c6c..f0971cfa39579608cda24cfa7b65cc07cdf318c1 100644 --- a/lib/compiler/test_runner.zig +++ b/lib/compiler/test_runner.zig @@ -65,13 +65,13 @@ pub fn main(init: std.process.Init.Minimal) void { } if (listen) { - return mainServer(args) catch @panic("internal test runner failure"); + return mainServer(init) catch @panic("internal test runner failure"); } else { - return mainTerminal(args); + return mainTerminal(init); } } -fn mainServer(args: []const [:0]const u8) !void { +fn mainServer(init: std.process.Init.Minimal) !void { @disableInstrumentation(); var stdin_reader = Io.File.stdin().readerStreaming(runner_threaded_io, &stdin_buffer); var stdout_writer = Io.File.stdout().writerStreaming(runner_threaded_io, &stdout_buffer); @@ -131,7 +131,8 @@ fn mainServer(args: []const [:0]const u8) !void { .run_test => { testing.allocator_instance = .{}; testing.io_instance = .init(testing.allocator, .{ - .argv0 = if (@hasField(Io.Threaded.Argv0, "value")) .{ .value = args[0] } else .{}, + .argv0 = .init(init.args), + .environ = init.environ, }); log_err_count = 0; const index = try server.receiveBody_u32(); @@ -216,7 +217,7 @@ fn mainServer(args: []const [:0]const u8) !void { } } -fn mainTerminal(args: []const [:0]const u8) void { +fn mainTerminal(init: std.process.Init.Minimal) void { @disableInstrumentation(); if (builtin.fuzz) @panic("fuzz test requires server"); @@ -235,7 +236,8 @@ fn mainTerminal(args: []const [:0]const u8) void { for (test_fn_list, 0..) |test_fn, i| { testing.allocator_instance = .{}; testing.io_instance = .init(testing.allocator, .{ - .argv0 = if (@hasField(Io.Threaded.Argv0, "value")) .{ .value = args[0] } else .{}, + .argv0 = .init(init.args), + .environ = init.environ, }); defer { testing.io_instance.deinit(); diff --git a/lib/std/Build.zig b/lib/std/Build.zig index 3ade95ae060d691bb1ab9084250aab3d14e309ab..7e8c782dbdde1a0a1e366eee768a9a8e98b75d69 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -1881,19 +1881,11 @@ pub fn runAllowFail( /// inside step make() functions. If any errors occur, it fails the build with /// a helpful message. pub fn run(b: *Build, argv: []const []const u8) []u8 { - if (!process.can_spawn) { - std.debug.print("unable to spawn the following command: cannot spawn child process\n{s}\n", .{ - try Step.allocPrintCmd(b.allocator, null, null, argv), - }); - process.exit(1); - } - var code: u8 = undefined; - return b.runAllowFail(argv, &code, .inherit) catch |err| { - const printed_cmd = Step.allocPrintCmd(b.allocator, null, null, argv) catch @panic("OOM"); - std.debug.print("unable to spawn the following command: {t}\n{s}\n", .{ err, printed_cmd }); - process.exit(1); - }; + return b.runAllowFail(argv, &code, .inherit) catch |err| process.fatal( + "the following command failed with {t}:\n{s}", + .{ err, Step.allocPrintCmd(b.allocator, null, null, argv) catch @panic("OOM") }, + ); } pub fn addSearchPrefix(b: *Build, search_prefix: []const u8) void { diff --git a/lib/std/Io/Threaded.zig b/lib/std/Io/Threaded.zig index a94b20ab79e91dad3e28fef0dc7db9d191d7ce03..08c12a565394be0999442e40a27adfb71e568fa9 100644 --- a/lib/std/Io/Threaded.zig +++ b/lib/std/Io/Threaded.zig @@ -66,12 +66,25 @@ environ: Environ, pub const Argv0 = switch (native_os) { .openbsd, .haiku => struct { - value: ?[*:0]const u8 = null, + value: ?[*:0]const u8, + + pub const empty: Argv0 = .{ .value = null }; + + pub fn init(args: process.Args) Argv0 { + return .{ .value = args.value[0] }; + } + }, + else => struct { + pub const empty: Argv0 = .{}; + + pub fn init(args: process.Args) Argv0 { + _ = args; + return .{}; + } }, - else => struct {}, }; -pub const Environ = struct { +const Environ = struct { /// Unmodified data directly from the OS. block: process.Environ.Block = &.{}, /// Protected by `mutex`. Determines whether the other fields have been @@ -1141,7 +1154,8 @@ pub const InitOptions = struct { /// Affects the following operations: /// * `fileIsTty` /// * `processExecutablePath` on OpenBSD and Haiku (observes "PATH"). - environ: Environ = .{}, + /// * `processSpawn`, `processSpawnPath`, `processReplace`, `processReplacePath` + environ: process.Environ, }; /// Related: @@ -1171,8 +1185,9 @@ pub fn init( .old_sig_pipe = undefined, .have_signal_handler = false, .argv0 = options.argv0, - .environ = options.environ, .worker_threads = .init(null), + .environ = .{ .block = options.environ.block }, + .robust_cancel = options.robust_cancel, }; if (posix.Sigaction != void) { diff --git a/lib/std/Io/Threaded/test.zig b/lib/std/Io/Threaded/test.zig index 74bba51b90a01a2ab8e55d0bda2775dfec1cf9ef..f41493653fb62769323a24c61b2fe7102bb6e753 100644 --- a/lib/std/Io/Threaded/test.zig +++ b/lib/std/Io/Threaded/test.zig @@ -13,7 +13,10 @@ test "concurrent vs main prevents deadlock via oversubscription" { return error.SkipZigTest; } - var threaded: Io.Threaded = .init(std.testing.allocator, .{}); + var threaded: Io.Threaded = .init(std.testing.allocator, .{ + .argv0 = .empty, + .environ = .empty, + }); defer threaded.deinit(); const io = threaded.io(); @@ -46,7 +49,10 @@ test "concurrent vs concurrent prevents deadlock via oversubscription" { return error.SkipZigTest; } - var threaded: Io.Threaded = .init(std.testing.allocator, .{}); + var threaded: Io.Threaded = .init(std.testing.allocator, .{ + .argv0 = .empty, + .environ = .empty, + }); defer threaded.deinit(); const io = threaded.io(); @@ -80,7 +86,10 @@ test "async/concurrent context and result alignment" { var buffer: [2048]u8 align(@alignOf(ByteArray512)) = undefined; var fba: std.heap.FixedBufferAllocator = .init(&buffer); - var threaded: std.Io.Threaded = .init(fba.allocator(), .{}); + var threaded: std.Io.Threaded = .init(fba.allocator(), .{ + .argv0 = .empty, + .environ = .empty, + }); defer threaded.deinit(); const io = threaded.io(); @@ -113,7 +122,10 @@ test "Group.async context alignment" { var buffer: [2048]u8 align(@alignOf(ByteArray512)) = undefined; var fba: std.heap.FixedBufferAllocator = .init(&buffer); - var threaded: std.Io.Threaded = .init(fba.allocator(), .{}); + var threaded: std.Io.Threaded = .init(fba.allocator(), .{ + .argv0 = .empty, + .environ = .empty, + }); defer threaded.deinit(); const io = threaded.io(); @@ -133,7 +145,10 @@ fn returnArray() [32]u8 { } test "async with array return type" { - var threaded: std.Io.Threaded = .init(std.testing.allocator, .{}); + var threaded: std.Io.Threaded = .init(std.testing.allocator, .{ + .argv0 = .empty, + .environ = .empty, + }); defer threaded.deinit(); const io = threaded.io(); diff --git a/lib/std/process/Environ.zig b/lib/std/process/Environ.zig index 3581634516613cde402ad908490633d86e04f9ac..2556ae558eaa79bb659a511b8f949ad0c9a697ee 100644 --- a/lib/std/process/Environ.zig +++ b/lib/std/process/Environ.zig @@ -19,6 +19,13 @@ const mem = std.mem; /// queried and heap-allocated at runtime. block: Block, +pub const empty: Environ = .{ + .block = switch (@TypeOf(Block)) { + void => {}, + else => &.{}, + }, +}; + pub const Block = switch (native_os) { .windows => [*:0]const u16, .wasi => switch (builtin.link_libc) { diff --git a/src/main.zig b/src/main.zig index a265b22512c50ed91c475cd0e1453042f4799eb9..a7b6efa33fe4f53d5823ae44b8a32ceecda81140 100644 --- a/src/main.zig +++ b/src/main.zig @@ -186,36 +186,43 @@ pub fn main(init: std.process.Init.Minimal) anyerror!void { if (args.len > 0) crash_report.zig_argv0 = args[0]; - var env_map = init.environ.createMap(arena) catch |err| fatal("failed to parse environment: {t}", .{err}); - - if (tracy.enable_allocation) { - var gpa_tracy = tracy.tracyAllocator(gpa); - return mainArgs(gpa_tracy.allocator(), arena, args, &env_map); - } - - if (native_os == .wasi) { - wasi_preopens = try fs.wasi.preopensAlloc(arena); - } - - return mainArgs(gpa, arena, args, &env_map); -} - -fn mainArgs(gpa: Allocator, arena: Allocator, args: []const [:0]const u8, env_map: *process.Environ.Map) !void { - Compilation.setMainThread(); - if (args.len <= 1) { std.log.info("{s}", .{usage}); fatal("expected command argument", .{}); } + var env_map = init.environ.createMap(arena) catch |err| fatal("failed to parse environment: {t}", .{err}); + + Compilation.setMainThread(); + var threaded: Io.Threaded = .init(gpa, .{ - .argv0 = if (@hasField(Io.Threaded.Argv0, "value")) .{ .value = args[0] } else .{}, + .argv0 = .init(init.args), + .environ = init.environ, }); defer threaded.deinit(); threaded_impl_ptr = &threaded; threaded.stack_size = thread_stack_size; const io = threaded.io(); + if (tracy.enable_allocation) { + var gpa_tracy = tracy.tracyAllocator(gpa); + return mainArgs(gpa_tracy.allocator(), arena, io, args, &env_map); + } + + if (native_os == .wasi) { + wasi_preopens = try fs.wasi.preopensAlloc(arena); + } + + return mainArgs(gpa, arena, io, args, &env_map); +} + +fn mainArgs( + gpa: Allocator, + arena: Allocator, + io: Io, + args: []const [:0]const u8, + env_map: *process.Environ.Map, +) !void { if (process.can_replace and EnvVar.ZIG_IS_DETECTING_LIBC_PATHS.isSet(env_map)) { dev.check(.cc_command); // In this case we have accidentally invoked ourselves as "the system C compiler"