| ... | @@ -16,6 +16,7 @@ const allocPrint = std.fmt.allocPrint; | ... | @@ -16,6 +16,7 @@ const allocPrint = std.fmt.allocPrint; |
| 16 | | 16 | |
| 17 | const Step = @import("../Step.zig"); | 17 | const Step = @import("../Step.zig"); |
| 18 | const Maker = @import("../../Maker.zig"); | 18 | const Maker = @import("../../Maker.zig"); |
| | 19 | const Fuzz = @import("../../Maker/Fuzz.zig"); |
| 19 | | 20 | |
| 20 | /// If this is a Zig unit test binary, this tracks the names of the unit | 21 | /// If this is a Zig unit test binary, this tracks the names of the unit |
| 21 | /// tests that are also fuzz tests. Indexes cannot be used as they may | 22 | /// tests that are also fuzz tests. Indexes cannot be used as they may |
| ... | @@ -31,6 +32,8 @@ rebuilt_executable: ?Path = null, | ... | @@ -31,6 +32,8 @@ rebuilt_executable: ?Path = null, |
| 31 | argv: std.ArrayList([]const u8) = .empty, | 32 | argv: std.ArrayList([]const u8) = .empty, |
| 32 | /// Persisted to reuse memory on subsequent calls to `make`. | 33 | /// Persisted to reuse memory on subsequent calls to `make`. |
| 33 | output_placeholders: std.ArrayList(IndexedOutput) = .empty, | 34 | output_placeholders: std.ArrayList(IndexedOutput) = .empty, |
| | 35 | /// Persisted to reuse memory on subsequent calls to `make`. |
| | 36 | environ_map: std.process.Environ.Map = .{ .array_hash_map = .empty, .allocator = undefined }, |
| 34 | | 37 | |
| 35 | pub fn make( | 38 | pub fn make( |
| 36 | run: *Run, | 39 | run: *Run, |
| ... | @@ -67,6 +70,8 @@ pub fn make( | ... | @@ -67,6 +70,8 @@ pub fn make( |
| 67 | man.hash.add(conf_run.flags.color); | 70 | man.hash.add(conf_run.flags.color); |
| 68 | man.hash.add(conf_run.flags.disable_zig_progress); | 71 | man.hash.add(conf_run.flags.disable_zig_progress); |
| 69 | | 72 | |
| | 73 | var dep_file_count: usize = 0; |
| | 74 | |
| 70 | for (conf_run.args.slice) |arg_index| { | 75 | for (conf_run.args.slice) |arg_index| { |
| 71 | const arg = arg_index.get(conf); | 76 | const arg = arg_index.get(conf); |
| 72 | try argv_list.ensureUnusedCapacity(gpa, 1); | 77 | try argv_list.ensureUnusedCapacity(gpa, 1); |
| ... | @@ -157,6 +162,9 @@ pub fn make( | ... | @@ -157,6 +162,9 @@ pub fn make( |
| 157 | man.hash.addBytesZ(basename); | 162 | man.hash.addBytesZ(basename); |
| 158 | man.hash.addBytesZ(suffix); | 163 | man.hash.addBytesZ(suffix); |
| 159 | | 164 | |
| | 165 | man.hash.add(arg.flags.dep_file); |
| | 166 | dep_file_count += @intFromBool(arg.flags.dep_file); |
| | 167 | |
| 160 | // Add a placeholder into the argument list because we need the | 168 | // Add a placeholder into the argument list because we need the |
| 161 | // manifest hash to be updated with all arguments before the | 169 | // manifest hash to be updated with all arguments before the |
| 162 | // object directory is computed. | 170 | // object directory is computed. |
| ... | @@ -220,145 +228,95 @@ pub fn make( | ... | @@ -220,145 +228,95 @@ pub fn make( |
| 220 | | 228 | |
| 221 | const has_side_effects = conf_run.flags.has_side_effects; | 229 | const has_side_effects = conf_run.flags.has_side_effects; |
| 222 | | 230 | |
| 223 | if (true) @panic("TODO"); | | |
| 224 | | | |
| 225 | if (!has_side_effects and try step.cacheHitAndWatch(maker, &man)) { | 231 | if (!has_side_effects and try step.cacheHitAndWatch(maker, &man)) { |
| 226 | // cache hit, skip running command | 232 | // Cache hit; skip running command. |
| 227 | const digest = man.final(); | 233 | const digest = man.final(); |
| 228 | | 234 | try populateGeneratedStdIo(maker, &conf_run, cache_root, &digest); |
| 229 | try populateGeneratedPaths( | 235 | try populateGeneratedPaths(maker, output_placeholders.items, cache_root, &digest); |
| 230 | arena, | | |
| 231 | output_placeholders.items, | | |
| 232 | &conf_run, | | |
| 233 | cache_root, | | |
| 234 | &digest, | | |
| 235 | ); | | |
| 236 | | | |
| 237 | step.result_cached = true; | 236 | step.result_cached = true; |
| 238 | return; | 237 | return; |
| 239 | } | 238 | } |
| 240 | | 239 | |
| 241 | const dep_output_file = conf_run.dep_output_file orelse { | 240 | if (dep_file_count == 0) { |
| 242 | // We already know the final output paths, use them directly. | 241 | // We already know the final output paths; use them directly. |
| 243 | const digest = if (has_side_effects) | 242 | const digest = if (has_side_effects) man.hash.final() else man.final(); |
| 244 | man.hash.final() | | |
| 245 | else | | |
| 246 | man.final(); | | |
| 247 | | | |
| 248 | try populateGeneratedPaths( | | |
| 249 | arena, | | |
| 250 | output_placeholders.items, | | |
| 251 | &conf_run, | | |
| 252 | cache_root, | | |
| 253 | &digest, | | |
| 254 | ); | | |
| 255 | | | |
| 256 | const output_dir_path = "o" ++ Dir.path.sep_str ++ &digest; | 243 | const output_dir_path = "o" ++ Dir.path.sep_str ++ &digest; |
| 257 | for (output_placeholders.items) |placeholder| { | 244 | try populateGeneratedStdIo(maker, &conf_run, cache_root, &digest); |
| 258 | const output_sub_path = graph.pathJoin(&.{ output_dir_path, placeholder.output.basename }); | 245 | try populateGeneratedPathsCreateDirs(run, run_index, maker, output_dir_path); |
| 259 | const output_sub_dir_path = switch (placeholder.tag) { | 246 | try runCommand(run, run_index, maker, progress_node, argv_list.items, has_side_effects, output_dir_path, null); |
| 260 | .output_file => Dir.path.dirname(output_sub_path).?, | 247 | if (!has_side_effects) try step.writeManifestAndWatch(maker, &man); |
| 261 | .output_directory => output_sub_path, | | |
| 262 | else => unreachable, | | |
| 263 | }; | | |
| 264 | cache_root.handle.createDirPath(io, output_sub_dir_path) catch |err| { | | |
| 265 | return step.fail(maker, "unable to make path '{f}{s}': {t}", .{ | | |
| 266 | cache_root, output_sub_dir_path, err, | | |
| 267 | }); | | |
| 268 | }; | | |
| 269 | const arg_output_path = try convertPathArg(run_index, maker, .{ | | |
| 270 | .root_dir = .cwd(), | | |
| 271 | .sub_path = placeholder.output.generated_file.getPath(), | | |
| 272 | }); | | |
| 273 | argv_list.items[placeholder.index] = if (placeholder.output.prefix.len == 0) | | |
| 274 | arg_output_path | | |
| 275 | else | | |
| 276 | try allocPrint(arena, "{s}{s}", .{ placeholder.output.prefix, arg_output_path }); | | |
| 277 | } | | |
| 278 | | | |
| 279 | try runCommand(run, maker, progress_node, argv_list.items, has_side_effects, output_dir_path, null); | | |
| 280 | if (!has_side_effects) try step.writeManifestAndWatch(&man); | | |
| 281 | return; | 248 | return; |
| 282 | }; | 249 | } |
| 283 | | 250 | |
| 284 | // We do not know the final output paths yet, use temp paths to run the command. | 251 | // We do not know the final output paths yet; use temporary directory to run the command. |
| 285 | var rand_int: u64 = undefined; | 252 | var rand_int: u64 = undefined; |
| 286 | io.random(@ptrCast(&rand_int)); | 253 | io.random(@ptrCast(&rand_int)); |
| 287 | const tmp_dir_path = "tmp" ++ Dir.path.sep_str ++ std.fmt.hex(rand_int); | 254 | const tmp_dir_path = "tmp" ++ Dir.path.sep_str ++ std.fmt.hex(rand_int); |
| 288 | | 255 | |
| | 256 | try populateGeneratedPathsCreateDirs(run, run_index, maker, tmp_dir_path); |
| | 257 | try runCommand(run, run_index, maker, progress_node, argv_list.items, has_side_effects, tmp_dir_path, null); |
| | 258 | |
| 289 | for (output_placeholders.items) |placeholder| { | 259 | for (output_placeholders.items) |placeholder| { |
| 290 | const output_components = .{ tmp_dir_path, placeholder.output.basename }; | 260 | const arg = placeholder.arg_index.get(conf); |
| 291 | const output_sub_path = graph.pathJoin(&output_components); | 261 | switch (arg.flags.tag) { |
| 292 | const output_sub_dir_path = switch (placeholder.tag) { | 262 | .output_file => if (arg.flags.dep_file) { |
| 293 | .output_file => Dir.path.dirname(output_sub_path).?, | 263 | const generated_path = maker.generatedPath(arg.generated.value.?).*; |
| 294 | .output_directory => output_sub_path, | 264 | const result = if (has_side_effects) |
| | 265 | man.addDepFile(generated_path.root_dir.handle, generated_path.sub_path) |
| | 266 | else |
| | 267 | man.addDepFilePost(generated_path.root_dir.handle, generated_path.sub_path); |
| | 268 | result catch |err| switch (err) { |
| | 269 | error.OutOfMemory, error.Canceled => |e| return e, |
| | 270 | else => |e| return step.fail(maker, "failed adding to cache the file {f}: {t}", .{ |
| | 271 | generated_path, e, |
| | 272 | }), |
| | 273 | }; |
| | 274 | }, |
| | 275 | .output_directory => continue, |
| 295 | else => unreachable, | 276 | else => unreachable, |
| 296 | }; | 277 | } |
| 297 | cache_root.handle.createDirPath(io, output_sub_dir_path) catch |err| { | | |
| 298 | return step.fail(maker, "unable to make path '{f}{s}': {t}", .{ | | |
| 299 | cache_root, output_sub_dir_path, err, | | |
| 300 | }); | | |
| 301 | }; | | |
| 302 | const raw_output_path: Path = .{ | | |
| 303 | .root_dir = cache_root, | | |
| 304 | .sub_path = graph.pathJoin(&output_components), | | |
| 305 | }; | | |
| 306 | placeholder.output.generated_file.path = raw_output_path.toString(arena) catch @panic("OOM"); | | |
| 307 | argv_list.items[placeholder.index] = try mem.concat(arena, u8, .{ | | |
| 308 | placeholder.output.prefix, | | |
| 309 | try convertPathArg(run_index, maker, raw_output_path), | | |
| 310 | }); | | |
| 311 | } | 278 | } |
| 312 | | 279 | |
| 313 | try runCommand(run, maker, progress_node, argv_list.items, has_side_effects, tmp_dir_path, null); | 280 | const digest = if (has_side_effects) man.hash.final() else man.final(); |
| 314 | | | |
| 315 | const dep_file_dir = Dir.cwd(); | | |
| 316 | const dep_file_basename = dep_output_file.generated_file.getPath2(graph, step); | | |
| 317 | if (has_side_effects) | | |
| 318 | try man.addDepFile(dep_file_dir, dep_file_basename) | | |
| 319 | else | | |
| 320 | try man.addDepFilePost(dep_file_dir, dep_file_basename); | | |
| 321 | | | |
| 322 | const digest = if (has_side_effects) | | |
| 323 | man.hash.final() | | |
| 324 | else | | |
| 325 | man.final(); | | |
| 326 | | 281 | |
| 327 | const any_output = output_placeholders.items.len > 0 or | 282 | const any_output = output_placeholders.items.len > 0 or |
| 328 | conf_run.captured_stdout != null or conf_run.captured_stderr != null; | 283 | conf_run.captured_stdout.value != null or conf_run.captured_stderr.value != null; |
| 329 | | 284 | |
| 330 | // Rename into place | | |
| 331 | if (any_output) { | 285 | if (any_output) { |
| 332 | const o_sub_path = "o" ++ Dir.path.sep_str ++ &digest; | 286 | // Rename into place. |
| 333 | | 287 | const tmp_path: Path = .{ .root_dir = cache_root, .sub_path = tmp_dir_path }; |
| 334 | cache_root.handle.rename(tmp_dir_path, cache_root.handle, o_sub_path, io) catch |err| switch (err) { | 288 | const dst_path: Path = .{ .root_dir = cache_root, .sub_path = "o" ++ Dir.path.sep_str ++ &digest }; |
| 335 | Dir.RenameError.DirNotEmpty => { | 289 | Dir.rename( |
| 336 | cache_root.handle.deleteTree(io, o_sub_path) catch |del_err| { | 290 | tmp_path.root_dir.handle, |
| 337 | return step.fail(maker, "unable to remove dir '{f}'{s}: {t}", .{ | 291 | tmp_path.sub_path, |
| 338 | cache_root, tmp_dir_path, del_err, | 292 | dst_path.root_dir.handle, |
| 339 | }); | 293 | dst_path.sub_path, |
| 340 | }; | 294 | io, |
| 341 | cache_root.handle.rename(tmp_dir_path, cache_root.handle, o_sub_path, io) catch |retry_err| { | 295 | ) catch |err| switch (err) { |
| 342 | return step.fail(maker, "unable to rename dir '{f}{s}' to '{f}{s}': {t}", .{ | 296 | error.DirNotEmpty => { |
| 343 | cache_root, tmp_dir_path, cache_root, o_sub_path, retry_err, | 297 | dst_path.root_dir.handle.deleteTree(io, dst_path.sub_path) catch |del_err| |
| 344 | }); | 298 | return step.fail(maker, "failed to remove tree {f}: {t}", .{ dst_path, del_err }); |
| 345 | }; | 299 | |
| | 300 | Dir.rename( |
| | 301 | tmp_path.root_dir.handle, |
| | 302 | tmp_path.sub_path, |
| | 303 | dst_path.root_dir.handle, |
| | 304 | dst_path.sub_path, |
| | 305 | io, |
| | 306 | ) catch |retry_err| return step.fail(maker, "failed to rename directory {f} to {f}: {t}", .{ |
| | 307 | tmp_path, dst_path, retry_err, |
| | 308 | }); |
| 346 | }, | 309 | }, |
| 347 | else => return step.fail(maker, "unable to rename dir '{f}{s}' to '{f}{s}': {t}", .{ | 310 | else => return step.fail(maker, "failed to rename directory {f} to {f}: {t}", .{ |
| 348 | cache_root, tmp_dir_path, cache_root, o_sub_path, err, | 311 | tmp_path, dst_path, err, |
| 349 | }), | 312 | }), |
| 350 | }; | 313 | }; |
| 351 | } | 314 | } |
| 352 | | 315 | |
| 353 | if (!has_side_effects) try step.writeManifestAndWatch(&man); | 316 | if (!has_side_effects) try step.writeManifestAndWatch(maker, &man); |
| 354 | | 317 | |
| 355 | try populateGeneratedPaths( | 318 | try populateGeneratedStdIo(maker, &conf_run, cache_root, &digest); |
| 356 | arena, | 319 | try populateGeneratedPaths(maker, output_placeholders.items, cache_root, &digest); |
| 357 | output_placeholders.items, | | |
| 358 | &conf_run, | | |
| 359 | cache_root, | | |
| 360 | &digest, | | |
| 361 | ); | | |
| 362 | } | 320 | } |
| 363 | | 321 | |
| 364 | /// Reads stdout of a Zig test process until a termination condition is reached: | 322 | /// Reads stdout of a Zig test process until a termination condition is reached: |
| ... | @@ -918,9 +876,12 @@ const FuzzTestRunner = struct { | ... | @@ -918,9 +876,12 @@ const FuzzTestRunner = struct { |
| 918 | } | 876 | } |
| 919 | | 877 | |
| 920 | fn saveCrash(f: *FuzzTestRunner, id: u32, term: process.Child.Term) !void { | 878 | fn saveCrash(f: *FuzzTestRunner, id: u32, term: process.Child.Term) !void { |
| | 879 | const fuzz = f.context.fuzz; |
| | 880 | const maker = fuzz.maker; |
| 921 | const step = &f.run.step; | 881 | const step = &f.run.step; |
| 922 | const b = step.owner; | 882 | const graph = maker.graph; |
| 923 | const io = b.graph.io; | 883 | const io = graph.io; |
| | 884 | const cache_root = graph.local_cache_root; |
| 924 | | 885 | |
| 925 | if (f.coverage_id == null) return; | 886 | if (f.coverage_id == null) return; |
| 926 | | 887 | |
| ... | @@ -938,7 +899,7 @@ const FuzzTestRunner = struct { | ... | @@ -938,7 +899,7 @@ const FuzzTestRunner = struct { |
| 938 | }) { | 899 | }) { |
| 939 | const name_prefix = "f" ++ Io.Dir.path.sep_str ++ "in"; | 900 | const name_prefix = "f" ++ Io.Dir.path.sep_str ++ "in"; |
| 940 | in_name = std.fmt.bufPrint(&in_name_buf, name_prefix ++ "{x}", .{i}) catch unreachable; | 901 | in_name = std.fmt.bufPrint(&in_name_buf, name_prefix ++ "{x}", .{i}) catch unreachable; |
| 941 | in_f = b.cache_root.handle.openFile(io, in_name, .{ | 902 | in_f = cache_root.handle.openFile(io, in_name, .{ |
| 942 | .lock = .exclusive, | 903 | .lock = .exclusive, |
| 943 | .lock_nonblocking = true, | 904 | .lock_nonblocking = true, |
| 944 | }) catch |e| switch (e) { | 905 | }) catch |e| switch (e) { |
| ... | @@ -946,7 +907,7 @@ const FuzzTestRunner = struct { | ... | @@ -946,7 +907,7 @@ const FuzzTestRunner = struct { |
| 946 | error.WouldBlock => continue, // Can not be from | 907 | error.WouldBlock => continue, // Can not be from |
| 947 | // the crashed instance since it is still locked. | 908 | // the crashed instance since it is still locked. |
| 948 | else => return step.fail("failed to open file '{f}{s}': {t}", .{ | 909 | else => return step.fail("failed to open file '{f}{s}': {t}", .{ |
| 949 | b.cache_root, in_name, e, | 910 | cache_root, in_name, e, |
| 950 | }), | 911 | }), |
| 951 | }; | 912 | }; |
| 952 | | 913 | |
| ... | @@ -955,7 +916,7 @@ const FuzzTestRunner = struct { | ... | @@ -955,7 +916,7 @@ const FuzzTestRunner = struct { |
| 955 | in_f.close(io); | 916 | in_f.close(io); |
| 956 | switch (e) { | 917 | switch (e) { |
| 957 | error.ReadFailed => return step.fail("failed to read file '{f}{s}': {t}", .{ | 918 | error.ReadFailed => return step.fail("failed to read file '{f}{s}': {t}", .{ |
| 958 | b.cache_root, in_name, in_r.err.?, | 919 | cache_root, in_name, in_r.err.?, |
| 959 | }), | 920 | }), |
| 960 | error.EndOfStream => continue, | 921 | error.EndOfStream => continue, |
| 961 | } | 922 | } |
| ... | @@ -974,10 +935,10 @@ const FuzzTestRunner = struct { | ... | @@ -974,10 +935,10 @@ const FuzzTestRunner = struct { |
| 974 | | 935 | |
| 975 | // Save it to a seperate file | 936 | // Save it to a seperate file |
| 976 | const crash_name = "f" ++ Io.Dir.path.sep_str ++ "crash"; | 937 | const crash_name = "f" ++ Io.Dir.path.sep_str ++ "crash"; |
| 977 | const out = b.cache_root.handle.createFile(io, crash_name, .{ | 938 | const out = cache_root.handle.createFile(io, crash_name, .{ |
| 978 | .lock = .exclusive, // Multiple run steps could have found a crash at the same time | 939 | .lock = .exclusive, // Multiple run steps could have found a crash at the same time |
| 979 | }) catch |e| return step.fail("failed to create file '{f}{s}': {t}", .{ | 940 | }) catch |e| return step.fail("failed to create file '{f}{s}': {t}", .{ |
| 980 | b.cache_root, crash_name, e, | 941 | cache_root, crash_name, e, |
| 981 | }); | 942 | }); |
| 982 | defer out.close(io); | 943 | defer out.close(io); |
| 983 | | 944 | |
| ... | @@ -985,17 +946,17 @@ const FuzzTestRunner = struct { | ... | @@ -985,17 +946,17 @@ const FuzzTestRunner = struct { |
| 985 | var out_w = out.writerStreaming(io, &out_w_buf); | 946 | var out_w = out.writerStreaming(io, &out_w_buf); |
| 986 | _ = out_w.interface.sendFileAll(&in_r, .limited(header.len)) catch |e| switch (e) { | 947 | _ = out_w.interface.sendFileAll(&in_r, .limited(header.len)) catch |e| switch (e) { |
| 987 | error.ReadFailed => return step.fail("failed to read file '{f}{s}': {t}", .{ | 948 | error.ReadFailed => return step.fail("failed to read file '{f}{s}': {t}", .{ |
| 988 | b.cache_root, in_name, in_r.err.?, | 949 | cache_root, in_name, in_r.err.?, |
| 989 | }), | 950 | }), |
| 990 | error.WriteFailed => return step.fail("failed to write file '{f}{s}': {t}", .{ | 951 | error.WriteFailed => return step.fail("failed to write file '{f}{s}': {t}", .{ |
| 991 | b.cache_root, crash_name, out_w.err.?, | 952 | cache_root, crash_name, out_w.err.?, |
| 992 | }), | 953 | }), |
| 993 | }; | 954 | }; |
| 994 | | 955 | |
| 995 | return f.run.step.fail("test '{s}' {f}; input saved to '{f}{s}'", .{ | 956 | return f.run.step.fail("test '{s}' {f}; input saved to '{f}{s}'", .{ |
| 996 | f.run.fuzz_tests.items[header.test_i], | 957 | f.run.fuzz_tests.items[header.test_i], |
| 997 | fmtTerm(term), | 958 | fmtTerm(term), |
| 998 | b.cache_root, | 959 | cache_root, |
| 999 | crash_name, | 960 | crash_name, |
| 1000 | }); | 961 | }); |
| 1001 | } | 962 | } |
| ... | @@ -1492,54 +1453,85 @@ pub fn rerunInFuzzMode( | ... | @@ -1492,54 +1453,85 @@ pub fn rerunInFuzzMode( |
| 1492 | const maker = fuzz.maker; | 1453 | const maker = fuzz.maker; |
| 1493 | const graph = maker.graph; | 1454 | const graph = maker.graph; |
| 1494 | const step = &run.step; | 1455 | const step = &run.step; |
| 1495 | const b = step.owner; | | |
| 1496 | const io = graph.io; | 1456 | const io = graph.io; |
| 1497 | const arena = b.allocator; | 1457 | const arena = graph.arena; // TODO don't leak into the process arena |
| 1498 | var argv_list: std.ArrayList([]const u8) = .empty; | 1458 | const gpa = maker.gpa; |
| 1499 | for (run.argv.items) |arg| { | 1459 | const conf = &maker.scanned_config.configuration; |
| 1500 | switch (arg) { | 1460 | const conf_step = run_index.ptr(conf); |
| 1501 | .bytes => |bytes| { | 1461 | const conf_run = conf_step.extended.get(conf.extra).run; |
| 1502 | try argv_list.append(arena, bytes); | 1462 | const argv_list = &run.argv; |
| | 1463 | |
| | 1464 | argv_list.clearRetainingCapacity(); |
| | 1465 | |
| | 1466 | for (conf_run.args.slice) |arg_index| { |
| | 1467 | const arg = arg_index.get(conf); |
| | 1468 | try argv_list.ensureUnusedCapacity(gpa, 1); |
| | 1469 | switch (arg.flags.tag) { |
| | 1470 | .string => { |
| | 1471 | const prefix = arg.prefix.value.?.slice(conf); |
| | 1472 | argv_list.appendAssumeCapacity(prefix); |
| 1503 | }, | 1473 | }, |
| 1504 | .lazy_path => |file| { | 1474 | .path_file => { |
| 1505 | const file_path = file.lazy_path.getPath3(b, step); | 1475 | const prefix = if (arg.prefix.value) |p| p.slice(conf) else ""; |
| 1506 | try argv_list.append(arena, b.fmt("{s}{s}", .{ file.prefix, convertPathArg(run_index, maker, file_path) })); | 1476 | const suffix = if (arg.suffix.value) |p| p.slice(conf) else ""; |
| | 1477 | const file_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index); |
| | 1478 | argv_list.appendAssumeCapacity(try mem.concat(arena, u8, &.{ |
| | 1479 | prefix, try convertPathArg(run_index, maker, file_path), suffix, |
| | 1480 | })); |
| 1507 | }, | 1481 | }, |
| 1508 | .decorated_directory => |dd| { | 1482 | .path_directory => { |
| 1509 | const file_path = dd.lazy_path.getPath3(b, step); | 1483 | const prefix = if (arg.prefix.value) |p| p.slice(conf) else ""; |
| 1510 | try argv_list.append(arena, b.fmt("{s}{s}{s}", .{ dd.prefix, convertPathArg(run_index, maker, file_path), dd.suffix })); | 1484 | const suffix = if (arg.suffix.value) |p| p.slice(conf) else ""; |
| | 1485 | const file_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index); |
| | 1486 | const resolved_arg = try mem.concat(arena, u8, &.{ |
| | 1487 | prefix, try convertPathArg(run_index, maker, file_path), suffix, |
| | 1488 | }); |
| | 1489 | argv_list.appendAssumeCapacity(resolved_arg); |
| 1511 | }, | 1490 | }, |
| 1512 | .file_content => |file_plp| { | 1491 | .file_content => { |
| 1513 | const file_path = file_plp.lazy_path.getPath3(b, step); | 1492 | const prefix = if (arg.prefix.value) |p| p.slice(conf) else ""; |
| | 1493 | const suffix = if (arg.suffix.value) |p| p.slice(conf) else ""; |
| | 1494 | const file_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index); |
| 1514 | | 1495 | |
| 1515 | var result: std.Io.Writer.Allocating = .init(arena); | 1496 | var result: std.Io.Writer.Allocating = .init(arena); |
| 1516 | errdefer result.deinit(); | 1497 | result.writer.writeAll(prefix) catch return error.OutOfMemory; |
| 1517 | result.writer.writeAll(file_plp.prefix) catch return error.OutOfMemory; | | |
| 1518 | | 1498 | |
| 1519 | const file = try file_path.root_dir.handle.openFile(io, file_path.subPathOrDot(), .{}); | 1499 | const file = file_path.root_dir.handle.openFile(io, file_path.sub_path, .{}) catch |err| |
| | 1500 | return step.fail(maker, "unable to open input file {f}: {t}", .{ file_path, err }); |
| 1520 | defer file.close(io); | 1501 | defer file.close(io); |
| 1521 | | 1502 | |
| 1522 | var buf: [1024]u8 = undefined; | 1503 | var file_reader = file.reader(io, &.{}); |
| 1523 | var file_reader = file.reader(io, &buf); | | |
| 1524 | _ = file_reader.interface.streamRemaining(&result.writer) catch |err| switch (err) { | 1504 | _ = file_reader.interface.streamRemaining(&result.writer) catch |err| switch (err) { |
| 1525 | error.ReadFailed => return file_reader.err.?, | 1505 | error.ReadFailed => switch (file_reader.err.?) { |
| | 1506 | error.Canceled => |e| return e, |
| | 1507 | else => |e| return step.fail(maker, "failed to read from {f}: {t}", .{ file_path, e }), |
| | 1508 | }, |
| 1526 | error.WriteFailed => return error.OutOfMemory, | 1509 | error.WriteFailed => return error.OutOfMemory, |
| 1527 | }; | 1510 | }; |
| | 1511 | result.writer.writeAll(suffix) catch return error.OutOfMemory; |
| 1528 | | 1512 | |
| 1529 | try argv_list.append(arena, result.written()); | 1513 | argv_list.appendAssumeCapacity(result.written()); |
| 1530 | }, | 1514 | }, |
| 1531 | .artifact => |pa| { | 1515 | .artifact => { |
| 1532 | const artifact = pa.artifact; | 1516 | const prefix = if (arg.prefix.value) |p| p.slice(conf) else ""; |
| 1533 | const file_path: []const u8 = p: { | 1517 | const suffix = if (arg.suffix.value) |p| p.slice(conf) else ""; |
| 1534 | if (artifact == run.producer.?) break :p b.fmt("{f}", .{run.rebuilt_executable.?}); | 1518 | const producer_index = arg.producer.value.?; |
| 1535 | break :p artifact.installed_path orelse artifact.generated_bin.?.path.?; | 1519 | const producer_step = producer_index.ptr(conf); |
| 1536 | }; | 1520 | const producer = producer_step.extended.get(conf.extra).compile; |
| 1537 | try argv_list.append(arena, b.fmt("{s}{s}", .{ | 1521 | const producer_make_comp_step = maker.stepByIndex(producer_index); |
| 1538 | pa.prefix, | 1522 | const producer_make_comp = &producer_make_comp_step.extended.compile; |
| 1539 | convertPathArg(run_index, maker, .{ .root_dir = .cwd(), .sub_path = file_path }), | 1523 | const file_path: Path = if (producer_index == conf_run.producer.value.?) |
| | 1524 | run.rebuilt_executable.? |
| | 1525 | else |
| | 1526 | producer_make_comp.installed_path orelse |
| | 1527 | maker.generatedPath(producer.generated_bin.value.?).*; |
| | 1528 | argv_list.appendAssumeCapacity(try mem.concat(arena, u8, &.{ |
| | 1529 | prefix, try convertPathArg(run_index, maker, file_path), suffix, |
| 1540 | })); | 1530 | })); |
| 1541 | }, | 1531 | }, |
| 1542 | .output_file, .output_directory => unreachable, | 1532 | .output_file => unreachable, |
| | 1533 | .output_directory => unreachable, |
| | 1534 | .cli_rest_positionals => unreachable, |
| 1543 | } | 1535 | } |
| 1544 | } | 1536 | } |
| 1545 | | 1537 | |
| ... | @@ -1552,7 +1544,7 @@ pub fn rerunInFuzzMode( | ... | @@ -1552,7 +1544,7 @@ pub fn rerunInFuzzMode( |
| 1552 | var rand_int: u64 = undefined; | 1544 | var rand_int: u64 = undefined; |
| 1553 | io.random(@ptrCast(&rand_int)); | 1545 | io.random(@ptrCast(&rand_int)); |
| 1554 | const tmp_dir_path = "tmp" ++ Dir.path.sep_str ++ std.fmt.hex(rand_int); | 1546 | const tmp_dir_path = "tmp" ++ Dir.path.sep_str ++ std.fmt.hex(rand_int); |
| 1555 | try runCommand(run, maker, prog_node, argv_list.items, has_side_effects, tmp_dir_path, .{ | 1547 | try runCommand(run, run_index, maker, prog_node, argv_list.items, has_side_effects, tmp_dir_path, .{ |
| 1556 | .fuzz = fuzz, | 1548 | .fuzz = fuzz, |
| 1557 | }); | 1549 | }); |
| 1558 | } | 1550 | } |
| ... | @@ -1560,28 +1552,94 @@ pub fn rerunInFuzzMode( | ... | @@ -1560,28 +1552,94 @@ pub fn rerunInFuzzMode( |
| 1560 | const CapturedStdIo = void; // TODO get it from Configuration | 1552 | const CapturedStdIo = void; // TODO get it from Configuration |
| 1561 | | 1553 | |
| 1562 | fn populateGeneratedPaths( | 1554 | fn populateGeneratedPaths( |
| 1563 | arena: std.mem.Allocator, | 1555 | maker: *Maker, |
| 1564 | output_placeholders: []const IndexedOutput, | 1556 | output_placeholders: []const IndexedOutput, |
| 1565 | conf_run: *const Configuration.Step.Run, | | |
| 1566 | cache_root: Cache.Directory, | 1557 | cache_root: Cache.Directory, |
| 1567 | digest: *const Cache.HexDigest, | 1558 | digest: *const Cache.HexDigest, |
| 1568 | ) !void { | 1559 | ) !void { |
| | 1560 | const conf = &maker.scanned_config.configuration; |
| | 1561 | const graph = maker.graph; |
| | 1562 | const arena = graph.arena; // TODO don't leak into the process arena |
| | 1563 | |
| 1569 | for (output_placeholders) |placeholder| { | 1564 | for (output_placeholders) |placeholder| { |
| 1570 | placeholder.output.generated_file.path = try cache_root.join(arena, &.{ | 1565 | const arg = placeholder.arg_index.get(conf); |
| 1571 | "o", digest, placeholder.output.basename, | 1566 | maker.generatedPath(arg.generated.value.?).* = .{ |
| 1572 | }); | 1567 | .root_dir = cache_root, |
| | 1568 | .sub_path = try Dir.path.join(arena, &.{ |
| | 1569 | "o", digest, arg.basename.value.?.slice(conf), |
| | 1570 | }), |
| | 1571 | }; |
| | 1572 | } |
| | 1573 | } |
| | 1574 | |
| | 1575 | fn populateGeneratedPathsCreateDirs( |
| | 1576 | run: *Run, |
| | 1577 | run_index: Configuration.Step.Index, |
| | 1578 | maker: *Maker, |
| | 1579 | output_dir_path: []const u8, |
| | 1580 | ) !void { |
| | 1581 | const step = maker.stepByIndex(run_index); |
| | 1582 | const conf = &maker.scanned_config.configuration; |
| | 1583 | const graph = maker.graph; |
| | 1584 | const io = graph.io; |
| | 1585 | const arena = graph.arena; // TODO don't leak into the process arena |
| | 1586 | const cache_root = graph.local_cache_root; |
| | 1587 | const argv = run.argv.items; |
| | 1588 | |
| | 1589 | for (run.output_placeholders.items) |placeholder| { |
| | 1590 | const arg = placeholder.arg_index.get(conf); |
| | 1591 | const prefix = if (arg.prefix.value) |p| p.slice(conf) else ""; |
| | 1592 | const suffix = if (arg.suffix.value) |p| p.slice(conf) else ""; |
| | 1593 | const basename = arg.basename.value.?.slice(conf); |
| | 1594 | |
| | 1595 | const generated_path: Path = .{ |
| | 1596 | .root_dir = cache_root, |
| | 1597 | .sub_path = try Dir.path.join(arena, &.{ output_dir_path, basename }), |
| | 1598 | }; |
| | 1599 | const create_path: Path = .{ |
| | 1600 | .root_dir = cache_root, |
| | 1601 | .sub_path = switch (arg.flags.tag) { |
| | 1602 | .output_file => Dir.path.dirname(generated_path.sub_path).?, |
| | 1603 | .output_directory => generated_path.sub_path, |
| | 1604 | else => unreachable, |
| | 1605 | }, |
| | 1606 | }; |
| | 1607 | create_path.root_dir.handle.createDirPath(io, create_path.sub_path) catch |err| |
| | 1608 | return step.fail(maker, "unable to make path {f}: {t}", .{ create_path, err }); |
| | 1609 | |
| | 1610 | maker.generatedPath(arg.generated.value.?).* = generated_path; |
| | 1611 | |
| | 1612 | const arg_output_path = try convertPathArg(run_index, maker, generated_path); |
| | 1613 | argv[placeholder.index] = try mem.concat(arena, u8, &.{ prefix, arg_output_path, suffix }); |
| 1573 | } | 1614 | } |
| | 1615 | } |
| | 1616 | |
| | 1617 | fn populateGeneratedStdIo( |
| | 1618 | maker: *Maker, |
| | 1619 | conf_run: *const Configuration.Step.Run, |
| | 1620 | cache_root: Cache.Directory, |
| | 1621 | digest: *const Cache.HexDigest, |
| | 1622 | ) !void { |
| | 1623 | const conf = &maker.scanned_config.configuration; |
| | 1624 | const graph = maker.graph; |
| | 1625 | const arena = graph.arena; // TODO don't leak into the process arena |
| 1574 | | 1626 | |
| 1575 | if (conf_run.captured_stdout.value) |captured| { | 1627 | if (conf_run.captured_stdout.value) |captured| { |
| 1576 | captured.output.generated_file.path = try cache_root.join(arena, &.{ | 1628 | maker.generatedPath(captured.generated_file).* = .{ |
| 1577 | "o", digest, captured.output.basename, | 1629 | .root_dir = cache_root, |
| 1578 | }); | 1630 | .sub_path = try Dir.path.join(arena, &.{ |
| | 1631 | "o", digest, captured.basename.slice(conf), |
| | 1632 | }), |
| | 1633 | }; |
| 1579 | } | 1634 | } |
| 1580 | | 1635 | |
| 1581 | if (conf_run.captured_stderr.value) |captured| { | 1636 | if (conf_run.captured_stderr.value) |captured| { |
| 1582 | captured.output.generated_file.path = try cache_root.join(arena, &.{ | 1637 | maker.generatedPath(captured.generated_file).* = .{ |
| 1583 | "o", digest, captured.output.basename, | 1638 | .root_dir = cache_root, |
| 1584 | }); | 1639 | .sub_path = try Dir.path.join(arena, &.{ |
| | 1640 | "o", digest, captured.basename.slice(conf), |
| | 1641 | }), |
| | 1642 | }; |
| 1585 | } | 1643 | } |
| 1586 | } | 1644 | } |
| 1587 | | 1645 | |
| ... | @@ -1600,11 +1658,12 @@ fn fmtTerm(term: ?process.Child.Term) std.fmt.Alt(?process.Child.Term, formatTer | ... | @@ -1600,11 +1658,12 @@ fn fmtTerm(term: ?process.Child.Term) std.fmt.Alt(?process.Child.Term, formatTer |
| 1600 | } | 1658 | } |
| 1601 | | 1659 | |
| 1602 | const FuzzContext = struct { | 1660 | const FuzzContext = struct { |
| 1603 | fuzz: *std.Build.Fuzz, | 1661 | fuzz: *Fuzz, |
| 1604 | }; | 1662 | }; |
| 1605 | | 1663 | |
| 1606 | fn runCommand( | 1664 | fn runCommand( |
| 1607 | run: *Run, | 1665 | run: *Run, |
| | 1666 | run_index: Configuration.Step.Index, |
| 1608 | maker: *Maker, | 1667 | maker: *Maker, |
| 1609 | progress_node: std.Progress.Node, | 1668 | progress_node: std.Progress.Node, |
| 1610 | argv: []const []const u8, | 1669 | argv: []const []const u8, |
| ... | @@ -1615,30 +1674,45 @@ fn runCommand( | ... | @@ -1615,30 +1674,45 @@ fn runCommand( |
| 1615 | const graph = maker.graph; | 1674 | const graph = maker.graph; |
| 1616 | const arena = graph.arena; // TODO don't leak into process arena | 1675 | const arena = graph.arena; // TODO don't leak into process arena |
| 1617 | const gpa = maker.gpa; | 1676 | const gpa = maker.gpa; |
| 1618 | const step = &run.step; | 1677 | const step = maker.stepByIndex(run_index); |
| 1619 | const b = step.owner; | | |
| 1620 | const io = graph.io; | 1678 | const io = graph.io; |
| | 1679 | const cache_root = graph.local_cache_root; |
| | 1680 | const conf = &maker.scanned_config.configuration; |
| | 1681 | const conf_step = run_index.ptr(conf); |
| | 1682 | const conf_run = conf_step.extended.get(conf.extra).run; |
| | 1683 | const environ_map = &run.environ_map; |
| 1621 | | 1684 | |
| 1622 | const cwd: process.Child.Cwd = if (run.cwd) |lazy_cwd| .{ .path = lazy_cwd.getPath2(b, step) } else .inherit; | 1685 | const cwd: process.Child.Cwd = if (conf_run.cwd.value) |lazy_cwd| |
| 1623 | | 1686 | .{ .path = try maker.resolveLazyPathIndexAbs(arena, lazy_cwd, run_index) } |
| 1624 | try step.handleChildProcUnsupported(); | 1687 | else |
| 1625 | try Step.handleVerbose(step.owner, cwd, run.environ_map, argv); | 1688 | .inherit; |
| 1626 | | 1689 | |
| 1627 | const allow_skip = switch (run.stdio) { | 1690 | const allow_skip = switch (conf_run.flags.stdio) { |
| 1628 | .check, .zig_test => run.skip_foreign_checks, | 1691 | .check, .zig_test => conf_run.flags.skip_foreign_checks, |
| 1629 | else => false, | 1692 | else => false, |
| 1630 | }; | 1693 | }; |
| 1631 | | 1694 | |
| 1632 | var interp_argv = std.array_list.Managed([]const u8).init(b.allocator); | 1695 | var interp_argv: std.ArrayList([]const u8) = .empty; |
| 1633 | defer interp_argv.deinit(); | 1696 | |
| | 1697 | // `environ_map` is initialized with an undefined `allocator` field; lazily |
| | 1698 | // initialize it here. |
| | 1699 | environ_map.allocator = gpa; |
| | 1700 | // In either case we add to this mutatable data structure so that we can |
| | 1701 | // tweak the environment below. |
| | 1702 | environ_map.clearRetainingCapacity(); |
| | 1703 | if (conf_run.environ_map.value) |env_map_index| { |
| | 1704 | const conf_env_map = env_map_index.get(conf); |
| | 1705 | for (conf_env_map.keys.slice(conf), conf_env_map.values.slice(conf)) |k, v| { |
| | 1706 | try environ_map.put(k.slice(conf), v.slice(conf)); |
| | 1707 | } |
| | 1708 | } else { |
| | 1709 | try environ_map.putAll(&graph.environ_map); |
| | 1710 | } |
| | 1711 | try graph.handleVerbose(cwd, environ_map, argv); |
| 1634 | | 1712 | |
| 1635 | var environ_map: EnvMap = env: { | 1713 | if (true) @panic("TODO"); |
| 1636 | const orig = run.environ_map orelse &graph.environ_map; | | |
| 1637 | break :env try orig.clone(gpa); | | |
| 1638 | }; | | |
| 1639 | defer environ_map.deinit(); | | |
| 1640 | | 1714 | |
| 1641 | const opt_generic_result = spawnChildAndCollect(run, maker, progress_node, argv, &environ_map, has_side_effects, fuzz_context) catch |err| term: { | 1715 | const opt_generic_result = spawnChildAndCollect(run_index, run, maker, progress_node, argv, &environ_map, has_side_effects, fuzz_context) catch |err| term: { |
| 1642 | // InvalidExe: cpu arch mismatch | 1716 | // InvalidExe: cpu arch mismatch |
| 1643 | // FileNotFound: can happen with a wrong dynamic linker path | 1717 | // FileNotFound: can happen with a wrong dynamic linker path |
| 1644 | if (err == error.InvalidExe or err == error.FileNotFound) interpret: { | 1718 | if (err == error.InvalidExe or err == error.FileNotFound) interpret: { |
| ... | @@ -1660,7 +1734,7 @@ fn runCommand( | ... | @@ -1660,7 +1734,7 @@ fn runCommand( |
| 1660 | (root_target.isGnuLibC() or (root_target.isMuslLibC() and exe.linkage == .dynamic)); | 1734 | (root_target.isGnuLibC() or (root_target.isMuslLibC() and exe.linkage == .dynamic)); |
| 1661 | const other_target = exe.root_module.resolved_target.?.result; | 1735 | const other_target = exe.root_module.resolved_target.?.result; |
| 1662 | switch (std.zig.system.getExternalExecutor(io, &graph.host.result, &other_target, .{ | 1736 | switch (std.zig.system.getExternalExecutor(io, &graph.host.result, &other_target, .{ |
| 1663 | .qemu_fixes_dl = need_cross_libc and b.libc_runtimes_dir != null, | 1737 | .qemu_fixes_dl = need_cross_libc and graph.libc_runtimes_dir != null, |
| 1664 | .link_libc = exe.is_linking_libc, | 1738 | .link_libc = exe.is_linking_libc, |
| 1665 | })) { | 1739 | })) { |
| 1666 | .native, .rosetta => { | 1740 | .native, .rosetta => { |
| ... | @@ -1668,7 +1742,7 @@ fn runCommand( | ... | @@ -1668,7 +1742,7 @@ fn runCommand( |
| 1668 | break :interpret; | 1742 | break :interpret; |
| 1669 | }, | 1743 | }, |
| 1670 | .wine => |bin_name| { | 1744 | .wine => |bin_name| { |
| 1671 | if (b.enable_wine) { | 1745 | if (graph.enable_wine) { |
| 1672 | try interp_argv.append(bin_name); | 1746 | try interp_argv.append(bin_name); |
| 1673 | try interp_argv.appendSlice(argv); | 1747 | try interp_argv.appendSlice(argv); |
| 1674 | | 1748 | |
| ... | @@ -1682,21 +1756,21 @@ fn runCommand( | ... | @@ -1682,21 +1756,21 @@ fn runCommand( |
| 1682 | } | 1756 | } |
| 1683 | }, | 1757 | }, |
| 1684 | .qemu => |bin_name| { | 1758 | .qemu => |bin_name| { |
| 1685 | if (b.enable_qemu) { | 1759 | if (graph.enable_qemu) { |
| 1686 | try interp_argv.append(bin_name); | 1760 | try interp_argv.append(bin_name); |
| 1687 | | 1761 | |
| 1688 | if (need_cross_libc) { | 1762 | if (need_cross_libc) { |
| 1689 | if (b.libc_runtimes_dir) |dir| { | 1763 | if (graph.libc_runtimes_dir) |dir| { |
| 1690 | try interp_argv.append("-L"); | 1764 | try interp_argv.append("-L"); |
| 1691 | try interp_argv.append(b.pathJoin(&.{ | 1765 | try interp_argv.append(try Dir.path.join(arena, &.{ |
| 1692 | dir, | 1766 | dir, |
| 1693 | try if (root_target.isGnuLibC()) std.zig.target.glibcRuntimeTriple( | 1767 | try if (root_target.isGnuLibC()) std.zig.target.glibcRuntimeTriple( |
| 1694 | b.allocator, | 1768 | arena, |
| 1695 | root_target.cpu.arch, | 1769 | root_target.cpu.arch, |
| 1696 | root_target.os.tag, | 1770 | root_target.os.tag, |
| 1697 | root_target.abi, | 1771 | root_target.abi, |
| 1698 | ) else if (root_target.isMuslLibC()) std.zig.target.muslRuntimeTriple( | 1772 | ) else if (root_target.isMuslLibC()) std.zig.target.muslRuntimeTriple( |
| 1699 | b.allocator, | 1773 | arena, |
| 1700 | root_target.cpu.arch, | 1774 | root_target.cpu.arch, |
| 1701 | root_target.abi, | 1775 | root_target.abi, |
| 1702 | ) else unreachable, | 1776 | ) else unreachable, |
| ... | @@ -1708,7 +1782,7 @@ fn runCommand( | ... | @@ -1708,7 +1782,7 @@ fn runCommand( |
| 1708 | } else return failForeign(run, "-fqemu", argv[0], exe); | 1782 | } else return failForeign(run, "-fqemu", argv[0], exe); |
| 1709 | }, | 1783 | }, |
| 1710 | .darling => |bin_name| { | 1784 | .darling => |bin_name| { |
| 1711 | if (b.enable_darling) { | 1785 | if (graph.enable_darling) { |
| 1712 | try interp_argv.append(bin_name); | 1786 | try interp_argv.append(bin_name); |
| 1713 | try interp_argv.appendSlice(argv); | 1787 | try interp_argv.appendSlice(argv); |
| 1714 | } else { | 1788 | } else { |
| ... | @@ -1716,7 +1790,7 @@ fn runCommand( | ... | @@ -1716,7 +1790,7 @@ fn runCommand( |
| 1716 | } | 1790 | } |
| 1717 | }, | 1791 | }, |
| 1718 | .wasmtime => |bin_name| { | 1792 | .wasmtime => |bin_name| { |
| 1719 | if (b.enable_wasmtime) { | 1793 | if (graph.enable_wasmtime) { |
| 1720 | try interp_argv.append(bin_name); | 1794 | try interp_argv.append(bin_name); |
| 1721 | try interp_argv.append("--dir=."); | 1795 | try interp_argv.append("--dir=."); |
| 1722 | // Wasmtime doeesn't inherit environment variables from the parent process | 1796 | // Wasmtime doeesn't inherit environment variables from the parent process |
| ... | @@ -1743,8 +1817,8 @@ fn runCommand( | ... | @@ -1743,8 +1817,8 @@ fn runCommand( |
| 1743 | .bad_os_or_cpu => { | 1817 | .bad_os_or_cpu => { |
| 1744 | if (allow_skip) return error.MakeSkipped; | 1818 | if (allow_skip) return error.MakeSkipped; |
| 1745 | | 1819 | |
| 1746 | const host_name = try graph.host.result.zigTriple(b.allocator); | 1820 | const host_name = try graph.host.result.zigTriple(arena); |
| 1747 | const foreign_name = try root_target.zigTriple(b.allocator); | 1821 | const foreign_name = try root_target.zigTriple(arena); |
| 1748 | | 1822 | |
| 1749 | return step.fail(maker, "the host system ({s}) is unable to execute binaries from the target ({s})", .{ | 1823 | return step.fail(maker, "the host system ({s}) is unable to execute binaries from the target ({s})", .{ |
| 1750 | host_name, foreign_name, | 1824 | host_name, foreign_name, |
| ... | @@ -1761,7 +1835,7 @@ fn runCommand( | ... | @@ -1761,7 +1835,7 @@ fn runCommand( |
| 1761 | step.result_failed_command = null; | 1835 | step.result_failed_command = null; |
| 1762 | try Step.handleVerbose(step.owner, cwd, run.environ_map, interp_argv.items); | 1836 | try Step.handleVerbose(step.owner, cwd, run.environ_map, interp_argv.items); |
| 1763 | | 1837 | |
| 1764 | break :term spawnChildAndCollect(run, maker, progress_node, interp_argv.items, &environ_map, has_side_effects, fuzz_context) catch |e| { | 1838 | break :term spawnChildAndCollect(run_index, run, maker, progress_node, interp_argv.items, &environ_map, has_side_effects, fuzz_context) catch |e| { |
| 1765 | if (!run.failing_to_execute_foreign_is_an_error) return error.MakeSkipped; | 1839 | if (!run.failing_to_execute_foreign_is_an_error) return error.MakeSkipped; |
| 1766 | if (e == error.MakeFailed) return error.MakeFailed; // error already reported | 1840 | if (e == error.MakeFailed) return error.MakeFailed; // error already reported |
| 1767 | return step.fail(maker, "unable to spawn interpreter {s}: {t}", .{ interp_argv.items[0], e }); | 1841 | return step.fail(maker, "unable to spawn interpreter {s}: {t}", .{ interp_argv.items[0], e }); |
| ... | @@ -1800,14 +1874,14 @@ fn runCommand( | ... | @@ -1800,14 +1874,14 @@ fn runCommand( |
| 1800 | }) |stream| { | 1874 | }) |stream| { |
| 1801 | if (stream.captured) |captured| { | 1875 | if (stream.captured) |captured| { |
| 1802 | const output_components = .{ output_dir_path, captured.output.basename }; | 1876 | const output_components = .{ output_dir_path, captured.output.basename }; |
| 1803 | const output_path = try b.cache_root.join(arena, &output_components); | 1877 | const output_path = try cache_root.join(arena, &output_components); |
| 1804 | captured.output.generated_file.path = output_path; | 1878 | captured.output.generated_file.path = output_path; |
| 1805 | | 1879 | |
| 1806 | const sub_path = b.pathJoin(&output_components); | 1880 | const sub_path = try Dir.path.join(arena, &output_components); |
| 1807 | const sub_path_dirname = Dir.path.dirname(sub_path).?; | 1881 | const sub_path_dirname = Dir.path.dirname(sub_path).?; |
| 1808 | b.cache_root.handle.createDirPath(io, sub_path_dirname) catch |err| { | 1882 | cache_root.handle.createDirPath(io, sub_path_dirname) catch |err| { |
| 1809 | return step.fail(maker, "unable to make path '{f}{s}': {s}", .{ | 1883 | return step.fail(maker, "unable to make path '{f}{s}': {t}", .{ |
| 1810 | b.cache_root, sub_path_dirname, @errorName(err), | 1884 | cache_root, sub_path_dirname, err, |
| 1811 | }); | 1885 | }); |
| 1812 | }; | 1886 | }; |
| 1813 | const data = switch (captured.trim_whitespace) { | 1887 | const data = switch (captured.trim_whitespace) { |
| ... | @@ -1816,9 +1890,9 @@ fn runCommand( | ... | @@ -1816,9 +1890,9 @@ fn runCommand( |
| 1816 | .leading => mem.trimStart(u8, stream.bytes.?, &std.ascii.whitespace), | 1890 | .leading => mem.trimStart(u8, stream.bytes.?, &std.ascii.whitespace), |
| 1817 | .trailing => mem.trimEnd(u8, stream.bytes.?, &std.ascii.whitespace), | 1891 | .trailing => mem.trimEnd(u8, stream.bytes.?, &std.ascii.whitespace), |
| 1818 | }; | 1892 | }; |
| 1819 | b.cache_root.handle.writeFile(io, .{ .sub_path = sub_path, .data = data }) catch |err| { | 1893 | cache_root.handle.writeFile(io, .{ .sub_path = sub_path, .data = data }) catch |err| { |
| 1820 | return step.fail(maker, "unable to write file '{f}{s}': {s}", .{ | 1894 | return step.fail(maker, "unable to write file '{f}{s}': {t}", .{ |
| 1821 | b.cache_root, sub_path, @errorName(err), | 1895 | cache_root, sub_path, err, |
| 1822 | }); | 1896 | }); |
| 1823 | }; | 1897 | }; |
| 1824 | } | 1898 | } |
| ... | @@ -1912,6 +1986,7 @@ const EvalGenericResult = struct { | ... | @@ -1912,6 +1986,7 @@ const EvalGenericResult = struct { |
| 1912 | }; | 1986 | }; |
| 1913 | | 1987 | |
| 1914 | fn spawnChildAndCollect( | 1988 | fn spawnChildAndCollect( |
| | 1989 | run_index: Configuration.Step.Index, |
| 1915 | run: *Run, | 1990 | run: *Run, |
| 1916 | maker: *Maker, | 1991 | maker: *Maker, |
| 1917 | progress_node: std.Progress.Node, | 1992 | progress_node: std.Progress.Node, |
| ... | @@ -1920,25 +1995,34 @@ fn spawnChildAndCollect( | ... | @@ -1920,25 +1995,34 @@ fn spawnChildAndCollect( |
| 1920 | has_side_effects: bool, | 1995 | has_side_effects: bool, |
| 1921 | fuzz_context: ?FuzzContext, | 1996 | fuzz_context: ?FuzzContext, |
| 1922 | ) !?EvalGenericResult { | 1997 | ) !?EvalGenericResult { |
| 1923 | const b = run.step.owner; | 1998 | const step = run.step; |
| 1924 | const graph = maker.graph; | 1999 | const graph = maker.graph; |
| 1925 | const gpa = maker.gpa; | 2000 | const gpa = maker.gpa; |
| 1926 | const io = graph.io; | 2001 | const io = graph.io; |
| | 2002 | const arena = graph.arena; // TODO don't leak into process arena |
| | 2003 | const conf = &maker.scanned_config.configuration; |
| | 2004 | const conf_step = run_index.ptr(conf); |
| | 2005 | const conf_run = conf_step.extended.get(conf.extra).run; |
| 1927 | | 2006 | |
| 1928 | if (fuzz_context != null) { | 2007 | if (fuzz_context != null) { |
| 1929 | assert(!has_side_effects); | 2008 | assert(!has_side_effects); |
| 1930 | assert(run.stdio == .zig_test); | 2009 | assert(run.stdio == .zig_test); |
| 1931 | } | 2010 | } |
| 1932 | | 2011 | |
| 1933 | const child_cwd: process.Child.Cwd = if (run.cwd) |lazy_cwd| .{ .path = lazy_cwd.getPath2(b, &run.step) } else .inherit; | 2012 | const child_cwd: process.Child.Cwd = if (conf_run.cwd) |lazy_cwd| |
| | 2013 | .{ .path = try maker.resolveLazyPathIndexAbs(arena, lazy_cwd, run_index) } |
| | 2014 | else |
| | 2015 | .inherit; |
| 1934 | | 2016 | |
| 1935 | // If an error occurs, it's caused by this command: | 2017 | // If an error occurs, it's caused by this command: |
| 1936 | assert(run.step.result_failed_command == null); | 2018 | assert(step.result_failed_command == null); |
| 1937 | run.step.result_failed_command = try Step.allocPrintCmd(gpa, child_cwd, .{ | 2019 | step.result_failed_command = try Step.allocPrintCmd(gpa, child_cwd, .{ |
| 1938 | .child = environ_map, | 2020 | .child = environ_map, |
| 1939 | .parent = &graph.environ_map, | 2021 | .parent = &graph.environ_map, |
| 1940 | }, argv); | 2022 | }, argv); |
| 1941 | | 2023 | |
| | 2024 | try step.handleChildProcUnsupported(maker); |
| | 2025 | |
| 1942 | var spawn_options: process.SpawnOptions = .{ | 2026 | var spawn_options: process.SpawnOptions = .{ |
| 1943 | .argv = argv, | 2027 | .argv = argv, |
| 1944 | .cwd = child_cwd, | 2028 | .cwd = child_cwd, |
| ... | @@ -1973,7 +2057,7 @@ fn spawnChildAndCollect( | ... | @@ -1973,7 +2057,7 @@ fn spawnChildAndCollect( |
| 1973 | error.Canceled => |e| return e, | 2057 | error.Canceled => |e| return e, |
| 1974 | else => |e| e, | 2058 | else => |e| e, |
| 1975 | }; | 2059 | }; |
| 1976 | run.step.result_duration_ns = @intCast(started.untilNow(io).raw.nanoseconds); | 2060 | step.result_duration_ns = @intCast(started.untilNow(io).raw.nanoseconds); |
| 1977 | try result; | 2061 | try result; |
| 1978 | return null; | 2062 | return null; |
| 1979 | } else { | 2063 | } else { |
| ... | @@ -1993,7 +2077,7 @@ fn spawnChildAndCollect( | ... | @@ -1993,7 +2077,7 @@ fn spawnChildAndCollect( |
| 1993 | error.Canceled => |e| return e, | 2077 | error.Canceled => |e| return e, |
| 1994 | else => |e| e, | 2078 | else => |e| e, |
| 1995 | }; | 2079 | }; |
| 1996 | run.step.result_duration_ns = @intCast(started.untilNow(io).raw.nanoseconds); | 2080 | step.result_duration_ns = @intCast(started.untilNow(io).raw.nanoseconds); |
| 1997 | return try result; | 2081 | return try result; |
| 1998 | } | 2082 | } |
| 1999 | } | 2083 | } |