mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-04-30 14:52:41 +03:00
170 lines
5.7 KiB
Zig
170 lines
5.7 KiB
Zig
const Step = @This();
|
|
const builtin = @import("builtin");
|
|
|
|
const std = @import("../std.zig");
|
|
const Io = std.Io;
|
|
const Build = std.Build;
|
|
const Allocator = std.mem.Allocator;
|
|
const assert = std.debug.assert;
|
|
const Cache = Build.Cache;
|
|
const Path = Cache.Path;
|
|
const ArrayList = std.ArrayList;
|
|
|
|
tag: std.Build.Configuration.Step.Tag,
|
|
name: []const u8,
|
|
owner: *Build,
|
|
|
|
dependencies: ArrayList(*Step),
|
|
|
|
/// Set this field to declare an upper bound on the amount of bytes of memory it will
|
|
/// take to run the step. Zero means no limit.
|
|
///
|
|
/// The idea to annotate steps that might use a high amount of RAM with an
|
|
/// upper bound. For example, perhaps a particular set of unit tests require 4
|
|
/// GiB of RAM, and those tests will be run under 4 different build
|
|
/// configurations at once. This would potentially require 16 GiB of memory on
|
|
/// the system if all 4 steps executed simultaneously, which could easily be
|
|
/// greater than what is actually available, potentially causing the system to
|
|
/// crash when using `zig build` at the default concurrency level.
|
|
///
|
|
/// This field causes the build runner to do two things:
|
|
/// 1. ulimit child processes, so that they will fail if it would exceed this
|
|
/// memory limit. This serves to enforce that this upper bound value is
|
|
/// correct.
|
|
/// 2. Ensure that the set of concurrent steps at any given time have a total
|
|
/// max_rss value that does not exceed the `max_total_rss` value of the build
|
|
/// runner. This value is configurable on the command line, and defaults to the
|
|
/// total system memory available.
|
|
max_rss: usize,
|
|
|
|
state: State,
|
|
|
|
/// The return address associated with creation of this step that can be useful
|
|
/// to print along with debugging messages.
|
|
debug_stack_trace: std.debug.StackTrace,
|
|
|
|
pub const State = enum {
|
|
precheck_unstarted,
|
|
precheck_started,
|
|
/// This is also used to indicate "dirty" steps that have been modified
|
|
/// after a previous build completed, in which case, the step may or may
|
|
/// not have been completed before. Either way, one or more of its direct
|
|
/// file system inputs have been modified, meaning that the step needs to
|
|
/// be re-evaluated.
|
|
precheck_done,
|
|
dependency_failure,
|
|
};
|
|
|
|
pub const Tag = std.Build.Configuration.Step.Tag;
|
|
|
|
pub fn Type(comptime tag: Tag) type {
|
|
return switch (tag) {
|
|
.top_level => Build.TopLevelStep,
|
|
.compile => Compile,
|
|
.install_artifact => InstallArtifact,
|
|
.install_file => InstallFile,
|
|
.install_dir => InstallDir,
|
|
.fail => Fail,
|
|
.fmt => Fmt,
|
|
.translate_c => TranslateC,
|
|
.write_file => WriteFile,
|
|
.update_source_files => UpdateSourceFiles,
|
|
.run => Run,
|
|
.check_file => CheckFile,
|
|
.config_header => ConfigHeader,
|
|
.objcopy => ObjCopy,
|
|
.options => Options,
|
|
};
|
|
}
|
|
|
|
pub const CheckFile = @import("Step/CheckFile.zig");
|
|
pub const ConfigHeader = @import("Step/ConfigHeader.zig");
|
|
pub const Fail = @import("Step/Fail.zig");
|
|
pub const Fmt = @import("Step/Fmt.zig");
|
|
pub const InstallArtifact = @import("Step/InstallArtifact.zig");
|
|
pub const InstallDir = @import("Step/InstallDir.zig");
|
|
pub const InstallFile = @import("Step/InstallFile.zig");
|
|
pub const ObjCopy = @import("Step/ObjCopy.zig");
|
|
pub const Compile = @import("Step/Compile.zig");
|
|
pub const Options = @import("Step/Options.zig");
|
|
pub const Run = @import("Step/Run.zig");
|
|
pub const TranslateC = @import("Step/TranslateC.zig");
|
|
pub const WriteFile = @import("Step/WriteFile.zig");
|
|
pub const UpdateSourceFiles = @import("Step/UpdateSourceFiles.zig");
|
|
|
|
pub const TopLevel = struct {
|
|
pub const base_tag: Step.Tag = .top_level;
|
|
|
|
step: Step,
|
|
description: []const u8,
|
|
};
|
|
|
|
pub const StepOptions = struct {
|
|
tag: Tag,
|
|
name: []const u8,
|
|
owner: *Build,
|
|
first_ret_addr: ?usize = null,
|
|
max_rss: usize = 0,
|
|
};
|
|
|
|
pub fn init(options: StepOptions) Step {
|
|
const arena = options.owner.allocator;
|
|
|
|
return .{
|
|
.tag = options.tag,
|
|
.name = arena.dupe(u8, options.name) catch @panic("OOM"),
|
|
.owner = options.owner,
|
|
.dependencies = .empty,
|
|
.state = .precheck_unstarted,
|
|
.max_rss = options.max_rss,
|
|
.debug_stack_trace = blk: {
|
|
const addr_buf = arena.alloc(usize, options.owner.debug_stack_frames_count) catch @panic("OOM");
|
|
const first_ret_addr = options.first_ret_addr orelse @returnAddress();
|
|
break :blk std.debug.captureCurrentStackTrace(.{ .first_address = first_ret_addr }, addr_buf);
|
|
},
|
|
};
|
|
}
|
|
|
|
pub fn dependOn(step: *Step, other: *Step) void {
|
|
const arena = step.owner.allocator;
|
|
step.dependencies.append(arena, other) catch @panic("OOM");
|
|
}
|
|
|
|
pub fn cast(step: *Step, comptime T: type) ?*T {
|
|
if (step.tag == T.base_tag) {
|
|
return @fieldParentPtr("step", step);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/// For debugging purposes, prints identifying information about this Step.
|
|
pub fn dump(step: *Step, t: Io.Terminal) void {
|
|
const w = t.writer;
|
|
if (step.debug_stack_trace.return_addresses.len > 0) {
|
|
w.print("name: '{s}'. creation stack trace:\n", .{step.name}) catch {};
|
|
std.debug.writeStackTrace(&step.debug_stack_trace, t) catch {};
|
|
} else {
|
|
const field = "debug_stack_frames_count";
|
|
comptime assert(@hasField(Build, field));
|
|
t.setColor(.yellow) catch {};
|
|
w.print("name: '{s}'. no stack trace collected for this step, see std.Build." ++ field ++ "\n", .{step.name}) catch {};
|
|
t.setColor(.reset) catch {};
|
|
}
|
|
}
|
|
|
|
test {
|
|
_ = CheckFile;
|
|
_ = Fail;
|
|
_ = Fmt;
|
|
_ = InstallArtifact;
|
|
_ = InstallDir;
|
|
_ = InstallFile;
|
|
_ = ObjCopy;
|
|
_ = Compile;
|
|
_ = Options;
|
|
_ = Run;
|
|
_ = TranslateC;
|
|
_ = WriteFile;
|
|
_ = UpdateSourceFiles;
|
|
}
|