| ... | ... | @@ -5,7 +5,6 @@ const Step = Build.Step; |
| 5 | 5 | const fs = std.fs; |
| 6 | 6 | const mem = std.mem; |
| 7 | 7 | const process = std.process; |
| 8 | | const ArrayList = std.ArrayList; |
| 9 | 8 | const EnvMap = process.EnvMap; |
| 10 | 9 | const assert = std.debug.assert; |
| 11 | 10 | |
| ... | ... | @@ -16,7 +15,7 @@ pub const base_id: Step.Id = .run; |
| 16 | 15 | step: Step, |
| 17 | 16 | |
| 18 | 17 | /// See also addArg and addArgs to modifying this directly |
| 19 | | argv: ArrayList(Arg), |
| 18 | argv: std.ArrayListUnmanaged(Arg), |
| 20 | 19 | |
| 21 | 20 | /// Use `setCwd` to set the initial current working directory |
| 22 | 21 | cwd: ?Build.LazyPath, |
| ... | ... | @@ -32,22 +31,26 @@ env_map: ?*EnvMap, |
| 32 | 31 | /// If the Run step is determined to not have side-effects, then execution will |
| 33 | 32 | /// be skipped if all output files are up-to-date and input files are |
| 34 | 33 | /// unchanged. |
| 35 | | stdio: StdIo = .infer_from_args, |
| 34 | stdio: StdIo, |
| 36 | 35 | |
| 37 | 36 | /// This field must be `.none` if stdio is `inherit`. |
| 38 | 37 | /// It should be only set using `setStdIn`. |
| 39 | | stdin: StdIn = .none, |
| 38 | stdin: StdIn, |
| 40 | 39 | |
| 41 | | /// Additional file paths relative to build.zig that, when modified, indicate |
| 42 | | /// that the Run step should be re-executed. |
| 43 | | /// If the Run step is determined to have side-effects, this field is ignored |
| 44 | | /// and the Run step is always executed when it appears in the build graph. |
| 45 | | extra_file_dependencies: []const []const u8 = &.{}, |
| 40 | /// Deprecated: use `addFileInput` |
| 41 | extra_file_dependencies: []const []const u8, |
| 42 | |
| 43 | /// Additional input files that, when modified, indicate that the Run step |
| 44 | /// should be re-executed. |
| 45 | /// If the Run step is determined to have side-effects, the Run step is always |
| 46 | /// executed when it appears in the build graph, regardless of whether these |
| 47 | /// files have been modified. |
| 48 | file_inputs: std.ArrayListUnmanaged(std.Build.LazyPath), |
| 46 | 49 | |
| 47 | 50 | /// After adding an output argument, this step will by default rename itself |
| 48 | 51 | /// for a better display name in the build summary. |
| 49 | 52 | /// This can be disabled by setting this to false. |
| 50 | | rename_step_with_output_arg: bool = true, |
| 53 | rename_step_with_output_arg: bool, |
| 51 | 54 | |
| 52 | 55 | /// If this is true, a Run step which is configured to check the output of the |
| 53 | 56 | /// executed binary will not fail the build if the binary cannot be executed |
| ... | ... | @@ -58,25 +61,25 @@ rename_step_with_output_arg: bool = true, |
| 58 | 61 | /// Rosetta (macOS) and binfmt_misc (Linux). |
| 59 | 62 | /// If this Run step is considered to have side-effects, then this flag does |
| 60 | 63 | /// nothing. |
| 61 | | skip_foreign_checks: bool = false, |
| 64 | skip_foreign_checks: bool, |
| 62 | 65 | |
| 63 | 66 | /// If this is true, failing to execute a foreign binary will be considered an |
| 64 | 67 | /// error. However if this is false, the step will be skipped on failure instead. |
| 65 | 68 | /// |
| 66 | 69 | /// This allows for a Run step to attempt to execute a foreign binary using an |
| 67 | 70 | /// external executor (such as qemu) but not fail if the executor is unavailable. |
| 68 | | failing_to_execute_foreign_is_an_error: bool = true, |
| 71 | failing_to_execute_foreign_is_an_error: bool, |
| 69 | 72 | |
| 70 | 73 | /// If stderr or stdout exceeds this amount, the child process is killed and |
| 71 | 74 | /// the step fails. |
| 72 | | max_stdio_size: usize = 10 * 1024 * 1024, |
| 75 | max_stdio_size: usize, |
| 73 | 76 | |
| 74 | | captured_stdout: ?*Output = null, |
| 75 | | captured_stderr: ?*Output = null, |
| 77 | captured_stdout: ?*Output, |
| 78 | captured_stderr: ?*Output, |
| 76 | 79 | |
| 77 | | dep_output_file: ?*Output = null, |
| 80 | dep_output_file: ?*Output, |
| 78 | 81 | |
| 79 | | has_side_effects: bool = false, |
| 82 | has_side_effects: bool, |
| 80 | 83 | |
| 81 | 84 | pub const StdIn = union(enum) { |
| 82 | 85 | none, |
| ... | ... | @@ -103,7 +106,7 @@ pub const StdIo = union(enum) { |
| 103 | 106 | /// conditions. |
| 104 | 107 | /// Note that an explicit check for exit code 0 needs to be added to this |
| 105 | 108 | /// list if such a check is desirable. |
| 106 | | check: std.ArrayList(Check), |
| 109 | check: std.ArrayListUnmanaged(Check), |
| 107 | 110 | /// This Run step is running a zig unit test binary and will communicate |
| 108 | 111 | /// extra metadata over the IPC protocol. |
| 109 | 112 | zig_test, |
| ... | ... | @@ -145,9 +148,21 @@ pub fn create(owner: *std.Build, name: []const u8) *Run { |
| 145 | 148 | .owner = owner, |
| 146 | 149 | .makeFn = make, |
| 147 | 150 | }), |
| 148 | | .argv = ArrayList(Arg).init(owner.allocator), |
| 151 | .argv = .{}, |
| 149 | 152 | .cwd = null, |
| 150 | 153 | .env_map = null, |
| 154 | .stdio = .infer_from_args, |
| 155 | .stdin = .none, |
| 156 | .extra_file_dependencies = &.{}, |
| 157 | .file_inputs = .{}, |
| 158 | .rename_step_with_output_arg = true, |
| 159 | .skip_foreign_checks = false, |
| 160 | .failing_to_execute_foreign_is_an_error = true, |
| 161 | .max_stdio_size = 10 * 1024 * 1024, |
| 162 | .captured_stdout = null, |
| 163 | .captured_stderr = null, |
| 164 | .dep_output_file = null, |
| 165 | .has_side_effects = false, |
| 151 | 166 | }; |
| 152 | 167 | return self; |
| 153 | 168 | } |
| ... | ... | @@ -163,9 +178,10 @@ pub fn enableTestRunnerMode(self: *Run) void { |
| 163 | 178 | } |
| 164 | 179 | |
| 165 | 180 | pub fn addArtifactArg(self: *Run, artifact: *Step.Compile) void { |
| 181 | const b = self.step.owner; |
| 166 | 182 | const bin_file = artifact.getEmittedBin(); |
| 167 | 183 | bin_file.addStepDependencies(&self.step); |
| 168 | | self.argv.append(Arg{ .artifact = artifact }) catch @panic("OOM"); |
| 184 | self.argv.append(b.allocator, Arg{ .artifact = artifact }) catch @panic("OOM"); |
| 169 | 185 | } |
| 170 | 186 | |
| 171 | 187 | /// Provides a file path as a command line argument to the command being run. |
| ... | ... | @@ -181,6 +197,7 @@ pub fn addOutputFileArg(self: *Run, basename: []const u8) std.Build.LazyPath { |
| 181 | 197 | } |
| 182 | 198 | |
| 183 | 199 | /// Provides a file path as a command line argument to the command being run. |
| 200 | /// Asserts `basename` is not empty. |
| 184 | 201 | /// |
| 185 | 202 | /// For example, a prefix of "-o" and basename of "output.txt" will result in |
| 186 | 203 | /// the child process seeing something like this: "-ozig-cache/.../output.txt" |
| ... | ... | @@ -200,14 +217,15 @@ pub fn addPrefixedOutputFileArg( |
| 200 | 217 | basename: []const u8, |
| 201 | 218 | ) std.Build.LazyPath { |
| 202 | 219 | const b = self.step.owner; |
| 220 | if (basename.len == 0) @panic("basename must not be empty"); |
| 203 | 221 | |
| 204 | 222 | const output = b.allocator.create(Output) catch @panic("OOM"); |
| 205 | 223 | output.* = .{ |
| 206 | | .prefix = prefix, |
| 207 | | .basename = basename, |
| 224 | .prefix = b.dupe(prefix), |
| 225 | .basename = b.dupe(basename), |
| 208 | 226 | .generated_file = .{ .step = &self.step }, |
| 209 | 227 | }; |
| 210 | | self.argv.append(.{ .output = output }) catch @panic("OOM"); |
| 228 | self.argv.append(b.allocator, .{ .output = output }) catch @panic("OOM"); |
| 211 | 229 | |
| 212 | 230 | if (self.rename_step_with_output_arg) { |
| 213 | 231 | self.setName(b.fmt("{s} ({s})", .{ self.step.name, basename })); |
| ... | ... | @@ -248,7 +266,7 @@ pub fn addPrefixedFileArg(self: *Run, prefix: []const u8, lp: std.Build.LazyPath |
| 248 | 266 | .prefix = b.dupe(prefix), |
| 249 | 267 | .lazy_path = lp.dupe(b), |
| 250 | 268 | }; |
| 251 | | self.argv.append(.{ .lazy_path = prefixed_file_source }) catch @panic("OOM"); |
| 269 | self.argv.append(b.allocator, .{ .lazy_path = prefixed_file_source }) catch @panic("OOM"); |
| 252 | 270 | lp.addStepDependencies(&self.step); |
| 253 | 271 | } |
| 254 | 272 | |
| ... | ... | @@ -269,7 +287,7 @@ pub fn addPrefixedDirectoryArg(self: *Run, prefix: []const u8, directory_source: |
| 269 | 287 | .prefix = b.dupe(prefix), |
| 270 | 288 | .lazy_path = directory_source.dupe(b), |
| 271 | 289 | }; |
| 272 | | self.argv.append(.{ .directory_source = prefixed_directory_source }) catch @panic("OOM"); |
| 290 | self.argv.append(b.allocator, .{ .directory_source = prefixed_directory_source }) catch @panic("OOM"); |
| 273 | 291 | directory_source.addStepDependencies(&self.step); |
| 274 | 292 | } |
| 275 | 293 | |
| ... | ... | @@ -284,9 +302,8 @@ pub fn addDepFileOutputArg(self: *Run, basename: []const u8) std.Build.LazyPath |
| 284 | 302 | /// write its discovered additional dependencies. |
| 285 | 303 | /// Only one dep file argument is allowed by instance. |
| 286 | 304 | pub fn addPrefixedDepFileOutputArg(self: *Run, prefix: []const u8, basename: []const u8) std.Build.LazyPath { |
| 287 | | assert(self.dep_output_file == null); |
| 288 | | |
| 289 | 305 | const b = self.step.owner; |
| 306 | assert(self.dep_output_file == null); |
| 290 | 307 | |
| 291 | 308 | const dep_file = b.allocator.create(Output) catch @panic("OOM"); |
| 292 | 309 | dep_file.* = .{ |
| ... | ... | @@ -297,13 +314,14 @@ pub fn addPrefixedDepFileOutputArg(self: *Run, prefix: []const u8, basename: []c |
| 297 | 314 | |
| 298 | 315 | self.dep_output_file = dep_file; |
| 299 | 316 | |
| 300 | | self.argv.append(.{ .output = dep_file }) catch @panic("OOM"); |
| 317 | self.argv.append(b.allocator, .{ .output = dep_file }) catch @panic("OOM"); |
| 301 | 318 | |
| 302 | 319 | return .{ .generated = &dep_file.generated_file }; |
| 303 | 320 | } |
| 304 | 321 | |
| 305 | 322 | pub fn addArg(self: *Run, arg: []const u8) void { |
| 306 | | self.argv.append(.{ .bytes = self.step.owner.dupe(arg) }) catch @panic("OOM"); |
| 323 | const b = self.step.owner; |
| 324 | self.argv.append(b.allocator, .{ .bytes = self.step.owner.dupe(arg) }) catch @panic("OOM"); |
| 307 | 325 | } |
| 308 | 326 | |
| 309 | 327 | pub fn addArgs(self: *Run, args: []const []const u8) void { |
| ... | ... | @@ -401,12 +419,14 @@ pub fn hasTermCheck(self: Run) bool { |
| 401 | 419 | } |
| 402 | 420 | |
| 403 | 421 | pub fn addCheck(self: *Run, new_check: StdIo.Check) void { |
| 422 | const b = self.step.owner; |
| 423 | |
| 404 | 424 | switch (self.stdio) { |
| 405 | 425 | .infer_from_args => { |
| 406 | | self.stdio = .{ .check = std.ArrayList(StdIo.Check).init(self.step.owner.allocator) }; |
| 407 | | self.stdio.check.append(new_check) catch @panic("OOM"); |
| 426 | self.stdio = .{ .check = .{} }; |
| 427 | self.stdio.check.append(b.allocator, new_check) catch @panic("OOM"); |
| 408 | 428 | }, |
| 409 | | .check => |*checks| checks.append(new_check) catch @panic("OOM"), |
| 429 | .check => |*checks| checks.append(b.allocator, new_check) catch @panic("OOM"), |
| 410 | 430 | else => @panic("illegal call to addCheck: conflicting helper method calls. Suggest to directly set stdio field of Run instead"), |
| 411 | 431 | } |
| 412 | 432 | } |
| ... | ... | @@ -441,6 +461,16 @@ pub fn captureStdOut(self: *Run) std.Build.LazyPath { |
| 441 | 461 | return .{ .generated = &output.generated_file }; |
| 442 | 462 | } |
| 443 | 463 | |
| 464 | /// Adds an additional input files that, when modified, indicates that this Run |
| 465 | /// step should be re-executed. |
| 466 | /// If the Run step is determined to have side-effects, the Run step is always |
| 467 | /// executed when it appears in the build graph, regardless of whether this |
| 468 | /// file has been modified. |
| 469 | pub fn addFileInput(self: *Run, file_input: std.Build.LazyPath) void { |
| 470 | file_input.addStepDependencies(&self.step); |
| 471 | self.file_inputs.append(self.step.owner.allocator, file_input.dupe(self.step.owner)) catch @panic("OOM"); |
| 472 | } |
| 473 | |
| 444 | 474 | /// Returns whether the Run step has side effects *other than* updating the output arguments. |
| 445 | 475 | fn hasSideEffects(self: Run) bool { |
| 446 | 476 | if (self.has_side_effects) return true; |
| ... | ... | @@ -500,8 +530,8 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 500 | 530 | const self: *Run = @fieldParentPtr("step", step); |
| 501 | 531 | const has_side_effects = self.hasSideEffects(); |
| 502 | 532 | |
| 503 | | var argv_list = ArrayList([]const u8).init(arena); |
| 504 | | var output_placeholders = ArrayList(IndexedOutput).init(arena); |
| 533 | var argv_list = std.ArrayList([]const u8).init(arena); |
| 534 | var output_placeholders = std.ArrayList(IndexedOutput).init(arena); |
| 505 | 535 | |
| 506 | 536 | var man = b.graph.cache.obtain(); |
| 507 | 537 | defer man.deinit(); |
| ... | ... | @@ -579,6 +609,9 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 579 | 609 | for (self.extra_file_dependencies) |file_path| { |
| 580 | 610 | _ = try man.addFile(b.pathFromRoot(file_path), null); |
| 581 | 611 | } |
| 612 | for (self.file_inputs.items) |lazy_path| { |
| 613 | _ = try man.addFile(lazy_path.getPath2(b, step), null); |
| 614 | } |
| 582 | 615 | |
| 583 | 616 | if (try step.cacheHit(&man)) { |
| 584 | 617 | // cache hit, skip running command |