1const Step = @This();
2
3const std = @import("../std.zig");
4const Build = std.Build;
5const assert = std.debug.assert;
6const Configuration = std.Build.Configuration;
7
8tag: Configuration.Step.Tag,
9name: []const u8,
10owner: *Build,
11
12dependencies: std.ArrayList(*Step),
13
14/// Set this field to declare an upper bound on the amount of bytes of memory it will
15/// take to run the step. Zero means no limit.
16///
17/// The idea to annotate steps that might use a high amount of RAM with an
18/// upper bound. For example, perhaps a particular set of unit tests require 4
19/// GiB of RAM, and those tests will be run under 4 different build
20/// configurations at once. This would potentially require 16 GiB of memory on
21/// the system if all 4 steps executed simultaneously, which could easily be
22/// greater than what is actually available, potentially causing the system to
23/// crash when using `zig build` at the default concurrency level.
24///
25/// This field causes the build runner to do two things:
26/// 1. ulimit child processes, so that they will fail if it would exceed this
27/// memory limit. This serves to enforce that this upper bound value is
28/// correct.
29/// 2. Ensure that the set of concurrent steps at any given time have a total
30/// max_rss value that does not exceed the `max_total_rss` value of the build
31/// runner. This value is configurable on the command line, and defaults to the
32/// total system memory available.
33max_rss: u64,
34
35/// The return address associated with creation of this step that can be useful
36/// to print along with debugging messages.
37debug_stack_trace: std.debug.StackTrace,
38
39pub const Tag = Configuration.Step.Tag;
40
41pub fn Type(comptime tag: Tag) type {
42 return switch (tag) {
43 .check_file => CheckFile,
44 .compile => Compile,
45 .config_header => ConfigHeader,
46 .fail => Fail,
47 .find_program => FindProgram,
48 .fmt => Fmt,
49 .install_artifact => InstallArtifact,
50 .install_dir => InstallDir,
51 .install_file => InstallFile,
52 .obj_copy => ObjCopy,
53 .options => Options,
54 .run => Run,
55 .top_level => TopLevel,
56 .translate_c => TranslateC,
57 .update_source_files => UpdateSourceFiles,
58 .write_file => WriteFile,
59 };
60}
61
62pub const CheckFile = @import("Step/CheckFile.zig");
63pub const Compile = @import("Step/Compile.zig");
64pub const ConfigHeader = @import("Step/ConfigHeader.zig");
65pub const Fail = @import("Step/Fail.zig");
66pub const FindProgram = @import("Step/FindProgram.zig");
67pub const Fmt = @import("Step/Fmt.zig");
68pub const InstallArtifact = @import("Step/InstallArtifact.zig");
69pub const InstallDir = @import("Step/InstallDir.zig");
70pub const InstallFile = @import("Step/InstallFile.zig");
71pub const ObjCopy = @import("Step/ObjCopy.zig");
72pub const Options = @import("Step/Options.zig");
73pub const Run = @import("Step/Run.zig");
74pub const TranslateC = @import("Step/TranslateC.zig");
75pub const UpdateSourceFiles = @import("Step/UpdateSourceFiles.zig");
76pub const WriteFile = @import("Step/WriteFile.zig");
77
78pub const TopLevel = struct {
79 pub const base_tag: Step.Tag = .top_level;
80
81 step: Step,
82 description: []const u8,
83};
84
85pub const StepOptions = struct {
86 tag: Tag,
87 name: []const u8,
88 owner: *Build,
89 first_ret_addr: ?usize = null,
90 max_rss: u64 = 0,
91};
92
93pub fn init(options: StepOptions) Step {
94 const arena = options.owner.allocator;
95
96 return .{
97 .tag = options.tag,
98 .name = arena.dupe(u8, options.name) catch @panic("OOM"),
99 .owner = options.owner,
100 .dependencies = .empty,
101 .max_rss = options.max_rss,
102 .debug_stack_trace = blk: {
103 const addr_buf = arena.alloc(usize, options.owner.debug_stack_frames_count) catch @panic("OOM");
104 const first_ret_addr = options.first_ret_addr orelse @returnAddress();
105 break :blk std.debug.captureCurrentStackTrace(.{ .first_address = first_ret_addr }, addr_buf);
106 },
107 };
108}
109
110pub fn dependOn(step: *Step, other: *Step) void {
111 const arena = step.owner.allocator;
112 step.dependencies.append(arena, other) catch @panic("OOM");
113}
114
115pub fn cast(step: *Step, comptime T: type) ?*T {
116 if (step.tag == T.base_tag) return @fieldParentPtr("step", step);
117 return null;
118}
119
120/// For debugging purposes, prints identifying information about this Step.
121pub fn dump(step: *Step, t: std.Io.Terminal) void {
122 const w = t.writer;
123 if (step.debug_stack_trace.return_addresses.len > 0) {
124 w.print("name: '{s}'. creation stack trace:\n", .{step.name}) catch {};
125 std.debug.writeStackTrace(&step.debug_stack_trace, t) catch {};
126 } else {
127 const field = "debug_stack_frames_count";
128 comptime assert(@hasField(Build, field));
129 t.setColor(.yellow) catch {};
130 w.print("name: '{s}'. no stack trace collected for this step, see std.Build." ++ field ++ "\n", .{step.name}) catch {};
131 t.setColor(.reset) catch {};
132 }
133}
134
135test {
136 _ = CheckFile;
137 _ = Compile;
138 _ = ConfigHeader;
139 _ = Fail;
140 _ = FindProgram;
141 _ = Fmt;
142 _ = InstallArtifact;
143 _ = InstallDir;
144 _ = InstallFile;
145 _ = ObjCopy;
146 _ = Options;
147 _ = Run;
148 _ = TranslateC;
149 _ = UpdateSourceFiles;
150 _ = WriteFile;
151}