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