mirror of
https://github.com/ziglang/zig.git
synced 2024-11-14 16:13:24 +00:00
build system: capture stderr and report it later
Instead of dumping directly to stderr. This prevents processes running simultaneously from racing their stderr against each other. For now it only reports at the end, but an improvement would be to report as soon as a failed step occurs.
This commit is contained in:
parent
1fa1484288
commit
9580fbcf35
@ -676,10 +676,7 @@ fn addCxxKnownPath(
|
||||
) !void {
|
||||
if (!std.process.can_spawn)
|
||||
return error.RequiredLibraryNotFound;
|
||||
const path_padded = try b.exec(&[_][]const u8{
|
||||
ctx.cxx_compiler,
|
||||
b.fmt("-print-file-name={s}", .{objname}),
|
||||
});
|
||||
const path_padded = b.exec(&.{ ctx.cxx_compiler, b.fmt("-print-file-name={s}", .{objname}) });
|
||||
var tokenizer = mem.tokenize(u8, path_padded, "\r\n");
|
||||
const path_unpadded = tokenizer.next().?;
|
||||
if (mem.eql(u8, path_unpadded, objname)) {
|
||||
|
@ -318,8 +318,8 @@ fn runStepNames(b: *std.Build, step_names: []const []const u8) !void {
|
||||
.success => continue,
|
||||
.failure => {
|
||||
any_failed = true;
|
||||
std.debug.print("{s}: {s}\n", .{
|
||||
s.name, @errorName(s.result.err_code),
|
||||
std.debug.print("{s}: {s}\n{s}", .{
|
||||
s.name, @errorName(s.result.err_code), s.result.stderr,
|
||||
});
|
||||
},
|
||||
}
|
||||
@ -404,9 +404,7 @@ fn workerMakeOneStep(
|
||||
// *Build object in install header steps that might be able to be removed
|
||||
// by passing the *Build object through the make() functions.
|
||||
s.make() catch |err| {
|
||||
s.result = .{
|
||||
.err_code = err,
|
||||
};
|
||||
s.result.err_code = err;
|
||||
@atomicStore(Step.State, &s.state, .failure, .SeqCst);
|
||||
return;
|
||||
};
|
||||
|
@ -1133,17 +1133,24 @@ pub fn spawnChild(self: *Build, argv: []const []const u8) !void {
|
||||
return self.spawnChildEnvMap(null, self.env_map, argv);
|
||||
}
|
||||
|
||||
fn printCmd(cwd: ?[]const u8, argv: []const []const u8) void {
|
||||
if (cwd) |yes_cwd| std.debug.print("cd {s} && ", .{yes_cwd});
|
||||
fn allocPrintCmd(ally: Allocator, opt_cwd: ?[]const u8, argv: []const []const u8) ![]u8 {
|
||||
var buf = ArrayList(u8).init(ally);
|
||||
if (opt_cwd) |cwd| try buf.writer().print("cd {s} && ", .{cwd});
|
||||
for (argv) |arg| {
|
||||
std.debug.print("{s} ", .{arg});
|
||||
try buf.writer().print("{s} ", .{arg});
|
||||
}
|
||||
std.debug.print("\n", .{});
|
||||
try buf.append('\n');
|
||||
return buf.toOwnedSlice();
|
||||
}
|
||||
|
||||
fn printCmd(ally: Allocator, cwd: ?[]const u8, argv: []const []const u8) void {
|
||||
const text = allocPrintCmd(ally, cwd, argv) catch @panic("OOM");
|
||||
std.debug.print("{s}", .{text});
|
||||
}
|
||||
|
||||
pub fn spawnChildEnvMap(self: *Build, cwd: ?[]const u8, env_map: *const EnvMap, argv: []const []const u8) !void {
|
||||
if (self.verbose) {
|
||||
printCmd(cwd, argv);
|
||||
printCmd(self.allocator, cwd, argv);
|
||||
}
|
||||
|
||||
if (!std.process.can_spawn)
|
||||
@ -1162,13 +1169,13 @@ pub fn spawnChildEnvMap(self: *Build, cwd: ?[]const u8, env_map: *const EnvMap,
|
||||
.Exited => |code| {
|
||||
if (code != 0) {
|
||||
log.err("The following command exited with error code {}:", .{code});
|
||||
printCmd(cwd, argv);
|
||||
printCmd(self.allocator, cwd, argv);
|
||||
return error.UncleanExit;
|
||||
}
|
||||
},
|
||||
else => {
|
||||
log.err("The following command terminated unexpectedly:", .{});
|
||||
printCmd(cwd, argv);
|
||||
printCmd(self.allocator, cwd, argv);
|
||||
|
||||
return error.UncleanExit;
|
||||
},
|
||||
@ -1381,57 +1388,91 @@ pub fn execAllowFail(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn execFromStep(self: *Build, argv: []const []const u8, src_step: ?*Step) ![]u8 {
|
||||
pub fn execFromStep(b: *Build, argv: []const []const u8, s: *Step) ![]u8 {
|
||||
assert(argv.len != 0);
|
||||
|
||||
if (self.verbose) {
|
||||
printCmd(null, argv);
|
||||
if (b.verbose) {
|
||||
printCmd(b.allocator, null, argv);
|
||||
}
|
||||
|
||||
if (!std.process.can_spawn) {
|
||||
if (src_step) |s| log.err("{s}...", .{s.name});
|
||||
log.err("Unable to spawn the following command: cannot spawn child process", .{});
|
||||
printCmd(null, argv);
|
||||
std.os.abort();
|
||||
s.result.stderr = b.fmt("Unable to spawn the following command: cannot spawn child processes\n{s}", .{
|
||||
try allocPrintCmd(b.allocator, null, argv),
|
||||
});
|
||||
return error.CannotSpawnProcesses;
|
||||
}
|
||||
|
||||
var code: u8 = undefined;
|
||||
return self.execAllowFail(argv, &code, .Inherit) catch |err| switch (err) {
|
||||
error.ExecNotSupported => {
|
||||
if (src_step) |s| log.err("{s}...", .{s.name});
|
||||
log.err("Unable to spawn the following command: cannot spawn child process", .{});
|
||||
printCmd(null, argv);
|
||||
std.os.abort();
|
||||
},
|
||||
const result = unwrapExecResult(&code, std.ChildProcess.exec(.{
|
||||
.allocator = b.allocator,
|
||||
.argv = argv,
|
||||
.env_map = b.env_map,
|
||||
.max_output_bytes = 10 * 1024 * 1024,
|
||||
})) catch |err| switch (err) {
|
||||
error.FileNotFound => {
|
||||
if (src_step) |s| log.err("{s}...", .{s.name});
|
||||
log.err("Unable to spawn the following command: file not found", .{});
|
||||
printCmd(null, argv);
|
||||
std.os.exit(@truncate(u8, code));
|
||||
s.result.stderr = b.fmt("unable to spawn the following command: file not found\n{s}", .{
|
||||
try allocPrintCmd(b.allocator, null, argv),
|
||||
});
|
||||
return error.ExecFailed;
|
||||
},
|
||||
error.ExitCodeFailure => {
|
||||
if (src_step) |s| log.err("{s}...", .{s.name});
|
||||
if (self.prominent_compile_errors) {
|
||||
log.err("The step exited with error code {d}", .{code});
|
||||
} else {
|
||||
log.err("The following command exited with error code {d}:", .{code});
|
||||
printCmd(null, argv);
|
||||
}
|
||||
|
||||
std.os.exit(@truncate(u8, code));
|
||||
s.result.stderr = b.fmt("the following command exited with error code {d}:\n{s}", .{
|
||||
code, try allocPrintCmd(b.allocator, null, argv),
|
||||
});
|
||||
return error.ExecFailed;
|
||||
},
|
||||
error.ProcessTerminated => {
|
||||
if (src_step) |s| log.err("{s}...", .{s.name});
|
||||
log.err("The following command terminated unexpectedly:", .{});
|
||||
printCmd(null, argv);
|
||||
std.os.exit(@truncate(u8, code));
|
||||
s.result.stderr = b.fmt("the following command terminated unexpectedly:\n{s}", .{
|
||||
try allocPrintCmd(b.allocator, null, argv),
|
||||
});
|
||||
return error.ExecFailed;
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
|
||||
s.result.stderr = result.stderr;
|
||||
return result.stdout;
|
||||
}
|
||||
|
||||
pub fn exec(self: *Build, argv: []const []const u8) ![]u8 {
|
||||
return self.execFromStep(argv, null);
|
||||
fn unwrapExecResult(
|
||||
code_ptr: *u8,
|
||||
wrapped: std.ChildProcess.ExecError!std.ChildProcess.ExecResult,
|
||||
) !std.ChildProcess.ExecResult {
|
||||
const result = try wrapped;
|
||||
switch (result.term) {
|
||||
.Exited => |code| {
|
||||
code_ptr.* = code;
|
||||
if (code != 0) {
|
||||
return error.ExitCodeFailure;
|
||||
}
|
||||
return result;
|
||||
},
|
||||
.Signal, .Stopped, .Unknown => |code| {
|
||||
_ = code;
|
||||
return error.ProcessTerminated;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// This is a helper function to be called from build.zig scripts, *not* from
|
||||
/// inside step make() functions. If any errors occur, it fails the build with
|
||||
/// a helpful message.
|
||||
pub fn exec(b: *Build, argv: []const []const u8) []u8 {
|
||||
if (!std.process.can_spawn) {
|
||||
std.debug.print("unable to spawn the following command: cannot spawn child process\n{s}", .{
|
||||
try allocPrintCmd(b.allocator, null, argv),
|
||||
});
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var code: u8 = undefined;
|
||||
return b.execAllowFail(argv, &code, .Inherit) catch |err| {
|
||||
const printed_cmd = allocPrintCmd(b.allocator, null, argv) catch @panic("OOM");
|
||||
std.debug.print("unable to spawn the following command: {s}\n{s}", .{
|
||||
@errorName(err), printed_cmd,
|
||||
});
|
||||
process.exit(1);
|
||||
};
|
||||
}
|
||||
|
||||
pub fn addSearchPrefix(self: *Build, search_prefix: []const u8) void {
|
||||
|
@ -9,6 +9,7 @@ state: State,
|
||||
/// Populated only if state is success.
|
||||
result: struct {
|
||||
err_code: anyerror,
|
||||
stderr: []u8,
|
||||
},
|
||||
|
||||
pub const State = enum {
|
||||
@ -78,7 +79,10 @@ pub fn init(
|
||||
.dependencies = std.ArrayList(*Step).init(allocator),
|
||||
.dependants = .{},
|
||||
.state = .precheck_unstarted,
|
||||
.result = undefined,
|
||||
.result = .{
|
||||
.err_code = undefined,
|
||||
.stderr = &.{},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user