From f28802a9c6c3bd36368101981243aab7cf4f453f Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 1 Jan 2026 20:20:58 -0800 Subject: [PATCH] zig libc: fix subcommand This branch regressed the child process "run" mechanism because it didn't pass the correct stdin, stdout, stderr values to process.spawn Fixed now. --- lib/compiler/aro/main.zig | 4 +- lib/compiler/libc.zig | 25 +++++---- lib/compiler/reduce.zig | 41 ++++++--------- lib/compiler/resinator/main.zig | 4 +- lib/compiler/translate-c/main.zig | 2 +- lib/std/Build/Step.zig | 4 +- lib/std/Random/benchmark.zig | 11 ++-- lib/std/crypto/benchmark.zig | 20 +++---- lib/std/hash/benchmark.zig | 11 ++-- lib/std/process.zig | 42 ++++++++++++++- lib/std/zig/LibCInstallation.zig | 52 +++++++++---------- lib/std/zig/system/darwin.zig | 6 +-- test/standalone/child_process/child.zig | 24 +++------ .../install_headers/check_exists.zig | 12 ++--- test/standalone/libfuzzer/main.zig | 13 ++--- test/standalone/run_output_caching/main.zig | 6 +-- test/standalone/windows_bat_args/fuzz.zig | 13 ++--- test/standalone/windows_bat_args/test.zig | 12 ++--- test/standalone/windows_spawn/main.zig | 13 ++--- tools/docgen.zig | 16 ++---- tools/doctest.zig | 16 ++---- tools/incr-check.zig | 2 +- tools/update_cpu_features.zig | 17 ++---- 23 files changed, 167 insertions(+), 199 deletions(-) diff --git a/lib/compiler/aro/main.zig b/lib/compiler/aro/main.zig index ca079c0e5f..dcc07eaca6 100644 --- a/lib/compiler/aro/main.zig +++ b/lib/compiler/aro/main.zig @@ -18,7 +18,7 @@ var debug_allocator: std.heap.DebugAllocator(.{ .canary = @truncate(0xc647026dc6875134), }) = .{}; -pub fn main() u8 { +pub fn main(init: std.process.Init.Minimal) u8 { const gpa = if (@import("builtin").link_libc) std.heap.c_allocator else @@ -37,7 +37,7 @@ pub fn main() u8 { const fast_exit = @import("builtin").mode != .Debug; - const args = process.argsAlloc(arena) catch { + const args = init.args.toSlice(arena) catch { std.debug.print("out of memory\n", .{}); if (fast_exit) process.exit(1); return 1; diff --git a/lib/compiler/libc.zig b/lib/compiler/libc.zig index eb4614c95d..a27e96dab6 100644 --- a/lib/compiler/libc.zig +++ b/lib/compiler/libc.zig @@ -24,23 +24,19 @@ const usage_libc = var stdout_buffer: [4096]u8 = undefined; -pub fn main() !void { - var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator); - defer arena_instance.deinit(); - const arena = arena_instance.allocator(); - const gpa = arena; +pub fn main(init: std.process.Init) !void { + const arena = init.arena.allocator(); + const gpa = init.gpa; + const io = init.io; + const args = try init.minimal.args.toSlice(arena); + const env_map = init.env_map; - var threaded: std.Io.Threaded = .init(gpa, .{}); - defer threaded.deinit(); - const io = threaded.io(); - - const args = try std.process.argsAlloc(arena); const zig_lib_directory = args[1]; var input_file: ?[]const u8 = null; var target_arch_os_abi: []const u8 = "native"; var print_includes: bool = false; - var stdout_writer = Io.File.stdout().writer(&stdout_buffer); + var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer); const stdout = &stdout_writer.interface; { var i: usize = 2; @@ -77,7 +73,7 @@ pub fn main() !void { const libc_installation: ?*LibCInstallation = libc: { if (input_file) |libc_file| { const libc = try arena.create(LibCInstallation); - libc.* = LibCInstallation.parse(arena, libc_file, &target) catch |err| { + libc.* = LibCInstallation.parse(arena, io, libc_file, &target) catch |err| { fatal("unable to parse libc file at path {s}: {t}", .{ libc_file, err }); }; break :libc libc; @@ -90,11 +86,13 @@ pub fn main() !void { const libc_dirs = std.zig.LibCDirs.detect( arena, + io, zig_lib_directory, &target, is_native_abi, true, libc_installation, + env_map, ) catch |err| { const zig_target = try target.zigTriple(arena); fatal("unable to detect libc for target {s}: {t}", .{ zig_target, err }); @@ -114,7 +112,7 @@ pub fn main() !void { } if (input_file) |libc_file| { - var libc = LibCInstallation.parse(gpa, libc_file, &target) catch |err| { + var libc = LibCInstallation.parse(gpa, io, libc_file, &target) catch |err| { fatal("unable to parse libc file at path {s}: {t}", .{ libc_file, err }); }; defer libc.deinit(gpa); @@ -125,6 +123,7 @@ pub fn main() !void { var libc = LibCInstallation.findNative(gpa, io, .{ .verbose = true, .target = &target, + .env_map = env_map, }) catch |err| { fatal("unable to detect native libc: {t}", .{err}); }; diff --git a/lib/compiler/reduce.zig b/lib/compiler/reduce.zig index b0fa94cb06..abdd9f8436 100644 --- a/lib/compiler/reduce.zig +++ b/lib/compiler/reduce.zig @@ -47,19 +47,11 @@ const Interestingness = enum { interesting, unknown, boring }; // - reduce flags sent to the compiler // - integrate with the build system? -pub fn main() !void { - var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator); - defer arena_instance.deinit(); - const arena = arena_instance.allocator(); - - var general_purpose_allocator: std.heap.GeneralPurposeAllocator(.{}) = .init; - const gpa = general_purpose_allocator.allocator(); - - var threaded: std.Io.Threaded = .init(gpa, .{}); - defer threaded.deinit(); - const io = threaded.io(); - - const args = try std.process.argsAlloc(arena); +pub fn main(init: std.process.Init) !void { + const arena = init.arena.allocator(); + const gpa = init.gpa; + const io = init.io; + const args = try init.minimal.args.toSlice(arena); var opt_checker_path: ?[]const u8 = null; var opt_root_source_file_path: ?[]const u8 = null; @@ -73,8 +65,7 @@ pub fn main() !void { const arg = args[i]; if (mem.startsWith(u8, arg, "-")) { if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) { - const stdout = Io.File.stdout(); - try stdout.writeAll(usage); + try Io.File.stdout().writeStreamingAll(io, usage); return std.process.cleanExit(io); } else if (mem.eql(u8, arg, "--")) { argv = args[i + 1 ..]; @@ -131,12 +122,10 @@ pub fn main() !void { if (!skip_smoke_test) { std.debug.print("smoke testing the interestingness check...\n", .{}); - switch (try runCheck(arena, interestingness_argv.items)) { + switch (try runCheck(arena, io, interestingness_argv.items)) { .interesting => {}, .boring, .unknown => |t| { - fatal("interestingness check returned {s} for unmodified input\n", .{ - @tagName(t), - }); + fatal("interestingness check returned {t} for unmodified input\n", .{t}); }, } } @@ -238,7 +227,7 @@ pub fn main() !void { try Io.Dir.cwd().writeFile(io, .{ .sub_path = root_source_file_path, .data = rendered.written() }); // std.debug.print("trying this code:\n{s}\n", .{rendered.items}); - const interestingness = try runCheck(arena, interestingness_argv.items); + const interestingness = try runCheck(arena, io, interestingness_argv.items); std.debug.print("{d} random transformations: {t}. {d}/{d}\n", .{ subset_size, interestingness, start_index, transformations.items.len, }); @@ -293,20 +282,24 @@ fn sortTransformations(transformations: []Walk.Transformation, rng: std.Random) fn termToInteresting(term: std.process.Child.Term) Interestingness { return switch (term) { - .Exited => |code| switch (code) { + .exited => |code| switch (code) { 0 => .interesting, 1 => .unknown, else => .boring, }, - else => b: { + .signal => |sig| { + std.debug.print("interestingness check terminated with signal {t}\n", .{sig}); + return .boring; + }, + else => { std.debug.print("interestingness check aborted unexpectedly\n", .{}); - break :b .boring; + return .boring; }, }; } fn runCheck(arena: Allocator, io: Io, argv: []const []const u8) !Interestingness { - const result = try std.process.run(arena, io, .{ .spawn_options = .{ .argv = argv } }); + const result = try std.process.run(arena, io, .{ .argv = argv }); if (result.stderr.len != 0) std.debug.print("{s}", .{result.stderr}); return termToInteresting(result.term); diff --git a/lib/compiler/resinator/main.zig b/lib/compiler/resinator/main.zig index e286a5f4b9..562fb86541 100644 --- a/lib/compiler/resinator/main.zig +++ b/lib/compiler/resinator/main.zig @@ -19,7 +19,7 @@ const fmtResourceType = @import("res.zig").NameOrOrdinal.fmtResourceType; const aro = @import("aro"); const compiler_util = @import("../util.zig"); -pub fn main() !void { +pub fn main(init: std.process.Init.Minimal) !void { var debug_allocator: std.heap.DebugAllocator(.{}) = .init; defer std.debug.assert(debug_allocator.deinit() == .ok); const gpa = debug_allocator.allocator(); @@ -32,7 +32,7 @@ pub fn main() !void { defer arena_state.deinit(); const arena = arena_state.allocator(); - const args = try std.process.argsAlloc(arena); + const args = try init.args.toSlice(arena); if (args.len < 2) { const stderr = try io.lockStderr(&.{}, null); diff --git a/lib/compiler/translate-c/main.zig b/lib/compiler/translate-c/main.zig index 825d132776..a257f65ce4 100644 --- a/lib/compiler/translate-c/main.zig +++ b/lib/compiler/translate-c/main.zig @@ -14,7 +14,7 @@ pub fn main(init: std.process.Init) u8 { const arena = init.arena.allocator(); const io = init.io; - const args = process.argsAlloc(arena) catch { + const args = init.minimal.args.toSlice(arena) catch { std.debug.print("ran out of memory allocating arguments\n", .{}); if (fast_exit) process.exit(1); return 1; diff --git a/lib/std/Build/Step.zig b/lib/std/Build/Step.zig index 93d6b9cdd6..745894551d 100644 --- a/lib/std/Build/Step.zig +++ b/lib/std/Build/Step.zig @@ -360,11 +360,11 @@ pub fn captureChildProcess( try handleChildProcUnsupported(s); try handleVerbose(s.owner, null, argv); - const result = std.process.run(arena, io, .{ .spawn_options = .{ + const result = std.process.run(arena, io, .{ .argv = argv, .env_map = &graph.env_map, .progress_node = progress_node, - } }) catch |err| return s.fail("failed to run {s}: {t}", .{ argv[0], err }); + }) catch |err| return s.fail("failed to run {s}: {t}", .{ argv[0], err }); if (result.stderr.len > 0) { try s.result_error_msgs.append(arena, result.stderr); diff --git a/lib/std/Random/benchmark.zig b/lib/std/Random/benchmark.zig index 97afe23b95..a545cda6d5 100644 --- a/lib/std/Random/benchmark.zig +++ b/lib/std/Random/benchmark.zig @@ -123,14 +123,15 @@ fn mode(comptime x: comptime_int) comptime_int { return if (builtin.mode == .Debug) x / 64 else x; } -pub fn main() !void { +pub fn main(init: std.process.Init) !void { + const io = init.io; + const arena = init.arena.allocator(); + var stdout_buffer: [0x100]u8 = undefined; - var stdout_writer = Io.File.stdout().writer(&stdout_buffer); + var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer); const stdout = &stdout_writer.interface; - var buffer: [1024]u8 = undefined; - var fixed = std.heap.FixedBufferAllocator.init(buffer[0..]); - const args = try std.process.argsAlloc(fixed.allocator()); + const args = try init.minimal.args.toSlice(arena); var filter: ?[]u8 = ""; var count: usize = mode(128 * MiB); diff --git a/lib/std/crypto/benchmark.zig b/lib/std/crypto/benchmark.zig index 23154324bc..22f2b6fd10 100644 --- a/lib/std/crypto/benchmark.zig +++ b/lib/std/crypto/benchmark.zig @@ -503,16 +503,16 @@ fn mode(comptime x: comptime_int) comptime_int { return if (builtin.mode == .Debug) x / 64 else x; } -pub fn main() !void { +pub fn main(init: std.process.Init) !void { + const io = init.io; + const arena = init.arena.allocator(); + // Size of buffer is about size of printed message. var stdout_buffer: [0x100]u8 = undefined; - var stdout_writer = Io.File.stdout().writer(&stdout_buffer); + var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer); const stdout = &stdout_writer.interface; - var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); - defer arena.deinit(); - const arena_allocator = arena.allocator(); - const args = try std.process.argsAlloc(arena_allocator); + const args = try init.minimal.args.toSlice(arena); var filter: ?[]u8 = ""; @@ -556,13 +556,9 @@ pub fn main() !void { } } - var io_threaded = std.Io.Threaded.init(arena_allocator, .{}); - defer io_threaded.deinit(); - const io = io_threaded.io(); - inline for (parallel_hashes) |H| { if (filter == null or std.mem.find(u8, H.name, filter.?) != null) { - const throughput = try benchmarkHashParallel(H.ty, mode(128 * MiB), arena_allocator, io); + const throughput = try benchmarkHashParallel(H.ty, mode(128 * MiB), arena, io); try stdout.print("{s:>17}: {:10} MiB/s\n", .{ H.name, throughput / (1 * MiB) }); try stdout.flush(); } @@ -634,7 +630,7 @@ pub fn main() !void { inline for (pwhashes) |H| { if (filter == null or std.mem.find(u8, H.name, filter.?) != null) { - const throughput = try benchmarkPwhash(arena_allocator, H.ty, H.params, mode(64), io); + const throughput = try benchmarkPwhash(arena, H.ty, H.params, mode(64), io); try stdout.print("{s:>17}: {d:10.3} s/ops\n", .{ H.name, throughput }); try stdout.flush(); } diff --git a/lib/std/hash/benchmark.zig b/lib/std/hash/benchmark.zig index 6744b87fac..76538be4a8 100644 --- a/lib/std/hash/benchmark.zig +++ b/lib/std/hash/benchmark.zig @@ -353,14 +353,15 @@ fn mode(comptime x: comptime_int) comptime_int { return if (builtin.mode == .Debug) x / 64 else x; } -pub fn main() !void { +pub fn main(init: std.process.Init) !void { + const io = init.io; + const arena = init.arena.allocator(); + var stdout_buffer: [0x100]u8 = undefined; - var stdout_writer = Io.File.stdout().writer(&stdout_buffer); + var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer); const stdout = &stdout_writer.interface; - var buffer: [1024]u8 = undefined; - var fixed = std.heap.FixedBufferAllocator.init(buffer[0..]); - const args = try std.process.argsAlloc(fixed.allocator()); + const args = try init.minimal.args.toSlice(arena); var filter: ?[]u8 = ""; var count: usize = mode(128 * MiB); diff --git a/lib/std/process.zig b/lib/std/process.zig index 1fd31d2634..c226b0c453 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -463,8 +463,33 @@ pub const RunError = posix.GetCwdError || posix.ReadError || SpawnError || posix }; pub const RunOptions = struct { - spawn_options: SpawnOptions, + argv: []const []const u8, max_output_bytes: usize = 50 * 1024, + + /// Set to change the current working directory when spawning the child process. + cwd: ?[]const u8 = null, + /// Set to change the current working directory when spawning the child process. + /// This is not yet implemented for Windows. See https://github.com/ziglang/zig/issues/5190 + /// Once that is done, `cwd` will be deprecated in favor of this field. + cwd_dir: ?Io.Dir = null, + /// Replaces the child environment when provided. The PATH value from here + /// is not used to resolve `argv[0]`; that resolution always uses parent + /// environment. + env_map: ?*const Environ.Map = null, + expand_arg0: ArgExpansion = .no_expand, + /// When populated, a pipe will be created for the child process to + /// communicate progress back to the parent. The file descriptor of the + /// write end of the pipe will be specified in the `ZIG_PROGRESS` + /// environment variable inside the child process. The progress reported by + /// the child will be attached to this progress node in the parent process. + /// + /// The child's progress tree will be grafted into the parent's progress tree, + /// by substituting this node with the child's root node. + progress_node: std.Progress.Node = std.Progress.Node.none, + /// Windows-only. Sets the CREATE_NO_WINDOW flag in CreateProcess. + create_no_window: bool = true, + /// Darwin-only. Disable ASLR for the child process. + disable_aslr: bool = false, }; pub const RunResult = struct { @@ -476,7 +501,20 @@ pub const RunResult = struct { /// Spawns a child process, waits for it, collecting stdout and stderr, and then returns. /// If it succeeds, the caller owns result.stdout and result.stderr memory. pub fn run(gpa: Allocator, io: Io, options: RunOptions) RunError!RunResult { - var child = try spawn(io, options.spawn_options); + var child = try spawn(io, .{ + .argv = options.argv, + .cwd = options.cwd, + .cwd_dir = options.cwd_dir, + .env_map = options.env_map, + .expand_arg0 = options.expand_arg0, + .progress_node = options.progress_node, + .create_no_window = options.create_no_window, + .disable_aslr = options.disable_aslr, + + .stdin = .ignore, + .stdout = .pipe, + .stderr = .pipe, + }); defer child.kill(io); var stdout: std.ArrayList(u8) = .empty; diff --git a/lib/std/zig/LibCInstallation.zig b/lib/std/zig/LibCInstallation.zig index 80c41c594b..2f7650b0fe 100644 --- a/lib/std/zig/LibCInstallation.zig +++ b/lib/std/zig/LibCInstallation.zig @@ -208,16 +208,16 @@ pub fn findNative(gpa: Allocator, io: Io, args: FindNativeOptions) FindError!Lib } else if (is_haiku) { try self.findNativeIncludeDirPosix(gpa, io, args); try self.findNativeGccDirHaiku(gpa, io, args); - self.crt_dir = try gpa.dupeZ(u8, "/system/develop/lib"); + self.crt_dir = try gpa.dupe(u8, "/system/develop/lib"); } else if (builtin.target.os.tag == .illumos) { // There is only one libc, and its headers/libraries are always in the same spot. - self.include_dir = try gpa.dupeZ(u8, "/usr/include"); - self.sys_include_dir = try gpa.dupeZ(u8, "/usr/include"); - self.crt_dir = try gpa.dupeZ(u8, "/usr/lib/64"); + self.include_dir = try gpa.dupe(u8, "/usr/include"); + self.sys_include_dir = try gpa.dupe(u8, "/usr/include"); + self.crt_dir = try gpa.dupe(u8, "/usr/lib/64"); } else if (std.process.can_spawn) { try self.findNativeIncludeDirPosix(gpa, io, args); switch (builtin.target.os.tag) { - .freebsd, .netbsd, .openbsd, .dragonfly => self.crt_dir = try gpa.dupeZ(u8, "/usr/lib"), + .freebsd, .netbsd, .openbsd, .dragonfly => self.crt_dir = try gpa.dupe(u8, "/usr/lib"), .linux => try self.findNativeCrtDirPosix(gpa, io, args), else => {}, } @@ -269,15 +269,13 @@ fn findNativeIncludeDirPosix(self: *LibCInstallation, gpa: Allocator, io: Io, ar const run_res = std.process.run(gpa, io, .{ .max_output_bytes = 1024 * 1024, - .spawn_options = .{ - .argv = argv.items, - .env_map = &env_map, - // Some C compilers, such as Clang, are known to rely on argv[0] to find the path - // to their own executable, without even bothering to resolve PATH. This results in the message: - // error: unable to execute command: Executable "" doesn't exist! - // So we use the expandArg0 variant of ChildProcess to give them a helping hand. - .expand_arg0 = .expand, - }, + .argv = argv.items, + .env_map = &env_map, + // Some C compilers, such as Clang, are known to rely on argv[0] to find the path + // to their own executable, without even bothering to resolve PATH. This results in the message: + // error: unable to execute command: Executable "" doesn't exist! + // So we use the expandArg0 variant of ChildProcess to give them a helping hand. + .expand_arg0 = .expand, }) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, else => { @@ -337,7 +335,7 @@ fn findNativeIncludeDirPosix(self: *LibCInstallation, gpa: Allocator, io: Io, ar if (self.include_dir == null) { if (search_dir.access(io, include_dir_example_file, .{})) |_| { - self.include_dir = try gpa.dupeZ(u8, search_path); + self.include_dir = try gpa.dupe(u8, search_path); } else |err| switch (err) { error.FileNotFound => {}, else => return error.FileSystem, @@ -346,7 +344,7 @@ fn findNativeIncludeDirPosix(self: *LibCInstallation, gpa: Allocator, io: Io, ar if (self.sys_include_dir == null) { if (search_dir.access(io, sys_include_dir_example_file, .{})) |_| { - self.sys_include_dir = try gpa.dupeZ(u8, search_path); + self.sys_include_dir = try gpa.dupe(u8, search_path); } else |err| switch (err) { error.FileNotFound => {}, else => return error.FileSystem, @@ -560,7 +558,7 @@ pub const CCPrintFileNameOptions = struct { }; /// caller owns returned memory -fn ccPrintFileName(gpa: Allocator, io: Io, args: CCPrintFileNameOptions) ![:0]u8 { +fn ccPrintFileName(gpa: Allocator, io: Io, args: CCPrintFileNameOptions) ![]u8 { // Detect infinite loops. var env_map = try args.env_map.clone(gpa); defer env_map.deinit(); @@ -587,15 +585,13 @@ fn ccPrintFileName(gpa: Allocator, io: Io, args: CCPrintFileNameOptions) ![:0]u8 const run_res = std.process.run(gpa, io, .{ .max_output_bytes = 1024 * 1024, - .spawn_options = .{ - .argv = argv.items, - .env_map = &env_map, - // Some C compilers, such as Clang, are known to rely on argv[0] to find the path - // to their own executable, without even bothering to resolve PATH. This results in the message: - // error: unable to execute command: Executable "" doesn't exist! - // So we use the expandArg0 variant of ChildProcess to give them a helping hand. - .expand_arg0 = .expand, - }, + .argv = argv.items, + .env_map = &env_map, + // Some C compilers, such as Clang, are known to rely on argv[0] to find the path + // to their own executable, without even bothering to resolve PATH. This results in the message: + // error: unable to execute command: Executable "" doesn't exist! + // So we use the expandArg0 variant of ChildProcess to give them a helping hand. + .expand_arg0 = .expand, }) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, else => return error.UnableToSpawnCCompiler, @@ -621,10 +617,10 @@ fn ccPrintFileName(gpa: Allocator, io: Io, args: CCPrintFileNameOptions) ![:0]u8 // So we detect failure by checking if the output matches exactly the input. if (std.mem.eql(u8, line, args.search_basename)) return error.LibCRuntimeNotFound; switch (args.want_dirname) { - .full_path => return gpa.dupeZ(u8, line), + .full_path => return gpa.dupe(u8, line), .only_dir => { const dirname = fs.path.dirname(line) orelse return error.LibCRuntimeNotFound; - return gpa.dupeZ(u8, dirname); + return gpa.dupe(u8, dirname); }, } } diff --git a/lib/std/zig/system/darwin.zig b/lib/std/zig/system/darwin.zig index df07c68cba..b31dc484ce 100644 --- a/lib/std/zig/system/darwin.zig +++ b/lib/std/zig/system/darwin.zig @@ -17,9 +17,9 @@ pub const macos = @import("darwin/macos.zig"); /// /// If error.OutOfMemory occurs in Allocator, this function returns null. pub fn isSdkInstalled(gpa: Allocator, io: Io) bool { - const result = std.process.run(gpa, io, .{ .spawn_options = .{ + const result = std.process.run(gpa, io, .{ .argv = &.{ "xcode-select", "--print-path" }, - } }) catch return false; + }) catch return false; defer { gpa.free(result.stderr); gpa.free(result.stdout); @@ -47,7 +47,7 @@ pub fn getSdk(gpa: Allocator, io: Io, target: *const Target) ?[]const u8 { else => return null, }; const argv = &[_][]const u8{ "xcrun", "--sdk", sdk, "--show-sdk-path" }; - const result = std.process.run(gpa, io, .{ .spawn_options = .{ .argv = argv } }) catch return null; + const result = std.process.run(gpa, io, .{ .argv = argv }) catch return null; defer { gpa.free(result.stderr); gpa.free(result.stdout); diff --git a/test/standalone/child_process/child.zig b/test/standalone/child_process/child.zig index 80e2edaa7f..8e19d53b3c 100644 --- a/test/standalone/child_process/child.zig +++ b/test/standalone/child_process/child.zig @@ -4,31 +4,23 @@ const Io = std.Io; // 42 is expected by parent; other values result in test failure var exit_code: u8 = 42; -pub fn main() !void { - var arena_state = std.heap.ArenaAllocator.init(std.heap.page_allocator); - const arena = arena_state.allocator(); - - var threaded: std.Io.Threaded = .init(arena, .{}); - defer threaded.deinit(); - const io = threaded.io(); - - try run(arena, io); - arena_state.deinit(); +pub fn main(init: std.process.Init) !void { + try run(init.arena.allocator(), init.io, init.minimal.args); std.process.exit(exit_code); } -fn run(allocator: std.mem.Allocator, io: Io) !void { - var args = try std.process.argsWithAllocator(allocator); - defer args.deinit(); - _ = args.next() orelse unreachable; // skip binary name +fn run(arena: std.mem.Allocator, io: Io, args: std.process.Args) !void { + var it = try args.iterateAllocator(arena); + defer it.deinit(); + _ = it.next() orelse unreachable; // skip binary name // test cmd args const hello_arg = "hello arg"; - const a1 = args.next() orelse unreachable; + const a1 = it.next() orelse unreachable; if (!std.mem.eql(u8, a1, hello_arg)) { testError(io, "first arg: '{s}'; want '{s}'", .{ a1, hello_arg }); } - if (args.next()) |a2| { + if (it.next()) |a2| { testError(io, "expected only one arg; got more: {s}", .{a2}); } diff --git a/test/standalone/install_headers/check_exists.zig b/test/standalone/install_headers/check_exists.zig index 50ad4d0818..ac7dc62592 100644 --- a/test/standalone/install_headers/check_exists.zig +++ b/test/standalone/install_headers/check_exists.zig @@ -2,17 +2,13 @@ const std = @import("std"); /// Checks the existence of files relative to cwd. /// A path starting with ! should not exist. -pub fn main() !void { - var arena_state = std.heap.ArenaAllocator.init(std.heap.page_allocator); - defer arena_state.deinit(); +pub fn main(init: std.process.Init) !void { + const arena = init.arena.allocator(); + const io = init.io; - const arena = arena_state.allocator(); - - var arg_it = try std.process.argsWithAllocator(arena); + var arg_it = try init.minimal.args.iterateAllocator(arena); _ = arg_it.next(); - const io = std.Io.Threaded.global_single_threaded.ioBasic(); - const cwd = std.Io.Dir.cwd(); const cwd_realpath = try cwd.realPathFileAlloc(io, ".", arena); diff --git a/test/standalone/libfuzzer/main.zig b/test/standalone/libfuzzer/main.zig index 0bc093d870..836f25285b 100644 --- a/test/standalone/libfuzzer/main.zig +++ b/test/standalone/libfuzzer/main.zig @@ -6,19 +6,14 @@ fn testOne(in: abi.Slice) callconv(.c) void { std.debug.assertReadable(in.toSlice()); } -pub fn main() !void { - var debug_gpa_ctx: std.heap.DebugAllocator(.{}) = .init; - defer _ = debug_gpa_ctx.deinit(); - const gpa = debug_gpa_ctx.allocator(); +pub fn main(init: std.process.Init) !void { + const gpa = init.gpa; + const io = init.io; - var args = try std.process.argsWithAllocator(gpa); + var args = try init.minimal.args.iterateAllocator(gpa); defer args.deinit(); _ = args.skip(); // executable name - var threaded: std.Io.Threaded = .init(gpa, .{}); - defer threaded.deinit(); - const io = threaded.io(); - const cache_dir_path = args.next() orelse @panic("expected cache directory path argument"); var cache_dir = try std.Io.Dir.cwd().openDir(io, cache_dir_path, .{}); defer cache_dir.close(io); diff --git a/test/standalone/run_output_caching/main.zig b/test/standalone/run_output_caching/main.zig index 9786101d32..d7838cab99 100644 --- a/test/standalone/run_output_caching/main.zig +++ b/test/standalone/run_output_caching/main.zig @@ -1,8 +1,8 @@ const std = @import("std"); -pub fn main() !void { - const io = std.Io.Threaded.global_single_threaded.ioBasic(); - var args = try std.process.argsWithAllocator(std.heap.page_allocator); +pub fn main(init: std.process.Init) !void { + const io = init.io; + var args = try init.minimal.argsAllocator(init.arena.allocator()); _ = args.skip(); const filename = args.next().?; const file = try std.Io.Dir.cwd().createFile(io, filename, .{}); diff --git a/test/standalone/windows_bat_args/fuzz.zig b/test/standalone/windows_bat_args/fuzz.zig index f0da2321b1..123c0be314 100644 --- a/test/standalone/windows_bat_args/fuzz.zig +++ b/test/standalone/windows_bat_args/fuzz.zig @@ -4,16 +4,11 @@ const std = @import("std"); const Io = std.Io; const Allocator = std.mem.Allocator; -pub fn main() anyerror!void { - var debug_alloc_inst: std.heap.DebugAllocator(.{}) = .init; - defer std.debug.assert(debug_alloc_inst.deinit() == .ok); - const gpa = debug_alloc_inst.allocator(); +pub fn main(init: std.process.Init) !void { + const gpa = init.gpa; + const io = init.io; - var threaded: Io.Threaded = .init(gpa, .{}); - defer threaded.deinit(); - const io = threaded.io(); - - var it = try std.process.argsWithAllocator(gpa); + var it = try init.minimal.argsAllocator(gpa); defer it.deinit(); _ = it.next() orelse unreachable; // skip binary name const child_exe_path_orig = it.next() orelse unreachable; diff --git a/test/standalone/windows_bat_args/test.zig b/test/standalone/windows_bat_args/test.zig index ac851cf8f6..38ecb5e2f8 100644 --- a/test/standalone/windows_bat_args/test.zig +++ b/test/standalone/windows_bat_args/test.zig @@ -2,15 +2,11 @@ const std = @import("std"); const Io = std.Io; const Allocator = std.mem.Allocator; -pub fn main() anyerror!void { - var debug_alloc_inst: std.heap.DebugAllocator(.{}) = .init; - defer std.debug.assert(debug_alloc_inst.deinit() == .ok); - const gpa = debug_alloc_inst.allocator(); +pub fn main(init: std.process.Init) !void { + const gpa = init.gpa; + const io = init.io; - var threaded: Io.Threaded = .init(gpa, .{}); - const io = threaded.io(); - - var it = try std.process.argsWithAllocator(gpa); + var it = try init.minimal.argsAllocator(gpa); defer it.deinit(); _ = it.next() orelse unreachable; // skip binary name const child_exe_path_orig = it.next() orelse unreachable; diff --git a/test/standalone/windows_spawn/main.zig b/test/standalone/windows_spawn/main.zig index c9522bf4de..32db164a5a 100644 --- a/test/standalone/windows_spawn/main.zig +++ b/test/standalone/windows_spawn/main.zig @@ -5,16 +5,11 @@ const Allocator = std.mem.Allocator; const windows = std.os.windows; const utf16Literal = std.unicode.utf8ToUtf16LeStringLiteral; -pub fn main() anyerror!void { - var debug_allocator: std.heap.DebugAllocator(.{}) = .init; - defer if (debug_allocator.deinit() == .leak) @panic("found memory leaks"); - const gpa = debug_allocator.allocator(); +pub fn main(init: std.process.Init) !void { + const gpa = init.gpa; + const io = init.io; - var threaded: std.Io.Threaded = .init(gpa, .{}); - defer threaded.deinit(); - const io = threaded.io(); - - var it = try std.process.argsWithAllocator(gpa); + var it = try init.minimal.argsAllocator(gpa); defer it.deinit(); _ = it.next() orelse unreachable; // skip binary name const hello_exe_cache_path = it.next() orelse unreachable; diff --git a/tools/docgen.zig b/tools/docgen.zig index ac0d26b995..c526233f51 100644 --- a/tools/docgen.zig +++ b/tools/docgen.zig @@ -28,21 +28,13 @@ const usage = \\ ; -pub fn main() !void { - var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator); - defer arena_instance.deinit(); +pub fn main(init: std.process.Init) !void { + const arena = init.arena.allocator(); + const io = init.io; - const arena = arena_instance.allocator(); - - var args_it = try process.argsWithAllocator(arena); + var args_it = try init.minimal.args.iterateAllocator(arena); if (!args_it.skip()) @panic("expected self arg"); - const gpa = arena; - - var threaded: std.Io.Threaded = .init(gpa, .{}); - defer threaded.deinit(); - const io = threaded.io(); - var opt_code_dir: ?[]const u8 = null; var opt_input: ?[]const u8 = null; var opt_output: ?[]const u8 = null; diff --git a/tools/doctest.zig b/tools/doctest.zig index cd836c624e..44d5954f7e 100644 --- a/tools/doctest.zig +++ b/tools/doctest.zig @@ -29,21 +29,13 @@ const usage = \\ ; -pub fn main() !void { - var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator); - defer arena_instance.deinit(); +pub fn main(init: std.process.Init) !void { + const arena = init.arena.allocator(); + const io = init.io; - const arena = arena_instance.allocator(); - - var args_it = try process.argsWithAllocator(arena); + var args_it = try init.minimal.args.iterateAllocator(arena); if (!args_it.skip()) fatal("missing argv[0]", .{}); - const gpa = arena; - - var threaded: std.Io.Threaded = .init(gpa, .{}); - defer threaded.deinit(); - const io = threaded.io(); - var opt_input: ?[]const u8 = null; var opt_output: ?[]const u8 = null; var opt_zig: ?[]const u8 = null; diff --git a/tools/incr-check.zig b/tools/incr-check.zig index 06b6daa648..d9664be710 100644 --- a/tools/incr-check.zig +++ b/tools/incr-check.zig @@ -44,7 +44,7 @@ pub fn main(init: std.process.Init) !void { var debug_log_args: std.ArrayList([]const u8) = .empty; - var arg_it = try std.process.argsWithAllocator(arena); + var arg_it = try init.minimal.argsIterator(arena); _ = arg_it.skip(); while (arg_it.next()) |arg| { if (arg.len > 0 and arg[0] == '-') { diff --git a/tools/update_cpu_features.zig b/tools/update_cpu_features.zig index 3852a85193..6def3db6ba 100644 --- a/tools/update_cpu_features.zig +++ b/tools/update_cpu_features.zig @@ -1883,20 +1883,11 @@ const targets = [_]ArchTarget{ }, }; -pub fn main() anyerror!void { - var debug_allocator: std.heap.DebugAllocator(.{}) = .init; - defer _ = debug_allocator.deinit(); - const gpa = debug_allocator.allocator(); +pub fn main(init: std.process.Init) !void { + const arena = init.arena_allocator.allocator(); + const io = init.io; - var arena_state: std.heap.ArenaAllocator = .init(gpa); - defer arena_state.deinit(); - const arena = arena_state.allocator(); - - var threaded: std.Io.Threaded = .init(gpa, .{}); - defer threaded.deinit(); - const io = threaded.io(); - - var args = try std.process.argsWithAllocator(arena); + var args = try init.minimal.args.iterateAllocator(arena); const args0 = args.next().?; const llvm_tblgen_exe = args.next() orelse