mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-10-28 10:45:48 +08:00
std: move child process APIs to std.Io
this gets the build runner compiling again on linux this work is incomplete; it only moves code around so that environment variables can be wrangled properly. a future commit will need to audit the cancelation and error handling of this moved logic.
This commit is contained in:
1 parent
d6a1e73142
commit
32af0f6154
30 files changed
+2169
-2222
No files matched your search
@@ -261,7 +261,7 @@ pub fn build(b: *std.Build) !void {
|
||||
"--git-dir", ".git", // affected by the -C argument
|
||||
"describe", "--match", "*.*.*", //
|
||||
"--tags", "--abbrev=9",
|
||||
}, &code, .Ignore) catch {
|
||||
}, &code, .ignore) catch {
|
||||
break :v version_string;
|
||||
};
|
||||
const git_describe = mem.trim(u8, git_describe_untrimmed, " \n\r");
|
||||
|
||||
Vendored
+6
-6
@@ -1256,9 +1256,9 @@ fn invokeAssembler(d: *Driver, tc: *Toolchain, input_path: []const u8, output_pa
|
||||
|
||||
var child = std.process.Child.init(&argv, d.comp.gpa);
|
||||
// TODO handle better
|
||||
child.stdin_behavior = .Inherit;
|
||||
child.stdout_behavior = .Inherit;
|
||||
child.stderr_behavior = .Inherit;
|
||||
child.stdin_behavior = .inherit;
|
||||
child.stdout_behavior = .inherit;
|
||||
child.stderr_behavior = .inherit;
|
||||
|
||||
const term = child.spawnAndWait() catch |er| {
|
||||
return d.fatal("unable to spawn linker: {s}", .{errorDescription(er)});
|
||||
@@ -1508,9 +1508,9 @@ pub fn invokeLinker(d: *Driver, tc: *Toolchain, comptime fast_exit: bool) Compil
|
||||
}
|
||||
var child = std.process.Child.init(argv.items, d.comp.gpa);
|
||||
// TODO handle better
|
||||
child.stdin_behavior = .Inherit;
|
||||
child.stdout_behavior = .Inherit;
|
||||
child.stderr_behavior = .Inherit;
|
||||
child.stdin_behavior = .inherit;
|
||||
child.stdout_behavior = .inherit;
|
||||
child.stderr_behavior = .inherit;
|
||||
|
||||
const term = child.spawnAndWait() catch |er| {
|
||||
return d.fatal("unable to spawn linker: {s}", .{errorDescription(er)});
|
||||
|
||||
@@ -306,7 +306,7 @@ fn termToInteresting(term: std.process.Child.Term) Interestingness {
|
||||
}
|
||||
|
||||
fn runCheck(arena: Allocator, io: Io, argv: []const []const u8) !Interestingness {
|
||||
const result = try std.process.Child.run(arena, io, .{ .argv = argv });
|
||||
const result = try std.process.run(arena, io, .{ .spawn_options = .{ .argv = argv } });
|
||||
if (result.stderr.len != 0)
|
||||
std.debug.print("{s}", .{result.stderr});
|
||||
return termToInteresting(result.term);
|
||||
|
||||
@@ -447,9 +447,9 @@ fn openBrowserTabThread(gpa: Allocator, io: Io, url: []const u8) !void {
|
||||
else => "xdg-open",
|
||||
};
|
||||
var child = std.process.Child.init(&.{ main_exe, url }, gpa);
|
||||
child.stdin_behavior = .Ignore;
|
||||
child.stdout_behavior = .Ignore;
|
||||
child.stderr_behavior = .Ignore;
|
||||
child.stdin_behavior = .ignore;
|
||||
child.stdout_behavior = .ignore;
|
||||
child.stderr_behavior = .ignore;
|
||||
try child.spawn(io);
|
||||
_ = try child.wait(io);
|
||||
}
|
||||
+20
-13
@@ -190,7 +190,7 @@ pub const RunError = error{
|
||||
ExitCodeFailure,
|
||||
ProcessTerminated,
|
||||
ExecNotSupported,
|
||||
} || std.process.Child.SpawnError;
|
||||
} || std.process.SpawnError;
|
||||
|
||||
pub const PkgConfigError = error{
|
||||
PkgConfigCrashed,
|
||||
@@ -1755,7 +1755,7 @@ pub fn fmt(b: *Build, comptime format: []const u8, args: anytype) []u8 {
|
||||
}
|
||||
|
||||
fn supportedWindowsProgramExtension(ext: []const u8) bool {
|
||||
inline for (@typeInfo(std.process.Child.WindowsExtension).@"enum".fields) |field| {
|
||||
inline for (@typeInfo(std.process.WindowsExtension).@"enum".fields) |field| {
|
||||
if (std.ascii.eqlIgnoreCase(ext, "." ++ field.name)) return true;
|
||||
}
|
||||
return false;
|
||||
@@ -1830,23 +1830,26 @@ pub fn runAllowFail(
|
||||
b: *Build,
|
||||
argv: []const []const u8,
|
||||
out_code: *u8,
|
||||
stderr_behavior: std.process.Child.StdIo,
|
||||
stderr_behavior: std.process.SpawnOptions.StdIo,
|
||||
) RunError![]u8 {
|
||||
assert(argv.len != 0);
|
||||
|
||||
if (!process.can_spawn)
|
||||
return error.ExecNotSupported;
|
||||
|
||||
const io = b.graph.io;
|
||||
const graph = b.graph;
|
||||
const io = graph.io;
|
||||
|
||||
const max_output_size = 400 * 1024;
|
||||
var child = std.process.Child.init(b.allocator, argv, .{ .map = &b.graph.env_map });
|
||||
child.stdin_behavior = .Ignore;
|
||||
child.stdout_behavior = .Pipe;
|
||||
child.stderr_behavior = stderr_behavior;
|
||||
try Step.handleVerbose2(b, null, &graph.env_map, argv);
|
||||
|
||||
try Step.handleVerbose2(b, null, child.environ.map, argv);
|
||||
try child.spawn(io);
|
||||
var child = try std.process.spawn(io, .{
|
||||
.argv = argv,
|
||||
.env_map = &graph.env_map,
|
||||
.stdin = .ignore,
|
||||
.stdout = .pipe,
|
||||
.stderr = stderr_behavior,
|
||||
});
|
||||
|
||||
var stdout_reader = child.stdout.?.readerStreaming(io, &.{});
|
||||
const stdout = stdout_reader.interface.allocRemaining(b.allocator, .limited(max_output_size)) catch {
|
||||
@@ -1856,14 +1859,18 @@ pub fn runAllowFail(
|
||||
|
||||
const term = try child.wait(io);
|
||||
switch (term) {
|
||||
.Exited => |code| {
|
||||
.exited => |code| {
|
||||
if (code != 0) {
|
||||
out_code.* = @as(u8, @truncate(code));
|
||||
return error.ExitCodeFailure;
|
||||
}
|
||||
return stdout;
|
||||
},
|
||||
.Signal, .Stopped, .Unknown => |code| {
|
||||
.signal => |sig| {
|
||||
out_code.* = @as(u8, @truncate(@intFromEnum(sig)));
|
||||
return error.ProcessTerminated;
|
||||
},
|
||||
.stopped, .unknown => |code| {
|
||||
out_code.* = @as(u8, @truncate(code));
|
||||
return error.ProcessTerminated;
|
||||
},
|
||||
@@ -1882,7 +1889,7 @@ pub fn run(b: *Build, argv: []const []const u8) []u8 {
|
||||
}
|
||||
|
||||
var code: u8 = undefined;
|
||||
return b.runAllowFail(argv, &code, .Inherit) catch |err| {
|
||||
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);
|
||||
|
||||
+21
-17
@@ -348,7 +348,7 @@ pub fn captureChildProcess(
|
||||
gpa: Allocator,
|
||||
progress_node: std.Progress.Node,
|
||||
argv: []const []const u8,
|
||||
) !std.process.Child.RunResult {
|
||||
) !std.process.RunResult {
|
||||
const graph = s.owner.graph;
|
||||
const arena = graph.arena;
|
||||
const io = graph.io;
|
||||
@@ -360,11 +360,11 @@ pub fn captureChildProcess(
|
||||
try handleChildProcUnsupported(s);
|
||||
try handleVerbose(s.owner, null, argv);
|
||||
|
||||
const result = std.process.Child.run(arena, io, .{
|
||||
const result = std.process.run(arena, io, .{ .spawn_options = .{
|
||||
.argv = argv,
|
||||
.environ = .{ .map = &graph.env_map },
|
||||
.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);
|
||||
@@ -444,19 +444,20 @@ pub fn evalZigProcess(
|
||||
return result;
|
||||
}
|
||||
assert(argv.len != 0);
|
||||
const arena = b.allocator;
|
||||
|
||||
try handleChildProcUnsupported(s);
|
||||
try handleVerbose(s.owner, null, argv);
|
||||
|
||||
var child = std.process.Child.init(arena, argv, .{ .map = &b.graph.env_map });
|
||||
child.stdin_behavior = .Pipe;
|
||||
child.stdout_behavior = .Pipe;
|
||||
child.stderr_behavior = .Pipe;
|
||||
child.request_resource_usage_statistics = true;
|
||||
child.progress_node = prog_node;
|
||||
|
||||
child.spawn(io) catch |err| return s.fail("failed to spawn zig compiler {s}: {t}", .{ argv[0], err });
|
||||
var child = std.process.spawn(io, .{
|
||||
.argv = argv,
|
||||
.env_map = &b.graph.env_map,
|
||||
.stdin = .pipe,
|
||||
.stdout = .pipe,
|
||||
.stderr = .pipe,
|
||||
.request_resource_usage_statistics = true,
|
||||
.progress_node = prog_node,
|
||||
}) catch |err| return s.fail("failed to spawn zig compiler {s}: {t}", .{ argv[0], err });
|
||||
defer if (!watch) child.kill(io);
|
||||
|
||||
const zp = try gpa.create(ZigProcess);
|
||||
zp.* = .{
|
||||
@@ -465,7 +466,7 @@ pub fn evalZigProcess(
|
||||
.stdout = child.stdout.?,
|
||||
.stderr = child.stderr.?,
|
||||
}),
|
||||
.progress_ipc_fd = if (std.Progress.have_ipc) child.progress_node.getIpcFd() else {},
|
||||
.progress_ipc_fd = if (std.Progress.have_ipc) prog_node.getIpcFd() else {},
|
||||
};
|
||||
if (watch) s.setZigProcess(zp);
|
||||
defer if (!watch) {
|
||||
@@ -487,7 +488,7 @@ pub fn evalZigProcess(
|
||||
|
||||
// Special handling for Compile step that is expecting compile errors.
|
||||
if (s.cast(Compile)) |compile| switch (term) {
|
||||
.Exited => {
|
||||
.exited => {
|
||||
// Note that the exit code may be 0 in this case due to the
|
||||
// compiler server protocol.
|
||||
if (compile.expect_errors != null) {
|
||||
@@ -719,12 +720,15 @@ pub inline fn handleChildProcUnsupported(s: *Step) error{ OutOfMemory, MakeFaile
|
||||
pub fn handleChildProcessTerm(s: *Step, term: std.process.Child.Term) error{ MakeFailed, OutOfMemory }!void {
|
||||
assert(s.result_failed_command != null);
|
||||
switch (term) {
|
||||
.Exited => |code| {
|
||||
.exited => |code| {
|
||||
if (code != 0) {
|
||||
return s.fail("process exited with error code {d}", .{code});
|
||||
}
|
||||
},
|
||||
.Signal, .Stopped, .Unknown => {
|
||||
.signal => |sig| {
|
||||
return s.fail("process terminated with signal {t}", .{sig});
|
||||
},
|
||||
.stopped, .unknown => {
|
||||
return s.fail("process terminated unexpectedly", .{});
|
||||
},
|
||||
}
|
||||
|
||||
@@ -747,7 +747,7 @@ fn runPkgConfig(compile: *Compile, lib_name: []const u8) !PkgConfigResult {
|
||||
pkg_name,
|
||||
"--cflags",
|
||||
"--libs",
|
||||
}, &code, .Ignore)) |stdout| stdout else |err| switch (err) {
|
||||
}, &code, .ignore)) |stdout| stdout else |err| switch (err) {
|
||||
error.ProcessTerminated => return error.PkgConfigCrashed,
|
||||
error.ExecNotSupported => return error.PkgConfigFailed,
|
||||
error.ExitCodeFailure => return error.PkgConfigFailed,
|
||||
@@ -1847,7 +1847,7 @@ pub fn doAtomicSymLinks(
|
||||
|
||||
fn execPkgConfigList(b: *std.Build, out_code: *u8) (PkgConfigError || RunError)![]const PkgConfigPkg {
|
||||
const pkg_config_exe = b.graph.env_map.get("PKG_CONFIG") orelse "pkg-config";
|
||||
const stdout = try b.runAllowFail(&[_][]const u8{ pkg_config_exe, "--list-all" }, out_code, .Ignore);
|
||||
const stdout = try b.runAllowFail(&[_][]const u8{ pkg_config_exe, "--list-all" }, out_code, .ignore);
|
||||
var list = std.array_list.Managed(PkgConfigPkg).init(b.allocator);
|
||||
errdefer list.deinit();
|
||||
var line_it = mem.tokenizeAny(u8, stdout, "\r\n");
|
||||
|
||||
@@ -69,7 +69,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
|
||||
|
||||
const run_result = try step.captureChildProcess(options.gpa, prog_node, argv.items);
|
||||
if (fmt.check) switch (run_result.term) {
|
||||
.Exited => |code| if (code != 0 and run_result.stdout.len != 0) {
|
||||
.exited => |code| if (code != 0 and run_result.stdout.len != 0) {
|
||||
var it = std.mem.tokenizeScalar(u8, run_result.stdout, '\n');
|
||||
while (it.next()) |bad_file_name| {
|
||||
try step.addError("{s}: non-conforming formatting", .{bad_file_name});
|
||||
|
||||
+67
-73
@@ -149,7 +149,7 @@ pub const StdIo = union(enum) {
|
||||
expect_stderr_match: []const u8,
|
||||
expect_stdout_exact: []const u8,
|
||||
expect_stdout_match: []const u8,
|
||||
expect_term: std.process.Child.Term,
|
||||
expect_term: process.Child.Term,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -618,7 +618,7 @@ pub fn expectStdOutEqual(run: *Run, bytes: []const u8) void {
|
||||
}
|
||||
|
||||
pub fn expectExitCode(run: *Run, code: u8) void {
|
||||
const new_check: StdIo.Check = .{ .expect_term = .{ .Exited = code } };
|
||||
const new_check: StdIo.Check = .{ .expect_term = .{ .exited = code } };
|
||||
run.addCheck(new_check);
|
||||
}
|
||||
|
||||
@@ -1182,40 +1182,40 @@ fn populateGeneratedPaths(
|
||||
}
|
||||
}
|
||||
|
||||
fn formatTerm(term: ?std.process.Child.Term, w: *std.Io.Writer) std.Io.Writer.Error!void {
|
||||
fn formatTerm(term: ?process.Child.Term, w: *std.Io.Writer) std.Io.Writer.Error!void {
|
||||
if (term) |t| switch (t) {
|
||||
.Exited => |code| try w.print("exited with code {d}", .{code}),
|
||||
.Signal => |sig| try w.print("terminated with signal {d}", .{sig}),
|
||||
.Stopped => |sig| try w.print("stopped with signal {d}", .{sig}),
|
||||
.Unknown => |code| try w.print("terminated for unknown reason with code {d}", .{code}),
|
||||
.exited => |code| try w.print("exited with code {d}", .{code}),
|
||||
.signal => |sig| try w.print("terminated with signal {t}", .{sig}),
|
||||
.stopped => |sig| try w.print("stopped with signal {d}", .{sig}),
|
||||
.unknown => |code| try w.print("terminated for unknown reason with code {d}", .{code}),
|
||||
} else {
|
||||
try w.writeAll("exited with any code");
|
||||
}
|
||||
}
|
||||
fn fmtTerm(term: ?std.process.Child.Term) std.fmt.Alt(?std.process.Child.Term, formatTerm) {
|
||||
fn fmtTerm(term: ?process.Child.Term) std.fmt.Alt(?process.Child.Term, formatTerm) {
|
||||
return .{ .data = term };
|
||||
}
|
||||
|
||||
fn termMatches(expected: ?std.process.Child.Term, actual: std.process.Child.Term) bool {
|
||||
fn termMatches(expected: ?process.Child.Term, actual: process.Child.Term) bool {
|
||||
return if (expected) |e| switch (e) {
|
||||
.Exited => |expected_code| switch (actual) {
|
||||
.Exited => |actual_code| expected_code == actual_code,
|
||||
.exited => |expected_code| switch (actual) {
|
||||
.exited => |actual_code| expected_code == actual_code,
|
||||
else => false,
|
||||
},
|
||||
.Signal => |expected_sig| switch (actual) {
|
||||
.Signal => |actual_sig| expected_sig == actual_sig,
|
||||
.signal => |expected_sig| switch (actual) {
|
||||
.signal => |actual_sig| expected_sig == actual_sig,
|
||||
else => false,
|
||||
},
|
||||
.Stopped => |expected_sig| switch (actual) {
|
||||
.Stopped => |actual_sig| expected_sig == actual_sig,
|
||||
.stopped => |expected_sig| switch (actual) {
|
||||
.stopped => |actual_sig| expected_sig == actual_sig,
|
||||
else => false,
|
||||
},
|
||||
.Unknown => |expected_code| switch (actual) {
|
||||
.Unknown => |actual_code| expected_code == actual_code,
|
||||
.unknown => |expected_code| switch (actual) {
|
||||
.unknown => |actual_code| expected_code == actual_code,
|
||||
else => false,
|
||||
},
|
||||
} else switch (actual) {
|
||||
.Exited => true,
|
||||
.exited => true,
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
@@ -1526,8 +1526,8 @@ fn runCommand(
|
||||
else => {
|
||||
// On failure, report captured stderr like normal standard error output.
|
||||
const bad_exit = switch (generic_result.term) {
|
||||
.Exited => |code| code != 0,
|
||||
.Signal, .Stopped, .Unknown => true,
|
||||
.exited => |code| code != 0,
|
||||
.signal, .stopped, .unknown => true,
|
||||
};
|
||||
if (bad_exit) {
|
||||
if (generic_result.stderr) |bytes| {
|
||||
@@ -1541,7 +1541,7 @@ fn runCommand(
|
||||
}
|
||||
|
||||
const EvalGenericResult = struct {
|
||||
term: std.process.Child.Term,
|
||||
term: process.Child.Term,
|
||||
stdout: ?[]const u8,
|
||||
stderr: ?[]const u8,
|
||||
};
|
||||
@@ -1555,7 +1555,6 @@ fn spawnChildAndCollect(
|
||||
fuzz_context: ?FuzzContext,
|
||||
) !?EvalGenericResult {
|
||||
const b = run.step.owner;
|
||||
const arena = b.allocator;
|
||||
const graph = b.graph;
|
||||
const io = graph.io;
|
||||
|
||||
@@ -1564,53 +1563,52 @@ fn spawnChildAndCollect(
|
||||
assert(run.stdio == .zig_test);
|
||||
}
|
||||
|
||||
var child = std.process.Child.init(arena, argv, .{ .map = env_map });
|
||||
if (run.cwd) |lazy_cwd| {
|
||||
child.cwd = lazy_cwd.getPath2(b, &run.step);
|
||||
}
|
||||
child.request_resource_usage_statistics = true;
|
||||
|
||||
child.stdin_behavior = switch (run.stdio) {
|
||||
.infer_from_args => if (has_side_effects) .Inherit else .Ignore,
|
||||
.inherit => .Inherit,
|
||||
.check => .Ignore,
|
||||
.zig_test => .Pipe,
|
||||
};
|
||||
child.stdout_behavior = switch (run.stdio) {
|
||||
.infer_from_args => if (has_side_effects) .Inherit else .Ignore,
|
||||
.inherit => .Inherit,
|
||||
.check => |checks| if (checksContainStdout(checks.items)) .Pipe else .Ignore,
|
||||
.zig_test => .Pipe,
|
||||
};
|
||||
child.stderr_behavior = switch (run.stdio) {
|
||||
.infer_from_args => if (has_side_effects) .Inherit else .Pipe,
|
||||
.inherit => .Inherit,
|
||||
.check => .Pipe,
|
||||
.zig_test => .Pipe,
|
||||
};
|
||||
if (run.captured_stdout != null) child.stdout_behavior = .Pipe;
|
||||
if (run.captured_stderr != null) child.stderr_behavior = .Pipe;
|
||||
if (run.stdin != .none) {
|
||||
assert(run.stdio != .inherit);
|
||||
child.stdin_behavior = .Pipe;
|
||||
}
|
||||
const child_cwd = if (run.cwd) |lazy_cwd| lazy_cwd.getPath2(b, &run.step) else null;
|
||||
|
||||
// If an error occurs, it's caused by this command:
|
||||
assert(run.step.result_failed_command == null);
|
||||
run.step.result_failed_command = try Step.allocPrintCmd(options.gpa, child.cwd, .{
|
||||
run.step.result_failed_command = try Step.allocPrintCmd(options.gpa, child_cwd, .{
|
||||
.child = env_map,
|
||||
.parent = &graph.env_map,
|
||||
}, argv);
|
||||
|
||||
var spawn_options: process.SpawnOptions = .{
|
||||
.argv = argv,
|
||||
.cwd = child_cwd,
|
||||
.env_map = &graph.env_map,
|
||||
.request_resource_usage_statistics = true,
|
||||
.stdin = if (run.stdin != .none) s: {
|
||||
assert(run.stdio != .inherit);
|
||||
break :s .pipe;
|
||||
} else switch (run.stdio) {
|
||||
.infer_from_args => if (has_side_effects) .inherit else .ignore,
|
||||
.inherit => .inherit,
|
||||
.check => .ignore,
|
||||
.zig_test => .pipe,
|
||||
},
|
||||
.stdout = if (run.captured_stdout != null) .pipe else switch (run.stdio) {
|
||||
.infer_from_args => if (has_side_effects) .inherit else .ignore,
|
||||
.inherit => .inherit,
|
||||
.check => |checks| if (checksContainStdout(checks.items)) .pipe else .ignore,
|
||||
.zig_test => .pipe,
|
||||
},
|
||||
.stderr = if (run.captured_stderr != null) .pipe else switch (run.stdio) {
|
||||
.infer_from_args => if (has_side_effects) .inherit else .pipe,
|
||||
.inherit => .inherit,
|
||||
.check => .pipe,
|
||||
.zig_test => .pipe,
|
||||
},
|
||||
};
|
||||
|
||||
if (run.stdio == .zig_test) {
|
||||
var timer = try std.time.Timer.start();
|
||||
defer run.step.result_duration_ns = timer.read();
|
||||
try evalZigTest(run, &child, options, fuzz_context);
|
||||
try evalZigTest(run, spawn_options, options, fuzz_context);
|
||||
return null;
|
||||
} else {
|
||||
const inherit = child.stdout_behavior == .Inherit or child.stderr_behavior == .Inherit;
|
||||
const inherit = spawn_options.stdout == .inherit or spawn_options.stderr == .inherit;
|
||||
if (!run.disable_zig_progress and !inherit) {
|
||||
child.progress_node = options.progress_node;
|
||||
spawn_options.progress_node = options.progress_node;
|
||||
}
|
||||
const terminal_mode: Io.Terminal.Mode = if (inherit) m: {
|
||||
const stderr = try io.lockStderr(&.{}, graph.stderr_mode);
|
||||
@@ -1619,7 +1617,7 @@ fn spawnChildAndCollect(
|
||||
defer if (inherit) io.unlockStderr();
|
||||
try setColorEnvironmentVariables(run, env_map, terminal_mode);
|
||||
var timer = try std.time.Timer.start();
|
||||
const res = try evalGeneric(run, &child);
|
||||
const res = try evalGeneric(run, spawn_options);
|
||||
run.step.result_duration_ns = timer.read();
|
||||
return .{ .term = res.term, .stdout = res.stdout, .stderr = res.stderr };
|
||||
}
|
||||
@@ -1658,7 +1656,7 @@ const StdioPollEnum = enum { stdout, stderr };
|
||||
|
||||
fn evalZigTest(
|
||||
run: *Run,
|
||||
child: *std.process.Child,
|
||||
spawn_options: process.SpawnOptions,
|
||||
options: Step.MakeOptions,
|
||||
fuzz_context: ?FuzzContext,
|
||||
) !void {
|
||||
@@ -1682,14 +1680,14 @@ fn evalZigTest(
|
||||
var test_metadata: ?TestMetadata = null;
|
||||
|
||||
while (true) {
|
||||
try child.spawn(io);
|
||||
var child = try process.spawn(io, spawn_options);
|
||||
var poller = std.Io.poll(gpa, StdioPollEnum, .{
|
||||
.stdout = child.stdout.?,
|
||||
.stderr = child.stderr.?,
|
||||
});
|
||||
var child_killed = false;
|
||||
defer if (!child_killed) {
|
||||
_ = child.kill(io) catch {};
|
||||
child.kill(io);
|
||||
poller.deinit();
|
||||
run.step.result_peak_rss = @max(
|
||||
run.step.result_peak_rss,
|
||||
@@ -1697,11 +1695,9 @@ fn evalZigTest(
|
||||
);
|
||||
};
|
||||
|
||||
try child.waitForSpawn();
|
||||
|
||||
switch (try pollZigTest(
|
||||
run,
|
||||
child,
|
||||
&child,
|
||||
options,
|
||||
fuzz_context,
|
||||
&poller,
|
||||
@@ -1763,7 +1759,7 @@ fn evalZigTest(
|
||||
// Report an error if the child terminated uncleanly or if we were still trying to run more tests.
|
||||
run.step.result_stderr = stderr_owned;
|
||||
const tests_done = test_metadata != null and test_metadata.?.next_index == std.math.maxInt(u32);
|
||||
if (!tests_done or !termMatches(.{ .Exited = 0 }, term)) {
|
||||
if (!tests_done or !termMatches(.{ .exited = 0 }, term)) {
|
||||
// The individual unit test results are irrelevant: the test runner itself broke!
|
||||
// Fail immediately without populating `s.test_results`.
|
||||
return run.step.fail("test process unexpectedly {f}", .{fmtTerm(term)});
|
||||
@@ -1818,7 +1814,7 @@ fn evalZigTest(
|
||||
/// * `poll` fails, indicating the child closed stdout and stderr
|
||||
fn pollZigTest(
|
||||
run: *Run,
|
||||
child: *std.process.Child,
|
||||
child: *process.Child,
|
||||
options: Step.MakeOptions,
|
||||
fuzz_context: ?FuzzContext,
|
||||
poller: *std.Io.Poller(StdioPollEnum),
|
||||
@@ -2176,15 +2172,13 @@ fn sendRunFuzzTestMessage(
|
||||
};
|
||||
}
|
||||
|
||||
fn evalGeneric(run: *Run, child: *std.process.Child) !EvalGenericResult {
|
||||
fn evalGeneric(run: *Run, spawn_options: process.SpawnOptions) !EvalGenericResult {
|
||||
const b = run.step.owner;
|
||||
const io = b.graph.io;
|
||||
const arena = b.allocator;
|
||||
|
||||
try child.spawn(io);
|
||||
errdefer _ = child.kill(io) catch {};
|
||||
|
||||
try child.waitForSpawn();
|
||||
var child = try process.spawn(io, spawn_options);
|
||||
defer child.kill(io);
|
||||
|
||||
switch (run.stdin) {
|
||||
.bytes => |bytes| {
|
||||
@@ -2334,10 +2328,10 @@ fn hashStdIo(hh: *std.Build.Cache.HashHelper, stdio: StdIo) void {
|
||||
=> |s| hh.addBytes(s),
|
||||
|
||||
.expect_term => |term| {
|
||||
hh.add(@as(std.meta.Tag(std.process.Child.Term), term));
|
||||
hh.add(@as(std.meta.Tag(process.Child.Term), term));
|
||||
switch (term) {
|
||||
.Exited => |x| hh.add(x),
|
||||
.Signal, .Stopped, .Unknown => |x| hh.add(x),
|
||||
inline .exited, .signal => |x| hh.add(x),
|
||||
.stopped, .unknown => |x| hh.add(x),
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@@ -572,11 +572,14 @@ fn buildClientWasm(ws: *WebServer, arena: Allocator, optimize: std.builtin.Optim
|
||||
"--listen=-",
|
||||
});
|
||||
|
||||
var child: std.process.Child = .init(gpa, argv.items, .{ .map = &graph.env_map });
|
||||
child.stdin_behavior = .Pipe;
|
||||
child.stdout_behavior = .Pipe;
|
||||
child.stderr_behavior = .Pipe;
|
||||
try child.spawn(io);
|
||||
var child = try std.process.spawn(io, .{
|
||||
.argv = argv.items,
|
||||
.env_map = &graph.env_map,
|
||||
.stdin = .pipe,
|
||||
.stdout = .pipe,
|
||||
.stderr = .pipe,
|
||||
});
|
||||
defer child.kill(io);
|
||||
|
||||
var poller = Io.poll(gpa, enum { stdout, stderr }, .{
|
||||
.stdout = child.stdout.?,
|
||||
@@ -636,7 +639,7 @@ fn buildClientWasm(ws: *WebServer, arena: Allocator, optimize: std.builtin.Optim
|
||||
child.stdin = null;
|
||||
|
||||
switch (try child.wait(io)) {
|
||||
.Exited => |code| {
|
||||
.exited => |code| {
|
||||
if (code != 0) {
|
||||
log.err(
|
||||
"the following command exited with error code {d}:\n{s}",
|
||||
@@ -645,7 +648,14 @@ fn buildClientWasm(ws: *WebServer, arena: Allocator, optimize: std.builtin.Optim
|
||||
return error.WasmCompilationFailed;
|
||||
}
|
||||
},
|
||||
.Signal, .Stopped, .Unknown => {
|
||||
.signal => |sig| {
|
||||
log.err(
|
||||
"the following command terminated with signal {t}:\n{s}",
|
||||
.{ sig, try Build.Step.allocPrintCmd(arena, null, null, argv.items) },
|
||||
);
|
||||
return error.WasmCompilationFailed;
|
||||
},
|
||||
.stopped, .unknown => {
|
||||
log.err(
|
||||
"the following command terminated unexpectedly:\n{s}",
|
||||
.{try Build.Step.allocPrintCmd(arena, null, null, argv.items)},
|
||||
|
||||
@@ -717,6 +717,12 @@ pub const VTable = struct {
|
||||
tryLockStderr: *const fn (?*anyopaque, ?Terminal.Mode) Cancelable!?LockedStderr,
|
||||
unlockStderr: *const fn (?*anyopaque) void,
|
||||
processSetCurrentDir: *const fn (?*anyopaque, Dir) std.process.SetCurrentDirError!void,
|
||||
processReplace: *const fn (?*anyopaque, std.process.ReplaceOptions) std.process.ReplaceError,
|
||||
processReplacePath: *const fn (?*anyopaque, Dir, std.process.ReplaceOptions) std.process.ReplaceError,
|
||||
processSpawn: *const fn (?*anyopaque, std.process.SpawnOptions) std.process.SpawnError!std.process.Child,
|
||||
processSpawnPath: *const fn (?*anyopaque, Dir, std.process.SpawnOptions) std.process.SpawnError!std.process.Child,
|
||||
childWait: *const fn (?*anyopaque, *std.process.Child) std.process.Child.WaitError!std.process.Child.Term,
|
||||
childKill: *const fn (?*anyopaque, *std.process.Child) void,
|
||||
|
||||
now: *const fn (?*anyopaque, Clock) Clock.Error!Timestamp,
|
||||
sleep: *const fn (?*anyopaque, Timeout) SleepError!void,
|
||||
|
||||
+1675
-23
File diff suppressed because it is too large.
Load diff
+22
-22
@@ -3764,8 +3764,8 @@ pub const W = switch (native_os) {
|
||||
pub fn EXITSTATUS(x: u32) u8 {
|
||||
return @as(u8, @intCast(x >> 8));
|
||||
}
|
||||
pub fn TERMSIG(x: u32) u32 {
|
||||
return status(x);
|
||||
pub fn TERMSIG(x: u32) SIG {
|
||||
return @enumFromInt(status(x));
|
||||
}
|
||||
pub fn STOPSIG(x: u32) u32 {
|
||||
return x >> 8;
|
||||
@@ -3797,14 +3797,14 @@ pub const W = switch (native_os) {
|
||||
pub fn EXITSTATUS(s: u32) u8 {
|
||||
return @as(u8, @intCast((s & 0xff00) >> 8));
|
||||
}
|
||||
pub fn TERMSIG(s: u32) u32 {
|
||||
return s & 0x7f;
|
||||
pub fn TERMSIG(s: u32) SIG {
|
||||
return @enumFromInt(s & 0x7f);
|
||||
}
|
||||
pub fn STOPSIG(s: u32) u32 {
|
||||
return EXITSTATUS(s);
|
||||
}
|
||||
pub fn IFEXITED(s: u32) bool {
|
||||
return TERMSIG(s) == 0;
|
||||
return (s & 0x7f) == 0;
|
||||
}
|
||||
pub fn IFSTOPPED(s: u32) bool {
|
||||
return @as(u16, @truncate((((s & 0xffff) *% 0x10001) >> 8))) > 0x7f00;
|
||||
@@ -3825,14 +3825,14 @@ pub const W = switch (native_os) {
|
||||
pub fn EXITSTATUS(s: u32) u8 {
|
||||
return @as(u8, @intCast((s >> 8) & 0xff));
|
||||
}
|
||||
pub fn TERMSIG(s: u32) u32 {
|
||||
return s & 0x7f;
|
||||
pub fn TERMSIG(s: u32) SIG {
|
||||
return @enumFromInt(s & 0x7f);
|
||||
}
|
||||
pub fn STOPSIG(s: u32) u32 {
|
||||
return EXITSTATUS(s);
|
||||
}
|
||||
pub fn IFEXITED(s: u32) bool {
|
||||
return TERMSIG(s) == 0;
|
||||
return (s & 0x7f) == 0;
|
||||
}
|
||||
|
||||
pub fn IFCONTINUED(s: u32) bool {
|
||||
@@ -3859,14 +3859,14 @@ pub const W = switch (native_os) {
|
||||
pub fn EXITSTATUS(s: u32) u8 {
|
||||
return @as(u8, @intCast((s >> 8) & 0xff));
|
||||
}
|
||||
pub fn TERMSIG(s: u32) u32 {
|
||||
return s & 0x7f;
|
||||
pub fn TERMSIG(s: u32) SIG {
|
||||
return @enumFromInt(s & 0x7f);
|
||||
}
|
||||
pub fn STOPSIG(s: u32) u32 {
|
||||
return EXITSTATUS(s);
|
||||
}
|
||||
pub fn IFEXITED(s: u32) bool {
|
||||
return TERMSIG(s) == 0;
|
||||
return (s & 0x7f) == 0;
|
||||
}
|
||||
|
||||
pub fn IFCONTINUED(s: u32) bool {
|
||||
@@ -3893,14 +3893,14 @@ pub const W = switch (native_os) {
|
||||
pub fn EXITSTATUS(s: u32) u8 {
|
||||
return @as(u8, @intCast((s & 0xff00) >> 8));
|
||||
}
|
||||
pub fn TERMSIG(s: u32) u32 {
|
||||
return s & 0x7f;
|
||||
pub fn TERMSIG(s: u32) SIG {
|
||||
return @enumFromInt(s & 0x7f);
|
||||
}
|
||||
pub fn STOPSIG(s: u32) u32 {
|
||||
return EXITSTATUS(s);
|
||||
}
|
||||
pub fn IFEXITED(s: u32) bool {
|
||||
return TERMSIG(s) == 0;
|
||||
return (s & 0x7f) == 0;
|
||||
}
|
||||
pub fn IFSTOPPED(s: u32) bool {
|
||||
return @as(u16, @truncate((((s & 0xffff) *% 0x10001) >> 8))) > 0x7f00;
|
||||
@@ -3921,8 +3921,8 @@ pub const W = switch (native_os) {
|
||||
return @as(u8, @intCast(s & 0xff));
|
||||
}
|
||||
|
||||
pub fn TERMSIG(s: u32) u32 {
|
||||
return (s >> 8) & 0xff;
|
||||
pub fn TERMSIG(s: u32) SIG {
|
||||
return @enumFromInt((s >> 8) & 0xff);
|
||||
}
|
||||
|
||||
pub fn STOPSIG(s: u32) u32 {
|
||||
@@ -3949,14 +3949,14 @@ pub const W = switch (native_os) {
|
||||
pub fn EXITSTATUS(s: u32) u8 {
|
||||
return @as(u8, @intCast((s >> 8) & 0xff));
|
||||
}
|
||||
pub fn TERMSIG(s: u32) u32 {
|
||||
return (s & 0x7f);
|
||||
pub fn TERMSIG(s: u32) SIG {
|
||||
return @enumFromInt(s & 0x7f);
|
||||
}
|
||||
pub fn STOPSIG(s: u32) u32 {
|
||||
return EXITSTATUS(s);
|
||||
}
|
||||
pub fn IFEXITED(s: u32) bool {
|
||||
return TERMSIG(s) == 0;
|
||||
return (s & 0x7f) == 0;
|
||||
}
|
||||
|
||||
pub fn IFCONTINUED(s: u32) bool {
|
||||
@@ -3988,12 +3988,12 @@ pub const W = switch (native_os) {
|
||||
return EXITSTATUS(s);
|
||||
}
|
||||
|
||||
pub fn TERMSIG(s: u32) u32 {
|
||||
return s & 0x7f;
|
||||
pub fn TERMSIG(s: u32) SIG {
|
||||
return @enumFromInt(s & 0x7f);
|
||||
}
|
||||
|
||||
pub fn IFEXITED(s: u32) bool {
|
||||
return TERMSIG(s) == 0;
|
||||
return (s & 0x7f) == 0;
|
||||
}
|
||||
|
||||
pub fn IFSTOPPED(s: u32) bool {
|
||||
|
||||
@@ -224,14 +224,14 @@ pub const W = struct {
|
||||
pub fn EXITSTATUS(s: u32) u8 {
|
||||
return @as(u8, @intCast((s & 0xff00) >> 8));
|
||||
}
|
||||
pub fn TERMSIG(s: u32) u32 {
|
||||
return s & 0x7f;
|
||||
pub fn TERMSIG(s: u32) SIG {
|
||||
return @enumFromInt(s & 0x7f);
|
||||
}
|
||||
pub fn STOPSIG(s: u32) u32 {
|
||||
return EXITSTATUS(s);
|
||||
}
|
||||
pub fn IFEXITED(s: u32) bool {
|
||||
return TERMSIG(s) == 0;
|
||||
return (s & 0x7f) == 0;
|
||||
}
|
||||
pub fn IFSTOPPED(s: u32) bool {
|
||||
return @as(u16, @truncate(((s & 0xffff) *% 0x10001) >> 8)) > 0x7f00;
|
||||
|
||||
@@ -3616,14 +3616,14 @@ pub const W = struct {
|
||||
pub fn EXITSTATUS(s: u32) u8 {
|
||||
return @as(u8, @intCast((s & 0xff00) >> 8));
|
||||
}
|
||||
pub fn TERMSIG(s: u32) u32 {
|
||||
return s & 0x7f;
|
||||
pub fn TERMSIG(s: u32) SIG {
|
||||
return @enumFromInt(s & 0x7f);
|
||||
}
|
||||
pub fn STOPSIG(s: u32) u32 {
|
||||
return EXITSTATUS(s);
|
||||
}
|
||||
pub fn IFEXITED(s: u32) bool {
|
||||
return TERMSIG(s) == 0;
|
||||
return (s & 0x7f) == 0;
|
||||
}
|
||||
pub fn IFSTOPPED(s: u32) bool {
|
||||
return @as(u16, @truncate(((s & 0xffff) *% 0x10001) >> 8)) > 0x7f00;
|
||||
|
||||
@@ -795,79 +795,10 @@ pub fn dup2(old_fd: fd_t, new_fd: fd_t) !void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getpid() pid_t {
|
||||
return system.getpid();
|
||||
}
|
||||
|
||||
pub fn getppid() pid_t {
|
||||
return system.getppid();
|
||||
}
|
||||
|
||||
pub const ExecveError = error{
|
||||
SystemResources,
|
||||
AccessDenied,
|
||||
PermissionDenied,
|
||||
InvalidExe,
|
||||
FileSystem,
|
||||
IsDir,
|
||||
FileNotFound,
|
||||
NotDir,
|
||||
FileBusy,
|
||||
ProcessFdQuotaExceeded,
|
||||
SystemFdQuotaExceeded,
|
||||
NameTooLong,
|
||||
} || UnexpectedError;
|
||||
|
||||
/// This function ignores PATH environment variable. See `execvpeZ` for that.
|
||||
pub fn execveZ(
|
||||
path: [*:0]const u8,
|
||||
child_argv: [*:null]const ?[*:0]const u8,
|
||||
envp: [*:null]const ?[*:0]const u8,
|
||||
) ExecveError {
|
||||
switch (errno(system.execve(path, child_argv, envp))) {
|
||||
.SUCCESS => unreachable,
|
||||
.FAULT => unreachable,
|
||||
.@"2BIG" => return error.SystemResources,
|
||||
.MFILE => return error.ProcessFdQuotaExceeded,
|
||||
.NAMETOOLONG => return error.NameTooLong,
|
||||
.NFILE => return error.SystemFdQuotaExceeded,
|
||||
.NOMEM => return error.SystemResources,
|
||||
.ACCES => return error.AccessDenied,
|
||||
.PERM => return error.PermissionDenied,
|
||||
.INVAL => return error.InvalidExe,
|
||||
.NOEXEC => return error.InvalidExe,
|
||||
.IO => return error.FileSystem,
|
||||
.LOOP => return error.FileSystem,
|
||||
.ISDIR => return error.IsDir,
|
||||
.NOENT => return error.FileNotFound,
|
||||
.NOTDIR => return error.NotDir,
|
||||
.TXTBSY => return error.FileBusy,
|
||||
else => |err| switch (native_os) {
|
||||
.driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => switch (err) {
|
||||
.BADEXEC => return error.InvalidExe,
|
||||
.BADARCH => return error.InvalidExe,
|
||||
else => return unexpectedErrno(err),
|
||||
},
|
||||
.linux => switch (err) {
|
||||
.LIBBAD => return error.InvalidExe,
|
||||
else => return unexpectedErrno(err),
|
||||
},
|
||||
else => return unexpectedErrno(err),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// This function also uses the PATH environment variable to get the full path to the executable.
|
||||
/// If `file` is an absolute path, this is the same as `execveZ`.
|
||||
pub fn execvpeZ(
|
||||
file: [*:0]const u8,
|
||||
argv_ptr: [*:null]const ?[*:0]const u8,
|
||||
envp: [*:null]const ?[*:0]const u8,
|
||||
optional_PATH: ?[]const u8,
|
||||
) ExecveError {
|
||||
return execvpeZ_expandArg0(.no_expand, file, argv_ptr, envp, optional_PATH);
|
||||
}
|
||||
|
||||
pub const GetCwdError = error{
|
||||
NameTooLong,
|
||||
CurrentWorkingDirectoryUnlinked,
|
||||
@@ -1119,16 +1050,6 @@ pub fn seteuid(uid: uid_t) SetEidError!void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setreuid(ruid: uid_t, euid: uid_t) SetIdError!void {
|
||||
switch (errno(system.setreuid(ruid, euid))) {
|
||||
.SUCCESS => return,
|
||||
.AGAIN => return error.ResourceLimitReached,
|
||||
.INVAL => return error.InvalidUserId,
|
||||
.PERM => return error.PermissionDenied,
|
||||
else => |err| return unexpectedErrno(err),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setgid(gid: gid_t) SetIdError!void {
|
||||
switch (errno(system.setgid(gid))) {
|
||||
.SUCCESS => return,
|
||||
@@ -1158,24 +1079,6 @@ pub fn setregid(rgid: gid_t, egid: gid_t) SetIdError!void {
|
||||
}
|
||||
}
|
||||
|
||||
pub const SetPgidError = error{
|
||||
ProcessAlreadyExec,
|
||||
InvalidProcessGroupId,
|
||||
PermissionDenied,
|
||||
ProcessNotFound,
|
||||
} || UnexpectedError;
|
||||
|
||||
pub fn setpgid(pid: pid_t, pgid: pid_t) SetPgidError!void {
|
||||
switch (errno(system.setpgid(pid, pgid))) {
|
||||
.SUCCESS => return,
|
||||
.ACCES => return error.ProcessAlreadyExec,
|
||||
.INVAL => return error.InvalidProcessGroupId,
|
||||
.PERM => return error.PermissionDenied,
|
||||
.SRCH => return error.ProcessNotFound,
|
||||
else => |err| return unexpectedErrno(err),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getuid() uid_t {
|
||||
return system.getuid();
|
||||
}
|
||||
|
||||
+201
-104
@@ -259,20 +259,44 @@ pub fn getBaseAddress() usize {
|
||||
}
|
||||
}
|
||||
|
||||
/// Deprecated in favor of `Child.can_spawn`.
|
||||
pub const can_spawn = Child.can_spawn;
|
||||
/// Deprecated in favor of `can_replace`.
|
||||
pub const can_execv = can_replace;
|
||||
|
||||
/// Tells whether the target operating system supports replacing the current
|
||||
/// process image. If this is `false` then calling `execv` or `replace`
|
||||
/// functions will cause compilation to fail.
|
||||
/// process image. If this is `false` then calling `replace` or `replaceFile`
|
||||
/// functions will return `error.OperationUnsupported`.
|
||||
pub const can_replace = switch (native_os) {
|
||||
.windows, .haiku, .wasi => false,
|
||||
else => true,
|
||||
};
|
||||
|
||||
pub const ReplaceError = std.posix.ExecveError || error{OutOfMemory};
|
||||
/// Tells whether spawning child processes is supported.
|
||||
pub const can_spawn = switch (native_os) {
|
||||
.wasi, .ios, .tvos, .visionos, .watchos => false,
|
||||
else => true,
|
||||
};
|
||||
|
||||
pub const ReplaceError = error{
|
||||
/// The target operating system cannot replace the process image with a new
|
||||
/// one.
|
||||
OperationUnsupported,
|
||||
SystemResources,
|
||||
AccessDenied,
|
||||
PermissionDenied,
|
||||
InvalidExe,
|
||||
FileSystem,
|
||||
IsDir,
|
||||
FileNotFound,
|
||||
NotDir,
|
||||
FileBusy,
|
||||
ProcessFdQuotaExceeded,
|
||||
SystemFdQuotaExceeded,
|
||||
} || Io.Dir.PathNameError || Io.Cancelable || Io.UnexpectedError;
|
||||
|
||||
pub const ReplaceOptions = struct {
|
||||
argv: []const []const u8,
|
||||
arg0_expand: ArgExpansion = .no_expand,
|
||||
/// Replaces the environment when provided. The PATH value from here is
|
||||
/// never used to resolve `argv[0]`.
|
||||
env_map: ?*const Environ.Map = null,
|
||||
};
|
||||
|
||||
/// Replaces the current process image with the executed process. If this
|
||||
/// function succeeds, it does not return.
|
||||
@@ -281,25 +305,9 @@ pub const ReplaceError = std.posix.ExecveError || error{OutOfMemory};
|
||||
/// is not already a file path (i.e. it contains '/'), it is resolved into a
|
||||
/// file path based on PATH from the parent environment.
|
||||
///
|
||||
/// This operation is not available on targets for which `can_replace` is
|
||||
/// `false`.
|
||||
///
|
||||
/// This function must allocate memory to add a null terminating bytes on path
|
||||
/// and each arg.
|
||||
///
|
||||
/// Due to the heap allocation, it is illegal to call this function in a fork()
|
||||
/// child.
|
||||
pub fn replace(io: Io, gpa: Allocator, argv: []const []const u8, env: Environ.Block) ReplaceError {
|
||||
if (!can_replace) @compileError("unsupported operation: replace");
|
||||
|
||||
var arena_allocator = std.heap.ArenaAllocator.init(gpa);
|
||||
defer arena_allocator.deinit();
|
||||
const arena = arena_allocator.allocator();
|
||||
|
||||
const argv_buf = try arena.allocSentinel(?[*:0]const u8, argv.len, null);
|
||||
for (argv, 0..) |arg, i| argv_buf[i] = (try arena.dupeZ(u8, arg)).ptr;
|
||||
|
||||
return posix.execvpeZ_expandArg0(.no_expand, argv_buf.ptr[0].?, argv_buf.ptr, env);
|
||||
/// It is illegal to call this function in a fork() child.
|
||||
pub fn replace(io: Io, options: ReplaceOptions) ReplaceError {
|
||||
return io.vtable.processReplace(io.userdata, options);
|
||||
}
|
||||
|
||||
/// Replaces the current process image with the executed process. If this
|
||||
@@ -309,92 +317,181 @@ pub fn replace(io: Io, gpa: Allocator, argv: []const []const u8, env: Environ.Bl
|
||||
/// relative to `dir`. It is *always* treated as a file path, even if it does
|
||||
/// not contain '/'.
|
||||
///
|
||||
/// This operation is not available on targets for which `can_replace` is
|
||||
/// `false`.
|
||||
///
|
||||
/// This function must allocate memory to add a null terminating bytes on path
|
||||
/// and each arg.
|
||||
///
|
||||
/// Due to the heap allocation, it is illegal to call this
|
||||
/// function in a fork() child. For that use case, use the `std.posix`
|
||||
/// functions directly.
|
||||
pub fn replaceFile(io: Io, gpa: Allocator, argv: []const []const u8, env: Environ.Block) ReplaceError {
|
||||
if (!can_replace) @compileError("unsupported operation: replaceFile");
|
||||
|
||||
var arena_allocator = std.heap.ArenaAllocator.init(gpa);
|
||||
defer arena_allocator.deinit();
|
||||
const arena = arena_allocator.allocator();
|
||||
|
||||
const argv_buf = try arena.allocSentinel(?[*:0]const u8, argv.len, null);
|
||||
for (argv, 0..) |arg, i| argv_buf[i] = (try arena.dupeZ(u8, arg)).ptr;
|
||||
|
||||
return posix.execvpeZ_expandArg0(.no_expand, argv_buf.ptr[0].?, argv_buf.ptr, env);
|
||||
/// It is illegal to call this function in a fork() child.
|
||||
pub fn replacePath(io: Io, dir: Io.Dir, options: ReplaceOptions) ReplaceError {
|
||||
return io.vtable.processReplacePath(io.userdata, dir, options);
|
||||
}
|
||||
|
||||
pub const Arg0Expand = enum { expand, no_expand };
|
||||
pub const ArgExpansion = enum { expand, no_expand };
|
||||
|
||||
/// Replaces the current process image with the executed process. If this
|
||||
/// function succeeds, it does not return.
|
||||
///
|
||||
/// This operation is not available on all targets. `can_execv`
|
||||
///
|
||||
/// This function also uses the PATH environment variable to get the full path to the executable.
|
||||
/// If `file` is an absolute path, this is the same as `execveZ`.
|
||||
///
|
||||
/// Like `execvpeZ` except if `arg0_expand` is `.expand`, then `argv` is mutable,
|
||||
/// and `argv[0]` is expanded to be the same absolute path that is passed to the execve syscall.
|
||||
/// If this function returns with an error, `argv[0]` will be restored to the value it was when it was passed in.
|
||||
pub fn replace(
|
||||
comptime arg0_expand: Arg0Expand,
|
||||
file: [*:0]const u8,
|
||||
child_argv: switch (arg0_expand) {
|
||||
.expand => [*:null]?[*:0]const u8,
|
||||
.no_expand => [*:null]const ?[*:0]const u8,
|
||||
},
|
||||
envp: [*:null]const ?[*:0]const u8,
|
||||
optional_PATH: ?[]const u8,
|
||||
) ExecveError {
|
||||
const file_slice = mem.sliceTo(file, 0);
|
||||
if (mem.findScalar(u8, file_slice, '/') != null) return execveZ(file, child_argv, envp);
|
||||
/// File name extensions supported natively by `CreateProcess()` on Windows.
|
||||
pub const WindowsExtension = enum { bat, cmd, com, exe };
|
||||
|
||||
const PATH = optional_PATH orelse "/usr/local/bin:/bin/:/usr/bin";
|
||||
// Use of PATH_MAX here is valid as the path_buf will be passed
|
||||
// directly to the operating system in execveZ.
|
||||
var path_buf: [PATH_MAX]u8 = undefined;
|
||||
var it = mem.tokenizeScalar(u8, PATH, ':');
|
||||
var seen_eacces = false;
|
||||
var err: ExecveError = error.FileNotFound;
|
||||
pub const SpawnError = error{
|
||||
OutOfMemory,
|
||||
/// POSIX-only. `StdIo.ignore` was selected and opening `/dev/null` returned ENODEV.
|
||||
NoDevice,
|
||||
/// Windows-only. `cwd` or `argv` was provided and it was invalid WTF-8.
|
||||
/// https://wtf-8.codeberg.page/
|
||||
InvalidWtf8,
|
||||
/// Windows-only. `cwd` was provided, but the path did not exist when spawning the child process.
|
||||
CurrentWorkingDirectoryUnlinked,
|
||||
/// Windows-only. NUL (U+0000), LF (U+000A), CR (U+000D) are not allowed
|
||||
/// within arguments when executing a `.bat`/`.cmd` script.
|
||||
/// - NUL/LF signifiies end of arguments, so anything afterwards
|
||||
/// would be lost after execution.
|
||||
/// - CR is stripped by `cmd.exe`, so any CR codepoints
|
||||
/// would be lost after execution.
|
||||
InvalidBatchScriptArg,
|
||||
SystemResources,
|
||||
AccessDenied,
|
||||
PermissionDenied,
|
||||
InvalidExe,
|
||||
FileSystem,
|
||||
IsDir,
|
||||
FileNotFound,
|
||||
NotDir,
|
||||
FileBusy,
|
||||
ProcessFdQuotaExceeded,
|
||||
SystemFdQuotaExceeded,
|
||||
ResourceLimitReached,
|
||||
InvalidUserId,
|
||||
InvalidProcessGroupId,
|
||||
SymLinkLoop,
|
||||
InvalidName,
|
||||
/// An attempt was made to change the process group ID of one of the
|
||||
/// children of the calling process and the child had already performed an
|
||||
/// image replacement.
|
||||
ProcessAlreadyExec,
|
||||
} || Io.Dir.PathNameError || Io.Cancelable || Io.UnexpectedError;
|
||||
|
||||
// In case of expanding arg0 we must put it back if we return with an error.
|
||||
const prev_arg0 = child_argv[0];
|
||||
defer switch (arg0_expand) {
|
||||
.expand => child_argv[0] = prev_arg0,
|
||||
.no_expand => {},
|
||||
pub const SpawnOptions = struct {
|
||||
argv: []const []const u8,
|
||||
|
||||
/// 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,
|
||||
|
||||
stdin: StdIo = .inherit,
|
||||
stdout: StdIo = .inherit,
|
||||
stderr: StdIo = .inherit,
|
||||
|
||||
/// Set to true to obtain rusage information for the child process.
|
||||
/// Depending on the target platform and implementation status, the
|
||||
/// requested statistics may or may not be available. If they are
|
||||
/// available, then the `resource_usage_statistics` field will be populated
|
||||
/// after calling `wait`.
|
||||
/// On Linux and Darwin, this obtains rusage statistics from wait4().
|
||||
request_resource_usage_statistics: bool = false,
|
||||
|
||||
/// Set to change the user id when spawning the child process.
|
||||
uid: ?posix.uid_t = null,
|
||||
/// Set to change the group id when spawning the child process.
|
||||
gid: ?posix.gid_t = null,
|
||||
/// Set to change the process group id when spawning the child process.
|
||||
pgid: ?posix.pid_t = null,
|
||||
|
||||
/// Start child process in suspended state.
|
||||
/// For Posix systems it's started as if SIGSTOP was sent.
|
||||
start_suspended: bool = false,
|
||||
/// Windows-only. Sets the CREATE_NO_WINDOW flag in CreateProcess.
|
||||
create_no_window: bool = false,
|
||||
/// Darwin-only. Disable ASLR for the child process.
|
||||
disable_aslr: bool = false,
|
||||
|
||||
/// Behavior of the child process's standard input, output, and error streams.
|
||||
pub const StdIo = union(enum) {
|
||||
/// Inherit the corresponding stream from the parent process.
|
||||
inherit,
|
||||
/// Pass an already open file from the parent to the child.
|
||||
file: File,
|
||||
/// Pass a null stream to the child process by opening "/dev/null" on POSIX
|
||||
/// and "NUL" on Windows.
|
||||
ignore,
|
||||
/// Create a new pipe for the stream.
|
||||
///
|
||||
/// The corresponding field (`stdout`, `stderr`, or `stdin`) will be
|
||||
/// assigned a `File` object that can be used to read from or write to the
|
||||
/// pipe.
|
||||
pipe,
|
||||
/// Spawn the child process with the corresponding stream missing. This
|
||||
/// will likely result in the child encountering EBADF if it tries to use
|
||||
/// stdin, stdout, or stderr, or if only one stream is closed, it will
|
||||
/// result in them getting mixed up. Generally, this option is for advanced
|
||||
/// use cases only.
|
||||
close,
|
||||
};
|
||||
};
|
||||
|
||||
while (it.next()) |search_path| {
|
||||
const path_len = search_path.len + file_slice.len + 1;
|
||||
if (path_buf.len < path_len + 1) return error.NameTooLong;
|
||||
@memcpy(path_buf[0..search_path.len], search_path);
|
||||
path_buf[search_path.len] = '/';
|
||||
@memcpy(path_buf[search_path.len + 1 ..][0..file_slice.len], file_slice);
|
||||
path_buf[path_len] = 0;
|
||||
const full_path = path_buf[0..path_len :0].ptr;
|
||||
switch (arg0_expand) {
|
||||
.expand => child_argv[0] = full_path,
|
||||
.no_expand => {},
|
||||
}
|
||||
err = execveZ(full_path, child_argv, envp);
|
||||
switch (err) {
|
||||
error.AccessDenied => seen_eacces = true,
|
||||
error.FileNotFound, error.NotDir => {},
|
||||
else => |e| return e,
|
||||
}
|
||||
}
|
||||
if (seen_eacces) return error.AccessDenied;
|
||||
return err;
|
||||
/// Creates a child process.
|
||||
///
|
||||
/// `argv[0]` is the name of the program to execute. If it is not already a
|
||||
/// file path (i.e. it contains '/'), it is resolved into a file path based on
|
||||
/// PATH from the parent environment.
|
||||
pub fn spawn(io: Io, options: SpawnOptions) SpawnError!Child {
|
||||
return io.vtable.processSpawn(io.userdata, options);
|
||||
}
|
||||
|
||||
/// Creates a child process.
|
||||
///
|
||||
/// `argv[0]` is the file path of the program to execute, relative to `dir`. It
|
||||
/// is *always* treated as a file path, even if it does not contain '/'.
|
||||
pub fn spawnPath(io: Io, dir: Io.Dir, options: SpawnOptions) SpawnError!Child {
|
||||
return io.vtable.processSpawnPath(io.userdata, dir, options);
|
||||
}
|
||||
|
||||
pub const RunError = posix.GetCwdError || posix.ReadError || SpawnError || posix.PollError || error{
|
||||
StdoutStreamTooLong,
|
||||
StderrStreamTooLong,
|
||||
};
|
||||
|
||||
pub const RunOptions = struct {
|
||||
spawn_options: SpawnOptions,
|
||||
max_output_bytes: usize = 50 * 1024,
|
||||
};
|
||||
|
||||
pub const RunResult = struct {
|
||||
term: Child.Term,
|
||||
stdout: []u8,
|
||||
stderr: []u8,
|
||||
};
|
||||
|
||||
/// 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);
|
||||
defer child.kill(io);
|
||||
|
||||
var stdout: std.ArrayList(u8) = .empty;
|
||||
defer stdout.deinit(gpa);
|
||||
var stderr: std.ArrayList(u8) = .empty;
|
||||
defer stderr.deinit(gpa);
|
||||
|
||||
try child.collectOutput(gpa, &stdout, &stderr, options.max_output_bytes);
|
||||
|
||||
return .{
|
||||
.stdout = try stdout.toOwnedSlice(gpa),
|
||||
.stderr = try stderr.toOwnedSlice(gpa),
|
||||
.term = try child.wait(io),
|
||||
};
|
||||
}
|
||||
|
||||
pub const TotalSystemMemoryError = error{
|
||||
UnknownTotalSystemMemory,
|
||||
|
||||
+39
-1760
File diff suppressed because it is too large.
Load diff
@@ -268,15 +268,17 @@ fn findNativeIncludeDirPosix(self: *LibCInstallation, gpa: Allocator, io: Io, ar
|
||||
dev_null,
|
||||
});
|
||||
|
||||
const run_res = std.process.Child.run(gpa, io, .{
|
||||
.argv = argv.items,
|
||||
const run_res = std.process.run(gpa, io, .{
|
||||
.max_output_bytes = 1024 * 1024,
|
||||
.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,
|
||||
.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,
|
||||
},
|
||||
}) catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
else => {
|
||||
@@ -289,7 +291,7 @@ fn findNativeIncludeDirPosix(self: *LibCInstallation, gpa: Allocator, io: Io, ar
|
||||
gpa.free(run_res.stderr);
|
||||
}
|
||||
switch (run_res.term) {
|
||||
.Exited => |code| if (code != 0) {
|
||||
.exited => |code| if (code != 0) {
|
||||
printVerboseInvocation(argv.items, null, args.verbose, run_res.stderr);
|
||||
return error.CCompilerExitCode;
|
||||
},
|
||||
@@ -585,15 +587,17 @@ fn ccPrintFileName(gpa: Allocator, io: Io, args: CCPrintFileNameOptions) ![:0]u8
|
||||
try appendCcExe(&argv, skip_cc_env_var);
|
||||
try argv.append(arg1);
|
||||
|
||||
const run_res = std.process.Child.run(gpa, io, .{
|
||||
.argv = argv.items,
|
||||
const run_res = std.process.run(gpa, io, .{
|
||||
.max_output_bytes = 1024 * 1024,
|
||||
.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,
|
||||
.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,
|
||||
},
|
||||
}) catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
else => return error.UnableToSpawnCCompiler,
|
||||
@@ -603,7 +607,7 @@ fn ccPrintFileName(gpa: Allocator, io: Io, args: CCPrintFileNameOptions) ![:0]u8
|
||||
gpa.free(run_res.stderr);
|
||||
}
|
||||
switch (run_res.term) {
|
||||
.Exited => |code| if (code != 0) {
|
||||
.exited => |code| if (code != 0) {
|
||||
printVerboseInvocation(argv.items, args.search_basename, args.verbose, run_res.stderr);
|
||||
return error.CCompilerExitCode;
|
||||
},
|
||||
|
||||
@@ -17,15 +17,15 @@ 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.Child.run(gpa, io, .{
|
||||
const result = std.process.run(gpa, io, .{ .spawn_options = .{
|
||||
.argv = &.{ "xcode-select", "--print-path" },
|
||||
}) catch return false;
|
||||
} }) catch return false;
|
||||
defer {
|
||||
gpa.free(result.stderr);
|
||||
gpa.free(result.stdout);
|
||||
}
|
||||
return switch (result.term) {
|
||||
.Exited => |code| if (code == 0) result.stdout.len > 0 else false,
|
||||
.exited => |code| if (code == 0) result.stdout.len > 0 else false,
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
@@ -35,7 +35,7 @@ pub fn isSdkInstalled(gpa: Allocator, io: Io) bool {
|
||||
/// Caller owns the memory.
|
||||
/// stderr from xcrun is ignored.
|
||||
/// If error.OutOfMemory occurs in Allocator, this function returns null.
|
||||
pub fn getSdk(gpa: Allocator, io: Io, environ: std.process.Child.Environ, target: *const Target) ?[]const u8 {
|
||||
pub fn getSdk(gpa: Allocator, io: Io, target: *const Target) ?[]const u8 {
|
||||
const is_simulator_abi = target.abi == .simulator;
|
||||
const sdk = switch (target.os.tag) {
|
||||
.driverkit => "driverkit",
|
||||
@@ -47,16 +47,13 @@ pub fn getSdk(gpa: Allocator, io: Io, environ: std.process.Child.Environ, target
|
||||
else => return null,
|
||||
};
|
||||
const argv = &[_][]const u8{ "xcrun", "--sdk", sdk, "--show-sdk-path" };
|
||||
const result = std.process.Child.run(gpa, io, .{
|
||||
.argv = argv,
|
||||
.environ = environ,
|
||||
}) catch return null;
|
||||
const result = std.process.run(gpa, io, .{ .spawn_options = .{ .argv = argv } }) catch return null;
|
||||
defer {
|
||||
gpa.free(result.stderr);
|
||||
gpa.free(result.stdout);
|
||||
}
|
||||
switch (result.term) {
|
||||
.Exited => |code| if (code != 0) return null,
|
||||
.exited => |code| if (code != 0) return null,
|
||||
else => return null,
|
||||
}
|
||||
return gpa.dupe(u8, mem.trimEnd(u8, result.stdout, "\r\n")) catch null;
|
||||
|
||||
+16
-12
@@ -6339,15 +6339,15 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
|
||||
if (std.process.can_spawn) {
|
||||
var child = std.process.Child.init(argv.items, arena);
|
||||
if (comp.clang_passthrough_mode) {
|
||||
child.stdin_behavior = .Inherit;
|
||||
child.stdout_behavior = .Inherit;
|
||||
child.stderr_behavior = .Inherit;
|
||||
child.stdin_behavior = .inherit;
|
||||
child.stdout_behavior = .inherit;
|
||||
child.stderr_behavior = .inherit;
|
||||
|
||||
const term = child.spawnAndWait(io) catch |err| {
|
||||
return comp.failCObj(c_object, "failed to spawn zig clang (passthrough mode) {s}: {s}", .{ argv.items[0], @errorName(err) });
|
||||
};
|
||||
switch (term) {
|
||||
.Exited => |code| {
|
||||
.exited => |code| {
|
||||
if (code != 0) {
|
||||
std.process.exit(code);
|
||||
}
|
||||
@@ -6357,9 +6357,9 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
|
||||
else => std.process.abort(),
|
||||
}
|
||||
} else {
|
||||
child.stdin_behavior = .Ignore;
|
||||
child.stdout_behavior = .Ignore;
|
||||
child.stderr_behavior = .Pipe;
|
||||
child.stdin_behavior = .ignore;
|
||||
child.stdout_behavior = .ignore;
|
||||
child.stderr_behavior = .pipe;
|
||||
|
||||
try child.spawn(io);
|
||||
|
||||
@@ -6371,7 +6371,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
|
||||
};
|
||||
|
||||
switch (term) {
|
||||
.Exited => |code| if (code != 0) if (out_diag_path) |diag_file_path| {
|
||||
.exited => |code| if (code != 0) if (out_diag_path) |diag_file_path| {
|
||||
const bundle = CObject.Diag.Bundle.parse(gpa, io, diag_file_path) catch |err| {
|
||||
log.err("{}: failed to parse clang diagnostics: {s}", .{ err, stderr });
|
||||
return comp.failCObj(c_object, "clang exited with code {d}", .{code});
|
||||
@@ -6742,9 +6742,9 @@ fn spawnZigRc(
|
||||
defer node_name.deinit(arena);
|
||||
|
||||
var child = std.process.Child.init(argv, arena);
|
||||
child.stdin_behavior = .Ignore;
|
||||
child.stdout_behavior = .Pipe;
|
||||
child.stderr_behavior = .Pipe;
|
||||
child.stdin_behavior = .ignore;
|
||||
child.stdout_behavior = .pipe;
|
||||
child.stderr_behavior = .pipe;
|
||||
child.progress_node = child_progress_node;
|
||||
|
||||
child.spawn(io) catch |err| {
|
||||
@@ -6785,12 +6785,16 @@ fn spawnZigRc(
|
||||
};
|
||||
|
||||
switch (term) {
|
||||
.Exited => |code| {
|
||||
.exited => |code| {
|
||||
if (code != 0) {
|
||||
log.err("zig rc failed with stderr:\n{s}", .{stderr.buffered()});
|
||||
return comp.failWin32Resource(win32_resource, "zig rc exited with code {d}", .{code});
|
||||
}
|
||||
},
|
||||
.signal => |sig| {
|
||||
log.err("zig rc signaled {t} with stderr:\n{s}", .{ sig, stderr.buffered() });
|
||||
return comp.failWin32Resource(win32_resource, "zig rc terminated unexpectedly", .{});
|
||||
},
|
||||
else => {
|
||||
log.err("zig rc terminated with stderr:\n{s}", .{stderr.buffered()});
|
||||
return comp.failWin32Resource(win32_resource, "zig rc terminated unexpectedly", .{});
|
||||
|
||||
+13
-13
@@ -1606,15 +1606,15 @@ fn spawnLld(comp: *Compilation, arena: Allocator, argv: []const []const u8) !voi
|
||||
|
||||
var child = std.process.Child.init(argv, arena);
|
||||
const term = (if (comp.clang_passthrough_mode) term: {
|
||||
child.stdin_behavior = .Inherit;
|
||||
child.stdout_behavior = .Inherit;
|
||||
child.stderr_behavior = .Inherit;
|
||||
child.stdin_behavior = .inherit;
|
||||
child.stdout_behavior = .inherit;
|
||||
child.stderr_behavior = .inherit;
|
||||
|
||||
break :term child.spawnAndWait(io);
|
||||
} else term: {
|
||||
child.stdin_behavior = .Ignore;
|
||||
child.stdout_behavior = .Ignore;
|
||||
child.stderr_behavior = .Pipe;
|
||||
child.stdin_behavior = .ignore;
|
||||
child.stdout_behavior = .ignore;
|
||||
child.stderr_behavior = .pipe;
|
||||
|
||||
child.spawn(io) catch |err| break :term err;
|
||||
var stderr_reader = child.stderr.?.readerStreaming(io, &.{});
|
||||
@@ -1656,15 +1656,15 @@ fn spawnLld(comp: *Compilation, arena: Allocator, argv: []const []const u8) !voi
|
||||
.{try comp.dirs.local_cache.join(arena, &.{rsp_path})},
|
||||
) }, arena);
|
||||
if (comp.clang_passthrough_mode) {
|
||||
rsp_child.stdin_behavior = .Inherit;
|
||||
rsp_child.stdout_behavior = .Inherit;
|
||||
rsp_child.stderr_behavior = .Inherit;
|
||||
rsp_child.stdin_behavior = .inherit;
|
||||
rsp_child.stdout_behavior = .inherit;
|
||||
rsp_child.stderr_behavior = .inherit;
|
||||
|
||||
break :term rsp_child.spawnAndWait(io) catch |err| break :err err;
|
||||
} else {
|
||||
rsp_child.stdin_behavior = .Ignore;
|
||||
rsp_child.stdout_behavior = .Ignore;
|
||||
rsp_child.stderr_behavior = .Pipe;
|
||||
rsp_child.stdin_behavior = .ignore;
|
||||
rsp_child.stdout_behavior = .ignore;
|
||||
rsp_child.stderr_behavior = .pipe;
|
||||
|
||||
rsp_child.spawn(io) catch |err| break :err err;
|
||||
var stderr_reader = rsp_child.stderr.?.readerStreaming(io, &.{});
|
||||
@@ -1680,7 +1680,7 @@ fn spawnLld(comp: *Compilation, arena: Allocator, argv: []const []const u8) !voi
|
||||
|
||||
const diags = &comp.link_diags;
|
||||
switch (term) {
|
||||
.Exited => |code| if (code != 0) {
|
||||
.exited => |code| if (code != 0) {
|
||||
if (comp.clang_passthrough_mode) std.process.exit(code);
|
||||
diags.lockAndParseLldStderr(argv[1], stderr);
|
||||
return error.LinkFailure;
|
||||
|
||||
+12
-12
@@ -4442,9 +4442,9 @@ fn runOrTest(
|
||||
} else if (process.can_spawn) {
|
||||
var child = std.process.Child.init(argv.items, gpa);
|
||||
child.env_map = &env_map;
|
||||
child.stdin_behavior = .Inherit;
|
||||
child.stdout_behavior = .Inherit;
|
||||
child.stderr_behavior = .Inherit;
|
||||
child.stdin_behavior = .inherit;
|
||||
child.stdout_behavior = .inherit;
|
||||
child.stderr_behavior = .inherit;
|
||||
|
||||
// Here we release all the locks associated with the Compilation so
|
||||
// that whatever this child process wants to do won't deadlock.
|
||||
@@ -4587,9 +4587,9 @@ fn runOrTestHotSwap(
|
||||
else => {
|
||||
var child = std.process.Child.init(argv.items, gpa);
|
||||
|
||||
child.stdin_behavior = .Inherit;
|
||||
child.stdout_behavior = .Inherit;
|
||||
child.stderr_behavior = .Inherit;
|
||||
child.stdin_behavior = .inherit;
|
||||
child.stdout_behavior = .inherit;
|
||||
child.stderr_behavior = .inherit;
|
||||
|
||||
try child.spawn(io);
|
||||
|
||||
@@ -5417,9 +5417,9 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8)
|
||||
|
||||
if (process.can_spawn) {
|
||||
var child = std.process.Child.init(child_argv.items, gpa);
|
||||
child.stdin_behavior = .Inherit;
|
||||
child.stdout_behavior = .Inherit;
|
||||
child.stderr_behavior = .Inherit;
|
||||
child.stdin_behavior = .inherit;
|
||||
child.stdout_behavior = .inherit;
|
||||
child.stderr_behavior = .inherit;
|
||||
|
||||
const term = t: {
|
||||
_ = try io.lockStderr(&.{}, .no_color);
|
||||
@@ -5686,9 +5686,9 @@ fn jitCmd(
|
||||
}
|
||||
|
||||
var child = std.process.Child.init(child_argv.items, gpa);
|
||||
child.stdin_behavior = .Inherit;
|
||||
child.stdout_behavior = if (options.capture == null) .Inherit else .Pipe;
|
||||
child.stderr_behavior = .Inherit;
|
||||
child.stdin_behavior = .inherit;
|
||||
child.stdout_behavior = if (options.capture == null) .inherit else .pipe;
|
||||
child.stderr_behavior = .inherit;
|
||||
|
||||
const term = t: {
|
||||
_ = try io.lockStderr(&.{}, .no_color);
|
||||
|
||||
+1
-1
@@ -871,7 +871,7 @@ fn testLinkDirectlyCppTbd(b: *Build, opts: Options) *Step {
|
||||
const io = b.graph.io;
|
||||
const test_step = addTestStep(b, "link-directly-cpp-tbd", opts);
|
||||
|
||||
const sdk = std.zig.system.darwin.getSdk(b.allocator, io, .{ .map = &b.graph.env_map }, &opts.target.result) orelse
|
||||
const sdk = std.zig.system.darwin.getSdk(b.allocator, io, &opts.target.result) orelse
|
||||
@panic("macOS SDK is required to run the test");
|
||||
|
||||
const exe = addExecutable(b, opts, .{
|
||||
|
||||
@@ -2306,7 +2306,7 @@ fn addTest(
|
||||
run.addArgs(db_argv2);
|
||||
run.addArtifactArg(exe);
|
||||
for (expected_output) |expected| run.addCheck(.{ .expect_stdout_match = db.b.fmt("{s}\n", .{expected}) });
|
||||
run.addCheck(.{ .expect_term = .{ .Exited = success } });
|
||||
run.addCheck(.{ .expect_term = .{ .exited = success } });
|
||||
run.setStdIn(.{ .bytes = "" });
|
||||
db.root_step.dependOn(&run.step);
|
||||
}
|
||||
|
||||
@@ -193,9 +193,9 @@ fn addCaseInstance(
|
||||
run.removeEnvironmentVariable("CLICOLOR_FORCE");
|
||||
run.setEnvironmentVariable("NO_COLOR", "1");
|
||||
run.addCheck(.{ .expect_term = term: {
|
||||
if (!expect_panic) break :term .{ .Exited = 0 };
|
||||
if (target.result.os.tag == .windows) break :term .{ .Exited = 3 };
|
||||
break :term .{ .Signal = 6 };
|
||||
if (!expect_panic) break :term .{ .exited = 0 };
|
||||
if (target.result.os.tag == .windows) break :term .{ .exited = 3 };
|
||||
break :term .{ .signal = @enumFromInt(6) };
|
||||
} });
|
||||
run.expectStdOutEqual("");
|
||||
|
||||
|
||||
@@ -26,9 +26,9 @@ pub fn main() !void {
|
||||
const io = threaded.io();
|
||||
|
||||
var child = std.process.Child.init(&.{ child_path, "hello arg" }, gpa);
|
||||
child.stdin_behavior = .Pipe;
|
||||
child.stdout_behavior = .Pipe;
|
||||
child.stderr_behavior = .Inherit;
|
||||
child.stdin_behavior = .pipe;
|
||||
child.stdout_behavior = .pipe;
|
||||
child.stderr_behavior = .inherit;
|
||||
try child.spawn(io);
|
||||
const child_stdin = child.stdin.?;
|
||||
try child_stdin.writeStreamingAll(io, "hello from stdin"); // verified in child
|
||||
|
||||
@@ -25,7 +25,7 @@ pub fn build(b: *std.Build) void {
|
||||
|
||||
const io = b.graph.io;
|
||||
|
||||
if (std.zig.system.darwin.getSdk(b.allocator, io, .{ .map = &b.graph.env_map }, &target.result)) |sdk| {
|
||||
if (std.zig.system.darwin.getSdk(b.allocator, io, &target.result)) |sdk| {
|
||||
b.sysroot = sdk;
|
||||
exe.root_module.addSystemIncludePath(.{ .cwd_relative = b.pathJoin(&.{ sdk, "/usr/include" }) });
|
||||
exe.root_module.addSystemFrameworkPath(.{ .cwd_relative = b.pathJoin(&.{ sdk, "/System/Library/Frameworks" }) });
|
||||
|
||||
@@ -1,15 +1,5 @@
|
||||
const std = @import("std");
|
||||
|
||||
// See https://github.com/ziglang/zig/issues/24510
|
||||
// for the plan to simplify this code.
|
||||
pub fn main() !void {
|
||||
var debug_allocator: std.heap.DebugAllocator(.{}) = .init;
|
||||
defer _ = debug_allocator.deinit();
|
||||
const gpa = debug_allocator.allocator();
|
||||
|
||||
var threaded: std.Io.Threaded = .init(gpa, .{});
|
||||
defer threaded.deinit();
|
||||
const io = threaded.io();
|
||||
|
||||
try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");
|
||||
pub fn main(init: std.process.Init) !void {
|
||||
try std.Io.File.stdout().writeStreamingAll(init.io, "Hello, World!\n");
|
||||
}
|
||||
+1
-1
@@ -2718,7 +2718,7 @@ pub fn addIncrementalTests(b: *std.Build, test_step: *Step, test_filters: []cons
|
||||
if (b.enable_wasmtime) run.addArg("-fwasmtime");
|
||||
if (b.enable_darling) run.addArg("-fdarling");
|
||||
|
||||
run.addCheck(.{ .expect_term = .{ .Exited = 0 } });
|
||||
run.addCheck(.{ .expect_term = .{ .exited = 0 } });
|
||||
|
||||
test_step.dependOn(&run.step);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user