| ... | @@ -63,9 +63,9 @@ protocol_server_mutex: Io.Mutex, | ... | @@ -63,9 +63,9 @@ protocol_server_mutex: Io.Mutex, |
| 63 | web_server: ?*AvoidableWebServer, | 63 | web_server: ?*AvoidableWebServer, |
| 64 | /// Allocated into `gpa`. | 64 | /// Allocated into `gpa`. |
| 65 | memory_blocked_steps: std.ArrayList(Configuration.Step.Index), | 65 | memory_blocked_steps: std.ArrayList(Configuration.Step.Index), |
| 66 | /// Allocated into `gpa`. | 66 | /// Allocated into `gpa` during `prepare`. |
| 67 | initial_steps: std.array_hash_map.Auto(Configuration.Step.Index, void), | 67 | initial_steps: std.array_hash_map.Auto(Configuration.Step.Index, void), |
| 68 | /// Allocated into `gpa`. | 68 | /// Allocated into `gpa` during `prepare`. |
| 69 | step_stack: std.array_hash_map.Auto(Configuration.Step.Index, void), | 69 | step_stack: std.array_hash_map.Auto(Configuration.Step.Index, void), |
| 70 | pkg_config: PkgConfig, | 70 | pkg_config: PkgConfig, |
| 71 | | 71 | |
| ... | @@ -163,7 +163,6 @@ pub fn main(init: process.Init.Minimal) !void { | ... | @@ -163,7 +163,6 @@ pub fn main(init: process.Init.Minimal) !void { |
| 163 | | 163 | |
| 164 | var arena_instance: std.heap.ArenaAllocator = .init(std.heap.page_allocator); | 164 | var arena_instance: std.heap.ArenaAllocator = .init(std.heap.page_allocator); |
| 165 | defer arena_instance.deinit(); | 165 | defer arena_instance.deinit(); |
| 166 | defer if (debugMakerLeaks()) log.debug("used {Bi} of arena", .{arena_instance.queryCapacity()}); | | |
| 167 | const arena = arena_instance.allocator(); | 166 | const arena = arena_instance.allocator(); |
| 168 | | 167 | |
| 169 | const args = try init.args.toSlice(arena); | 168 | const args = try init.args.toSlice(arena); |
| ... | @@ -445,8 +444,6 @@ pub fn main(init: process.Init.Minimal) !void { | ... | @@ -445,8 +444,6 @@ pub fn main(init: process.Init.Minimal) !void { |
| 445 | } else if (mem.cutPrefix(u8, arg, "--debug-rt=")) |rest| { | 444 | } else if (mem.cutPrefix(u8, arg, "--debug-rt=")) |rest| { |
| 446 | graph.debug_compiler_runtime_libs = stringToEnum(std.lang.Optimize, rest) orelse | 445 | graph.debug_compiler_runtime_libs = stringToEnum(std.lang.Optimize, rest) orelse |
| 447 | fatal("unrecognized optimization mode: {s}", .{rest}); | 446 | fatal("unrecognized optimization mode: {s}", .{rest}); |
| 448 | } else if (is_debug_mode and mem.eql(u8, arg, "--debug-maker-leaks")) { | | |
| 449 | debug_maker_leaks = true; | | |
| 450 | } else if (mem.eql(u8, arg, "--libc-runtimes") or mem.eql(u8, arg, "--glibc-runtimes")) { | 447 | } else if (mem.eql(u8, arg, "--libc-runtimes") or mem.eql(u8, arg, "--glibc-runtimes")) { |
| 451 | // --glibc-runtimes was the old name of the flag; kept for compatibility for now. | 448 | // --glibc-runtimes was the old name of the flag; kept for compatibility for now. |
| 452 | graph.libc_runtimes_dir = nextArgOrFatal(args, &arg_i); | 449 | graph.libc_runtimes_dir = nextArgOrFatal(args, &arg_i); |
| ... | @@ -682,9 +679,8 @@ pub fn main(init: process.Init.Minimal) !void { | ... | @@ -682,9 +679,8 @@ pub fn main(init: process.Init.Minimal) !void { |
| 682 | } else null; | 679 | } else null; |
| 683 | | 680 | |
| 684 | var stdin_buffer: [256]u8 = undefined; | 681 | var stdin_buffer: [256]u8 = undefined; |
| 685 | var stdout_buffer: [256]u8 = undefined; | | |
| 686 | var stdin_reader = Io.File.stdin().reader(io, &stdin_buffer); | 682 | var stdin_reader = Io.File.stdin().reader(io, &stdin_buffer); |
| 687 | var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer); | 683 | const stdout_writer = initStdoutWriter(io); |
| 688 | | 684 | |
| 689 | var protocol_server_allocation: AvoidableServer = undefined; | 685 | var protocol_server_allocation: AvoidableServer = undefined; |
| 690 | const protocol_server: ?*AvoidableServer = if (listen) s: { | 686 | const protocol_server: ?*AvoidableServer = if (listen) s: { |
| ... | @@ -694,9 +690,9 @@ pub fn main(init: process.Init.Minimal) !void { | ... | @@ -694,9 +690,9 @@ pub fn main(init: process.Init.Minimal) !void { |
| 694 | if (step_names.items.len > 0) fatal("build steps must be provided over the protocol instead of using CLI arguments", .{}); | 690 | if (step_names.items.len > 0) fatal("build steps must be provided over the protocol instead of using CLI arguments", .{}); |
| 695 | protocol_server_allocation = .{ | 691 | protocol_server_allocation = .{ |
| 696 | .in = &stdin_reader.interface, | 692 | .in = &stdin_reader.interface, |
| 697 | .out = &stdout_writer.interface, | 693 | .out = stdout_writer, |
| 698 | }; | 694 | }; |
| 699 | try serveBSPHandshake(&protocol_server_allocation); | 695 | try serveBspHandshake(&protocol_server_allocation); |
| 700 | break :s &protocol_server_allocation; | 696 | break :s &protocol_server_allocation; |
| 701 | } else null; | 697 | } else null; |
| 702 | | 698 | |
| ... | @@ -764,10 +760,8 @@ pub fn main(init: process.Init.Minimal) !void { | ... | @@ -764,10 +760,8 @@ pub fn main(init: process.Init.Minimal) !void { |
| 764 | .include = install_include_path, | 760 | .include = install_include_path, |
| 765 | }, | 761 | }, |
| 766 | | 762 | |
| 767 | // Extra step at the end which is the autogenerated placeholder | 763 | .steps = &.{}, |
| 768 | // step which indicates that we need to reconfigure. | 764 | .generated_files = &.{}, |
| 769 | .steps = try arena.alloc(Step, scanned_config.configuration.steps.len + 1), | | |
| 770 | .generated_files = try arena.alloc(Path, scanned_config.configuration.generated_files_len), | | |
| 771 | .run_args = run_args, | 765 | .run_args = run_args, |
| 772 | | 766 | |
| 773 | .available_rss = max_rss, | 767 | .available_rss = max_rss, |
| ... | @@ -794,11 +788,7 @@ pub fn main(init: process.Init.Minimal) !void { | ... | @@ -794,11 +788,7 @@ pub fn main(init: process.Init.Minimal) !void { |
| 794 | else | 788 | else |
| 795 | .failures, | 789 | .failures, |
| 796 | }; | 790 | }; |
| 797 | defer { | 791 | defer maker.deinit(); |
| 798 | maker.memory_blocked_steps.deinit(gpa); | | |
| 799 | maker.initial_steps.deinit(gpa); | | |
| 800 | maker.step_stack.deinit(gpa); | | |
| 801 | } | | |
| 802 | | 792 | |
| 803 | if (maker.available_rss == 0) { | 793 | if (maker.available_rss == 0) { |
| 804 | maker.available_rss = process.totalSystemMemory() catch std.math.maxInt(u64); | 794 | maker.available_rss = process.totalSystemMemory() catch std.math.maxInt(u64); |
| ... | @@ -820,6 +810,11 @@ pub fn main(init: process.Init.Minimal) !void { | ... | @@ -820,6 +810,11 @@ pub fn main(init: process.Init.Minimal) !void { |
| 820 | var select: Io.Select(Event) = .init(io, &select_buffer); | 810 | var select: Io.Select(Event) = .init(io, &select_buffer); |
| 821 | defer select.cancelDiscard(); | 811 | defer select.cancelDiscard(); |
| 822 | | 812 | |
| | 813 | // File watching cannot be canceled without blocking |
| | 814 | // https://codeberg.org/ziglang/zig/issues/31693 |
| | 815 | var is_fs_watching = false; |
| | 816 | defer if (is_fs_watching) @panic("(zig build system) TODO file watching cannot be canceled without blocking"); |
| | 817 | |
| 823 | try select.concurrent(.message, Server.receiveMessage, .{s}); | 818 | try select.concurrent(.message, Server.receiveMessage, .{s}); |
| 824 | | 819 | |
| 825 | var in_debounce = false; | 820 | var in_debounce = false; |
| ... | @@ -828,10 +823,13 @@ pub fn main(init: process.Init.Minimal) !void { | ... | @@ -828,10 +823,13 @@ pub fn main(init: process.Init.Minimal) !void { |
| 828 | const header: Client.Message.Header = try payload; | 823 | const header: Client.Message.Header = try payload; |
| 829 | switch (header.tag) { | 824 | switch (header.tag) { |
| 830 | .exit => { | 825 | .exit => { |
| 831 | cleanExit(io, &scanned_config); | 826 | // exit early until file watching supports cancelation without blocking |
| 832 | process.exit(0); | 827 | if (is_fs_watching) std.process.exit(0); |
| | 828 | return cleanExit(io, &scanned_config); |
| 833 | }, | 829 | }, |
| 834 | .bsp_build_steps => { | 830 | .bsp_build_steps => { |
| | 831 | if (is_fs_watching) @panic("(zig build system) TODO file watching cannot be canceled without blocking"); |
| | 832 | |
| 835 | // Cancel existing file watching | 833 | // Cancel existing file watching |
| 836 | select.cancelDiscard(); | 834 | select.cancelDiscard(); |
| 837 | in_debounce = false; | 835 | in_debounce = false; |
| ... | @@ -865,6 +863,10 @@ pub fn main(init: process.Init.Minimal) !void { | ... | @@ -865,6 +863,10 @@ pub fn main(init: process.Init.Minimal) !void { |
| 865 | &watch.?, | 863 | &watch.?, |
| 866 | if (in_debounce) .{ .ms = debounce_interval_ms } else .none, | 864 | if (in_debounce) .{ .ms = debounce_interval_ms } else .none, |
| 867 | }); | 865 | }); |
| | 866 | is_fs_watching = true; |
| | 867 | } else if (watch) |*w| { |
| | 868 | w.deinit(); |
| | 869 | watch = null; |
| 868 | } | 870 | } |
| 869 | | 871 | |
| 870 | continue :loop try select.await(); | 872 | continue :loop try select.await(); |
| ... | @@ -873,6 +875,7 @@ pub fn main(init: process.Init.Minimal) !void { | ... | @@ -873,6 +875,7 @@ pub fn main(init: process.Init.Minimal) !void { |
| 873 | } | 875 | } |
| 874 | }, | 876 | }, |
| 875 | .fs_event => |payload| { | 877 | .fs_event => |payload| { |
| | 878 | is_fs_watching = false; |
| 876 | if (!Watch.have_impl) unreachable; | 879 | if (!Watch.have_impl) unreachable; |
| 877 | switch (payload catch |err| switch (err) { | 880 | switch (payload catch |err| switch (err) { |
| 878 | error.MustReconfigure => { | 881 | error.MustReconfigure => { |
| ... | @@ -894,6 +897,7 @@ pub fn main(init: process.Init.Minimal) !void { | ... | @@ -894,6 +897,7 @@ pub fn main(init: process.Init.Minimal) !void { |
| 894 | &watch.?, | 897 | &watch.?, |
| 895 | if (in_debounce) .{ .ms = debounce_interval_ms } else .none, | 898 | if (in_debounce) .{ .ms = debounce_interval_ms } else .none, |
| 896 | }); | 899 | }); |
| | 900 | is_fs_watching = true; |
| 897 | continue :loop try select.await(); | 901 | continue :loop try select.await(); |
| 898 | }, | 902 | }, |
| 899 | } | 903 | } |
| ... | @@ -917,7 +921,7 @@ pub fn main(init: process.Init.Minimal) !void { | ... | @@ -917,7 +921,7 @@ pub fn main(init: process.Init.Minimal) !void { |
| 917 | if (!Watch.have_impl) fatal("--watch not yet implemented for {t}", .{native_os}); | 921 | if (!Watch.have_impl) fatal("--watch not yet implemented for {t}", .{native_os}); |
| 918 | break :w try .init(&maker); | 922 | break :w try .init(&maker); |
| 919 | }; | 923 | }; |
| 920 | defer w.deinit(); | 924 | defer if (watch_flag) w.deinit(); |
| 921 | | 925 | |
| 922 | if (web_server) |ws| try ws.updateConfiguration(&maker); | 926 | if (web_server) |ws| try ws.updateConfiguration(&maker); |
| 923 | | 927 | |
| ... | @@ -2333,6 +2337,11 @@ fn prepare( | ... | @@ -2333,6 +2337,11 @@ fn prepare( |
| 2333 | const step_stack = &maker.step_stack; | 2337 | const step_stack = &maker.step_stack; |
| 2334 | const c = &maker.scanned_config.configuration; | 2338 | const c = &maker.scanned_config.configuration; |
| 2335 | | 2339 | |
| | 2340 | // Extra step at the end which is the autogenerated placeholder |
| | 2341 | // step which indicates that we need to reconfigure. |
| | 2342 | maker.steps = try arena.alloc(Step, c.steps.len + 1); |
| | 2343 | maker.generated_files = try arena.alloc(Path, c.generated_files_len); |
| | 2344 | |
| 2336 | // The last element is a reserved special pseudostep which contains the | 2345 | // The last element is a reserved special pseudostep which contains the |
| 2337 | // watch inputs for the configurer executable. | 2346 | // watch inputs for the configurer executable. |
| 2338 | for (maker.steps[0 .. maker.steps.len - 1], 0..) |*step, step_index_usize| { | 2347 | for (maker.steps[0 .. maker.steps.len - 1], 0..) |*step, step_index_usize| { |
| ... | @@ -2652,8 +2661,7 @@ fn makeSteps( | ... | @@ -2652,8 +2661,7 @@ fn makeSteps( |
| 2652 | break :code 2; // failure; do not print build command | 2661 | break :code 2; // failure; do not print build command |
| 2653 | }; | 2662 | }; |
| 2654 | if (code == 0) { | 2663 | if (code == 0) { |
| 2655 | removePoisonedConfiguration(io, maker.scanned_config); | 2664 | return cleanExit(io, maker.scanned_config); |
| 2656 | if (debugMakerLeaks()) return deinit(maker); | | |
| 2657 | } | 2665 | } |
| 2658 | cleanup_task.await(io); // There is a defer above but an exit below. | 2666 | cleanup_task.await(io); // There is a defer above but an exit below. |
| 2659 | _ = io.lockStderr(&.{}, graph.stderr_mode) catch {}; | 2667 | _ = io.lockStderr(&.{}, graph.stderr_mode) catch {}; |
| ... | @@ -2662,12 +2670,10 @@ fn makeSteps( | ... | @@ -2662,12 +2670,10 @@ fn makeSteps( |
| 2662 | | 2670 | |
| 2663 | fn deinit(maker: *Maker) void { | 2671 | fn deinit(maker: *Maker) void { |
| 2664 | const gpa = maker.gpa; | 2672 | const gpa = maker.gpa; |
| 2665 | for (maker.steps) |*step| { | 2673 | for (maker.steps) |*step| step.deinit(gpa); |
| 2666 | step.clearResultStderr(gpa); | 2674 | maker.memory_blocked_steps.deinit(gpa); |
| 2667 | step.clearFailedCommand(gpa); | 2675 | maker.initial_steps.deinit(gpa); |
| 2668 | step.clearErrorBundle(gpa); | 2676 | maker.step_stack.deinit(gpa); |
| 2669 | step.inputs.deinit(gpa); | | |
| 2670 | } | | |
| 2671 | } | 2677 | } |
| 2672 | | 2678 | |
| 2673 | fn stepReady( | 2679 | fn stepReady( |
| ... | @@ -2800,9 +2806,10 @@ fn makeStep( | ... | @@ -2800,9 +2806,10 @@ fn makeStep( |
| 2800 | } | 2806 | } |
| 2801 | | 2807 | |
| 2802 | // No matter the result, we want to display error/warning messages. | 2808 | // No matter the result, we want to display error/warning messages. |
| 2803 | if (make_step.result_error_bundle.errorMessageCount() > 0 or | 2809 | if (maker.protocol_server == null and |
| 2804 | make_step.result_error_msgs.items.len > 0 or | 2810 | (make_step.result_error_bundle.errorMessageCount() > 0 or |
| 2805 | make_step.result_stderr.len > 0) | 2811 | make_step.result_error_msgs.items.len > 0 or |
| | 2812 | make_step.result_stderr.len > 0)) |
| 2806 | { | 2813 | { |
| 2807 | const stderr = try io.lockStderr(&stdio_buffer_allocation, graph.stderr_mode); | 2814 | const stderr = try io.lockStderr(&stdio_buffer_allocation, graph.stderr_mode); |
| 2808 | defer io.unlockStderr(); | 2815 | defer io.unlockStderr(); |
| ... | @@ -3360,7 +3367,7 @@ fn cleanTmpFiles(maker: *Maker, steps: []const Configuration.Step.Index) void { | ... | @@ -3360,7 +3367,7 @@ fn cleanTmpFiles(maker: *Maker, steps: []const Configuration.Step.Index) void { |
| 3360 | } | 3367 | } |
| 3361 | } | 3368 | } |
| 3362 | | 3369 | |
| 3363 | fn serveBSPHandshake(s: *const std.zig.Server) !void { | 3370 | fn serveBspHandshake(s: *const std.zig.Server) !void { |
| 3364 | const handshake_header: Server.Message.Handshake = .{ | 3371 | const handshake_header: Server.Message.Handshake = .{ |
| 3365 | .version = Server.build_system_version, | 3372 | .version = Server.build_system_version, |
| 3366 | .flags = .{ | 3373 | .flags = .{ |
| ... | @@ -3744,11 +3751,6 @@ fn removePoisonedConfiguration(io: Io, scanned_config: *const ScannedConfig) voi | ... | @@ -3744,11 +3751,6 @@ fn removePoisonedConfiguration(io: Io, scanned_config: *const ScannedConfig) voi |
| 3744 | } | 3751 | } |
| 3745 | } | 3752 | } |
| 3746 | | 3753 | |
| 3747 | inline fn debugMakerLeaks() bool { | | |
| 3748 | if (!is_debug_mode) return false; | | |
| 3749 | return debug_maker_leaks; | | |
| 3750 | } | | |
| 3751 | | | |
| 3752 | const BuildRoot = struct { | 3754 | const BuildRoot = struct { |
| 3753 | directory: Cache.Directory, | 3755 | directory: Cache.Directory, |
| 3754 | close_directory: bool, | 3756 | close_directory: bool, |