mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 14:23:09 +00:00
171 lines
5.1 KiB
Zig
171 lines
5.1 KiB
Zig
id: Id,
|
|
name: []const u8,
|
|
makeFn: MakeFn,
|
|
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,
|
|
|
|
pub const MakeFn = *const fn (self: *Step, prog_node: *std.Progress.Node) anyerror!void;
|
|
|
|
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: MakeFn = 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, prog_node: *std.Progress.Node) error{MakeFailed}!void {
|
|
return s.makeFn(s, prog_node) catch |err| {
|
|
if (err != error.MakeFailed) {
|
|
const gpa = s.dependencies.allocator;
|
|
s.result_error_msgs.append(gpa, @errorName(err)) 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, prog_node: *std.Progress.Node) anyerror!void {
|
|
_ = self;
|
|
_ = prog_node;
|
|
}
|
|
|
|
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;
|