| author | |
| committer | |
| log | 6b7ce1fa22b301ac06d3bfa0a8938546966f684c |
| tree | 88d5a9c33855fa67da2c0f1ab2ab1f70ab724fd2 |
| parent | b3d162d6bfe82d84d55edd58016347a420732fe2 |
10 files changed, 630 insertions(+), 453 deletions(-)
lib/compiler/Maker.zig+64-53| ... | ... | @@ -419,7 +419,7 @@ pub fn main(init: process.Init.Minimal) !void { |
| 419 | 419 | var top_level_steps: std.StringArrayHashMapUnmanaged(Configuration.Step.Index) = .empty; |
| 420 | 420 | for (configuration.steps, 0..) |*conf_step, step_index_usize| { |
| 421 | 421 | const step_index: Configuration.Step.Index = @enumFromInt(step_index_usize); |
| 422 | const flags: Configuration.Step.Flags = @bitCast(configuration.extra[conf_step.extra_index]); | |
| 422 | const flags = conf_step.flags(&configuration); | |
| 423 | 423 | if (flags.tag == .top_level) { |
| 424 | 424 | const name = step_index.ptr(&configuration).name.slice(&configuration); |
| 425 | 425 | try top_level_steps.put(arena, name, step_index); |
| ... | ... | @@ -538,7 +538,7 @@ pub fn main(init: process.Init.Minimal) !void { |
| 538 | 538 | var w: Watch = w: { |
| 539 | 539 | if (!watch) break :w undefined; |
| 540 | 540 | if (!Watch.have_impl) fatal("--watch not yet implemented for {t}", .{builtin.os.tag}); |
| 541 | break :w try .init(graph.cache.cwd, &scanned_config.configuration, maker.steps); | |
| 541 | break :w try .init(&maker); | |
| 542 | 542 | }; |
| 543 | 543 | |
| 544 | 544 | const now = Io.Clock.Timestamp.now(io, .awake); |
| ... | ... | @@ -546,14 +546,10 @@ pub fn main(init: process.Init.Minimal) !void { |
| 546 | 546 | maker.web_server = if (webui_listen) |listen_address| ws: { |
| 547 | 547 | if (builtin.single_threaded) unreachable; // `fatal` above |
| 548 | 548 | break :ws .init(.{ |
| 549 | .gpa = gpa, | |
| 550 | .graph = &graph, | |
| 551 | .all_steps = maker.step_stack.keys(), | |
| 549 | .maker = &maker, | |
| 552 | 550 | .root_prog_node = main_progress_node, |
| 553 | .watch = watch, | |
| 554 | 551 | .listen_address = listen_address, |
| 555 | 552 | .base_timestamp = now, |
| 556 | .configuration = &scanned_config.configuration, | |
| 557 | 553 | }); |
| 558 | 554 | } else null; |
| 559 | 555 | |
| ... | ... | @@ -564,7 +560,9 @@ pub fn main(init: process.Init.Minimal) !void { |
| 564 | 560 | rebuild: while (true) : (if (maker.error_style.clearOnUpdate()) { |
| 565 | 561 | const stderr = try io.lockStderr(&stdio_buffer_allocation, graph.stderr_mode); |
| 566 | 562 | defer io.unlockStderr(); |
| 567 | try stderr.file_writer.interface.writeAll("\x1B[2J\x1B[3J\x1B[H"); | |
| 563 | stderr.file_writer.interface.writeAll("\x1B[2J\x1B[3J\x1B[H") catch |err| switch (err) { | |
| 564 | error.WriteFailed => return stderr.file_writer.err.?, | |
| 565 | }; | |
| 568 | 566 | }) { |
| 569 | 567 | if (maker.web_server) |*ws| ws.startBuild(); |
| 570 | 568 | |
| ... | ... | @@ -608,15 +606,15 @@ pub fn main(init: process.Init.Minimal) !void { |
| 608 | 606 | // recursive dependants. |
| 609 | 607 | var caption_buf: [std.Progress.Node.max_name_len]u8 = undefined; |
| 610 | 608 | const caption = std.fmt.bufPrint(&caption_buf, "watching {d} directories, {d} processes", .{ |
| 611 | w.dir_count, countSubProcesses(maker.steps, maker.step_stack.keys()), | |
| 609 | w.dir_count, countSubProcesses(&maker), | |
| 612 | 610 | }) catch &caption_buf; |
| 613 | 611 | var debouncing_node = main_progress_node.start(caption, 0); |
| 614 | 612 | var in_debounce = false; |
| 615 | while (true) switch (try w.wait(gpa, io, if (in_debounce) .{ .ms = debounce_interval_ms } else .none)) { | |
| 613 | while (true) switch (try w.wait(if (in_debounce) .{ .ms = debounce_interval_ms } else .none)) { | |
| 616 | 614 | .timeout => { |
| 617 | 615 | assert(in_debounce); |
| 618 | 616 | debouncing_node.end(); |
| 619 | markFailedStepsDirty(gpa, maker.steps, maker.step_stack.keys()); | |
| 617 | markFailedStepsDirty(&maker); | |
| 620 | 618 | continue :rebuild; |
| 621 | 619 | }, |
| 622 | 620 | .dirty => if (!in_debounce) { |
| ... | ... | @@ -629,18 +627,20 @@ pub fn main(init: process.Init.Minimal) !void { |
| 629 | 627 | } |
| 630 | 628 | } |
| 631 | 629 | |
| 632 | fn markFailedStepsDirty(gpa: Allocator, make_steps: []Step, all_steps: []const Configuration.Step.Index) void { | |
| 630 | fn markFailedStepsDirty(maker: *Maker) void { | |
| 631 | const all_steps = maker.step_stack.keys(); | |
| 632 | ||
| 633 | 633 | for (all_steps) |step_index| { |
| 634 | const step = &make_steps[@intFromEnum(step_index)]; | |
| 634 | const step = maker.stepByIndex(step_index); | |
| 635 | 635 | switch (step.state) { |
| 636 | .dependency_failure, .failure, .skipped => _ = step.invalidateResult(gpa), | |
| 636 | .dependency_failure, .failure, .skipped => _ = maker.invalidateResult(step), | |
| 637 | 637 | else => continue, |
| 638 | 638 | } |
| 639 | 639 | } |
| 640 | 640 | // Now that all dirty steps have been found, the remaining steps that |
| 641 | 641 | // succeeded from last run shall be marked "cached". |
| 642 | 642 | for (all_steps) |step_index| { |
| 643 | const step = &make_steps[@intFromEnum(step_index)]; | |
| 643 | const step = maker.stepByIndex(step_index); | |
| 644 | 644 | switch (step.state) { |
| 645 | 645 | .success => step.result_cached = true, |
| 646 | 646 | else => continue, |
| ... | ... | @@ -648,10 +648,11 @@ fn markFailedStepsDirty(gpa: Allocator, make_steps: []Step, all_steps: []const C |
| 648 | 648 | } |
| 649 | 649 | } |
| 650 | 650 | |
| 651 | fn countSubProcesses(make_steps: []Step, all_steps: []const Configuration.Step.Index) usize { | |
| 651 | fn countSubProcesses(maker: *Maker) usize { | |
| 652 | const all_steps = maker.step_stack.keys(); | |
| 652 | 653 | var count: usize = 0; |
| 653 | 654 | for (all_steps) |step_index| { |
| 654 | const s = &make_steps[@intFromEnum(step_index)]; | |
| 655 | const s = maker.stepByIndex(step_index); | |
| 655 | 656 | count += @intFromBool(s.getZigProcess() != null); |
| 656 | 657 | } |
| 657 | 658 | return count; |
| ... | ... | @@ -664,7 +665,7 @@ const InstallPaths = struct { |
| 664 | 665 | include: Path, |
| 665 | 666 | }; |
| 666 | 667 | |
| 667 | fn stepByIndex(maker: *const Maker, i: Configuration.Step.Index) *Step { | |
| 668 | pub fn stepByIndex(maker: *const Maker, i: Configuration.Step.Index) *Step { | |
| 668 | 669 | return &maker.steps[@intFromEnum(i)]; |
| 669 | 670 | } |
| 670 | 671 | |
| ... | ... | @@ -676,7 +677,10 @@ fn prepare(maker: *Maker, step_names: []const []const u8) !void { |
| 676 | 677 | const step_stack = &maker.step_stack; |
| 677 | 678 | const c = &maker.scanned_config.configuration; |
| 678 | 679 | |
| 679 | @memset(maker.steps, .{}); | |
| 680 | for (maker.steps, 0..) |*step, step_index_usize| { | |
| 681 | const step_index: Configuration.Step.Index = @enumFromInt(step_index_usize); | |
| 682 | step.* = .{ .extended = .init(step_index.ptr(c).flags(c).tag) }; | |
| 683 | } | |
| 680 | 684 | |
| 681 | 685 | if (step_names.len == 0) { |
| 682 | 686 | try step_stack.put(gpa, c.default_step, {}); |
| ... | ... | @@ -699,7 +703,7 @@ fn prepare(maker: *Maker, step_names: []const []const u8) !void { |
| 699 | 703 | rand.shuffle(Configuration.Step.Index, starting_steps); |
| 700 | 704 | |
| 701 | 705 | for (starting_steps) |s| { |
| 702 | try constructGraphAndCheckForDependencyLoop(gpa, c, maker.steps, s, &maker.step_stack, rand); | |
| 706 | try constructGraphAndCheckForDependencyLoop(maker, s, &maker.step_stack, rand); | |
| 703 | 707 | } |
| 704 | 708 | |
| 705 | 709 | { |
| ... | ... | @@ -847,13 +851,8 @@ fn makeStepNames( |
| 847 | 851 | } |
| 848 | 852 | |
| 849 | 853 | assert(mode == .limit); |
| 850 | var f = Fuzz.init( | |
| 851 | gpa, | |
| 852 | io, | |
| 853 | step_stack.keys(), | |
| 854 | parent_prog_node, | |
| 855 | mode, | |
| 856 | ) catch |err| fatal("failed to start fuzzer: {t}", .{err}); | |
| 854 | var f = Fuzz.init(maker, step_stack.keys(), parent_prog_node, mode) catch |err| | |
| 855 | fatal("failed to start fuzzer: {t}", .{err}); | |
| 857 | 856 | defer f.deinit(); |
| 858 | 857 | |
| 859 | 858 | f.start(); |
| ... | ... | @@ -1048,13 +1047,7 @@ fn makeStep( |
| 1048 | 1047 | |
| 1049 | 1048 | .success, .skipped => {}, |
| 1050 | 1049 | } |
| 1051 | } else if (make_step.make(.{ | |
| 1052 | .progress_node = step_prog_node, | |
| 1053 | .watch = maker.watch, | |
| 1054 | .web_server = if (maker.web_server) |*ws| ws else null, | |
| 1055 | .unit_test_timeout_ns = maker.unit_test_timeout_ns, | |
| 1056 | .gpa = gpa, | |
| 1057 | })) state: { | |
| 1050 | } else if (Step.make(step_index, maker, step_prog_node)) state: { | |
| 1058 | 1051 | break :state .success; |
| 1059 | 1052 | } else |err| switch (err) { |
| 1060 | 1053 | error.MakeFailed => .failure, |
| ... | ... | @@ -1091,7 +1084,7 @@ fn makeStep( |
| 1091 | 1084 | { |
| 1092 | 1085 | const stderr = try io.lockStderr(&stdio_buffer_allocation, graph.stderr_mode); |
| 1093 | 1086 | defer io.unlockStderr(); |
| 1094 | printErrorMessages(gpa, c, maker.steps, step_index, .{}, stderr.terminal(), maker.error_style, maker.multiline_errors) catch |err| switch (err) { | |
| 1087 | printErrorMessages(maker, step_index, .{}, stderr.terminal(), maker.error_style, maker.multiline_errors) catch |err| switch (err) { | |
| 1095 | 1088 | error.Canceled => |e| return e, |
| 1096 | 1089 | error.WriteFailed => switch (stderr.file_writer.err.?) { |
| 1097 | 1090 | error.Canceled => |e| return e, |
| ... | ... | @@ -1136,7 +1129,7 @@ fn makeStep( |
| 1136 | 1129 | } |
| 1137 | 1130 | |
| 1138 | 1131 | fn printTreeStep( |
| 1139 | maker: *const Maker, | |
| 1132 | maker: *Maker, | |
| 1140 | 1133 | step_index: Configuration.Step.Index, |
| 1141 | 1134 | stderr: Io.Terminal, |
| 1142 | 1135 | parent_node: *PrintNode, |
| ... | ... | @@ -1211,7 +1204,7 @@ fn printTreeStep( |
| 1211 | 1204 | } |
| 1212 | 1205 | } |
| 1213 | 1206 | |
| 1214 | fn printStepStatus(maker: *const Maker, step_index: Configuration.Step.Index, stderr: Io.Terminal) !void { | |
| 1207 | fn printStepStatus(maker: *Maker, step_index: Configuration.Step.Index, stderr: Io.Terminal) !void { | |
| 1215 | 1208 | const s = maker.stepByIndex(step_index); |
| 1216 | 1209 | const writer = stderr.writer; |
| 1217 | 1210 | switch (s.state) { |
| ... | ... | @@ -1293,20 +1286,20 @@ fn printStepStatus(maker: *const Maker, step_index: Configuration.Step.Index, st |
| 1293 | 1286 | try stderr.setColor(.reset); |
| 1294 | 1287 | }, |
| 1295 | 1288 | .failure => { |
| 1296 | try printStepFailure(maker.steps, step_index, stderr, false); | |
| 1289 | try printStepFailure(maker, step_index, stderr, false); | |
| 1297 | 1290 | try stderr.setColor(.reset); |
| 1298 | 1291 | }, |
| 1299 | 1292 | } |
| 1300 | 1293 | } |
| 1301 | 1294 | |
| 1302 | 1295 | fn printStepFailure( |
| 1303 | make_steps: []Step, | |
| 1296 | maker: *Maker, | |
| 1304 | 1297 | step_index: Configuration.Step.Index, |
| 1305 | 1298 | stderr: Io.Terminal, |
| 1306 | 1299 | dim: bool, |
| 1307 | 1300 | ) !void { |
| 1308 | 1301 | const w = stderr.writer; |
| 1309 | const s = &make_steps[@intFromEnum(step_index)]; | |
| 1302 | const s = maker.stepByIndex(step_index); | |
| 1310 | 1303 | if (s.result_error_bundle.errorMessageCount() > 0) { |
| 1311 | 1304 | try stderr.setColor(.red); |
| 1312 | 1305 | try w.print(" {d} errors\n", .{ |
| ... | ... | @@ -1428,14 +1421,14 @@ fn printChildNodePrefix(stderr: Io.Terminal) !void { |
| 1428 | 1421 | /// when it finishes executing in `makeStep`, it spawns next steps to run in |
| 1429 | 1422 | /// random order |
| 1430 | 1423 | fn constructGraphAndCheckForDependencyLoop( |
| 1431 | gpa: Allocator, | |
| 1432 | c: *const Configuration, | |
| 1433 | steps: []Step, | |
| 1424 | maker: *Maker, | |
| 1434 | 1425 | step_index: Configuration.Step.Index, |
| 1435 | 1426 | step_stack: *std.AutoArrayHashMapUnmanaged(Configuration.Step.Index, void), |
| 1436 | 1427 | rand: std.Random, |
| 1437 | 1428 | ) error{ DependencyLoopDetected, OutOfMemory }!void { |
| 1438 | const make_step: *Step = &steps[@intFromEnum(step_index)]; | |
| 1429 | const c = &maker.scanned_config.configuration; | |
| 1430 | const gpa = maker.gpa; | |
| 1431 | const make_step = maker.stepByIndex(step_index); | |
| 1439 | 1432 | switch (make_step.state) { |
| 1440 | 1433 | .precheck_started => { |
| 1441 | 1434 | log.err("dependency loop detected: {s}", .{step_index.ptr(c).name.slice(c)}); |
| ... | ... | @@ -1456,10 +1449,10 @@ fn constructGraphAndCheckForDependencyLoop( |
| 1456 | 1449 | rand.shuffle(Configuration.Step.Index, deps); |
| 1457 | 1450 | |
| 1458 | 1451 | for (deps) |dep| { |
| 1459 | const dep_step: *Step = &steps[@intFromEnum(dep)]; | |
| 1452 | const dep_step = maker.stepByIndex(dep); | |
| 1460 | 1453 | try step_stack.put(gpa, dep, {}); |
| 1461 | 1454 | try dep_step.dependants.append(gpa, step_index); |
| 1462 | constructGraphAndCheckForDependencyLoop(gpa, c, steps, dep, step_stack, rand) catch |err| switch (err) { | |
| 1455 | constructGraphAndCheckForDependencyLoop(maker, dep, step_stack, rand) catch |err| switch (err) { | |
| 1463 | 1456 | error.DependencyLoopDetected => { |
| 1464 | 1457 | log.info("needed by: {s}", .{step_index.ptr(c).name.slice(c)}); |
| 1465 | 1458 | return err; |
| ... | ... | @@ -1482,16 +1475,34 @@ fn constructGraphAndCheckForDependencyLoop( |
| 1482 | 1475 | } |
| 1483 | 1476 | } |
| 1484 | 1477 | |
| 1478 | /// When file watching, prepares the step for being re-evaluated. Returns | |
| 1479 | /// `true` if the step was newly invalidated, `false` if it was already | |
| 1480 | /// invalidated. | |
| 1481 | pub fn invalidateResult(maker: *Maker, step: *Step) bool { | |
| 1482 | if (step.state == .precheck_done) return false; | |
| 1483 | const gpa = maker.gpa; | |
| 1484 | assert(step.pending_deps == 0); | |
| 1485 | step.state = .precheck_done; | |
| 1486 | step.reset(gpa); | |
| 1487 | for (step.dependants.items) |dependant_index| { | |
| 1488 | const dependant = maker.stepByIndex(dependant_index); | |
| 1489 | _ = invalidateResult(maker, dependant); | |
| 1490 | dependant.pending_deps += 1; | |
| 1491 | } | |
| 1492 | return true; | |
| 1493 | } | |
| 1494 | ||
| 1485 | 1495 | pub fn printErrorMessages( |
| 1486 | gpa: Allocator, | |
| 1487 | c: *const Configuration, | |
| 1488 | make_steps: []Step, | |
| 1496 | maker: *Maker, | |
| 1489 | 1497 | failing_step_index: Configuration.Step.Index, |
| 1490 | 1498 | options: std.zig.ErrorBundle.RenderOptions, |
| 1491 | 1499 | stderr: Io.Terminal, |
| 1492 | 1500 | error_style: ErrorStyle, |
| 1493 | 1501 | multiline_errors: MultilineErrors, |
| 1494 | 1502 | ) !void { |
| 1503 | const c = &maker.scanned_config.configuration; | |
| 1504 | const gpa = maker.gpa; | |
| 1505 | log.err("TODO also report if result_oom flag is set", .{}); | |
| 1495 | 1506 | const writer = stderr.writer; |
| 1496 | 1507 | if (error_style.verboseContext()) { |
| 1497 | 1508 | // Provide context for where these error messages are coming from by |
| ... | ... | @@ -1500,7 +1511,7 @@ pub fn printErrorMessages( |
| 1500 | 1511 | defer step_stack.deinit(gpa); |
| 1501 | 1512 | try step_stack.append(gpa, failing_step_index); |
| 1502 | 1513 | while (true) { |
| 1503 | const last_step = &make_steps[@intFromEnum(step_stack.items[step_stack.items.len - 1])]; | |
| 1514 | const last_step = maker.stepByIndex(step_stack.items[step_stack.items.len - 1]); | |
| 1504 | 1515 | if (last_step.dependants.items.len == 0) break; |
| 1505 | 1516 | try step_stack.append(gpa, last_step.dependants.items[0]); |
| 1506 | 1517 | } |
| ... | ... | @@ -1517,7 +1528,7 @@ pub fn printErrorMessages( |
| 1517 | 1528 | try writer.writeAll(step_index.ptr(c).name.slice(c)); |
| 1518 | 1529 | |
| 1519 | 1530 | if (step_index == failing_step_index) { |
| 1520 | try printStepFailure(make_steps, step_index, stderr, true); | |
| 1531 | try printStepFailure(maker, step_index, stderr, true); | |
| 1521 | 1532 | } else { |
| 1522 | 1533 | try writer.writeAll("\n"); |
| 1523 | 1534 | } |
| ... | ... | @@ -1527,11 +1538,11 @@ pub fn printErrorMessages( |
| 1527 | 1538 | // Just print the failing step itself. |
| 1528 | 1539 | try stderr.setColor(.dim); |
| 1529 | 1540 | try writer.writeAll(failing_step_index.ptr(c).name.slice(c)); |
| 1530 | try printStepFailure(make_steps, failing_step_index, stderr, true); | |
| 1541 | try printStepFailure(maker, failing_step_index, stderr, true); | |
| 1531 | 1542 | try stderr.setColor(.reset); |
| 1532 | 1543 | } |
| 1533 | 1544 | |
| 1534 | const failing_step = &make_steps[@intFromEnum(failing_step_index)]; | |
| 1545 | const failing_step = maker.stepByIndex(failing_step_index); | |
| 1535 | 1546 | |
| 1536 | 1547 | if (failing_step.result_stderr.len > 0) { |
| 1537 | 1548 | try writer.writeAll(failing_step.result_stderr); |
lib/compiler/Maker/Fuzz.zig+39-19| ... | ... | @@ -15,8 +15,7 @@ const log = std.log; |
| 15 | 15 | const Maker = @import("../Maker.zig"); |
| 16 | 16 | const WebServer = @import("WebServer.zig"); |
| 17 | 17 | |
| 18 | gpa: Allocator, | |
| 19 | io: Io, | |
| 18 | maker: *Maker, | |
| 20 | 19 | mode: Mode, |
| 21 | 20 | |
| 22 | 21 | /// Allocated into `gpa`. |
| ... | ... | @@ -76,12 +75,15 @@ const CoverageMap = struct { |
| 76 | 75 | }; |
| 77 | 76 | |
| 78 | 77 | pub fn init( |
| 79 | gpa: Allocator, | |
| 80 | io: Io, | |
| 78 | maker: *Maker, | |
| 81 | 79 | all_steps: []const Configuration.Step.Index, |
| 82 | 80 | root_prog_node: std.Progress.Node, |
| 83 | 81 | mode: Mode, |
| 84 | 82 | ) error{ OutOfMemory, Canceled }!Fuzz { |
| 83 | const graph = maker.graph; | |
| 84 | const gpa = graph.cache.gpa; | |
| 85 | const io = graph.io; | |
| 86 | ||
| 85 | 87 | const run_steps: []const Configuration.Step.Index = steps: { |
| 86 | 88 | var steps: std.ArrayList(Configuration.Step.Index) = .empty; |
| 87 | 89 | defer steps.deinit(gpa); |
| ... | ... | @@ -115,8 +117,7 @@ pub fn init( |
| 115 | 117 | } |
| 116 | 118 | |
| 117 | 119 | return .{ |
| 118 | .gpa = gpa, | |
| 119 | .io = io, | |
| 120 | .maker = maker, | |
| 120 | 121 | .mode = mode, |
| 121 | 122 | .run_steps = run_steps, |
| 122 | 123 | .group = .init, |
| ... | ... | @@ -131,7 +132,10 @@ pub fn init( |
| 131 | 132 | } |
| 132 | 133 | |
| 133 | 134 | pub fn start(fuzz: *Fuzz) void { |
| 134 | const io = fuzz.io; | |
| 135 | const maker = fuzz.maker; | |
| 136 | const graph = maker.graph; | |
| 137 | const io = graph.io; | |
| 138 | ||
| 135 | 139 | fuzz.prog_node = fuzz.root_prog_node.start("Fuzzing", 0); |
| 136 | 140 | |
| 137 | 141 | if (fuzz.mode == .forever) { |
| ... | ... | @@ -149,10 +153,14 @@ pub fn start(fuzz: *Fuzz) void { |
| 149 | 153 | } |
| 150 | 154 | |
| 151 | 155 | pub fn deinit(fuzz: *Fuzz) void { |
| 152 | const io = fuzz.io; | |
| 156 | const maker = fuzz.maker; | |
| 157 | const graph = maker.graph; | |
| 158 | const io = graph.io; | |
| 159 | const gpa = maker.gpa; | |
| 160 | ||
| 153 | 161 | fuzz.group.cancel(io); |
| 154 | 162 | fuzz.prog_node.end(); |
| 155 | fuzz.gpa.free(fuzz.run_steps); | |
| 163 | gpa.free(fuzz.run_steps); | |
| 156 | 164 | } |
| 157 | 165 | |
| 158 | 166 | fn rebuildTestsWorkerRun(run: Configuration.Step.Index, gpa: Allocator, parent_prog_node: std.Progress.Node) void { |
| ... | ... | @@ -215,19 +223,20 @@ fn fuzzWorkerRun(fuzz: *Fuzz, run: Configuration.Step.Index) void { |
| 215 | 223 | pub fn serveSourcesTar(fuzz: *Fuzz, req: *std.http.Server.Request) !void { |
| 216 | 224 | if (true) @panic("TODO"); |
| 217 | 225 | assert(fuzz.mode == .forever); |
| 226 | const gpa = fuzz.maker.gpa; | |
| 218 | 227 | |
| 219 | var arena_state: std.heap.ArenaAllocator = .init(fuzz.gpa); | |
| 228 | var arena_state: std.heap.ArenaAllocator = .init(gpa); | |
| 220 | 229 | defer arena_state.deinit(); |
| 221 | 230 | const arena = arena_state.allocator(); |
| 222 | 231 | |
| 223 | 232 | const DedupTable = std.ArrayHashMapUnmanaged(Build.Cache.Path, void, Build.Cache.Path.TableAdapter, false); |
| 224 | 233 | var dedup_table: DedupTable = .empty; |
| 225 | defer dedup_table.deinit(fuzz.gpa); | |
| 234 | defer dedup_table.deinit(gpa); | |
| 226 | 235 | |
| 227 | 236 | for (fuzz.run_steps) |run_step| { |
| 228 | 237 | const compile_inputs = run_step.producer.?.step.inputs.table; |
| 229 | 238 | for (compile_inputs.keys(), compile_inputs.values()) |dir_path, *file_list| { |
| 230 | try dedup_table.ensureUnusedCapacity(fuzz.gpa, file_list.items.len); | |
| 239 | try dedup_table.ensureUnusedCapacity(gpa, file_list.items.len); | |
| 231 | 240 | for (file_list.items) |sub_path| { |
| 232 | 241 | if (!std.mem.endsWith(u8, sub_path, ".zig")) continue; |
| 233 | 242 | const joined_path = try dir_path.join(arena, sub_path); |
| ... | ... | @@ -266,7 +275,9 @@ pub fn sendUpdate( |
| 266 | 275 | socket: *std.http.Server.WebSocket, |
| 267 | 276 | prev: *Previous, |
| 268 | 277 | ) !void { |
| 269 | const io = fuzz.io; | |
| 278 | const maker = fuzz.maker; | |
| 279 | const graph = maker.graph; | |
| 280 | const io = graph.io; | |
| 270 | 281 | |
| 271 | 282 | try fuzz.coverage_mutex.lock(io); |
| 272 | 283 | defer fuzz.coverage_mutex.unlock(io); |
| ... | ... | @@ -337,7 +348,9 @@ fn coverageRun(fuzz: *Fuzz) void { |
| 337 | 348 | } |
| 338 | 349 | |
| 339 | 350 | fn coverageRunCancelable(fuzz: *Fuzz) Io.Cancelable!void { |
| 340 | const io = fuzz.io; | |
| 351 | const maker = fuzz.maker; | |
| 352 | const graph = maker.graph; | |
| 353 | const io = graph.io; | |
| 341 | 354 | |
| 342 | 355 | try fuzz.queue_mutex.lock(io); |
| 343 | 356 | defer fuzz.queue_mutex.unlock(io); |
| ... | ... | @@ -363,8 +376,10 @@ fn prepareTables(fuzz: *Fuzz, run_step_index: Configuration.Step.Index, coverage |
| 363 | 376 | if (true) @panic("TODO"); |
| 364 | 377 | assert(fuzz.mode == .forever); |
| 365 | 378 | const ws = fuzz.mode.forever.ws; |
| 366 | const gpa = fuzz.gpa; | |
| 367 | const io = fuzz.io; | |
| 379 | const maker = fuzz.maker; | |
| 380 | const graph = maker.graph; | |
| 381 | const io = graph.io; | |
| 382 | const gpa = maker.gpa; | |
| 368 | 383 | |
| 369 | 384 | try fuzz.coverage_mutex.lock(io); |
| 370 | 385 | defer fuzz.coverage_mutex.unlock(io); |
| ... | ... | @@ -470,7 +485,10 @@ fn prepareTables(fuzz: *Fuzz, run_step_index: Configuration.Step.Index, coverage |
| 470 | 485 | } |
| 471 | 486 | |
| 472 | 487 | fn addEntryPoint(fuzz: *Fuzz, coverage_id: u64, addr: u64) error{ AlreadyReported, OutOfMemory, Canceled }!void { |
| 473 | const io = fuzz.io; | |
| 488 | const maker = fuzz.maker; | |
| 489 | const graph = maker.graph; | |
| 490 | const io = graph.io; | |
| 491 | const gpa = maker.gpa; | |
| 474 | 492 | |
| 475 | 493 | try fuzz.coverage_mutex.lock(io); |
| 476 | 494 | defer fuzz.coverage_mutex.unlock(io); |
| ... | ... | @@ -516,13 +534,15 @@ fn addEntryPoint(fuzz: *Fuzz, coverage_id: u64, addr: u64) error{ AlreadyReporte |
| 516 | 534 | }); |
| 517 | 535 | } |
| 518 | 536 | } |
| 519 | try coverage_map.entry_points.append(fuzz.gpa, @intCast(index)); | |
| 537 | try coverage_map.entry_points.append(gpa, @intCast(index)); | |
| 520 | 538 | } |
| 521 | 539 | |
| 522 | 540 | pub fn waitAndPrintReport(fuzz: *Fuzz) Io.Cancelable!void { |
| 523 | 541 | if (true) @panic("TODO"); |
| 524 | 542 | assert(fuzz.mode == .limit); |
| 525 | const io = fuzz.io; | |
| 543 | const maker = fuzz.maker; | |
| 544 | const graph = maker.graph; | |
| 545 | const io = graph.io; | |
| 526 | 546 | |
| 527 | 547 | try fuzz.group.await(io); |
| 528 | 548 | fuzz.group = .init; |
lib/compiler/Maker/Step.zig+124-49| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //! The state that maker needs in order to process a step. | |
| 1 | //! The *mutable* state that `Maker` needs in order to process one node from | |
| 2 | //! the build graph. | |
| 2 | 3 | const Step = @This(); |
| 3 | 4 | |
| 4 | 5 | const builtin = @import("builtin"); |
| ... | ... | @@ -14,14 +15,20 @@ const Configuration = std.Build.Configuration; |
| 14 | 15 | const assert = std.debug.assert; |
| 15 | 16 | |
| 16 | 17 | const WebServer = @import("WebServer.zig"); |
| 18 | const Maker = @import("../Maker.zig"); | |
| 17 | 19 | |
| 18 | pub const Compile = void; // @import("Step/Compile.zig"); | |
| 19 | pub const Run = void; // @import("Step/Run.zig"); | |
| 20 | const Compile = @import("Step/Compile.zig"); | |
| 21 | const Run = @import("Step/Run.zig"); | |
| 20 | 22 | |
| 21 | 23 | /// Avoid false sharing. |
| 22 | 24 | _: void align(std.atomic.cache_line) = {}, |
| 23 | 25 | |
| 26 | /// Extra data for specific types of steps. | |
| 27 | extended: Extended, | |
| 28 | ||
| 29 | /// This field is atomically accessed multi-threaded. | |
| 24 | 30 | state: State = .precheck_unstarted, |
| 31 | ||
| 25 | 32 | dependants: std.ArrayList(Configuration.Step.Index) = .empty, |
| 26 | 33 | /// Collects the set of files that retrigger this step to run. |
| 27 | 34 | /// |
| ... | ... | @@ -38,6 +45,8 @@ result_error_msgs: std.ArrayList([]const u8) = .empty, |
| 38 | 45 | result_error_bundle: std.zig.ErrorBundle = .empty, |
| 39 | 46 | result_stderr: []const u8 = "", |
| 40 | 47 | result_cached: bool = false, |
| 48 | /// Indicates error information is missing due to allocation failure. | |
| 49 | result_oom: bool = false, | |
| 41 | 50 | result_duration_ns: ?u64 = null, |
| 42 | 51 | /// 0 means unavailable or not reported. |
| 43 | 52 | result_peak_rss: usize = 0, |
| ... | ... | @@ -46,6 +55,70 @@ result_peak_rss: usize = 0, |
| 46 | 55 | result_failed_command: ?[]const u8 = null, |
| 47 | 56 | test_results: TestResults = .{}, |
| 48 | 57 | |
| 58 | comptime { | |
| 59 | // Common cache line size is 128. This check prevents accidentally crossing | |
| 60 | // an additional cache line. In the future it might be nice to try to fit | |
| 61 | // this struct in 128 bytes or less. | |
| 62 | assert(@sizeOf(@This()) <= 128 * 3); | |
| 63 | } | |
| 64 | ||
| 65 | pub const Extended = union(enum) { | |
| 66 | check_file: Todo, | |
| 67 | check_object: Todo, | |
| 68 | compile: Compile, | |
| 69 | config_header: Todo, | |
| 70 | fail: Todo, | |
| 71 | fmt: Todo, | |
| 72 | install_artifact: Todo, | |
| 73 | install_dir: Todo, | |
| 74 | install_file: Todo, | |
| 75 | objcopy: Todo, | |
| 76 | options: Todo, | |
| 77 | remove_dir: Todo, | |
| 78 | run: Run, | |
| 79 | top_level: Todo, | |
| 80 | translate_c: Todo, | |
| 81 | update_source_files: Todo, | |
| 82 | write_file: Todo, | |
| 83 | ||
| 84 | pub fn init(tag: Configuration.Step.Tag) Extended { | |
| 85 | return switch (tag) { | |
| 86 | .check_file => .{ .check_file = .{} }, | |
| 87 | .check_object => .{ .check_object = .{} }, | |
| 88 | .compile => .{ .compile = .{} }, | |
| 89 | .config_header => .{ .config_header = .{} }, | |
| 90 | .fail => .{ .fail = .{} }, | |
| 91 | .fmt => .{ .fmt = .{} }, | |
| 92 | .install_artifact => .{ .install_artifact = .{} }, | |
| 93 | .install_dir => .{ .install_dir = .{} }, | |
| 94 | .install_file => .{ .install_file = .{} }, | |
| 95 | .objcopy => .{ .objcopy = .{} }, | |
| 96 | .options => .{ .options = .{} }, | |
| 97 | .remove_dir => .{ .remove_dir = .{} }, | |
| 98 | .run => .{ .run = .{} }, | |
| 99 | .top_level => .{ .top_level = .{} }, | |
| 100 | .translate_c => .{ .translate_c = .{} }, | |
| 101 | .update_source_files => .{ .update_source_files = .{} }, | |
| 102 | .write_file => .{ .write_file = .{} }, | |
| 103 | }; | |
| 104 | } | |
| 105 | ||
| 106 | pub const Todo = struct { | |
| 107 | pub fn make( | |
| 108 | todo: *Todo, | |
| 109 | step_index: Configuration.Step.Index, | |
| 110 | maker: *Maker, | |
| 111 | progress_node: std.Progress.Node, | |
| 112 | ) Step.ExtendedMakeError!void { | |
| 113 | _ = todo; | |
| 114 | _ = step_index; | |
| 115 | _ = maker; | |
| 116 | _ = progress_node; | |
| 117 | @panic("TODO implement another step type"); | |
| 118 | } | |
| 119 | }; | |
| 120 | }; | |
| 121 | ||
| 49 | 122 | pub const State = enum { |
| 50 | 123 | precheck_unstarted, |
| 51 | 124 | precheck_started, |
| ... | ... | @@ -128,43 +201,51 @@ pub const TestResults = struct { |
| 128 | 201 | } |
| 129 | 202 | }; |
| 130 | 203 | |
| 131 | pub const MakeOptions = struct { | |
| 132 | progress_node: std.Progress.Node, | |
| 133 | watch: bool, | |
| 134 | web_server: ?*WebServer, | |
| 135 | /// If set, this is a timeout to enforce on all individual unit tests, in nanoseconds. | |
| 136 | unit_test_timeout_ns: ?u64, | |
| 137 | /// Not to be confused with `Build.allocator`, which is an alias of `Build.graph.arena`. | |
| 138 | gpa: Allocator, | |
| 204 | pub const MakeError = error{ | |
| 205 | /// Indicates the error is already reported. | |
| 206 | MakeFailed, | |
| 207 | MakeSkipped, | |
| 139 | 208 | }; |
| 140 | 209 | |
| 141 | pub const MakeFn = *const fn (step: *Step, options: MakeOptions) anyerror!void; | |
| 210 | pub const ExtendedMakeError = MakeError || Allocator.Error; | |
| 142 | 211 | |
| 143 | /// If the Step's `make` function reports `error.MakeFailed`, it indicates they | |
| 144 | /// have already reported the error. Otherwise, we add a simple error report | |
| 145 | /// here. | |
| 146 | pub fn make(s: *Step, options: MakeOptions) error{ MakeFailed, MakeSkipped }!void { | |
| 147 | if (true) @panic("TODO Step.make"); | |
| 148 | const arena = s.owner.allocator; | |
| 149 | const graph = s.owner.graph; | |
| 212 | pub fn make( | |
| 213 | step_index: Configuration.Step.Index, | |
| 214 | maker: *Maker, | |
| 215 | progress_node: std.Progress.Node, | |
| 216 | ) MakeError!void { | |
| 217 | const graph = maker.graph; | |
| 218 | const process_arena = graph.arena; // TODO don't leak into the process arena | |
| 150 | 219 | const io = graph.io; |
| 220 | const c = &maker.scanned_config.configuration; | |
| 221 | const conf_step = step_index.ptr(c); | |
| 222 | const s = maker.stepByIndex(step_index); | |
| 151 | 223 | |
| 152 | 224 | var start_ts: ?Io.Timestamp = t: { |
| 153 | 225 | if (!graph.time_report) break :t null; |
| 154 | if (s.id == .compile) break :t null; | |
| 155 | if (s.id == .run and s.cast(Run).?.stdio == .zig_test) break :t null; | |
| 226 | const flags = conf_step.flags(c); | |
| 227 | switch (flags.tag) { | |
| 228 | .compile => break :t null, | |
| 229 | .run => { | |
| 230 | const run_flags: Configuration.Step.Run.Flags = @bitCast(flags); | |
| 231 | if (run_flags.stdio == .zig_test) break :t null; | |
| 232 | }, | |
| 233 | else => {}, | |
| 234 | } | |
| 156 | 235 | break :t Io.Clock.awake.now(io); |
| 157 | 236 | }; |
| 158 | const make_result = s.makeFn(s, options); | |
| 237 | const make_result = switch (s.extended) { | |
| 238 | inline else => |*extended| extended.make(step_index, maker, progress_node), | |
| 239 | }; | |
| 159 | 240 | if (start_ts) |*ts| { |
| 160 | 241 | const duration = ts.untilNow(io, .awake); |
| 161 | options.web_server.?.updateTimeReportGeneric(s, duration); | |
| 242 | maker.web_server.?.updateTimeReportGeneric(step_index, duration); | |
| 162 | 243 | } |
| 163 | 244 | |
| 164 | 245 | make_result catch |err| switch (err) { |
| 165 | 246 | error.MakeFailed, error.MakeSkipped => |e| return e, |
| 166 | else => { | |
| 167 | s.result_error_msgs.append(arena, @errorName(err)) catch @panic("OOM"); | |
| 247 | error.OutOfMemory => { | |
| 248 | s.result_oom = true; | |
| 168 | 249 | return error.MakeFailed; |
| 169 | 250 | }, |
| 170 | 251 | }; |
| ... | ... | @@ -173,30 +254,19 @@ pub fn make(s: *Step, options: MakeOptions) error{ MakeFailed, MakeSkipped }!voi |
| 173 | 254 | return error.MakeFailed; |
| 174 | 255 | } |
| 175 | 256 | |
| 176 | if (s.max_rss != 0 and s.result_peak_rss > s.max_rss) { | |
| 177 | const msg = std.fmt.allocPrint(arena, "memory usage peaked at {0B:.2} ({0d} bytes), exceeding the declared upper bound of {1B:.2} ({1d} bytes)", .{ | |
| 178 | s.result_peak_rss, s.max_rss, | |
| 179 | }) catch @panic("OOM"); | |
| 180 | s.result_error_msgs.append(arena, msg) catch @panic("OOM"); | |
| 257 | const max_rss = conf_step.max_rss.toBytes(); | |
| 258 | if (max_rss != 0 and s.result_peak_rss > max_rss) { | |
| 259 | if (std.fmt.allocPrint( | |
| 260 | process_arena, | |
| 261 | "memory usage peaked at {0B:.2} ({0d} bytes), exceeding the declared upper bound of {1B:.2} ({1d} bytes)", | |
| 262 | .{ s.result_peak_rss, max_rss }, | |
| 263 | )) |msg| { | |
| 264 | s.oomWrap(s.result_error_msgs.append(process_arena, msg)); | |
| 265 | } else |_| s.result_oom = true; | |
| 181 | 266 | } |
| 182 | 267 | } |
| 183 | 268 | |
| 184 | /// Implementation detail of file watching. Prepares the step for being re-evaluated. | |
| 185 | /// Returns `true` if the step was newly invalidated, `false` if it was already invalidated. | |
| 186 | pub fn invalidateResult(step: *Step, gpa: Allocator) bool { | |
| 187 | if (true) @panic("TODO Step.invalidateResult"); | |
| 188 | if (step.state == .precheck_done) return false; | |
| 189 | assert(step.pending_deps == 0); | |
| 190 | step.state = .precheck_done; | |
| 191 | step.reset(gpa); | |
| 192 | for (step.dependants.items) |dependant| { | |
| 193 | _ = dependant.invalidateResult(gpa); | |
| 194 | dependant.pending_deps += 1; | |
| 195 | } | |
| 196 | return true; | |
| 197 | } | |
| 198 | ||
| 199 | /// Implementation detail of file watching and forced rebuilds. Prepares the step for being re-evaluated. | |
| 269 | /// Prepares the step for being re-evaluated. | |
| 200 | 270 | pub fn reset(step: *Step, gpa: Allocator) void { |
| 201 | 271 | assert(step.state == .precheck_done); |
| 202 | 272 | |
| ... | ... | @@ -547,9 +617,8 @@ fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool, web_server: ?*WebSer |
| 547 | 617 | } |
| 548 | 618 | |
| 549 | 619 | pub fn getZigProcess(s: *Step) ?*ZigProcess { |
| 550 | if (true) @panic("TODO getZigProcess"); | |
| 551 | return switch (s.id) { | |
| 552 | .compile => s.cast(Compile).?.zig_process, | |
| 620 | return switch (s.extended) { | |
| 621 | .compile => |*compile| compile.zig_process, | |
| 553 | 622 | else => null, |
| 554 | 623 | }; |
| 555 | 624 | } |
| ... | ... | @@ -838,3 +907,9 @@ pub fn allocPrintCmd( |
| 838 | 907 | } |
| 839 | 908 | return aw.toOwnedSlice(); |
| 840 | 909 | } |
| 910 | ||
| 911 | fn oomWrap(s: *Step, result: error{OutOfMemory}!void) void { | |
| 912 | result catch { | |
| 913 | s.result_oom = true; | |
| 914 | }; | |
| 915 | } |
lib/compiler/Maker/Step/Compile.zig+123-42| ... | ... | @@ -1,19 +1,40 @@ |
| 1 | const Compile = @This(); | |
| 2 | ||
| 3 | const std = @import("std"); | |
| 4 | const Allocator = std.mem.Allocator; | |
| 5 | const Configuration = std.Build.Configuration; | |
| 6 | const Dir = std.Io.Dir; | |
| 7 | const Path = std.Build.Cache.Path; | |
| 8 | const Module = std.Build.Configuration.Module; | |
| 9 | const Io = std.Io; | |
| 10 | const Sha256 = std.crypto.hash.sha2.Sha256; | |
| 11 | const assert = std.debug.assert; | |
| 12 | const mem = std.mem; | |
| 13 | ||
| 14 | const Step = @import("../Step.zig"); | |
| 15 | const Maker = @import("../../Maker.zig"); | |
| 16 | ||
| 1 | 17 | /// Populated during the make phase when there is a long-lived compiler process. |
| 2 | 18 | /// Managed by the build runner, not user build script. |
| 3 | zig_process: ?*Step.ZigProcess, | |
| 4 | ||
| 5 | fn make(step: *Step, options: Step.MakeOptions) !void { | |
| 6 | const b = step.owner; | |
| 7 | const compile: *Compile = @fieldParentPtr("step", step); | |
| 8 | ||
| 9 | const zig_args = try getZigArgs(compile, false); | |
| 19 | zig_process: ?*Step.ZigProcess = null, | |
| 20 | ||
| 21 | pub fn make( | |
| 22 | compile: *Compile, | |
| 23 | step_index: Configuration.Step.Index, | |
| 24 | maker: *Maker, | |
| 25 | progress_node: std.Progress.Node, | |
| 26 | ) Step.ExtendedMakeError!void { | |
| 27 | if (true) @panic("TODO implement compile.make()"); | |
| 28 | const graph = maker.graph; | |
| 29 | const step = maker.stepByIndex(step_index); | |
| 30 | const zig_args = try getZigArgs(compile, maker, false); | |
| 31 | const process_arena = graph.arena; // TODO don't leak into the process_arena | |
| 10 | 32 | |
| 11 | 33 | const maybe_output_dir = step.evalZigProcess( |
| 12 | 34 | zig_args, |
| 13 | options.progress_node, | |
| 14 | (b.graph.incremental == true) and (options.watch or options.web_server != null), | |
| 15 | options.web_server, | |
| 16 | options.gpa, | |
| 35 | progress_node, | |
| 36 | (graph.incremental == true) and (maker.watch or maker.web_server != null), | |
| 37 | maker, | |
| 17 | 38 | ) catch |err| switch (err) { |
| 18 | 39 | error.NeedCompileErrorCheck => { |
| 19 | 40 | assert(compile.expect_errors != null); |
| ... | ... | @@ -26,7 +47,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void { |
| 26 | 47 | // Update generated files |
| 27 | 48 | if (maybe_output_dir) |output_dir| { |
| 28 | 49 | if (compile.emit_directory) |lp| { |
| 29 | lp.path = b.fmt("{f}", .{output_dir}); | |
| 50 | lp.path = try std.fmt.allocPrint(process_arena, "{f}", .{output_dir}); | |
| 30 | 51 | } |
| 31 | 52 | |
| 32 | 53 | // zig fmt: off |
| ... | ... | @@ -49,22 +70,23 @@ fn make(step: *Step, options: Step.MakeOptions) !void { |
| 49 | 70 | { |
| 50 | 71 | try doAtomicSymLinks( |
| 51 | 72 | step, |
| 52 | compile.getEmittedBin().getPath2(b, step), | |
| 73 | compile.getEmittedBin().getPath2(step.owner, step), | |
| 53 | 74 | compile.major_only_filename.?, |
| 54 | 75 | compile.name_only_filename.?, |
| 55 | 76 | ); |
| 56 | 77 | } |
| 57 | 78 | } |
| 58 | 79 | |
| 59 | fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 { | |
| 80 | fn getZigArgs(compile: *Compile, maker: *Maker, fuzz: bool) ![][]const u8 { | |
| 60 | 81 | const step = &compile.step; |
| 61 | 82 | const b = step.owner; |
| 62 | const arena = b.allocator; | |
| 83 | const graph = maker.graph; | |
| 84 | const arena = graph.arena; // TODO don't leak into the process arena | |
| 63 | 85 | |
| 64 | 86 | var zig_args = std.array_list.Managed([]const u8).init(arena); |
| 65 | 87 | defer zig_args.deinit(); |
| 66 | 88 | |
| 67 | try zig_args.append(b.graph.zig_exe); | |
| 89 | try zig_args.append(graph.zig_exe); | |
| 68 | 90 | |
| 69 | 91 | const cmd = switch (compile.kind) { |
| 70 | 92 | .lib => "build-lib", |
| ... | ... | @@ -78,7 +100,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 { |
| 78 | 100 | if (b.reference_trace) |some| { |
| 79 | 101 | try zig_args.append(try std.fmt.allocPrint(arena, "-freference-trace={d}", .{some})); |
| 80 | 102 | } |
| 81 | try addFlag(&zig_args, "allow-so-scripts", compile.allow_so_scripts orelse b.graph.allow_so_scripts); | |
| 103 | try addFlag(&zig_args, "allow-so-scripts", compile.allow_so_scripts orelse graph.allow_so_scripts); | |
| 82 | 104 | |
| 83 | 105 | try addFlag(&zig_args, "llvm", compile.use_llvm); |
| 84 | 106 | try addFlag(&zig_args, "lld", compile.use_lld); |
| ... | ... | @@ -118,7 +140,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 { |
| 118 | 140 | // module, along with any arguments that need to be passed to the |
| 119 | 141 | // compiler for each module individually. |
| 120 | 142 | var seen_system_libs: std.StringHashMapUnmanaged([]const []const u8) = .empty; |
| 121 | var frameworks: std.StringArrayHashMapUnmanaged(Module.LinkFrameworkOptions) = .empty; | |
| 143 | var frameworks: std.StringArrayHashMapUnmanaged(Module.FrameworkFlags) = .empty; | |
| 122 | 144 | |
| 123 | 145 | var prev_has_cflags = false; |
| 124 | 146 | var prev_has_rcflags = false; |
| ... | ... | @@ -130,7 +152,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 { |
| 130 | 152 | |
| 131 | 153 | // Fully recursive iteration including dynamic libraries to detect |
| 132 | 154 | // libc and libc++ linkage. |
| 133 | for (compile.getCompileDependencies(true)) |some_compile| { | |
| 155 | for (getCompileDependencies(true)) |some_compile| { | |
| 134 | 156 | for (some_compile.root_module.getGraph().modules) |mod| { |
| 135 | 157 | if (mod.link_libc == true) compile.is_linking_libc = true; |
| 136 | 158 | if (mod.link_libcpp == true) compile.is_linking_libcpp = true; |
| ... | ... | @@ -141,7 +163,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 { |
| 141 | 163 | |
| 142 | 164 | // For this loop, don't chase dynamic libraries because their link |
| 143 | 165 | // objects are already linked. |
| 144 | for (compile.getCompileDependencies(false)) |dep_compile| { | |
| 166 | for (getCompileDependencies(false)) |dep_compile| { | |
| 145 | 167 | for (dep_compile.root_module.getGraph().modules) |mod| { |
| 146 | 168 | // While walking transitive dependencies, if a given link object is |
| 147 | 169 | // already included in a library, it should not redundantly be |
| ... | ... | @@ -207,7 +229,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 { |
| 207 | 229 | switch (system_lib.use_pkg_config) { |
| 208 | 230 | .no => try zig_args.append(b.fmt("{s}{s}", .{ prefix, system_lib.name })), |
| 209 | 231 | .yes, .force => { |
| 210 | if (compile.runPkgConfig(system_lib.name)) |result| { | |
| 232 | if (compile.runPkgConfig(maker, system_lib.name)) |result| { | |
| 211 | 233 | try zig_args.appendSlice(result.cflags); |
| 212 | 234 | try zig_args.appendSlice(result.libs); |
| 213 | 235 | try seen_system_libs.put(arena, system_lib.name, result.cflags); |
| ... | ... | @@ -227,7 +249,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 { |
| 227 | 249 | })); |
| 228 | 250 | }, |
| 229 | 251 | .force => { |
| 230 | panic("pkg-config failed for library {s}", .{system_lib.name}); | |
| 252 | return step.fail("pkg-config failed for library {s}", .{system_lib.name}); | |
| 231 | 253 | }, |
| 232 | 254 | .no => unreachable, |
| 233 | 255 | }, |
| ... | ... | @@ -272,7 +294,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 { |
| 272 | 294 | if (other.linkage == .dynamic and |
| 273 | 295 | compile.rootModuleTarget().os.tag != .windows) |
| 274 | 296 | { |
| 275 | if (fs.path.dirname(full_path_lib)) |dirname| { | |
| 297 | if (Dir.path.dirname(full_path_lib)) |dirname| { | |
| 276 | 298 | try zig_args.append("-rpath"); |
| 277 | 299 | try zig_args.append(dirname); |
| 278 | 300 | } |
| ... | ... | @@ -479,7 +501,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 { |
| 479 | 501 | if (b.verbose_link or compile.verbose_link) try zig_args.append("--verbose-link"); |
| 480 | 502 | if (b.verbose_cc or compile.verbose_cc) try zig_args.append("--verbose-cc"); |
| 481 | 503 | if (b.verbose_llvm_cpu_features) try zig_args.append("--verbose-llvm-cpu-features"); |
| 482 | if (b.graph.time_report) try zig_args.append("--time-report"); | |
| 504 | if (graph.time_report) try zig_args.append("--time-report"); | |
| 483 | 505 | |
| 484 | 506 | if (compile.generated_asm != null) try zig_args.append("-femit-asm"); |
| 485 | 507 | if (compile.generated_bin == null) try zig_args.append("-fno-emit-bin"); |
| ... | ... | @@ -555,9 +577,9 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 { |
| 555 | 577 | try zig_args.append(b.cache_root.path orelse "."); |
| 556 | 578 | |
| 557 | 579 | try zig_args.append("--global-cache-dir"); |
| 558 | try zig_args.append(b.graph.global_cache_root.path orelse "."); | |
| 580 | try zig_args.append(graph.global_cache_root.path orelse "."); | |
| 559 | 581 | |
| 560 | if (b.graph.debug_compiler_runtime_libs) |mode| | |
| 582 | if (graph.debug_compiler_runtime_libs) |mode| | |
| 561 | 583 | try zig_args.append(b.fmt("--debug-rt={t}", .{mode})); |
| 562 | 584 | |
| 563 | 585 | try zig_args.append("--name"); |
| ... | ... | @@ -681,7 +703,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 { |
| 681 | 703 | |
| 682 | 704 | // -I and -L arguments that appear after the last --mod argument apply to all modules. |
| 683 | 705 | const cwd: Io.Dir = .cwd(); |
| 684 | const io = b.graph.io; | |
| 706 | const io = graph.io; | |
| 685 | 707 | |
| 686 | 708 | for (b.search_prefixes.items) |search_prefix| { |
| 687 | 709 | var prefix_dir = cwd.openDir(io, search_prefix, .{}) catch |err| { |
| ... | ... | @@ -734,8 +756,8 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 { |
| 734 | 756 | |
| 735 | 757 | const opt_zig_lib_dir = if (compile.zig_lib_dir) |dir| |
| 736 | 758 | dir.getPath2(b, step) |
| 737 | else if (b.graph.zig_lib_directory.path) |_| | |
| 738 | b.fmt("{f}", .{b.graph.zig_lib_directory}) | |
| 759 | else if (graph.zig_lib_directory.path) |_| | |
| 760 | b.fmt("{f}", .{graph.zig_lib_directory}) | |
| 739 | 761 | else |
| 740 | 762 | null; |
| 741 | 763 | |
| ... | ... | @@ -769,7 +791,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 { |
| 769 | 791 | "--error-limit", b.fmt("{d}", .{err_limit}), |
| 770 | 792 | }); |
| 771 | 793 | |
| 772 | try addFlag(&zig_args, "incremental", b.graph.incremental); | |
| 794 | try addFlag(&zig_args, "incremental", graph.incremental); | |
| 773 | 795 | |
| 774 | 796 | try zig_args.append("--listen=-"); |
| 775 | 797 | |
| ... | ... | @@ -814,7 +836,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 { |
| 814 | 836 | var args_hex_hash: [Sha256.digest_length * 2]u8 = undefined; |
| 815 | 837 | _ = try std.fmt.bufPrint(&args_hex_hash, "{x}", .{&args_hash}); |
| 816 | 838 | |
| 817 | const args_file = "args" ++ fs.path.sep_str ++ args_hex_hash; | |
| 839 | const args_file = "args" ++ Dir.path.sep_str ++ args_hex_hash; | |
| 818 | 840 | if (b.cache_root.handle.access(io, args_file, .{})) |_| { |
| 819 | 841 | // The args file is already present from a previous run. |
| 820 | 842 | } else |err| switch (err) { |
| ... | ... | @@ -859,7 +881,9 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 { |
| 859 | 881 | return try zig_args.toOwnedSlice(); |
| 860 | 882 | } |
| 861 | 883 | |
| 862 | pub fn rebuildInFuzzMode(c: *Compile, gpa: Allocator, progress_node: std.Progress.Node) !Path { | |
| 884 | pub fn rebuildInFuzzMode(c: *Compile, maker: *Maker, progress_node: std.Progress.Node) !Path { | |
| 885 | const gpa = maker.graph.gpa; | |
| 886 | ||
| 863 | 887 | c.step.result_error_msgs.clearRetainingCapacity(); |
| 864 | 888 | c.step.result_stderr = ""; |
| 865 | 889 | |
| ... | ... | @@ -871,21 +895,23 @@ pub fn rebuildInFuzzMode(c: *Compile, gpa: Allocator, progress_node: std.Progres |
| 871 | 895 | c.step.result_failed_command = null; |
| 872 | 896 | } |
| 873 | 897 | |
| 874 | const zig_args = try getZigArgs(c, true); | |
| 898 | const zig_args = try getZigArgs(c, maker, true); | |
| 875 | 899 | const maybe_output_bin_path = try c.step.evalZigProcess(zig_args, progress_node, false, null, gpa); |
| 876 | 900 | return maybe_output_bin_path.?; |
| 877 | 901 | } |
| 878 | 902 | |
| 879 | 903 | pub fn doAtomicSymLinks( |
| 880 | 904 | step: *Step, |
| 905 | maker: *Maker, | |
| 881 | 906 | output_path: []const u8, |
| 882 | 907 | filename_major_only: []const u8, |
| 883 | 908 | filename_name_only: []const u8, |
| 884 | 909 | ) !void { |
| 885 | 910 | const b = step.owner; |
| 886 | const io = b.graph.io; | |
| 887 | const out_dir = fs.path.dirname(output_path) orelse "."; | |
| 888 | const out_basename = fs.path.basename(output_path); | |
| 911 | const graph = maker.graph; | |
| 912 | const io = graph.io; | |
| 913 | const out_dir = Dir.path.dirname(output_path) orelse "."; | |
| 914 | const out_basename = Dir.path.basename(output_path); | |
| 889 | 915 | // sym link for libfoo.so.1 to libfoo.so.1.2.3 |
| 890 | 916 | const major_only_path = b.pathJoin(&.{ out_dir, filename_major_only }); |
| 891 | 917 | const cwd: Io.Dir = .cwd(); |
| ... | ... | @@ -903,10 +929,24 @@ pub fn doAtomicSymLinks( |
| 903 | 929 | }; |
| 904 | 930 | } |
| 905 | 931 | |
| 906 | fn execPkgConfigList(b: *std.Build, out_code: *u8) (PkgConfigError || RunError)![]const PkgConfigPkg { | |
| 907 | const pkg_config_exe = b.graph.environ_map.get("PKG_CONFIG") orelse "pkg-config"; | |
| 908 | const stdout = try b.runAllowFail(&[_][]const u8{ pkg_config_exe, "--list-all" }, out_code, .ignore); | |
| 909 | var list = std.array_list.Managed(PkgConfigPkg).init(b.allocator); | |
| 932 | pub const PkgConfigError = error{ | |
| 933 | PkgConfigCrashed, | |
| 934 | PkgConfigFailed, | |
| 935 | PkgConfigNotInstalled, | |
| 936 | PkgConfigInvalidOutput, | |
| 937 | }; | |
| 938 | ||
| 939 | pub const PkgConfigPkg = struct { | |
| 940 | name: []const u8, | |
| 941 | desc: []const u8, | |
| 942 | }; | |
| 943 | ||
| 944 | fn execPkgConfigList(maker: *Maker, out_code: *u8) (PkgConfigError || Maker.RunError)![]const PkgConfigPkg { | |
| 945 | const graph = maker.graph; | |
| 946 | const process_arena = graph.arena; // TODO don't leak into process arena | |
| 947 | const pkg_config_exe = graph.environ_map.get("PKG_CONFIG") orelse "pkg-config"; | |
| 948 | const stdout = try maker.runAllowFail(&[_][]const u8{ pkg_config_exe, "--list-all" }, out_code, .ignore); | |
| 949 | var list = std.array_list.Managed(PkgConfigPkg).init(process_arena); | |
| 910 | 950 | errdefer list.deinit(); |
| 911 | 951 | var line_it = mem.tokenizeAny(u8, stdout, "\r\n"); |
| 912 | 952 | while (line_it.next()) |line| { |
| ... | ... | @@ -960,7 +1000,8 @@ const PkgConfigResult = struct { |
| 960 | 1000 | |
| 961 | 1001 | /// Run pkg-config for the given library name and parse the output, returning the arguments |
| 962 | 1002 | /// that should be passed to zig to link the given library. |
| 963 | fn runPkgConfig(compile: *Compile, lib_name: []const u8) !PkgConfigResult { | |
| 1003 | fn runPkgConfig(compile: *Compile, maker: *Maker, lib_name: []const u8) !PkgConfigResult { | |
| 1004 | const graph = maker.graph; | |
| 964 | 1005 | const wl_rpath_prefix = "-Wl,-rpath,"; |
| 965 | 1006 | |
| 966 | 1007 | const b = compile.step.owner; |
| ... | ... | @@ -1013,7 +1054,7 @@ fn runPkgConfig(compile: *Compile, lib_name: []const u8) !PkgConfigResult { |
| 1013 | 1054 | }; |
| 1014 | 1055 | |
| 1015 | 1056 | var code: u8 = undefined; |
| 1016 | const pkg_config_exe = b.graph.environ_map.get("PKG_CONFIG") orelse "pkg-config"; | |
| 1057 | const pkg_config_exe = graph.environ_map.get("PKG_CONFIG") orelse "pkg-config"; | |
| 1017 | 1058 | const stdout = if (b.runAllowFail(&[_][]const u8{ |
| 1018 | 1059 | pkg_config_exe, |
| 1019 | 1060 | pkg_name, |
| ... | ... | @@ -1198,3 +1239,43 @@ fn moduleNeedsCliArg(mod: *const Module) bool { |
| 1198 | 1239 | } else false; |
| 1199 | 1240 | } |
| 1200 | 1241 | |
| 1242 | const CliNamedModules = struct { | |
| 1243 | modules: std.AutoArrayHashMapUnmanaged(*Module, void), | |
| 1244 | names: std.StringArrayHashMapUnmanaged(void), | |
| 1245 | ||
| 1246 | /// Traverse the whole dependency graph and give every module a unique | |
| 1247 | /// name, ideally one named after what it's called somewhere in the graph. | |
| 1248 | /// It will help here to have both a mapping from module to name and a set | |
| 1249 | /// of all the currently-used names. | |
| 1250 | fn init(arena: Allocator, root_module: *Module) Allocator.Error!CliNamedModules { | |
| 1251 | var compile: CliNamedModules = .{ | |
| 1252 | .modules = .{}, | |
| 1253 | .names = .{}, | |
| 1254 | }; | |
| 1255 | const graph = root_module.getGraph(); | |
| 1256 | { | |
| 1257 | assert(graph.modules[0] == root_module); | |
| 1258 | try compile.modules.put(arena, root_module, {}); | |
| 1259 | try compile.names.put(arena, "root", {}); | |
| 1260 | } | |
| 1261 | for (graph.modules[1..], graph.names[1..]) |mod, orig_name| { | |
| 1262 | var name = orig_name; | |
| 1263 | var n: usize = 0; | |
| 1264 | while (true) { | |
| 1265 | const gop = try compile.names.getOrPut(arena, name); | |
| 1266 | if (!gop.found_existing) { | |
| 1267 | try compile.modules.putNoClobber(arena, mod, {}); | |
| 1268 | break; | |
| 1269 | } | |
| 1270 | name = try std.fmt.allocPrint(arena, "{s}{d}", .{ orig_name, n }); | |
| 1271 | n += 1; | |
| 1272 | } | |
| 1273 | } | |
| 1274 | return compile; | |
| 1275 | } | |
| 1276 | }; | |
| 1277 | ||
| 1278 | fn getCompileDependencies(chase_dynamic: bool) void { | |
| 1279 | _ = chase_dynamic; | |
| 1280 | @panic("TODO"); | |
| 1281 | } |
lib/compiler/Maker/Step/Run.zig+126-117| ... | ... | @@ -3,38 +3,46 @@ const Run = @This(); |
| 3 | 3 | const builtin = @import("builtin"); |
| 4 | 4 | |
| 5 | 5 | const std = @import("std"); |
| 6 | const Io = std.Io; | |
| 6 | const Cache = std.Build.Cache; | |
| 7 | const Configuration = std.Build.Configuration; | |
| 7 | 8 | const Dir = std.Io.Dir; |
| 8 | const mem = std.mem; | |
| 9 | const process = std.process; | |
| 10 | 9 | const EnvMap = std.process.Environ.Map; |
| 11 | const assert = std.debug.assert; | |
| 12 | const Cache = std.Build.Cache; | |
| 10 | const Io = std.Io; | |
| 13 | 11 | const Path = std.Build.Cache.Path; |
| 12 | const assert = std.debug.assert; | |
| 13 | const mem = std.mem; | |
| 14 | const process = std.process; | |
| 14 | 15 | |
| 15 | 16 | const Step = @import("../Step.zig"); |
| 17 | const Maker = @import("../../Maker.zig"); | |
| 16 | 18 | |
| 17 | 19 | /// If this is a Zig unit test binary, this tracks the names of the unit |
| 18 | 20 | /// tests that are also fuzz tests. Indexes cannot be used as they may |
| 19 | 21 | /// change between reruns. |
| 20 | fuzz_tests: std.ArrayList([]const u8), | |
| 22 | fuzz_tests: std.ArrayList([]const u8) = .empty, | |
| 21 | 23 | cached_test_metadata: ?CachedTestMetadata = null, |
| 22 | 24 | |
| 23 | 25 | /// Populated during the fuzz phase if this run step corresponds to a unit test |
| 24 | 26 | /// executable that contains fuzz tests. |
| 25 | rebuilt_executable: ?Path, | |
| 27 | rebuilt_executable: ?Path = null, | |
| 26 | 28 | |
| 27 | fn make(step: *Step, options: Step.MakeOptions) !void { | |
| 28 | const b = step.owner; | |
| 29 | const io = b.graph.io; | |
| 30 | const arena = b.allocator; | |
| 31 | const run: *Run = @fieldParentPtr("step", step); | |
| 29 | pub fn make( | |
| 30 | run: *Run, | |
| 31 | step_index: Configuration.Step.Index, | |
| 32 | maker: *Maker, | |
| 33 | progress_node: std.Progress.Node, | |
| 34 | ) Step.ExtendedMakeError!void { | |
| 35 | if (true) @panic("TODO implement run.make()"); | |
| 36 | const graph = maker.graph; | |
| 37 | const step = maker.stepByIndex(step_index); | |
| 38 | const io = graph.io; | |
| 39 | const arena = graph.arena; // TODO don't leak into the process arena | |
| 32 | 40 | const has_side_effects = run.hasSideEffects(); |
| 33 | 41 | |
| 34 | 42 | var argv_list = std.array_list.Managed([]const u8).init(arena); |
| 35 | 43 | var output_placeholders = std.array_list.Managed(IndexedOutput).init(arena); |
| 36 | 44 | |
| 37 | var man = b.graph.cache.obtain(); | |
| 45 | var man = graph.cache.obtain(); | |
| 38 | 46 | defer man.deinit(); |
| 39 | 47 | |
| 40 | 48 | if (run.environ_map) |environ_map| { |
| ... | ... | @@ -54,19 +62,19 @@ fn make(step: *Step, options: Step.MakeOptions) !void { |
| 54 | 62 | man.hash.addBytes(bytes); |
| 55 | 63 | }, |
| 56 | 64 | .lazy_path => |file| { |
| 57 | const file_path = file.lazy_path.getPath3(b, step); | |
| 58 | try argv_list.append(b.fmt("{s}{s}", .{ file.prefix, run.convertPathArg(file_path) })); | |
| 65 | const file_path = file.lazy_path.getPath3(graph, step); | |
| 66 | try argv_list.append(graph.fmt("{s}{s}", .{ file.prefix, run.convertPathArg(maker, file_path) })); | |
| 59 | 67 | man.hash.addBytes(file.prefix); |
| 60 | 68 | _ = try man.addFilePath(file_path, null); |
| 61 | 69 | }, |
| 62 | 70 | .decorated_directory => |dd| { |
| 63 | const file_path = dd.lazy_path.getPath3(b, step); | |
| 64 | const resolved_arg = b.fmt("{s}{s}{s}", .{ dd.prefix, run.convertPathArg(file_path), dd.suffix }); | |
| 71 | const file_path = dd.lazy_path.getPath3(graph, step); | |
| 72 | const resolved_arg = graph.fmt("{s}{s}{s}", .{ dd.prefix, run.convertPathArg(maker, file_path), dd.suffix }); | |
| 65 | 73 | try argv_list.append(resolved_arg); |
| 66 | 74 | man.hash.addBytes(resolved_arg); |
| 67 | 75 | }, |
| 68 | 76 | .file_content => |file_plp| { |
| 69 | const file_path = file_plp.lazy_path.getPath3(b, step); | |
| 77 | const file_path = file_plp.lazy_path.getPath3(graph, step); | |
| 70 | 78 | |
| 71 | 79 | var result: std.Io.Writer.Allocating = .init(arena); |
| 72 | 80 | errdefer result.deinit(); |
| ... | ... | @@ -99,13 +107,13 @@ fn make(step: *Step, options: Step.MakeOptions) !void { |
| 99 | 107 | |
| 100 | 108 | if (artifact.rootModuleTarget().os.tag == .windows) { |
| 101 | 109 | // On Windows we don't have rpaths so we have to add .dll search paths to PATH |
| 102 | run.addPathForDynLibs(artifact); | |
| 110 | addPathForDynLibs(artifact); | |
| 103 | 111 | } |
| 104 | 112 | const file_path = artifact.installed_path orelse artifact.generated_bin.?.path.?; |
| 105 | 113 | |
| 106 | try argv_list.append(b.fmt("{s}{s}", .{ | |
| 114 | try argv_list.append(graph.fmt("{s}{s}", .{ | |
| 107 | 115 | pa.prefix, |
| 108 | run.convertPathArg(.{ .root_dir = .cwd(), .sub_path = file_path }), | |
| 116 | run.convertPathArg(maker, .{ .root_dir = .cwd(), .sub_path = file_path }), | |
| 109 | 117 | })); |
| 110 | 118 | |
| 111 | 119 | _ = try man.addFile(file_path, null); |
| ... | ... | @@ -131,7 +139,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void { |
| 131 | 139 | man.hash.addBytes(bytes); |
| 132 | 140 | }, |
| 133 | 141 | .lazy_path => |lazy_path| { |
| 134 | const file_path = lazy_path.getPath2(b, step); | |
| 142 | const file_path = lazy_path.getPath2(graph, step); | |
| 135 | 143 | _ = try man.addFile(file_path, null); |
| 136 | 144 | }, |
| 137 | 145 | .none => {}, |
| ... | ... | @@ -147,14 +155,15 @@ fn make(step: *Step, options: Step.MakeOptions) !void { |
| 147 | 155 | man.hash.add(captured.trim_whitespace); |
| 148 | 156 | } |
| 149 | 157 | |
| 150 | hashStdIo(&man.hash, run.stdio); | |
| 158 | std.log.err("TODO hashStdIo", .{}); | |
| 159 | //hashStdIo(&man.hash, run.stdio); | |
| 151 | 160 | |
| 152 | 161 | for (run.file_inputs.items) |lazy_path| { |
| 153 | _ = try man.addFile(lazy_path.getPath2(b, step), null); | |
| 162 | _ = try man.addFile(lazy_path.getPath2(graph, step), null); | |
| 154 | 163 | } |
| 155 | 164 | |
| 156 | 165 | if (run.cwd) |cwd| { |
| 157 | const cwd_path = cwd.getPath3(b, step); | |
| 166 | const cwd_path = cwd.getPath3(graph, step); | |
| 158 | 167 | _ = man.hash.addBytes(try cwd_path.toString(arena)); |
| 159 | 168 | } |
| 160 | 169 | |
| ... | ... | @@ -165,9 +174,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void { |
| 165 | 174 | try populateGeneratedPaths( |
| 166 | 175 | arena, |
| 167 | 176 | output_placeholders.items, |
| 168 | run.captured_stdout, | |
| 169 | run.captured_stderr, | |
| 170 | b.cache_root, | |
| 177 | graph.cache_root, | |
| 171 | 178 | &digest, |
| 172 | 179 | ); |
| 173 | 180 | |
| ... | ... | @@ -185,36 +192,34 @@ fn make(step: *Step, options: Step.MakeOptions) !void { |
| 185 | 192 | try populateGeneratedPaths( |
| 186 | 193 | arena, |
| 187 | 194 | output_placeholders.items, |
| 188 | run.captured_stdout, | |
| 189 | run.captured_stderr, | |
| 190 | b.cache_root, | |
| 195 | graph.cache_root, | |
| 191 | 196 | &digest, |
| 192 | 197 | ); |
| 193 | 198 | |
| 194 | 199 | const output_dir_path = "o" ++ Dir.path.sep_str ++ &digest; |
| 195 | 200 | for (output_placeholders.items) |placeholder| { |
| 196 | const output_sub_path = b.pathJoin(&.{ output_dir_path, placeholder.output.basename }); | |
| 201 | const output_sub_path = graph.pathJoin(&.{ output_dir_path, placeholder.output.basename }); | |
| 197 | 202 | const output_sub_dir_path = switch (placeholder.tag) { |
| 198 | 203 | .output_file => Dir.path.dirname(output_sub_path).?, |
| 199 | 204 | .output_directory => output_sub_path, |
| 200 | 205 | else => unreachable, |
| 201 | 206 | }; |
| 202 | b.cache_root.handle.createDirPath(io, output_sub_dir_path) catch |err| { | |
| 203 | return step.fail("unable to make path '{f}{s}': {s}", .{ | |
| 204 | b.cache_root, output_sub_dir_path, @errorName(err), | |
| 207 | graph.cache_root.handle.createDirPath(io, output_sub_dir_path) catch |err| { | |
| 208 | return step.fail("unable to make path '{f}{s}': {t}", .{ | |
| 209 | graph.cache_root, output_sub_dir_path, err, | |
| 205 | 210 | }); |
| 206 | 211 | }; |
| 207 | const arg_output_path = run.convertPathArg(.{ | |
| 212 | const arg_output_path = run.convertPathArg(maker, .{ | |
| 208 | 213 | .root_dir = .cwd(), |
| 209 | 214 | .sub_path = placeholder.output.generated_file.getPath(), |
| 210 | 215 | }); |
| 211 | 216 | argv_list.items[placeholder.index] = if (placeholder.output.prefix.len == 0) |
| 212 | 217 | arg_output_path |
| 213 | 218 | else |
| 214 | b.fmt("{s}{s}", .{ placeholder.output.prefix, arg_output_path }); | |
| 219 | graph.fmt("{s}{s}", .{ placeholder.output.prefix, arg_output_path }); | |
| 215 | 220 | } |
| 216 | 221 | |
| 217 | try runCommand(run, argv_list.items, has_side_effects, output_dir_path, options, null); | |
| 222 | try runCommand(run, maker, progress_node, argv_list.items, has_side_effects, output_dir_path, null); | |
| 218 | 223 | if (!has_side_effects) try step.writeManifestAndWatch(&man); |
| 219 | 224 | return; |
| 220 | 225 | }; |
| ... | ... | @@ -226,32 +231,32 @@ fn make(step: *Step, options: Step.MakeOptions) !void { |
| 226 | 231 | |
| 227 | 232 | for (output_placeholders.items) |placeholder| { |
| 228 | 233 | const output_components = .{ tmp_dir_path, placeholder.output.basename }; |
| 229 | const output_sub_path = b.pathJoin(&output_components); | |
| 234 | const output_sub_path = graph.pathJoin(&output_components); | |
| 230 | 235 | const output_sub_dir_path = switch (placeholder.tag) { |
| 231 | 236 | .output_file => Dir.path.dirname(output_sub_path).?, |
| 232 | 237 | .output_directory => output_sub_path, |
| 233 | 238 | else => unreachable, |
| 234 | 239 | }; |
| 235 | b.cache_root.handle.createDirPath(io, output_sub_dir_path) catch |err| { | |
| 236 | return step.fail("unable to make path '{f}{s}': {s}", .{ | |
| 237 | b.cache_root, output_sub_dir_path, @errorName(err), | |
| 240 | graph.cache_root.handle.createDirPath(io, output_sub_dir_path) catch |err| { | |
| 241 | return step.fail("unable to make path '{f}{s}': {t}", .{ | |
| 242 | graph.cache_root, output_sub_dir_path, err, | |
| 238 | 243 | }); |
| 239 | 244 | }; |
| 240 | const raw_output_path: Cache.Path = .{ | |
| 241 | .root_dir = b.cache_root, | |
| 242 | .sub_path = b.pathJoin(&output_components), | |
| 245 | const raw_output_path: Path = .{ | |
| 246 | .root_dir = graph.cache_root, | |
| 247 | .sub_path = graph.pathJoin(&output_components), | |
| 243 | 248 | }; |
| 244 | placeholder.output.generated_file.path = raw_output_path.toString(b.graph.arena) catch @panic("OOM"); | |
| 245 | argv_list.items[placeholder.index] = b.fmt("{s}{s}", .{ | |
| 249 | placeholder.output.generated_file.path = raw_output_path.toString(arena) catch @panic("OOM"); | |
| 250 | argv_list.items[placeholder.index] = graph.fmt("{s}{s}", .{ | |
| 246 | 251 | placeholder.output.prefix, |
| 247 | run.convertPathArg(raw_output_path), | |
| 252 | run.convertPathArg(maker, raw_output_path), | |
| 248 | 253 | }); |
| 249 | 254 | } |
| 250 | 255 | |
| 251 | try runCommand(run, argv_list.items, has_side_effects, tmp_dir_path, options, null); | |
| 256 | try runCommand(run, maker, progress_node, argv_list.items, has_side_effects, tmp_dir_path, null); | |
| 252 | 257 | |
| 253 | 258 | const dep_file_dir = Dir.cwd(); |
| 254 | const dep_file_basename = dep_output_file.generated_file.getPath2(b, step); | |
| 259 | const dep_file_basename = dep_output_file.generated_file.getPath2(graph, step); | |
| 255 | 260 | if (has_side_effects) |
| 256 | 261 | try man.addDepFile(dep_file_dir, dep_file_basename) |
| 257 | 262 | else |
| ... | ... | @@ -269,21 +274,21 @@ fn make(step: *Step, options: Step.MakeOptions) !void { |
| 269 | 274 | if (any_output) { |
| 270 | 275 | const o_sub_path = "o" ++ Dir.path.sep_str ++ &digest; |
| 271 | 276 | |
| 272 | b.cache_root.handle.rename(tmp_dir_path, b.cache_root.handle, o_sub_path, io) catch |err| switch (err) { | |
| 277 | graph.cache_root.handle.rename(tmp_dir_path, graph.cache_root.handle, o_sub_path, io) catch |err| switch (err) { | |
| 273 | 278 | Dir.RenameError.DirNotEmpty => { |
| 274 | b.cache_root.handle.deleteTree(io, o_sub_path) catch |del_err| { | |
| 279 | graph.cache_root.handle.deleteTree(io, o_sub_path) catch |del_err| { | |
| 275 | 280 | return step.fail("unable to remove dir '{f}'{s}: {t}", .{ |
| 276 | b.cache_root, tmp_dir_path, del_err, | |
| 281 | graph.cache_root, tmp_dir_path, del_err, | |
| 277 | 282 | }); |
| 278 | 283 | }; |
| 279 | b.cache_root.handle.rename(tmp_dir_path, b.cache_root.handle, o_sub_path, io) catch |retry_err| { | |
| 284 | graph.cache_root.handle.rename(tmp_dir_path, graph.cache_root.handle, o_sub_path, io) catch |retry_err| { | |
| 280 | 285 | return step.fail("unable to rename dir '{f}{s}' to '{f}{s}': {t}", .{ |
| 281 | b.cache_root, tmp_dir_path, b.cache_root, o_sub_path, retry_err, | |
| 286 | graph.cache_root, tmp_dir_path, graph.cache_root, o_sub_path, retry_err, | |
| 282 | 287 | }); |
| 283 | 288 | }; |
| 284 | 289 | }, |
| 285 | 290 | else => return step.fail("unable to rename dir '{f}{s}' to '{f}{s}': {t}", .{ |
| 286 | b.cache_root, tmp_dir_path, b.cache_root, o_sub_path, err, | |
| 291 | graph.cache_root, tmp_dir_path, graph.cache_root, o_sub_path, err, | |
| 287 | 292 | }), |
| 288 | 293 | }; |
| 289 | 294 | } |
| ... | ... | @@ -293,9 +298,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void { |
| 293 | 298 | try populateGeneratedPaths( |
| 294 | 299 | arena, |
| 295 | 300 | output_placeholders.items, |
| 296 | run.captured_stdout, | |
| 297 | run.captured_stderr, | |
| 298 | b.cache_root, | |
| 301 | graph.cache_root, | |
| 299 | 302 | &digest, |
| 300 | 303 | ); |
| 301 | 304 | } |
| ... | ... | @@ -347,7 +350,6 @@ fn waitZigTest( |
| 347 | 350 | // start and it acknowledging the test starting, we terminate the child and raise an error. This |
| 348 | 351 | // *should* never happen, but could in theory be caused by some very unlucky IB in a test. |
| 349 | 352 | const response_timeout: Io.Clock.Duration = t: { |
| 350 | if (fuzz_context != null) break :t null; // don't timeout fuzz tests | |
| 351 | 353 | const ns = @max(options.unit_test_timeout_ns orelse 0, 60 * std.time.ns_per_s); |
| 352 | 354 | break :t .{ .clock = .awake, .raw = .fromNanoseconds(ns) }; |
| 353 | 355 | }; |
| ... | ... | @@ -773,8 +775,8 @@ const FuzzTestRunner = struct { |
| 773 | 775 | try f.pending_broadcasts.ensureUnusedCapacity(gpa, size); |
| 774 | 776 | f.pending_broadcasts.appendSliceAssumeCapacity(body); |
| 775 | 777 | f.pending_broadcasts.appendSliceAssumeCapacity(@ptrCast(&footer)); |
| 776 | } | |
| 777 | }, | |
| 778 | } | |
| 779 | }, | |
| 778 | 780 | else => {}, // ignore other messages |
| 779 | 781 | } |
| 780 | 782 | |
| ... | ... | @@ -863,7 +865,7 @@ const FuzzTestRunner = struct { |
| 863 | 865 | if (f.coverage_id == null) return; |
| 864 | 866 | |
| 865 | 867 | // Search for the input file corresponding to the instance |
| 866 | const InputHeader = Build.abi.fuzz.MmapInputHeader; | |
| 868 | const InputHeader = std.Build.abi.fuzz.MmapInputHeader; | |
| 867 | 869 | var in_r_buf: [@sizeOf(InputHeader)]u8 = undefined; |
| 868 | 870 | var in_r: Io.File.Reader = undefined; |
| 869 | 871 | var in_f: Io.File = undefined; |
| ... | ... | @@ -1299,11 +1301,11 @@ fn sendRunFuzzTestMessage( |
| 1299 | 1301 | } |
| 1300 | 1302 | } |
| 1301 | 1303 | |
| 1302 | fn evalGeneric(run: *Run, spawn_options: process.SpawnOptions) !EvalGenericResult { | |
| 1303 | const b = run.step.owner; | |
| 1304 | const io = b.graph.io; | |
| 1305 | const arena = b.allocator; | |
| 1306 | const gpa = b.allocator; | |
| 1304 | fn evalGeneric(run: *Run, maker: *Maker, spawn_options: process.SpawnOptions) !EvalGenericResult { | |
| 1305 | const graph = maker.graph; | |
| 1306 | const io = graph.io; | |
| 1307 | const arena = graph.allocator; // TODO don't leak into the process arena | |
| 1308 | const gpa = maker.gpa; | |
| 1307 | 1309 | |
| 1308 | 1310 | var child = try process.spawn(io, spawn_options); |
| 1309 | 1311 | defer child.kill(io); |
| ... | ... | @@ -1317,7 +1319,7 @@ fn evalGeneric(run: *Run, spawn_options: process.SpawnOptions) !EvalGenericResul |
| 1317 | 1319 | child.stdin = null; |
| 1318 | 1320 | }, |
| 1319 | 1321 | .lazy_path => |lazy_path| { |
| 1320 | const path = lazy_path.getPath3(b, &run.step); | |
| 1322 | const path = lazy_path.getPath3(graph, &run.step); | |
| 1321 | 1323 | const file = path.root_dir.handle.openFile(io, path.subPathOrDot(), .{}) catch |err| { |
| 1322 | 1324 | return run.step.fail("unable to open stdin file: {t}", .{err}); |
| 1323 | 1325 | }; |
| ... | ... | @@ -1417,18 +1419,22 @@ fn evalGeneric(run: *Run, spawn_options: process.SpawnOptions) !EvalGenericResul |
| 1417 | 1419 | |
| 1418 | 1420 | const IndexedOutput = struct { |
| 1419 | 1421 | index: usize, |
| 1420 | tag: @typeInfo(Arg).@"union".tag_type.?, | |
| 1422 | tag: Configuration.Step.Run.Arg.Tag, | |
| 1421 | 1423 | output: *Output, |
| 1422 | 1424 | }; |
| 1423 | 1425 | |
| 1426 | const Output = void; // TODO | |
| 1427 | ||
| 1424 | 1428 | pub fn rerunInFuzzMode( |
| 1425 | 1429 | run: *Run, |
| 1426 | 1430 | fuzz: *std.Build.Fuzz, |
| 1427 | 1431 | prog_node: std.Progress.Node, |
| 1428 | 1432 | ) !void { |
| 1433 | const maker = fuzz.maker; | |
| 1434 | const graph = maker.graph; | |
| 1429 | 1435 | const step = &run.step; |
| 1430 | 1436 | const b = step.owner; |
| 1431 | const io = b.graph.io; | |
| 1437 | const io = graph.io; | |
| 1432 | 1438 | const arena = b.allocator; |
| 1433 | 1439 | var argv_list: std.ArrayList([]const u8) = .empty; |
| 1434 | 1440 | for (run.argv.items) |arg| { |
| ... | ... | @@ -1438,11 +1444,11 @@ pub fn rerunInFuzzMode( |
| 1438 | 1444 | }, |
| 1439 | 1445 | .lazy_path => |file| { |
| 1440 | 1446 | const file_path = file.lazy_path.getPath3(b, step); |
| 1441 | try argv_list.append(arena, b.fmt("{s}{s}", .{ file.prefix, run.convertPathArg(file_path) })); | |
| 1447 | try argv_list.append(arena, b.fmt("{s}{s}", .{ file.prefix, run.convertPathArg(maker, file_path) })); | |
| 1442 | 1448 | }, |
| 1443 | 1449 | .decorated_directory => |dd| { |
| 1444 | 1450 | const file_path = dd.lazy_path.getPath3(b, step); |
| 1445 | try argv_list.append(arena, b.fmt("{s}{s}{s}", .{ dd.prefix, run.convertPathArg(file_path), dd.suffix })); | |
| 1451 | try argv_list.append(arena, b.fmt("{s}{s}{s}", .{ dd.prefix, run.convertPathArg(maker, file_path), dd.suffix })); | |
| 1446 | 1452 | }, |
| 1447 | 1453 | .file_content => |file_plp| { |
| 1448 | 1454 | const file_path = file_plp.lazy_path.getPath3(b, step); |
| ... | ... | @@ -1471,7 +1477,7 @@ pub fn rerunInFuzzMode( |
| 1471 | 1477 | }; |
| 1472 | 1478 | try argv_list.append(arena, b.fmt("{s}{s}", .{ |
| 1473 | 1479 | pa.prefix, |
| 1474 | run.convertPathArg(.{ .root_dir = .cwd(), .sub_path = file_path }), | |
| 1480 | run.convertPathArg(maker, .{ .root_dir = .cwd(), .sub_path = file_path }), | |
| 1475 | 1481 | })); |
| 1476 | 1482 | }, |
| 1477 | 1483 | .output_file, .output_directory => unreachable, |
| ... | ... | @@ -1487,17 +1493,13 @@ pub fn rerunInFuzzMode( |
| 1487 | 1493 | var rand_int: u64 = undefined; |
| 1488 | 1494 | io.random(@ptrCast(&rand_int)); |
| 1489 | 1495 | const tmp_dir_path = "tmp" ++ Dir.path.sep_str ++ std.fmt.hex(rand_int); |
| 1490 | try runCommand(run, argv_list.items, has_side_effects, tmp_dir_path, .{ | |
| 1491 | .progress_node = prog_node, | |
| 1492 | .watch = undefined, // not used by `runCommand` | |
| 1493 | .web_server = null, // only needed for time reports | |
| 1494 | .unit_test_timeout_ns = null, // don't time out fuzz tests for now | |
| 1495 | .gpa = fuzz.gpa, | |
| 1496 | }, .{ | |
| 1496 | try runCommand(run, maker, prog_node, argv_list.items, has_side_effects, tmp_dir_path, .{ | |
| 1497 | 1497 | .fuzz = fuzz, |
| 1498 | 1498 | }); |
| 1499 | 1499 | } |
| 1500 | 1500 | |
| 1501 | const CapturedStdIo = void; // TODO get it from Configuration | |
| 1502 | ||
| 1501 | 1503 | fn populateGeneratedPaths( |
| 1502 | 1504 | arena: std.mem.Allocator, |
| 1503 | 1505 | output_placeholders: []const IndexedOutput, |
| ... | ... | @@ -1545,17 +1547,19 @@ const FuzzContext = struct { |
| 1545 | 1547 | |
| 1546 | 1548 | fn runCommand( |
| 1547 | 1549 | run: *Run, |
| 1550 | maker: *Maker, | |
| 1551 | progress_node: std.Progress.Node, | |
| 1548 | 1552 | argv: []const []const u8, |
| 1549 | 1553 | has_side_effects: bool, |
| 1550 | 1554 | output_dir_path: []const u8, |
| 1551 | options: Step.MakeOptions, | |
| 1552 | 1555 | fuzz_context: ?FuzzContext, |
| 1553 | 1556 | ) !void { |
| 1557 | const graph = maker.graph; | |
| 1558 | const arena = graph.arena; // TODO don't leak into process arena | |
| 1559 | const gpa = maker.gpa; | |
| 1554 | 1560 | const step = &run.step; |
| 1555 | 1561 | const b = step.owner; |
| 1556 | const arena = b.allocator; | |
| 1557 | const gpa = options.gpa; | |
| 1558 | const io = b.graph.io; | |
| 1562 | const io = graph.io; | |
| 1559 | 1563 | |
| 1560 | 1564 | const cwd: process.Child.Cwd = if (run.cwd) |lazy_cwd| .{ .path = lazy_cwd.getPath2(b, step) } else .inherit; |
| 1561 | 1565 | |
| ... | ... | @@ -1571,12 +1575,12 @@ fn runCommand( |
| 1571 | 1575 | defer interp_argv.deinit(); |
| 1572 | 1576 | |
| 1573 | 1577 | var environ_map: EnvMap = env: { |
| 1574 | const orig = run.environ_map orelse &b.graph.environ_map; | |
| 1578 | const orig = run.environ_map orelse &graph.environ_map; | |
| 1575 | 1579 | break :env try orig.clone(gpa); |
| 1576 | 1580 | }; |
| 1577 | 1581 | defer environ_map.deinit(); |
| 1578 | 1582 | |
| 1579 | const opt_generic_result = spawnChildAndCollect(run, argv, &environ_map, has_side_effects, options, fuzz_context) catch |err| term: { | |
| 1583 | const opt_generic_result = spawnChildAndCollect(run, maker, progress_node, argv, &environ_map, has_side_effects, fuzz_context) catch |err| term: { | |
| 1580 | 1584 | // InvalidExe: cpu arch mismatch |
| 1581 | 1585 | // FileNotFound: can happen with a wrong dynamic linker path |
| 1582 | 1586 | if (err == error.InvalidExe or err == error.FileNotFound) interpret: { |
| ... | ... | @@ -1597,7 +1601,7 @@ fn runCommand( |
| 1597 | 1601 | const need_cross_libc = exe.is_linking_libc and |
| 1598 | 1602 | (root_target.isGnuLibC() or (root_target.isMuslLibC() and exe.linkage == .dynamic)); |
| 1599 | 1603 | const other_target = exe.root_module.resolved_target.?.result; |
| 1600 | switch (std.zig.system.getExternalExecutor(io, &b.graph.host.result, &other_target, .{ | |
| 1604 | switch (std.zig.system.getExternalExecutor(io, &graph.host.result, &other_target, .{ | |
| 1601 | 1605 | .qemu_fixes_dl = need_cross_libc and b.libc_runtimes_dir != null, |
| 1602 | 1606 | .link_libc = exe.is_linking_libc, |
| 1603 | 1607 | })) { |
| ... | ... | @@ -1669,7 +1673,7 @@ fn runCommand( |
| 1669 | 1673 | .bad_dl => |foreign_dl| { |
| 1670 | 1674 | if (allow_skip) return error.MakeSkipped; |
| 1671 | 1675 | |
| 1672 | const host_dl = b.graph.host.result.dynamic_linker.get() orelse "(none)"; | |
| 1676 | const host_dl = graph.host.result.dynamic_linker.get() orelse "(none)"; | |
| 1673 | 1677 | |
| 1674 | 1678 | return step.fail( |
| 1675 | 1679 | \\the host system is unable to execute binaries from the target |
| ... | ... | @@ -1681,7 +1685,7 @@ fn runCommand( |
| 1681 | 1685 | .bad_os_or_cpu => { |
| 1682 | 1686 | if (allow_skip) return error.MakeSkipped; |
| 1683 | 1687 | |
| 1684 | const host_name = try b.graph.host.result.zigTriple(b.allocator); | |
| 1688 | const host_name = try graph.host.result.zigTriple(b.allocator); | |
| 1685 | 1689 | const foreign_name = try root_target.zigTriple(b.allocator); |
| 1686 | 1690 | |
| 1687 | 1691 | return step.fail("the host system ({s}) is unable to execute binaries from the target ({s})", .{ |
| ... | ... | @@ -1692,14 +1696,14 @@ fn runCommand( |
| 1692 | 1696 | |
| 1693 | 1697 | if (root_target.os.tag == .windows) { |
| 1694 | 1698 | // On Windows we don't have rpaths so we have to add .dll search paths to PATH |
| 1695 | run.addPathForDynLibs(exe); | |
| 1699 | addPathForDynLibs(exe); | |
| 1696 | 1700 | } |
| 1697 | 1701 | |
| 1698 | 1702 | gpa.free(step.result_failed_command.?); |
| 1699 | 1703 | step.result_failed_command = null; |
| 1700 | 1704 | try Step.handleVerbose2(step.owner, cwd, run.environ_map, interp_argv.items); |
| 1701 | 1705 | |
| 1702 | break :term spawnChildAndCollect(run, interp_argv.items, &environ_map, has_side_effects, options, fuzz_context) catch |e| { | |
| 1706 | break :term spawnChildAndCollect(run, maker, progress_node, interp_argv.items, &environ_map, has_side_effects, fuzz_context) catch |e| { | |
| 1703 | 1707 | if (!run.failing_to_execute_foreign_is_an_error) return error.MakeSkipped; |
| 1704 | 1708 | if (e == error.MakeFailed) return error.MakeFailed; // error already reported |
| 1705 | 1709 | return step.fail("unable to spawn interpreter {s}: {t}", .{ interp_argv.items[0], e }); |
| ... | ... | @@ -1851,14 +1855,16 @@ const EvalGenericResult = struct { |
| 1851 | 1855 | |
| 1852 | 1856 | fn spawnChildAndCollect( |
| 1853 | 1857 | run: *Run, |
| 1858 | maker: *Maker, | |
| 1859 | progress_node: std.Progress.Node, | |
| 1854 | 1860 | argv: []const []const u8, |
| 1855 | 1861 | environ_map: *EnvMap, |
| 1856 | 1862 | has_side_effects: bool, |
| 1857 | options: Step.MakeOptions, | |
| 1858 | 1863 | fuzz_context: ?FuzzContext, |
| 1859 | 1864 | ) !?EvalGenericResult { |
| 1860 | 1865 | const b = run.step.owner; |
| 1861 | const graph = b.graph; | |
| 1866 | const graph = maker.graph; | |
| 1867 | const gpa = maker.gpa; | |
| 1862 | 1868 | const io = graph.io; |
| 1863 | 1869 | |
| 1864 | 1870 | if (fuzz_context != null) { |
| ... | ... | @@ -1870,7 +1876,7 @@ fn spawnChildAndCollect( |
| 1870 | 1876 | |
| 1871 | 1877 | // If an error occurs, it's caused by this command: |
| 1872 | 1878 | assert(run.step.result_failed_command == null); |
| 1873 | run.step.result_failed_command = try Step.allocPrintCmd(options.gpa, child_cwd, .{ | |
| 1879 | run.step.result_failed_command = try Step.allocPrintCmd(gpa, child_cwd, .{ | |
| 1874 | 1880 | .child = environ_map, |
| 1875 | 1881 | .parent = &graph.environ_map, |
| 1876 | 1882 | }, argv); |
| ... | ... | @@ -1905,7 +1911,7 @@ fn spawnChildAndCollect( |
| 1905 | 1911 | |
| 1906 | 1912 | if (run.stdio == .zig_test) { |
| 1907 | 1913 | const started: Io.Clock.Timestamp = .now(io, .awake); |
| 1908 | const result = evalZigTest(run, spawn_options, options, fuzz_context) catch |err| switch (err) { | |
| 1914 | const result = evalZigTest(run, maker, progress_node, spawn_options, fuzz_context) catch |err| switch (err) { | |
| 1909 | 1915 | error.Canceled => |e| return e, |
| 1910 | 1916 | else => |e| e, |
| 1911 | 1917 | }; |
| ... | ... | @@ -1915,7 +1921,7 @@ fn spawnChildAndCollect( |
| 1915 | 1921 | } else { |
| 1916 | 1922 | const inherit = spawn_options.stdout == .inherit or spawn_options.stderr == .inherit; |
| 1917 | 1923 | if (!run.disable_zig_progress and !inherit) { |
| 1918 | spawn_options.progress_node = options.progress_node; | |
| 1924 | spawn_options.progress_node = progress_node; | |
| 1919 | 1925 | } |
| 1920 | 1926 | const terminal_mode: Io.Terminal.Mode = if (inherit) m: { |
| 1921 | 1927 | const stderr = try io.lockStderr(&.{}, graph.stderr_mode); |
| ... | ... | @@ -1925,7 +1931,7 @@ fn spawnChildAndCollect( |
| 1925 | 1931 | try setColorEnvironmentVariables(run, environ_map, terminal_mode); |
| 1926 | 1932 | |
| 1927 | 1933 | const started: Io.Clock.Timestamp = .now(io, .awake); |
| 1928 | const result = evalGeneric(run, spawn_options) catch |err| switch (err) { | |
| 1934 | const result = evalGeneric(run, maker, spawn_options) catch |err| switch (err) { | |
| 1929 | 1935 | error.Canceled => |e| return e, |
| 1930 | 1936 | else => |e| e, |
| 1931 | 1937 | }; |
| ... | ... | @@ -1934,11 +1940,11 @@ fn spawnChildAndCollect( |
| 1934 | 1940 | } |
| 1935 | 1941 | } |
| 1936 | 1942 | |
| 1937 | fn hashStdIo(hh: *Cache.HashHelper, stdio: StdIo) void { | |
| 1943 | fn hashStdIo(hh: *Cache.HashHelper, stdio: void) void { | |
| 1938 | 1944 | switch (stdio) { |
| 1939 | 1945 | .infer_from_args, .inherit, .zig_test => {}, |
| 1940 | 1946 | .check => |checks| for (checks.items) |check| { |
| 1941 | hh.add(@as(std.meta.Tag(StdIo.Check), check)); | |
| 1947 | hh.add(@as(std.meta.Tag(@This().StdIo.Check), check)); | |
| 1942 | 1948 | switch (check) { |
| 1943 | 1949 | .expect_stderr_exact, |
| 1944 | 1950 | .expect_stderr_match, |
| ... | ... | @@ -2010,7 +2016,7 @@ fn setColorEnvironmentVariables(run: *Run, environ_map: *EnvMap, terminal_mode: |
| 2010 | 2016 | } |
| 2011 | 2017 | } |
| 2012 | 2018 | |
| 2013 | fn checksContainStdout(checks: []const StdIo.Check) bool { | |
| 2019 | fn checksContainStdout(checks: []const @This().StdIo.Check) bool { | |
| 2014 | 2020 | for (checks) |check| switch (check) { |
| 2015 | 2021 | .expect_stderr_exact, |
| 2016 | 2022 | .expect_stderr_match, |
| ... | ... | @@ -2024,7 +2030,7 @@ fn checksContainStdout(checks: []const StdIo.Check) bool { |
| 2024 | 2030 | return false; |
| 2025 | 2031 | } |
| 2026 | 2032 | |
| 2027 | fn checksContainStderr(checks: []const StdIo.Check) bool { | |
| 2033 | fn checksContainStderr(checks: []const @This().StdIo.Check) bool { | |
| 2028 | 2034 | for (checks) |check| switch (check) { |
| 2029 | 2035 | .expect_stdout_exact, |
| 2030 | 2036 | .expect_stdout_match, |
| ... | ... | @@ -2063,9 +2069,9 @@ fn hasAnyOutputArgs(run: Run) bool { |
| 2063 | 2069 | /// |
| 2064 | 2070 | /// Whenever a path is included in the argv of a child, it should be put through this function first |
| 2065 | 2071 | /// to make sure the child doesn't see paths relative to a cwd other than its own. |
| 2066 | fn convertPathArg(run: *Run, path: Build.Cache.Path) []const u8 { | |
| 2072 | fn convertPathArg(run: *Run, maker: *Maker, path: Path) []const u8 { | |
| 2067 | 2073 | const b = run.step.owner; |
| 2068 | const graph = b.graph; | |
| 2074 | const graph = maker.graph; | |
| 2069 | 2075 | const arena = graph.arena; |
| 2070 | 2076 | |
| 2071 | 2077 | const path_str = path.toString(arena) catch @panic("OOM"); |
| ... | ... | @@ -2091,40 +2097,43 @@ fn convertPathArg(run: *Run, path: Build.Cache.Path) []const u8 { |
| 2091 | 2097 | return Dir.path.join(arena, &.{ ".", child_cwd_rel }) catch @panic("OOM"); |
| 2092 | 2098 | } |
| 2093 | 2099 | |
| 2094 | fn addPathForDynLibs(run: *Run, artifact: *Step.Compile) void { | |
| 2095 | const b = run.step.owner; | |
| 2096 | const compiles = artifact.getCompileDependencies(true); | |
| 2097 | for (compiles) |compile| { | |
| 2100 | fn addPathForDynLibs(artifact: *Step.Compile) void { | |
| 2101 | if (true) @panic("TODO"); | |
| 2102 | for (artifact.getCompileDependencies(true)) |compile| { | |
| 2098 | 2103 | if (compile.root_module.resolved_target.?.result.os.tag == .windows and |
| 2099 | 2104 | compile.isDynamicLibrary()) |
| 2100 | 2105 | { |
| 2101 | addPathDir(run, Dir.path.dirname(compile.getEmittedBin().getPath2(b, &run.step)).?); | |
| 2106 | @panic("TODO"); | |
| 2107 | //addPathDir(run, Dir.path.dirname(compile.getEmittedBin().getPath2(b, &run.step)).?); | |
| 2102 | 2108 | } |
| 2103 | 2109 | } |
| 2104 | 2110 | } |
| 2105 | 2111 | |
| 2106 | 2112 | fn failForeign( |
| 2107 | 2113 | run: *Run, |
| 2114 | maker: *Maker, | |
| 2115 | step_index: Configuration.Step.Index, | |
| 2108 | 2116 | suggested_flag: []const u8, |
| 2109 | 2117 | argv0: []const u8, |
| 2110 | 2118 | exe: *Step.Compile, |
| 2111 | ) error{ MakeFailed, MakeSkipped, OutOfMemory } { | |
| 2119 | ) Step.ExtendedMakeError { | |
| 2120 | const step = maker.stepByIndex(step_index); | |
| 2112 | 2121 | switch (run.stdio) { |
| 2113 | 2122 | .check, .zig_test => { |
| 2114 | if (run.skip_foreign_checks) | |
| 2115 | return error.MakeSkipped; | |
| 2123 | if (run.skip_foreign_checks) return error.MakeSkipped; | |
| 2116 | 2124 | |
| 2117 | const b = run.step.owner; | |
| 2118 | const host_name = try b.graph.host.result.zigTriple(b.allocator); | |
| 2119 | const foreign_name = try exe.rootModuleTarget().zigTriple(b.allocator); | |
| 2125 | const graph = maker.graph; | |
| 2126 | const process_arena = graph.arena; // TODO don't leak into process arena | |
| 2127 | const host_name = try graph.host.result.zigTriple(process_arena); | |
| 2128 | const foreign_name = try exe.rootModuleTarget().zigTriple(process_arena); | |
| 2120 | 2129 | |
| 2121 | return run.step.fail( | |
| 2130 | return step.fail( | |
| 2122 | 2131 | \\unable to spawn foreign binary '{s}' ({s}) on host system ({s}) |
| 2123 | 2132 | \\ consider using {s} or enabling skip_foreign_checks in the Run step |
| 2124 | 2133 | , .{ argv0, foreign_name, host_name, suggested_flag }); |
| 2125 | 2134 | }, |
| 2126 | 2135 | else => { |
| 2127 | return run.step.fail("unable to spawn foreign binary '{s}'", .{argv0}); | |
| 2136 | return step.fail("unable to spawn foreign binary '{s}'", .{argv0}); | |
| 2128 | 2137 | }, |
| 2129 | 2138 | } |
| 2130 | 2139 | } |
lib/compiler/Maker/Watch.zig+45-38| ... | ... | @@ -10,6 +10,7 @@ const Configuration = std.Build.Configuration; |
| 10 | 10 | |
| 11 | 11 | const FsEvents = @import("Watch/FsEvents.zig"); |
| 12 | 12 | const Step = @import("Step.zig"); |
| 13 | const Maker = @import("../Maker.zig"); | |
| 13 | 14 | |
| 14 | 15 | os: Os, |
| 15 | 16 | /// The number to show as the number of directories being watched. |
| ... | ... | @@ -18,8 +19,7 @@ dir_count: usize, |
| 18 | 19 | // They are `undefined` on implementations which do not utilize then. |
| 19 | 20 | dir_table: DirTable, |
| 20 | 21 | generation: Generation, |
| 21 | configuration: *const Configuration, | |
| 22 | make_steps: []Step, | |
| 22 | maker: *Maker, | |
| 23 | 23 | |
| 24 | 24 | pub const have_impl = Os != void; |
| 25 | 25 | |
| ... | ... | @@ -105,8 +105,7 @@ const Os = switch (builtin.os.tag) { |
| 105 | 105 | }; |
| 106 | 106 | }; |
| 107 | 107 | |
| 108 | fn init(cwd_path: []const u8, configuration: *const Configuration, make_steps: []Step) !Watch { | |
| 109 | _ = cwd_path; | |
| 108 | fn init(maker: *Maker) !Watch { | |
| 110 | 109 | return .{ |
| 111 | 110 | .dir_table = .{}, |
| 112 | 111 | .dir_count = 0, |
| ... | ... | @@ -118,8 +117,7 @@ const Os = switch (builtin.os.tag) { |
| 118 | 117 | else => {}, |
| 119 | 118 | }, |
| 120 | 119 | .generation = 0, |
| 121 | .make_steps = make_steps, | |
| 122 | .configuration = configuration, | |
| 120 | .maker = maker, | |
| 123 | 121 | }; |
| 124 | 122 | } |
| 125 | 123 | |
| ... | ... | @@ -136,7 +134,8 @@ const Os = switch (builtin.os.tag) { |
| 136 | 134 | return stack_lfh.clone(gpa); |
| 137 | 135 | } |
| 138 | 136 | |
| 139 | fn markDirtySteps(w: *Watch, gpa: Allocator, fan_fd: posix.fd_t) !bool { | |
| 137 | fn markDirtySteps(w: *Watch, fan_fd: posix.fd_t) !bool { | |
| 138 | const maker = w.maker; | |
| 140 | 139 | const fanotify = std.os.linux.fanotify; |
| 141 | 140 | const M = fanotify.event_metadata; |
| 142 | 141 | var events_buf: [256 + 4096]u8 = undefined; |
| ... | ... | @@ -155,7 +154,7 @@ const Os = switch (builtin.os.tag) { |
| 155 | 154 | if (meta[0].mask.Q_OVERFLOW) { |
| 156 | 155 | any_dirty = true; |
| 157 | 156 | std.log.warn("file system watch queue overflowed; falling back to fstat", .{}); |
| 158 | markAllFilesDirty(w, gpa); | |
| 157 | markAllFilesDirty(w); | |
| 159 | 158 | return true; |
| 160 | 159 | } |
| 161 | 160 | const fid: *align(1) fanotify.event_info_fid = @ptrCast(meta + 1); |
| ... | ... | @@ -167,9 +166,9 @@ const Os = switch (builtin.os.tag) { |
| 167 | 166 | const lfh: FileHandle = .{ .handle = file_handle }; |
| 168 | 167 | if (w.os.handle_table.getPtr(lfh)) |value| { |
| 169 | 168 | if (value.reaction_set.getPtr(".")) |glob_set| |
| 170 | any_dirty = markStepSetDirty(gpa, w.make_steps, glob_set, any_dirty); | |
| 169 | any_dirty = markStepSetDirty(maker, glob_set, any_dirty); | |
| 171 | 170 | if (value.reaction_set.getPtr(file_name)) |step_set| |
| 172 | any_dirty = markStepSetDirty(gpa, w.make_steps, step_set, any_dirty); | |
| 171 | any_dirty = markStepSetDirty(maker, step_set, any_dirty); | |
| 173 | 172 | } |
| 174 | 173 | }, |
| 175 | 174 | else => |t| std.log.warn("unexpected fanotify event '{t}'", .{t}), |
| ... | ... | @@ -179,9 +178,11 @@ const Os = switch (builtin.os.tag) { |
| 179 | 178 | } |
| 180 | 179 | |
| 181 | 180 | fn update(w: *Watch, gpa: Allocator, steps: []const Configuration.Step.Index) !void { |
| 181 | const maker = w.maker; | |
| 182 | ||
| 182 | 183 | // Add missing marks and note persisted ones. |
| 183 | 184 | for (steps) |step_index| { |
| 184 | const step = &w.make_steps[@intFromEnum(step_index)]; | |
| 185 | const step = maker.stepByIndex(step_index); | |
| 185 | 186 | for (step.inputs.table.keys(), step.inputs.table.values()) |path, *files| { |
| 186 | 187 | const reaction_set = rs: { |
| 187 | 188 | const gop = try w.dir_table.getOrPut(gpa, path); |
| ... | ... | @@ -298,13 +299,12 @@ const Os = switch (builtin.os.tag) { |
| 298 | 299 | w.dir_count = w.dir_table.count(); |
| 299 | 300 | } |
| 300 | 301 | |
| 301 | fn wait(w: *Watch, gpa: Allocator, io: Io, timeout: Timeout) !WaitResult { | |
| 302 | _ = io; | |
| 302 | fn wait(w: *Watch, timeout: Timeout) !WaitResult { | |
| 303 | 303 | const events_len = try std.posix.poll(w.os.poll_fds.values(), timeout.to_i32_ms()); |
| 304 | 304 | if (events_len == 0) |
| 305 | 305 | return .timeout; |
| 306 | 306 | for (w.os.poll_fds.values()) |poll_fd| { |
| 307 | if (poll_fd.revents & std.posix.POLL.IN == std.posix.POLL.IN and try markDirtySteps(w, gpa, poll_fd.fd)) | |
| 307 | if (poll_fd.revents & std.posix.POLL.IN == std.posix.POLL.IN and try markDirtySteps(w, poll_fd.fd)) | |
| 308 | 308 | return .dirty; |
| 309 | 309 | } |
| 310 | 310 | return .clean; |
| ... | ... | @@ -515,12 +515,14 @@ const Os = switch (builtin.os.tag) { |
| 515 | 515 | return file_id; |
| 516 | 516 | } |
| 517 | 517 | |
| 518 | fn markDirtySteps(w: *Watch, gpa: Allocator, dir: *Directory) !bool { | |
| 518 | fn markDirtySteps(w: *Watch, dir: *Directory) !bool { | |
| 519 | const maker = w.maker; | |
| 520 | ||
| 519 | 521 | var any_dirty = false; |
| 520 | 522 | const bytes_returned = dir.iosb.Information; |
| 521 | 523 | if (bytes_returned == 0) { |
| 522 | 524 | std.log.warn("file system watch queue overflowed; falling back to fstat", .{}); |
| 523 | markAllFilesDirty(w, gpa); | |
| 525 | markAllFilesDirty(w); | |
| 524 | 526 | try dir.startListening(w); |
| 525 | 527 | return true; |
| 526 | 528 | } |
| ... | ... | @@ -530,9 +532,9 @@ const Os = switch (builtin.os.tag) { |
| 530 | 532 | const notify: *windows.FILE.NOTIFY.INFORMATION = @ptrCast(@alignCast(&dir.buffer[offset])); |
| 531 | 533 | const file_name = file_name_buf[0..std.unicode.wtf16LeToWtf8(&file_name_buf, notify.fileName())]; |
| 532 | 534 | if (dir.reaction_set.getPtr(".")) |glob_set| |
| 533 | any_dirty = markStepSetDirty(gpa, glob_set, any_dirty); | |
| 535 | any_dirty = markStepSetDirty(maker, glob_set, any_dirty); | |
| 534 | 536 | if (dir.reaction_set.getPtr(file_name)) |step_set| |
| 535 | any_dirty = markStepSetDirty(gpa, step_set, any_dirty); | |
| 537 | any_dirty = markStepSetDirty(maker, step_set, any_dirty); | |
| 536 | 538 | if (notify.NextEntryOffset == 0) |
| 537 | 539 | break; |
| 538 | 540 | |
| ... | ... | @@ -619,14 +621,17 @@ const Os = switch (builtin.os.tag) { |
| 619 | 621 | w.dir_count = w.dir_table.count(); |
| 620 | 622 | } |
| 621 | 623 | |
| 622 | fn wait(w: *Watch, gpa: Allocator, io: Io, timeout: Timeout) !WaitResult { | |
| 624 | fn wait(w: *Watch, timeout: Timeout) !WaitResult { | |
| 625 | const maker = w.maker; | |
| 626 | const io = maker.graph.io; | |
| 627 | ||
| 623 | 628 | for (0..2) |attempt| { |
| 624 | 629 | while (w.os.ready_dirs.popFirst()) |ready_node| { |
| 625 | 630 | const dir: *Directory = @fieldParentPtr("ready_node", ready_node); |
| 626 | 631 | assert(dir.state == .ready); |
| 627 | 632 | dir.state = .idle; |
| 628 | 633 | switch (dir.iosb.u.Status) { |
| 629 | .SUCCESS => return if (try markDirtySteps(w, gpa, dir)) .dirty else .clean, | |
| 634 | .SUCCESS => return if (try markDirtySteps(w, dir)) .dirty else .clean, | |
| 630 | 635 | .PENDING => unreachable, |
| 631 | 636 | .CANCELLED => {}, |
| 632 | 637 | else => |status| return windows.unexpectedStatus(status), |
| ... | ... | @@ -810,25 +815,25 @@ const Os = switch (builtin.os.tag) { |
| 810 | 815 | w.dir_count = w.dir_table.count(); |
| 811 | 816 | } |
| 812 | 817 | |
| 813 | fn wait(w: *Watch, gpa: Allocator, io: Io, timeout: Timeout) !WaitResult { | |
| 814 | _ = io; | |
| 818 | fn wait(w: *Watch, timeout: Timeout) !WaitResult { | |
| 819 | const maker = w.maker; | |
| 815 | 820 | var timespec_buffer: posix.timespec = undefined; |
| 816 | 821 | var event_buffer: [100]posix.Kevent = undefined; |
| 817 | 822 | var n = try Io.Kqueue.kevent(w.os.kq_fd, &.{}, &event_buffer, timeout.toTimespec(&timespec_buffer)); |
| 818 | 823 | if (n == 0) return .timeout; |
| 819 | 824 | const reaction_sets = w.os.handles.items(.rs); |
| 820 | var any_dirty = markDirtySteps(gpa, reaction_sets, event_buffer[0..n], false); | |
| 825 | var any_dirty = markDirtySteps(maker, reaction_sets, event_buffer[0..n], false); | |
| 821 | 826 | timespec_buffer = .{ .sec = 0, .nsec = 0 }; |
| 822 | 827 | while (n == event_buffer.len) { |
| 823 | 828 | n = try Io.Kqueue.kevent(w.os.kq_fd, &.{}, &event_buffer, &timespec_buffer); |
| 824 | 829 | if (n == 0) break; |
| 825 | any_dirty = markDirtySteps(gpa, reaction_sets, event_buffer[0..n], any_dirty); | |
| 830 | any_dirty = markDirtySteps(maker, reaction_sets, event_buffer[0..n], any_dirty); | |
| 826 | 831 | } |
| 827 | 832 | return if (any_dirty) .dirty else .clean; |
| 828 | 833 | } |
| 829 | 834 | |
| 830 | 835 | fn markDirtySteps( |
| 831 | gpa: Allocator, | |
| 836 | maker: *Maker, | |
| 832 | 837 | reaction_sets: []ReactionSet, |
| 833 | 838 | events: []const std.c.Kevent, |
| 834 | 839 | start_any_dirty: bool, |
| ... | ... | @@ -840,13 +845,13 @@ const Os = switch (builtin.os.tag) { |
| 840 | 845 | // If we knew the basename of the changed file, here we would |
| 841 | 846 | // mark only the step set dirty, and possibly the glob set: |
| 842 | 847 | //if (reaction_set.getPtr(".")) |glob_set| |
| 843 | // any_dirty = markStepSetDirty(gpa, glob_set, any_dirty); | |
| 848 | // any_dirty = markStepSetDirty(maker, glob_set, any_dirty); | |
| 844 | 849 | //if (reaction_set.getPtr(file_name)) |step_set| |
| 845 | // any_dirty = markStepSetDirty(gpa, step_set, any_dirty); | |
| 850 | // any_dirty = markStepSetDirty(maker, step_set, any_dirty); | |
| 846 | 851 | // However we don't know the file name so just mark all the |
| 847 | 852 | // sets dirty for this directory. |
| 848 | 853 | for (reaction_set.values()) |*step_set| { |
| 849 | any_dirty = markStepSetDirty(gpa, step_set, any_dirty); | |
| 854 | any_dirty = markStepSetDirty(maker, step_set, any_dirty); | |
| 850 | 855 | } |
| 851 | 856 | } |
| 852 | 857 | return any_dirty; |
| ... | ... | @@ -878,8 +883,8 @@ const Os = switch (builtin.os.tag) { |
| 878 | 883 | else => void, |
| 879 | 884 | }; |
| 880 | 885 | |
| 881 | pub fn init(cwd_path: []const u8, configuration: *const Configuration, make_steps: []Step) !Watch { | |
| 882 | return Os.init(cwd_path, configuration, make_steps); | |
| 886 | pub fn init(maker: *Maker) !Watch { | |
| 887 | return Os.init(maker); | |
| 883 | 888 | } |
| 884 | 889 | |
| 885 | 890 | pub const Match = struct { |
| ... | ... | @@ -904,7 +909,9 @@ pub const Match = struct { |
| 904 | 909 | }; |
| 905 | 910 | }; |
| 906 | 911 | |
| 907 | fn markAllFilesDirty(w: *Watch, gpa: Allocator) void { | |
| 912 | fn markAllFilesDirty(w: *Watch) void { | |
| 913 | const maker = w.maker; | |
| 914 | ||
| 908 | 915 | for (switch (builtin.os.tag) { |
| 909 | 916 | .windows => w.os.handle_table.keys(), |
| 910 | 917 | else => w.os.handle_table.values(), |
| ... | ... | @@ -915,18 +922,18 @@ fn markAllFilesDirty(w: *Watch, gpa: Allocator) void { |
| 915 | 922 | }; |
| 916 | 923 | for (reaction_set.values()) |step_set| { |
| 917 | 924 | for (step_set.keys()) |step_index| { |
| 918 | const step = &w.make_steps[@intFromEnum(step_index)]; | |
| 919 | _ = step.invalidateResult(gpa); | |
| 925 | const step = maker.stepByIndex(step_index); | |
| 926 | _ = maker.invalidateResult(step); | |
| 920 | 927 | } |
| 921 | 928 | } |
| 922 | 929 | } |
| 923 | 930 | } |
| 924 | 931 | |
| 925 | fn markStepSetDirty(gpa: Allocator, make_steps: []Step, step_set: *StepSet, any_dirty: bool) bool { | |
| 932 | fn markStepSetDirty(maker: *Maker, step_set: *StepSet, any_dirty: bool) bool { | |
| 926 | 933 | var this_any_dirty = false; |
| 927 | 934 | for (step_set.keys()) |step_index| { |
| 928 | const step = &make_steps[@intFromEnum(step_index)]; | |
| 929 | if (step.invalidateResult(gpa)) this_any_dirty = true; | |
| 935 | const step = maker.stepByIndex(step_index); | |
| 936 | if (maker.invalidateResult(step)) this_any_dirty = true; | |
| 930 | 937 | } |
| 931 | 938 | return any_dirty or this_any_dirty; |
| 932 | 939 | } |
| ... | ... | @@ -971,6 +978,6 @@ pub const WaitResult = enum { |
| 971 | 978 | clean, |
| 972 | 979 | }; |
| 973 | 980 | |
| 974 | pub fn wait(w: *Watch, gpa: Allocator, io: Io, timeout: Timeout) !WaitResult { | |
| 975 | return Os.wait(w, gpa, io, timeout); | |
| 981 | pub fn wait(w: *Watch, timeout: Timeout) !WaitResult { | |
| 982 | return Os.wait(w, timeout); | |
| 976 | 983 | } |
lib/compiler/Maker/WebServer.zig+94-71| ... | ... | @@ -14,16 +14,14 @@ const log = std.log.scoped(.web_server); |
| 14 | 14 | const mem = std.mem; |
| 15 | 15 | const net = std.Io.net; |
| 16 | 16 | |
| 17 | const Maker = @import("../Maker.zig"); | |
| 17 | 18 | const Fuzz = @import("Fuzz.zig"); |
| 18 | 19 | const Graph = @import("Graph.zig"); |
| 19 | 20 | const Step = @import("Step.zig"); |
| 20 | 21 | |
| 21 | gpa: Allocator, | |
| 22 | graph: *const Graph, | |
| 23 | all_steps: []const Configuration.Step.Index, | |
| 22 | maker: *Maker, | |
| 24 | 23 | listen_address: net.IpAddress, |
| 25 | 24 | root_prog_node: std.Progress.Node, |
| 26 | watch: bool, | |
| 27 | 25 | |
| 28 | 26 | tcp_server: ?net.Server, |
| 29 | 27 | serve_task: ?Io.Future(Io.Cancelable!void), |
| ... | ... | @@ -65,19 +63,16 @@ pub const base_clock: Io.Clock = .awake; |
| 65 | 63 | |
| 66 | 64 | /// Thread-safe. Triggers updates to be sent to connected WebSocket clients; see `update_id`. |
| 67 | 65 | pub fn notifyUpdate(ws: *WebServer) void { |
| 66 | const io = ws.maker.graph.io; | |
| 68 | 67 | _ = ws.update_id.rmw(.Add, 1, .release); |
| 69 | ws.graph.io.futexWake(u32, &ws.update_id.raw, 16); | |
| 68 | io.futexWake(u32, &ws.update_id.raw, 16); | |
| 70 | 69 | } |
| 71 | 70 | |
| 72 | 71 | pub const Options = struct { |
| 73 | gpa: Allocator, | |
| 74 | graph: *const Graph, | |
| 75 | all_steps: []const Configuration.Step.Index, | |
| 72 | maker: *Maker, | |
| 76 | 73 | root_prog_node: std.Progress.Node, |
| 77 | watch: bool, | |
| 78 | 74 | listen_address: net.IpAddress, |
| 79 | 75 | base_timestamp: Io.Clock.Timestamp, |
| 80 | configuration: *const Configuration, | |
| 81 | 76 | }; |
| 82 | 77 | pub fn init(opts: Options) WebServer { |
| 83 | 78 | // The upcoming `Io` interface should allow us to use `Io.async` and `Io.concurrent` |
| ... | ... | @@ -85,10 +80,13 @@ pub fn init(opts: Options) WebServer { |
| 85 | 80 | comptime assert(!builtin.single_threaded); |
| 86 | 81 | assert(opts.base_timestamp.clock == base_clock); |
| 87 | 82 | |
| 88 | const all_steps = opts.all_steps; | |
| 89 | const c = opts.configuration; | |
| 83 | const maker = opts.maker; | |
| 84 | const all_steps = maker.step_stack.keys(); | |
| 85 | const c = &maker.scanned_config.configuration; | |
| 86 | const gpa = maker.gpa; | |
| 87 | const graph = maker.graph; | |
| 90 | 88 | |
| 91 | const step_names_trailing = opts.gpa.alloc(u8, len: { | |
| 89 | const step_names_trailing = gpa.alloc(u8, len: { | |
| 92 | 90 | var name_bytes: usize = 0; |
| 93 | 91 | for (all_steps) |step_index| name_bytes += step_index.ptr(c).name.slice(c).len; |
| 94 | 92 | break :len name_bytes + all_steps.len * 4; |
| ... | ... | @@ -105,25 +103,22 @@ pub fn init(opts: Options) WebServer { |
| 105 | 103 | assert(idx == step_names_trailing.len); |
| 106 | 104 | } |
| 107 | 105 | |
| 108 | const step_status_bits = opts.gpa.alloc( | |
| 106 | const step_status_bits = gpa.alloc( | |
| 109 | 107 | u8, |
| 110 | 108 | std.math.divCeil(usize, all_steps.len, 4) catch unreachable, |
| 111 | 109 | ) catch @panic("out of memory"); |
| 112 | 110 | @memset(step_status_bits, 0); |
| 113 | 111 | |
| 114 | const time_reports_len: usize = if (opts.graph.time_report) all_steps.len else 0; | |
| 115 | const time_report_msgs = opts.gpa.alloc([]u8, time_reports_len) catch @panic("out of memory"); | |
| 116 | const time_report_update_times = opts.gpa.alloc(i64, time_reports_len) catch @panic("out of memory"); | |
| 112 | const time_reports_len: usize = if (graph.time_report) all_steps.len else 0; | |
| 113 | const time_report_msgs = gpa.alloc([]u8, time_reports_len) catch @panic("out of memory"); | |
| 114 | const time_report_update_times = gpa.alloc(i64, time_reports_len) catch @panic("out of memory"); | |
| 117 | 115 | @memset(time_report_msgs, &.{}); |
| 118 | 116 | @memset(time_report_update_times, std.math.minInt(i64)); |
| 119 | 117 | |
| 120 | 118 | return .{ |
| 121 | .gpa = opts.gpa, | |
| 122 | .graph = opts.graph, | |
| 123 | .all_steps = all_steps, | |
| 119 | .maker = maker, | |
| 124 | 120 | .listen_address = opts.listen_address, |
| 125 | 121 | .root_prog_node = opts.root_prog_node, |
| 126 | .watch = opts.watch, | |
| 127 | 122 | |
| 128 | 123 | .tcp_server = null, |
| 129 | 124 | .serve_task = null, |
| ... | ... | @@ -148,8 +143,9 @@ pub fn init(opts: Options) WebServer { |
| 148 | 143 | }; |
| 149 | 144 | } |
| 150 | 145 | pub fn deinit(ws: *WebServer) void { |
| 151 | const gpa = ws.gpa; | |
| 152 | const io = ws.graph.io; | |
| 146 | const maker = ws.maker; | |
| 147 | const gpa = maker.gpa; | |
| 148 | const io = maker.graph.io; | |
| 153 | 149 | |
| 154 | 150 | gpa.free(ws.step_names_trailing); |
| 155 | 151 | gpa.free(ws.step_status_bits); |
| ... | ... | @@ -170,7 +166,8 @@ pub fn deinit(ws: *WebServer) void { |
| 170 | 166 | pub fn start(ws: *WebServer) error{AlreadyReported}!void { |
| 171 | 167 | assert(ws.tcp_server == null); |
| 172 | 168 | assert(ws.serve_task == null); |
| 173 | const io = ws.graph.io; | |
| 169 | const maker = ws.maker; | |
| 170 | const io = maker.graph.io; | |
| 174 | 171 | |
| 175 | 172 | ws.tcp_server = ws.listen_address.listen(io, .{ .reuse_address = true }) catch |err| { |
| 176 | 173 | log.err("failed to listen to port {d}: {t}", .{ ws.listen_address.getPort(), err }); |
| ... | ... | @@ -189,9 +186,12 @@ pub fn start(ws: *WebServer) error{AlreadyReported}!void { |
| 189 | 186 | } |
| 190 | 187 | } |
| 191 | 188 | fn serve(ws: *WebServer) Io.Cancelable!void { |
| 192 | const io = ws.graph.io; | |
| 189 | const maker = ws.maker; | |
| 190 | const io = maker.graph.io; | |
| 191 | ||
| 193 | 192 | var group: Io.Group = .init; |
| 194 | 193 | defer group.cancel(io); |
| 194 | ||
| 195 | 195 | while (true) { |
| 196 | 196 | var stream = ws.tcp_server.?.accept(io) catch |err| switch (err) { |
| 197 | 197 | error.Canceled => |e| return e, |
| ... | ... | @@ -223,8 +223,10 @@ pub fn updateStepStatus( |
| 223 | 223 | step_index: Configuration.Step.Index, |
| 224 | 224 | new_status: abi.StepUpdate.Status, |
| 225 | 225 | ) void { |
| 226 | const maker = ws.maker; | |
| 227 | const all_steps = maker.step_stack.keys(); | |
| 226 | 228 | // TODO don't do linear search, especially in a hot loop like this |
| 227 | const step_idx: u32 = for (ws.all_steps, 0..) |s, i| { | |
| 229 | const step_idx: u32 = for (all_steps, 0..) |s, i| { | |
| 228 | 230 | if (s == step_index) break @intCast(i); |
| 229 | 231 | } else unreachable; |
| 230 | 232 | const ptr = &ws.step_status_bits[step_idx / 4]; |
| ... | ... | @@ -238,13 +240,16 @@ pub fn updateStepStatus( |
| 238 | 240 | pub fn finishBuild(ws: *WebServer, opts: struct { |
| 239 | 241 | fuzz: bool, |
| 240 | 242 | }) void { |
| 243 | const maker = ws.maker; | |
| 244 | const all_steps = maker.step_stack.keys(); | |
| 245 | ||
| 241 | 246 | if (opts.fuzz) { |
| 242 | 247 | switch (builtin.os.tag) { |
| 243 | 248 | // Current implementation depends on two things that need to be ported to Windows: |
| 244 | 249 | // * Memory-mapping to share data between the fuzzer and build runner. |
| 245 | 250 | // * COFF/PE support added to `std.debug.Info` (it needs a batching API for resolving |
| 246 | 251 | // many addresses to source locations). |
| 247 | .windows => std.process.fatal("--fuzz not yet implemented for {s}", .{@tagName(builtin.os.tag)}), | |
| 252 | .windows => std.process.fatal("--fuzz not yet implemented for {t}", .{builtin.os.tag}), | |
| 248 | 253 | else => {}, |
| 249 | 254 | } |
| 250 | 255 | if (@bitSizeOf(usize) != 64) { |
| ... | ... | @@ -260,28 +265,26 @@ pub fn finishBuild(ws: *WebServer, opts: struct { |
| 260 | 265 | ws.build_status.store(.fuzz_init, .monotonic); |
| 261 | 266 | ws.notifyUpdate(); |
| 262 | 267 | |
| 263 | ws.fuzz = Fuzz.init( | |
| 264 | ws.gpa, | |
| 265 | ws.graph.io, | |
| 266 | ws.all_steps, | |
| 267 | ws.root_prog_node, | |
| 268 | .{ .forever = .{ .ws = ws } }, | |
| 269 | ) catch |err| std.process.fatal("failed to start fuzzer: {s}", .{@errorName(err)}); | |
| 268 | ws.fuzz = Fuzz.init(maker, all_steps, ws.root_prog_node, .{ .forever = .{ .ws = ws } }) catch |err| | |
| 269 | std.process.fatal("failed to start fuzzer: {t}", .{err}); | |
| 270 | 270 | ws.fuzz.?.start(); |
| 271 | 271 | } |
| 272 | 272 | |
| 273 | ws.build_status.store(if (ws.watch) .watching else .idle, .monotonic); | |
| 273 | ws.build_status.store(if (maker.watch) .watching else .idle, .monotonic); | |
| 274 | 274 | ws.notifyUpdate(); |
| 275 | 275 | } |
| 276 | 276 | |
| 277 | pub fn now(s: *const WebServer) i64 { | |
| 278 | const io = s.graph.io; | |
| 277 | pub fn now(ws: *const WebServer) i64 { | |
| 278 | const maker = ws.maker; | |
| 279 | const io = maker.graph.io; | |
| 279 | 280 | const ts = base_clock.now(io); |
| 280 | return @intCast(s.base_timestamp.durationTo(ts).toNanoseconds()); | |
| 281 | return @intCast(ws.base_timestamp.durationTo(ts).toNanoseconds()); | |
| 281 | 282 | } |
| 282 | 283 | |
| 283 | 284 | fn accept(ws: *WebServer, stream: net.Stream) void { |
| 284 | const io = ws.graph.io; | |
| 285 | const maker = ws.maker; | |
| 286 | const io = maker.graph.io; | |
| 287 | ||
| 285 | 288 | defer { |
| 286 | 289 | // `net.Stream.close` wants to helpfully overwrite `stream` with |
| 287 | 290 | // `undefined`, but it cannot do so since it is an immutable parameter. |
| ... | ... | @@ -326,12 +329,16 @@ fn accept(ws: *WebServer, stream: net.Stream) void { |
| 326 | 329 | } |
| 327 | 330 | |
| 328 | 331 | fn serveWebSocket(ws: *WebServer, sock: *http.Server.WebSocket) !noreturn { |
| 329 | const io = ws.graph.io; | |
| 332 | const maker = ws.maker; | |
| 333 | const gpa = maker.gpa; | |
| 334 | const graph = maker.graph; | |
| 335 | const io = graph.io; | |
| 336 | const all_steps = maker.step_stack.keys(); | |
| 330 | 337 | |
| 331 | 338 | var prev_build_status = ws.build_status.load(.monotonic); |
| 332 | 339 | |
| 333 | const prev_step_status_bits = try ws.gpa.alloc(u8, ws.step_status_bits.len); | |
| 334 | defer ws.gpa.free(prev_step_status_bits); | |
| 340 | const prev_step_status_bits = try gpa.alloc(u8, ws.step_status_bits.len); | |
| 341 | defer gpa.free(prev_step_status_bits); | |
| 335 | 342 | for (prev_step_status_bits, ws.step_status_bits) |*copy, *shared| { |
| 336 | 343 | copy.* = @atomicLoad(u8, shared, .monotonic); |
| 337 | 344 | } |
| ... | ... | @@ -343,10 +350,10 @@ fn serveWebSocket(ws: *WebServer, sock: *http.Server.WebSocket) !noreturn { |
| 343 | 350 | const hello_header: abi.Hello = .{ |
| 344 | 351 | .status = prev_build_status, |
| 345 | 352 | .flags = .{ |
| 346 | .time_report = ws.graph.time_report, | |
| 353 | .time_report = graph.time_report, | |
| 347 | 354 | }, |
| 348 | 355 | .timestamp = ws.now(), |
| 349 | .steps_len = @intCast(ws.all_steps.len), | |
| 356 | .steps_len = @intCast(all_steps.len), | |
| 350 | 357 | }; |
| 351 | 358 | var bufs: [3][]const u8 = .{ @ptrCast(&hello_header), ws.step_names_trailing, prev_step_status_bits }; |
| 352 | 359 | try sock.writeMessageVec(&bufs, .binary); |
| ... | ... | @@ -369,8 +376,8 @@ fn serveWebSocket(ws: *WebServer, sock: *http.Server.WebSocket) !noreturn { |
| 369 | 376 | if (update_time <= prev_time) continue; |
| 370 | 377 | // We want to send `msg`, but shouldn't block `ws.time_report_mutex` while we do, so |
| 371 | 378 | // that we don't hold up the build system on the client accepting this packet. |
| 372 | const owned_msg = try ws.gpa.dupe(u8, msg); | |
| 373 | defer ws.gpa.free(owned_msg); | |
| 379 | const owned_msg = try gpa.dupe(u8, msg); | |
| 380 | defer gpa.free(owned_msg); | |
| 374 | 381 | // Temporarily unlock, then re-lock after the message is sent. |
| 375 | 382 | ws.time_report_mutex.unlock(io); |
| 376 | 383 | defer ws.time_report_mutex.lockUncancelable(io); |
| ... | ... | @@ -427,7 +434,8 @@ fn serveWebSocket(ws: *WebServer, sock: *http.Server.WebSocket) !noreturn { |
| 427 | 434 | } |
| 428 | 435 | } |
| 429 | 436 | fn recvWebSocketMessages(ws: *WebServer, sock: *http.Server.WebSocket) void { |
| 430 | const io = ws.graph.io; | |
| 437 | const maker = ws.maker; | |
| 438 | const io = maker.graph.io; | |
| 431 | 439 | |
| 432 | 440 | while (true) { |
| 433 | 441 | const msg = sock.readSmallMessage() catch return; |
| ... | ... | @@ -485,8 +493,11 @@ fn serveLibFile( |
| 485 | 493 | sub_path: []const u8, |
| 486 | 494 | content_type: []const u8, |
| 487 | 495 | ) !void { |
| 496 | const maker = ws.maker; | |
| 497 | const graph = maker.graph; | |
| 498 | ||
| 488 | 499 | return serveFile(ws, request, .{ |
| 489 | .root_dir = ws.graph.zig_lib_directory, | |
| 500 | .root_dir = graph.zig_lib_directory, | |
| 490 | 501 | .sub_path = sub_path, |
| 491 | 502 | }, content_type); |
| 492 | 503 | } |
| ... | ... | @@ -495,7 +506,9 @@ fn serveClientWasm( |
| 495 | 506 | req: *http.Server.Request, |
| 496 | 507 | optimize_mode: std.builtin.OptimizeMode, |
| 497 | 508 | ) !void { |
| 498 | var arena_state: std.heap.ArenaAllocator = .init(ws.gpa); | |
| 509 | const gpa = ws.maker.gpa; | |
| 510 | ||
| 511 | var arena_state: std.heap.ArenaAllocator = .init(gpa); | |
| 499 | 512 | defer arena_state.deinit(); |
| 500 | 513 | const arena = arena_state.allocator(); |
| 501 | 514 | |
| ... | ... | @@ -510,8 +523,10 @@ pub fn serveFile( |
| 510 | 523 | path: Cache.Path, |
| 511 | 524 | content_type: []const u8, |
| 512 | 525 | ) !void { |
| 513 | const gpa = ws.gpa; | |
| 514 | const io = ws.graph.io; | |
| 526 | const maker = ws.maker; | |
| 527 | const gpa = ws.maker.gpa; | |
| 528 | const io = maker.graph.io; | |
| 529 | ||
| 515 | 530 | // The desired API is actually sendfile, which will require enhancing http.Server. |
| 516 | 531 | // We load the file with every request so that the user can make changes to the file |
| 517 | 532 | // and refresh the HTML page without restarting this server. |
| ... | ... | @@ -528,7 +543,8 @@ pub fn serveFile( |
| 528 | 543 | }); |
| 529 | 544 | } |
| 530 | 545 | pub fn serveTarFile(ws: *WebServer, request: *http.Server.Request, paths: []const Cache.Path) !void { |
| 531 | const graph = ws.graph; | |
| 546 | const maker = ws.maker; | |
| 547 | const graph = maker.graph; | |
| 532 | 548 | const io = graph.io; |
| 533 | 549 | |
| 534 | 550 | var send_buffer: [0x4000]u8 = undefined; |
| ... | ... | @@ -576,8 +592,9 @@ fn buildClientWasm(ws: *WebServer, arena: Allocator, optimize: std.builtin.Optim |
| 576 | 592 | const arch_os_abi = "wasm32-freestanding"; |
| 577 | 593 | const cpu_features = "baseline+atomics+bulk_memory+multivalue+mutable_globals+nontrapping_fptoint+reference_types+sign_ext"; |
| 578 | 594 | |
| 579 | const gpa = ws.gpa; | |
| 580 | const graph = ws.graph; | |
| 595 | const maker = ws.maker; | |
| 596 | const gpa = maker.gpa; | |
| 597 | const graph = maker.graph; | |
| 581 | 598 | const io = graph.io; |
| 582 | 599 | |
| 583 | 600 | const main_src_path: Cache.Path = .{ |
| ... | ... | @@ -697,7 +714,7 @@ fn buildClientWasm(ws: *WebServer, arena: Allocator, optimize: std.builtin.Optim |
| 697 | 714 | if (code != 0) { |
| 698 | 715 | log.err( |
| 699 | 716 | "the following command exited with error code {d}:\n{s}", |
| 700 | .{ code, try Step.allocPrintCmd(arena, .inherit, null, argv.items) }, | |
| 717 | .{ code, try std.zig.allocPrintCmd(arena, .inherit, null, argv.items) }, | |
| 701 | 718 | ); |
| 702 | 719 | return error.WasmCompilationFailed; |
| 703 | 720 | } |
| ... | ... | @@ -705,21 +722,21 @@ fn buildClientWasm(ws: *WebServer, arena: Allocator, optimize: std.builtin.Optim |
| 705 | 722 | .signal => |sig| { |
| 706 | 723 | log.err( |
| 707 | 724 | "the following command terminated with signal {t}:\n{s}", |
| 708 | .{ sig, try Step.allocPrintCmd(arena, .inherit, null, argv.items) }, | |
| 725 | .{ sig, try std.zig.allocPrintCmd(arena, .inherit, null, argv.items) }, | |
| 709 | 726 | ); |
| 710 | 727 | return error.WasmCompilationFailed; |
| 711 | 728 | }, |
| 712 | 729 | .stopped => |sig| { |
| 713 | 730 | log.err( |
| 714 | 731 | "the following command stopped unexpectedly with signal {t}:\n{s}", |
| 715 | .{ sig, try Build.Step.allocPrintCmd(arena, .inherit, null, argv.items) }, | |
| 732 | .{ sig, try std.zig.allocPrintCmd(arena, .inherit, null, argv.items) }, | |
| 716 | 733 | ); |
| 717 | 734 | return error.WasmCompilationFailed; |
| 718 | 735 | }, |
| 719 | 736 | .unknown => { |
| 720 | 737 | log.err( |
| 721 | 738 | "the following command terminated unexpectedly:\n{s}", |
| 722 | .{try Step.allocPrintCmd(arena, .inherit, null, argv.items)}, | |
| 739 | .{try std.zig.allocPrintCmd(arena, .inherit, null, argv.items)}, | |
| 723 | 740 | ); |
| 724 | 741 | return error.WasmCompilationFailed; |
| 725 | 742 | }, |
| ... | ... | @@ -729,14 +746,14 @@ fn buildClientWasm(ws: *WebServer, arena: Allocator, optimize: std.builtin.Optim |
| 729 | 746 | try result_error_bundle.renderToStderr(io, .{}, .auto); |
| 730 | 747 | log.err("the following command failed with {d} compilation errors:\n{s}", .{ |
| 731 | 748 | result_error_bundle.errorMessageCount(), |
| 732 | try Step.allocPrintCmd(arena, .inherit, null, argv.items), | |
| 749 | try std.zig.allocPrintCmd(arena, .inherit, null, argv.items), | |
| 733 | 750 | }); |
| 734 | 751 | return error.WasmCompilationFailed; |
| 735 | 752 | } |
| 736 | 753 | |
| 737 | 754 | const base_path = result orelse { |
| 738 | 755 | log.err("child process failed to report result\n{s}", .{ |
| 739 | try Step.allocPrintCmd(arena, .inherit, null, argv.items), | |
| 756 | try std.zig.allocPrintCmd(arena, .inherit, null, argv.items), | |
| 740 | 757 | }); |
| 741 | 758 | return error.WasmCompilationFailed; |
| 742 | 759 | }; |
| ... | ... | @@ -773,11 +790,13 @@ pub fn updateTimeReportCompile(ws: *WebServer, opts: struct { |
| 773 | 790 | /// The trailing data of `abi.time_report.CompileResult`, except the step name. |
| 774 | 791 | trailing: []const u8, |
| 775 | 792 | }) void { |
| 776 | const gpa = ws.gpa; | |
| 777 | const io = ws.graph.io; | |
| 793 | const maker = ws.maker; | |
| 794 | const gpa = maker.gpa; | |
| 795 | const io = maker.graph.io; | |
| 796 | const all_steps = maker.step_stack.keys(); | |
| 778 | 797 | |
| 779 | 798 | // TODO don't do linear search |
| 780 | const step_idx: u32 = for (ws.all_steps, 0..) |s, i| { | |
| 799 | const step_idx: u32 = for (all_steps, 0..) |s, i| { | |
| 781 | 800 | if (s == opts.compile_step) break @intCast(i); |
| 782 | 801 | } else unreachable; |
| 783 | 802 | |
| ... | ... | @@ -815,11 +834,13 @@ pub fn updateTimeReportCompile(ws: *WebServer, opts: struct { |
| 815 | 834 | } |
| 816 | 835 | |
| 817 | 836 | pub fn updateTimeReportGeneric(ws: *WebServer, step_index: Configuration.Step.Index, duration: Io.Duration) void { |
| 818 | const gpa = ws.gpa; | |
| 819 | const io = ws.graph.io; | |
| 837 | const maker = ws.maker; | |
| 838 | const gpa = maker.gpa; | |
| 839 | const io = maker.graph.io; | |
| 840 | const all_steps = maker.step_stack.keys(); | |
| 820 | 841 | |
| 821 | 842 | // TODO don't do linear search |
| 822 | const step_idx: u32 = for (ws.all_steps, 0..) |s, i| { | |
| 843 | const step_idx: u32 = for (all_steps, 0..) |s, i| { | |
| 823 | 844 | if (s == step_index) break @intCast(i); |
| 824 | 845 | } else unreachable; |
| 825 | 846 | |
| ... | ... | @@ -852,11 +873,13 @@ pub fn updateTimeReportRunTest( |
| 852 | 873 | tests: *const Step.Run.CachedTestMetadata, |
| 853 | 874 | ns_per_test: []const u64, |
| 854 | 875 | ) void { |
| 855 | const gpa = ws.gpa; | |
| 856 | const io = ws.graph.io; | |
| 876 | const maker = ws.maker; | |
| 877 | const gpa = maker.gpa; | |
| 878 | const io = maker.graph.io; | |
| 879 | const all_steps = maker.step_stack.keys(); | |
| 857 | 880 | |
| 858 | 881 | // TODO don't do linear search |
| 859 | const step_idx: u32 = for (ws.all_steps, 0..) |s, i| { | |
| 882 | const step_idx: u32 = for (all_steps, 0..) |s, i| { | |
| 860 | 883 | if (s == run_step_index) break @intCast(i); |
| 861 | 884 | } else unreachable; |
| 862 | 885 | |
| ... | ... | @@ -910,7 +933,7 @@ const RunnerRequest = union(enum) { |
| 910 | 933 | rebuild, |
| 911 | 934 | }; |
| 912 | 935 | pub fn getRunnerRequest(ws: *WebServer) ?RunnerRequest { |
| 913 | const io = ws.graph.io; | |
| 936 | const io = ws.maker.graph.io; | |
| 914 | 937 | ws.runner_request_mutex.lock(io) catch return; |
| 915 | 938 | defer ws.runner_request_mutex.unlock(io); |
| 916 | 939 | if (ws.runner_request) |req| { |
| ... | ... | @@ -921,7 +944,7 @@ pub fn getRunnerRequest(ws: *WebServer) ?RunnerRequest { |
| 921 | 944 | return null; |
| 922 | 945 | } |
| 923 | 946 | pub fn wait(ws: *WebServer) Io.Cancelable!RunnerRequest { |
| 924 | const io = ws.graph.io; | |
| 947 | const io = ws.maker.graph.io; | |
| 925 | 948 | try ws.runner_request_mutex.lock(io); |
| 926 | 949 | defer ws.runner_request_mutex.unlock(io); |
| 927 | 950 | while (true) { |
lib/std/Build.zig-13| ... | ... | @@ -45,7 +45,6 @@ install_prefix: []const u8, |
| 45 | 45 | /// Path to the directory containing build.zig. |
| 46 | 46 | build_root: Cache.Directory, |
| 47 | 47 | cache_root: Cache.Directory, |
| 48 | pkg_config_pkg_list: ?(PkgConfigError![]const PkgConfigPkg) = null, | |
| 49 | 48 | debug_log_scopes: []const []const u8 = &.{}, |
| 50 | 49 | debug_compile_errors: bool = false, |
| 51 | 50 | debug_incremental: bool = false, |
| ... | ... | @@ -176,18 +175,6 @@ pub const RunError = error{ |
| 176 | 175 | ExecNotSupported, |
| 177 | 176 | } || std.process.SpawnError; |
| 178 | 177 | |
| 179 | pub const PkgConfigError = error{ | |
| 180 | PkgConfigCrashed, | |
| 181 | PkgConfigFailed, | |
| 182 | PkgConfigNotInstalled, | |
| 183 | PkgConfigInvalidOutput, | |
| 184 | }; | |
| 185 | ||
| 186 | pub const PkgConfigPkg = struct { | |
| 187 | name: []const u8, | |
| 188 | desc: []const u8, | |
| 189 | }; | |
| 190 | ||
| 191 | 178 | const UserInputOptionsMap = StringHashMap(UserInputOption); |
| 192 | 179 | const AvailableOptionsMap = StringHashMap(AvailableOption); |
| 193 | 180 |
lib/std/Build/Step/Compile.zig-40| ... | ... | @@ -8,13 +8,9 @@ const fs = std.fs; |
| 8 | 8 | const assert = std.debug.assert; |
| 9 | 9 | const panic = std.debug.panic; |
| 10 | 10 | const StringHashMap = std.StringHashMap; |
| 11 | const Sha256 = std.crypto.hash.sha2.Sha256; | |
| 12 | 11 | const Allocator = std.mem.Allocator; |
| 13 | 12 | const Step = std.Build.Step; |
| 14 | 13 | const LazyPath = std.Build.LazyPath; |
| 15 | const PkgConfigPkg = std.Build.PkgConfigPkg; | |
| 16 | const PkgConfigError = std.Build.PkgConfigError; | |
| 17 | const RunError = std.Build.RunError; | |
| 18 | 14 | const Module = std.Build.Module; |
| 19 | 15 | const InstallDir = std.Build.InstallDir; |
| 20 | 16 | const GeneratedFile = std.Build.GeneratedFile; |
| ... | ... | @@ -777,42 +773,6 @@ pub fn setExecCmd(compile: *Compile, args: []const ?[]const u8) void { |
| 777 | 773 | compile.exec_cmd_args = duped_args; |
| 778 | 774 | } |
| 779 | 775 | |
| 780 | const CliNamedModules = struct { | |
| 781 | modules: std.AutoArrayHashMapUnmanaged(*Module, void), | |
| 782 | names: std.StringArrayHashMapUnmanaged(void), | |
| 783 | ||
| 784 | /// Traverse the whole dependency graph and give every module a unique | |
| 785 | /// name, ideally one named after what it's called somewhere in the graph. | |
| 786 | /// It will help here to have both a mapping from module to name and a set | |
| 787 | /// of all the currently-used names. | |
| 788 | fn init(arena: Allocator, root_module: *Module) Allocator.Error!CliNamedModules { | |
| 789 | var compile: CliNamedModules = .{ | |
| 790 | .modules = .{}, | |
| 791 | .names = .{}, | |
| 792 | }; | |
| 793 | const graph = root_module.getGraph(); | |
| 794 | { | |
| 795 | assert(graph.modules[0] == root_module); | |
| 796 | try compile.modules.put(arena, root_module, {}); | |
| 797 | try compile.names.put(arena, "root", {}); | |
| 798 | } | |
| 799 | for (graph.modules[1..], graph.names[1..]) |mod, orig_name| { | |
| 800 | var name = orig_name; | |
| 801 | var n: usize = 0; | |
| 802 | while (true) { | |
| 803 | const gop = try compile.names.getOrPut(arena, name); | |
| 804 | if (!gop.found_existing) { | |
| 805 | try compile.modules.putNoClobber(arena, mod, {}); | |
| 806 | break; | |
| 807 | } | |
| 808 | name = try std.fmt.allocPrint(arena, "{s}{d}", .{ orig_name, n }); | |
| 809 | n += 1; | |
| 810 | } | |
| 811 | } | |
| 812 | return compile; | |
| 813 | } | |
| 814 | }; | |
| 815 | ||
| 816 | 776 | fn getGeneratedFilePath(compile: *Compile, comptime tag_name: []const u8, asking_step: ?*Step) ![]const u8 { |
| 817 | 777 | const step = &compile.step; |
| 818 | 778 | const b = step.owner; |
lib/std/zig/Configuration.zig+15-11| ... | ... | @@ -436,23 +436,23 @@ pub const Step = extern struct { |
| 436 | 436 | }; |
| 437 | 437 | |
| 438 | 438 | pub const Tag = enum(u5) { |
| 439 | top_level, | |
| 439 | check_file, | |
| 440 | check_object, | |
| 440 | 441 | compile, |
| 442 | config_header, | |
| 443 | fail, | |
| 444 | fmt, | |
| 441 | 445 | install_artifact, |
| 442 | install_file, | |
| 443 | 446 | install_dir, |
| 447 | install_file, | |
| 448 | objcopy, | |
| 449 | options, | |
| 444 | 450 | remove_dir, |
| 445 | fail, | |
| 446 | fmt, | |
| 451 | run, | |
| 452 | top_level, | |
| 447 | 453 | translate_c, |
| 448 | write_file, | |
| 449 | 454 | update_source_files, |
| 450 | run, | |
| 451 | check_file, | |
| 452 | check_object, | |
| 453 | config_header, | |
| 454 | objcopy, | |
| 455 | options, | |
| 455 | write_file, | |
| 456 | 456 | }; |
| 457 | 457 | |
| 458 | 458 | pub const TopLevel = struct { |
| ... | ... | @@ -808,6 +808,10 @@ pub const Step = extern struct { |
| 808 | 808 | _: u23 = 0, |
| 809 | 809 | }; |
| 810 | 810 | }; |
| 811 | ||
| 812 | pub fn flags(s: *const Step, c: *const Configuration) Flags { | |
| 813 | return @bitCast(c.extra[s.extra_index]); | |
| 814 | } | |
| 811 | 815 | }; |
| 812 | 816 | |
| 813 | 817 | pub const MaxRss = enum(u32) { |