| 1 | const Step = @This(); |
| 2 | |
| 3 | const std = @import("../std.zig"); |
| 4 | const Build = std.Build; |
| 5 | const assert = std.debug.assert; |
| 6 | const Configuration = std.Build.Configuration; |
| 7 | |
| 8 | tag: Configuration.Step.Tag, |
| 9 | name: []const u8, |
| 10 | owner: *Build, |
| 11 | |
| 12 | dependencies: 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. |
| 33 | max_rss: u64, |
| 34 | |
| 35 | /// The return address associated with creation of this step that can be useful |
| 36 | /// to print along with debugging messages. |
| 37 | debug_stack_trace: std.debug.StackTrace, |
| 38 | |
| 39 | pub const Tag = Configuration.Step.Tag; |
| 40 | |
| 41 | pub 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 | |
| 62 | pub const CheckFile = @import("Step/CheckFile.zig"); |
| 63 | pub const Compile = @import("Step/Compile.zig"); |
| 64 | pub const ConfigHeader = @import("Step/ConfigHeader.zig"); |
| 65 | pub const Fail = @import("Step/Fail.zig"); |
| 66 | pub const FindProgram = @import("Step/FindProgram.zig"); |
| 67 | pub const Fmt = @import("Step/Fmt.zig"); |
| 68 | pub const InstallArtifact = @import("Step/InstallArtifact.zig"); |
| 69 | pub const InstallDir = @import("Step/InstallDir.zig"); |
| 70 | pub const InstallFile = @import("Step/InstallFile.zig"); |
| 71 | pub const ObjCopy = @import("Step/ObjCopy.zig"); |
| 72 | pub const Options = @import("Step/Options.zig"); |
| 73 | pub const Run = @import("Step/Run.zig"); |
| 74 | pub const TranslateC = @import("Step/TranslateC.zig"); |
| 75 | pub const UpdateSourceFiles = @import("Step/UpdateSourceFiles.zig"); |
| 76 | pub const WriteFile = @import("Step/WriteFile.zig"); |
| 77 | |
| 78 | pub const TopLevel = struct { |
| 79 | pub const base_tag: Step.Tag = .top_level; |
| 80 | |
| 81 | step: Step, |
| 82 | description: []const u8, |
| 83 | }; |
| 84 | |
| 85 | pub 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 | |
| 93 | pub 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 | |
| 110 | pub fn dependOn(step: *Step, other: *Step) void { |
| 111 | const arena = step.owner.allocator; |
| 112 | step.dependencies.append(arena, other) catch @panic("OOM"); |
| 113 | } |
| 114 | |
| 115 | pub 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. |
| 121 | pub 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 | |
| 135 | test { |
| 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 | } |