mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
The compiler now provides a server protocol for an interactive session with another process. The build runner uses this protocol to communicate compilation errors semantically from zig compiler subprocesses to the build runner. The protocol is exposed via stdin/stdout, or on a network socket, depending on whether the CLI flag `--listen=-` or e.g. `--listen=127.0.0.1:1337` is used. Additionally: * add the zig version string to the build runner cache prefix * remove --prominent-compile-errors CLI flag because it no longer does anything. Compilation errors are now unconditionally displayed at the bottom of the build summary output when using the terminal-based build runner. * Remove the color field from std.Build. The build steps are no longer supposed to interact with stderr directly. Instead they communicate semantically back to the build runner, which has its own logic about TTY configuration. * Use the cleanExit() pattern in the build runner. * Build steps can now use error.MakeFailed when they have already properly reported an error, or they can fail with any other error code in which case the build runner will create a simple message based on this error code.
170 lines
5.1 KiB
Zig
170 lines
5.1 KiB
Zig
id: Id,
|
|
name: []const u8,
|
|
makeFn: *const fn (self: *Step) anyerror!void,
|
|
dependencies: std.ArrayList(*Step),
|
|
/// This field is empty during execution of the user's build script, and
|
|
/// then populated during dependency loop checking in the build runner.
|
|
dependants: std.ArrayListUnmanaged(*Step),
|
|
state: State,
|
|
/// The return addresss associated with creation of this step that can be useful
|
|
/// to print along with debugging messages.
|
|
debug_stack_trace: [n_debug_stack_frames]usize,
|
|
|
|
result_error_msgs: std.ArrayListUnmanaged([]const u8),
|
|
result_error_bundle: std.zig.ErrorBundle,
|
|
|
|
const n_debug_stack_frames = 4;
|
|
|
|
pub const State = enum {
|
|
precheck_unstarted,
|
|
precheck_started,
|
|
precheck_done,
|
|
running,
|
|
dependency_failure,
|
|
success,
|
|
failure,
|
|
};
|
|
|
|
pub const Id = enum {
|
|
top_level,
|
|
compile,
|
|
install_artifact,
|
|
install_file,
|
|
install_dir,
|
|
log,
|
|
remove_dir,
|
|
fmt,
|
|
translate_c,
|
|
write_file,
|
|
run,
|
|
emulatable_run,
|
|
check_file,
|
|
check_object,
|
|
config_header,
|
|
objcopy,
|
|
options,
|
|
custom,
|
|
|
|
pub fn Type(comptime id: Id) type {
|
|
return switch (id) {
|
|
.top_level => Build.TopLevelStep,
|
|
.compile => Build.CompileStep,
|
|
.install_artifact => Build.InstallArtifactStep,
|
|
.install_file => Build.InstallFileStep,
|
|
.install_dir => Build.InstallDirStep,
|
|
.log => Build.LogStep,
|
|
.remove_dir => Build.RemoveDirStep,
|
|
.fmt => Build.FmtStep,
|
|
.translate_c => Build.TranslateCStep,
|
|
.write_file => Build.WriteFileStep,
|
|
.run => Build.RunStep,
|
|
.emulatable_run => Build.EmulatableRunStep,
|
|
.check_file => Build.CheckFileStep,
|
|
.check_object => Build.CheckObjectStep,
|
|
.config_header => Build.ConfigHeaderStep,
|
|
.objcopy => Build.ObjCopyStep,
|
|
.options => Build.OptionsStep,
|
|
.custom => @compileError("no type available for custom step"),
|
|
};
|
|
}
|
|
};
|
|
|
|
pub const Options = struct {
|
|
id: Id,
|
|
name: []const u8,
|
|
makeFn: *const fn (self: *Step) anyerror!void = makeNoOp,
|
|
first_ret_addr: ?usize = null,
|
|
};
|
|
|
|
pub fn init(allocator: Allocator, options: Options) Step {
|
|
var addresses = [1]usize{0} ** n_debug_stack_frames;
|
|
const first_ret_addr = options.first_ret_addr orelse @returnAddress();
|
|
var stack_trace = std.builtin.StackTrace{
|
|
.instruction_addresses = &addresses,
|
|
.index = 0,
|
|
};
|
|
std.debug.captureStackTrace(first_ret_addr, &stack_trace);
|
|
|
|
return .{
|
|
.id = options.id,
|
|
.name = allocator.dupe(u8, options.name) catch @panic("OOM"),
|
|
.makeFn = options.makeFn,
|
|
.dependencies = std.ArrayList(*Step).init(allocator),
|
|
.dependants = .{},
|
|
.state = .precheck_unstarted,
|
|
.debug_stack_trace = addresses,
|
|
.result_error_msgs = .{},
|
|
.result_error_bundle = std.zig.ErrorBundle.empty,
|
|
};
|
|
}
|
|
|
|
/// If the Step's `make` function reports `error.MakeFailed`, it indicates they
|
|
/// have already reported the error. Otherwise, we add a simple error report
|
|
/// here.
|
|
pub fn make(s: *Step) error{MakeFailed}!void {
|
|
return s.makeFn(s) catch |err| {
|
|
if (err != error.MakeFailed) {
|
|
const gpa = s.dependencies.allocator;
|
|
s.result_error_msgs.append(gpa, std.fmt.allocPrint(gpa, "{s} failed: {s}", .{
|
|
s.name, @errorName(err),
|
|
}) catch @panic("OOM")) catch @panic("OOM");
|
|
}
|
|
return error.MakeFailed;
|
|
};
|
|
}
|
|
|
|
pub fn dependOn(self: *Step, other: *Step) void {
|
|
self.dependencies.append(other) catch @panic("OOM");
|
|
}
|
|
|
|
pub fn getStackTrace(s: *Step) std.builtin.StackTrace {
|
|
const stack_addresses = &s.debug_stack_trace;
|
|
var len: usize = 0;
|
|
while (len < n_debug_stack_frames and stack_addresses[len] != 0) {
|
|
len += 1;
|
|
}
|
|
return .{
|
|
.instruction_addresses = stack_addresses,
|
|
.index = len,
|
|
};
|
|
}
|
|
|
|
fn makeNoOp(self: *Step) anyerror!void {
|
|
_ = self;
|
|
}
|
|
|
|
pub fn cast(step: *Step, comptime T: type) ?*T {
|
|
if (step.id == T.base_id) {
|
|
return @fieldParentPtr(T, "step", step);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/// For debugging purposes, prints identifying information about this Step.
|
|
pub fn dump(step: *Step) void {
|
|
std.debug.getStderrMutex().lock();
|
|
defer std.debug.getStderrMutex().unlock();
|
|
|
|
const stderr = std.io.getStdErr();
|
|
const w = stderr.writer();
|
|
const tty_config = std.debug.detectTTYConfig(stderr);
|
|
const debug_info = std.debug.getSelfDebugInfo() catch |err| {
|
|
w.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{
|
|
@errorName(err),
|
|
}) catch {};
|
|
return;
|
|
};
|
|
const ally = debug_info.allocator;
|
|
w.print("name: '{s}'. creation stack trace:\n", .{step.name}) catch {};
|
|
std.debug.writeStackTrace(step.getStackTrace(), w, ally, debug_info, tty_config) catch |err| {
|
|
stderr.writer().print("Unable to dump stack trace: {s}\n", .{@errorName(err)}) catch {};
|
|
return;
|
|
};
|
|
}
|
|
|
|
const Step = @This();
|
|
const std = @import("../std.zig");
|
|
const Build = std.Build;
|
|
const Allocator = std.mem.Allocator;
|
|
const assert = std.debug.assert;
|