| author | |
| committer | |
| log | a333bb91ffcf63fbe377ddc82fd7f1633e269430 |
| tree | 95ed82003498b27d49e5e865b1e75d1a0fc0c3ff |
| parent | 59f5df3af9c31ffef33862c15bcbce6b4227ff1f |
This commit extracts out server code into src/Server.zig and uses it
both in the main CLI as well as `zig objcopy`.
std.Build.ObjCopyStep now adds `--listen=-` to the CLI for `zig objcopy`
and observes the protocol for progress and other kinds of integrations.
This fixes the last two test failures of this branch when I run
`zig build test` locally.5 files changed, 177 insertions(+), 97 deletions(-)
CMakeLists.txt+1| ... | ... | @@ -623,6 +623,7 @@ set(ZIG_STAGE2_SOURCES |
| 623 | 623 | "${CMAKE_SOURCE_DIR}/src/print_targets.zig" |
| 624 | 624 | "${CMAKE_SOURCE_DIR}/src/print_zir.zig" |
| 625 | 625 | "${CMAKE_SOURCE_DIR}/src/register_manager.zig" |
| 626 | "${CMAKE_SOURCE_DIR}/src/Server.zig" | |
| 626 | 627 | "${CMAKE_SOURCE_DIR}/src/target.zig" |
| 627 | 628 | "${CMAKE_SOURCE_DIR}/src/tracy.zig" |
| 628 | 629 | "${CMAKE_SOURCE_DIR}/src/translate_c.zig" |
lib/std/Build/ObjCopyStep.zig+2| ... | ... | @@ -113,6 +113,8 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 113 | 113 | }; |
| 114 | 114 | |
| 115 | 115 | try argv.appendSlice(&.{ full_src_path, full_dest_path }); |
| 116 | ||
| 117 | try argv.append("--listen=-"); | |
| 116 | 118 | _ = try step.evalZigProcess(argv.items, prog_node); |
| 117 | 119 | |
| 118 | 120 | self.output_file.path = full_dest_path; |
src/Server.zig created+113| ... | ... | @@ -0,0 +1,113 @@ |
| 1 | in: std.fs.File, | |
| 2 | out: std.fs.File, | |
| 3 | receive_fifo: std.fifo.LinearFifo(u8, .Dynamic), | |
| 4 | ||
| 5 | pub const Options = struct { | |
| 6 | gpa: Allocator, | |
| 7 | in: std.fs.File, | |
| 8 | out: std.fs.File, | |
| 9 | }; | |
| 10 | ||
| 11 | pub fn init(options: Options) !Server { | |
| 12 | var s: Server = .{ | |
| 13 | .in = options.in, | |
| 14 | .out = options.out, | |
| 15 | .receive_fifo = std.fifo.LinearFifo(u8, .Dynamic).init(options.gpa), | |
| 16 | }; | |
| 17 | try s.serveStringMessage(.zig_version, build_options.version); | |
| 18 | return s; | |
| 19 | } | |
| 20 | ||
| 21 | pub fn deinit(s: *Server) void { | |
| 22 | s.receive_fifo.deinit(); | |
| 23 | s.* = undefined; | |
| 24 | } | |
| 25 | ||
| 26 | pub fn receiveMessage(s: *Server) !InMessage.Header { | |
| 27 | const Header = InMessage.Header; | |
| 28 | const fifo = &s.receive_fifo; | |
| 29 | ||
| 30 | while (true) { | |
| 31 | const buf = fifo.readableSlice(0); | |
| 32 | assert(fifo.readableLength() == buf.len); | |
| 33 | if (buf.len >= @sizeOf(Header)) { | |
| 34 | const header = @ptrCast(*align(1) const Header, buf[0..@sizeOf(Header)]); | |
| 35 | if (header.bytes_len != 0) | |
| 36 | return error.InvalidClientMessage; | |
| 37 | const result = header.*; | |
| 38 | fifo.discard(@sizeOf(Header)); | |
| 39 | return result; | |
| 40 | } | |
| 41 | ||
| 42 | const write_buffer = try fifo.writableWithSize(256); | |
| 43 | const amt = try s.in.read(write_buffer); | |
| 44 | fifo.update(amt); | |
| 45 | } | |
| 46 | } | |
| 47 | ||
| 48 | pub fn serveStringMessage(s: *Server, tag: OutMessage.Tag, msg: []const u8) !void { | |
| 49 | return s.serveMessage(.{ | |
| 50 | .tag = tag, | |
| 51 | .bytes_len = @intCast(u32, msg.len), | |
| 52 | }, &.{msg}); | |
| 53 | } | |
| 54 | ||
| 55 | pub fn serveMessage( | |
| 56 | s: *const Server, | |
| 57 | header: OutMessage.Header, | |
| 58 | bufs: []const []const u8, | |
| 59 | ) !void { | |
| 60 | var iovecs: [10]std.os.iovec_const = undefined; | |
| 61 | iovecs[0] = .{ | |
| 62 | .iov_base = @ptrCast([*]const u8, &header), | |
| 63 | .iov_len = @sizeOf(OutMessage.Header), | |
| 64 | }; | |
| 65 | for (bufs, iovecs[1 .. bufs.len + 1]) |buf, *iovec| { | |
| 66 | iovec.* = .{ | |
| 67 | .iov_base = buf.ptr, | |
| 68 | .iov_len = buf.len, | |
| 69 | }; | |
| 70 | } | |
| 71 | try s.out.writevAll(iovecs[0 .. bufs.len + 1]); | |
| 72 | } | |
| 73 | ||
| 74 | pub fn serveEmitBinPath( | |
| 75 | s: *Server, | |
| 76 | fs_path: []const u8, | |
| 77 | header: std.zig.Server.Message.EmitBinPath, | |
| 78 | ) !void { | |
| 79 | try s.serveMessage(.{ | |
| 80 | .tag = .emit_bin_path, | |
| 81 | .bytes_len = @intCast(u32, fs_path.len + @sizeOf(std.zig.Server.Message.EmitBinPath)), | |
| 82 | }, &.{ | |
| 83 | std.mem.asBytes(&header), | |
| 84 | fs_path, | |
| 85 | }); | |
| 86 | } | |
| 87 | ||
| 88 | pub fn serveErrorBundle(s: *Server, error_bundle: std.zig.ErrorBundle) !void { | |
| 89 | const eb_hdr: std.zig.Server.Message.ErrorBundle = .{ | |
| 90 | .extra_len = @intCast(u32, error_bundle.extra.len), | |
| 91 | .string_bytes_len = @intCast(u32, error_bundle.string_bytes.len), | |
| 92 | }; | |
| 93 | const bytes_len = @sizeOf(std.zig.Server.Message.ErrorBundle) + | |
| 94 | 4 * error_bundle.extra.len + error_bundle.string_bytes.len; | |
| 95 | try s.serveMessage(.{ | |
| 96 | .tag = .error_bundle, | |
| 97 | .bytes_len = @intCast(u32, bytes_len), | |
| 98 | }, &.{ | |
| 99 | std.mem.asBytes(&eb_hdr), | |
| 100 | // TODO: implement @ptrCast between slices changing the length | |
| 101 | std.mem.sliceAsBytes(error_bundle.extra), | |
| 102 | error_bundle.string_bytes, | |
| 103 | }); | |
| 104 | } | |
| 105 | ||
| 106 | const OutMessage = std.zig.Server.Message; | |
| 107 | const InMessage = std.zig.Client.Message; | |
| 108 | ||
| 109 | const Server = @This(); | |
| 110 | const std = @import("std"); | |
| 111 | const build_options = @import("build_options"); | |
| 112 | const Allocator = std.mem.Allocator; | |
| 113 | const assert = std.debug.assert; |
src/main.zig+18-93| ... | ... | @@ -26,6 +26,7 @@ const target_util = @import("target.zig"); |
| 26 | 26 | const crash_report = @import("crash_report.zig"); |
| 27 | 27 | const Module = @import("Module.zig"); |
| 28 | 28 | const AstGen = @import("AstGen.zig"); |
| 29 | const Server = @import("Server.zig"); | |
| 29 | 30 | |
| 30 | 31 | pub const std_options = struct { |
| 31 | 32 | pub const wasiCwd = wasi_cwd; |
| ... | ... | @@ -3540,11 +3541,14 @@ fn serve( |
| 3540 | 3541 | ) !void { |
| 3541 | 3542 | const gpa = comp.gpa; |
| 3542 | 3543 | |
| 3543 | try serveStringMessage(out, .zig_version, build_options.version); | |
| 3544 | var server = try Server.init(.{ | |
| 3545 | .gpa = gpa, | |
| 3546 | .in = in, | |
| 3547 | .out = out, | |
| 3548 | }); | |
| 3549 | defer server.deinit(); | |
| 3544 | 3550 | |
| 3545 | 3551 | var child_pid: ?std.ChildProcess.Id = null; |
| 3546 | var receive_fifo = std.fifo.LinearFifo(u8, .Dynamic).init(gpa); | |
| 3547 | defer receive_fifo.deinit(); | |
| 3548 | 3552 | |
| 3549 | 3553 | var progress: std.Progress = .{ |
| 3550 | 3554 | .terminal = null, |
| ... | ... | @@ -3564,7 +3568,7 @@ fn serve( |
| 3564 | 3568 | main_progress_node.context = &progress; |
| 3565 | 3569 | |
| 3566 | 3570 | while (true) { |
| 3567 | const hdr = try receiveMessage(in, &receive_fifo); | |
| 3571 | const hdr = try server.receiveMessage(); | |
| 3568 | 3572 | |
| 3569 | 3573 | switch (hdr.tag) { |
| 3570 | 3574 | .exit => { |
| ... | ... | @@ -3580,7 +3584,7 @@ fn serve( |
| 3580 | 3584 | const arena = arena_instance.allocator(); |
| 3581 | 3585 | var output: TranslateCOutput = undefined; |
| 3582 | 3586 | try cmdTranslateC(comp, arena, &output); |
| 3583 | try serveEmitBinPath(out, output.path, .{ | |
| 3587 | try server.serveEmitBinPath(output.path, .{ | |
| 3584 | 3588 | .flags = .{ .cache_hit = output.cache_hit }, |
| 3585 | 3589 | }); |
| 3586 | 3590 | continue; |
| ... | ... | @@ -3594,7 +3598,7 @@ fn serve( |
| 3594 | 3598 | var reset: std.Thread.ResetEvent = .{}; |
| 3595 | 3599 | |
| 3596 | 3600 | var progress_thread = try std.Thread.spawn(.{}, progressThread, .{ |
| 3597 | &progress, out, &reset, | |
| 3601 | &progress, &server, &reset, | |
| 3598 | 3602 | }); |
| 3599 | 3603 | defer { |
| 3600 | 3604 | reset.set(); |
| ... | ... | @@ -3605,7 +3609,7 @@ fn serve( |
| 3605 | 3609 | } |
| 3606 | 3610 | |
| 3607 | 3611 | try comp.makeBinFileExecutable(); |
| 3608 | try serveUpdateResults(out, comp); | |
| 3612 | try serveUpdateResults(&server, comp); | |
| 3609 | 3613 | }, |
| 3610 | 3614 | .run => { |
| 3611 | 3615 | if (child_pid != null) { |
| ... | ... | @@ -3632,14 +3636,14 @@ fn serve( |
| 3632 | 3636 | assert(main_progress_node.recently_updated_child == null); |
| 3633 | 3637 | if (child_pid) |pid| { |
| 3634 | 3638 | try comp.hotCodeSwap(main_progress_node, pid); |
| 3635 | try serveUpdateResults(out, comp); | |
| 3639 | try serveUpdateResults(&server, comp); | |
| 3636 | 3640 | } else { |
| 3637 | 3641 | if (comp.bin_file.options.output_mode == .Exe) { |
| 3638 | 3642 | try comp.makeBinFileWritable(); |
| 3639 | 3643 | } |
| 3640 | 3644 | try comp.update(main_progress_node); |
| 3641 | 3645 | try comp.makeBinFileExecutable(); |
| 3642 | try serveUpdateResults(out, comp); | |
| 3646 | try serveUpdateResults(&server, comp); | |
| 3643 | 3647 | |
| 3644 | 3648 | child_pid = try runOrTestHotSwap( |
| 3645 | 3649 | comp, |
| ... | ... | @@ -3659,7 +3663,7 @@ fn serve( |
| 3659 | 3663 | } |
| 3660 | 3664 | } |
| 3661 | 3665 | |
| 3662 | fn progressThread(progress: *std.Progress, out: fs.File, reset: *std.Thread.ResetEvent) void { | |
| 3666 | fn progressThread(progress: *std.Progress, server: *const Server, reset: *std.Thread.ResetEvent) void { | |
| 3663 | 3667 | while (true) { |
| 3664 | 3668 | if (reset.timedWait(500 * std.time.ns_per_ms)) |_| { |
| 3665 | 3669 | // The Compilation update has completed. |
| ... | ... | @@ -3705,7 +3709,7 @@ fn progressThread(progress: *std.Progress, out: fs.File, reset: *std.Thread.Rese |
| 3705 | 3709 | |
| 3706 | 3710 | const progress_string = buf.slice(); |
| 3707 | 3711 | |
| 3708 | serveMessage(out, .{ | |
| 3712 | server.serveMessage(.{ | |
| 3709 | 3713 | .tag = .progress, |
| 3710 | 3714 | .bytes_len = @intCast(u32, progress_string.len), |
| 3711 | 3715 | }, &.{ |
| ... | ... | @@ -3716,100 +3720,21 @@ fn progressThread(progress: *std.Progress, out: fs.File, reset: *std.Thread.Rese |
| 3716 | 3720 | } |
| 3717 | 3721 | } |
| 3718 | 3722 | |
| 3719 | fn serveMessage( | |
| 3720 | out: fs.File, | |
| 3721 | header: std.zig.Server.Message.Header, | |
| 3722 | bufs: []const []const u8, | |
| 3723 | ) !void { | |
| 3724 | var iovecs: [10]std.os.iovec_const = undefined; | |
| 3725 | iovecs[0] = .{ | |
| 3726 | .iov_base = @ptrCast([*]const u8, &header), | |
| 3727 | .iov_len = @sizeOf(std.zig.Server.Message.Header), | |
| 3728 | }; | |
| 3729 | for (bufs, iovecs[1 .. bufs.len + 1]) |buf, *iovec| { | |
| 3730 | iovec.* = .{ | |
| 3731 | .iov_base = buf.ptr, | |
| 3732 | .iov_len = buf.len, | |
| 3733 | }; | |
| 3734 | } | |
| 3735 | try out.writevAll(iovecs[0 .. bufs.len + 1]); | |
| 3736 | } | |
| 3737 | ||
| 3738 | fn serveErrorBundle(out: fs.File, error_bundle: std.zig.ErrorBundle) !void { | |
| 3739 | const eb_hdr: std.zig.Server.Message.ErrorBundle = .{ | |
| 3740 | .extra_len = @intCast(u32, error_bundle.extra.len), | |
| 3741 | .string_bytes_len = @intCast(u32, error_bundle.string_bytes.len), | |
| 3742 | }; | |
| 3743 | const bytes_len = @sizeOf(std.zig.Server.Message.ErrorBundle) + | |
| 3744 | 4 * error_bundle.extra.len + error_bundle.string_bytes.len; | |
| 3745 | try serveMessage(out, .{ | |
| 3746 | .tag = .error_bundle, | |
| 3747 | .bytes_len = @intCast(u32, bytes_len), | |
| 3748 | }, &.{ | |
| 3749 | std.mem.asBytes(&eb_hdr), | |
| 3750 | // TODO: implement @ptrCast between slices changing the length | |
| 3751 | std.mem.sliceAsBytes(error_bundle.extra), | |
| 3752 | error_bundle.string_bytes, | |
| 3753 | }); | |
| 3754 | } | |
| 3755 | ||
| 3756 | fn serveUpdateResults(out: fs.File, comp: *Compilation) !void { | |
| 3723 | fn serveUpdateResults(s: *Server, comp: *Compilation) !void { | |
| 3757 | 3724 | const gpa = comp.gpa; |
| 3758 | 3725 | var error_bundle = try comp.getAllErrorsAlloc(); |
| 3759 | 3726 | defer error_bundle.deinit(gpa); |
| 3760 | 3727 | if (error_bundle.errorMessageCount() > 0) { |
| 3761 | try serveErrorBundle(out, error_bundle); | |
| 3728 | try s.serveErrorBundle(error_bundle); | |
| 3762 | 3729 | } else if (comp.bin_file.options.emit) |emit| { |
| 3763 | 3730 | const full_path = try emit.directory.join(gpa, &.{emit.sub_path}); |
| 3764 | 3731 | defer gpa.free(full_path); |
| 3765 | try serveEmitBinPath(out, full_path, .{ | |
| 3732 | try s.serveEmitBinPath(full_path, .{ | |
| 3766 | 3733 | .flags = .{ .cache_hit = comp.last_update_was_cache_hit }, |
| 3767 | 3734 | }); |
| 3768 | 3735 | } |
| 3769 | 3736 | } |
| 3770 | 3737 | |
| 3771 | fn serveEmitBinPath( | |
| 3772 | out: fs.File, | |
| 3773 | fs_path: []const u8, | |
| 3774 | header: std.zig.Server.Message.EmitBinPath, | |
| 3775 | ) !void { | |
| 3776 | try serveMessage(out, .{ | |
| 3777 | .tag = .emit_bin_path, | |
| 3778 | .bytes_len = @intCast(u32, fs_path.len + @sizeOf(std.zig.Server.Message.EmitBinPath)), | |
| 3779 | }, &.{ | |
| 3780 | std.mem.asBytes(&header), | |
| 3781 | fs_path, | |
| 3782 | }); | |
| 3783 | } | |
| 3784 | ||
| 3785 | fn serveStringMessage(out: fs.File, tag: std.zig.Server.Message.Tag, s: []const u8) !void { | |
| 3786 | try serveMessage(out, .{ | |
| 3787 | .tag = tag, | |
| 3788 | .bytes_len = @intCast(u32, s.len), | |
| 3789 | }, &.{s}); | |
| 3790 | } | |
| 3791 | ||
| 3792 | fn receiveMessage(in: fs.File, fifo: *std.fifo.LinearFifo(u8, .Dynamic)) !std.zig.Client.Message.Header { | |
| 3793 | const Header = std.zig.Client.Message.Header; | |
| 3794 | ||
| 3795 | while (true) { | |
| 3796 | const buf = fifo.readableSlice(0); | |
| 3797 | assert(fifo.readableLength() == buf.len); | |
| 3798 | if (buf.len >= @sizeOf(Header)) { | |
| 3799 | const header = @ptrCast(*align(1) const Header, buf[0..@sizeOf(Header)]); | |
| 3800 | if (header.bytes_len != 0) | |
| 3801 | return error.InvalidClientMessage; | |
| 3802 | const result = header.*; | |
| 3803 | fifo.discard(@sizeOf(Header)); | |
| 3804 | return result; | |
| 3805 | } | |
| 3806 | ||
| 3807 | const write_buffer = try fifo.writableWithSize(256); | |
| 3808 | const amt = try in.read(write_buffer); | |
| 3809 | fifo.update(amt); | |
| 3810 | } | |
| 3811 | } | |
| 3812 | ||
| 3813 | 3738 | const ModuleDepIterator = struct { |
| 3814 | 3739 | split: mem.SplitIterator(u8), |
| 3815 | 3740 |
src/objcopy.zig+43-4| ... | ... | @@ -4,22 +4,25 @@ const fs = std.fs; |
| 4 | 4 | const elf = std.elf; |
| 5 | 5 | const Allocator = std.mem.Allocator; |
| 6 | 6 | const File = std.fs.File; |
| 7 | const assert = std.debug.assert; | |
| 8 | ||
| 7 | 9 | const main = @import("main.zig"); |
| 8 | 10 | const fatal = main.fatal; |
| 9 | 11 | const cleanExit = main.cleanExit; |
| 12 | const Server = @import("Server.zig"); | |
| 10 | 13 | |
| 11 | 14 | pub fn cmdObjCopy( |
| 12 | 15 | gpa: Allocator, |
| 13 | 16 | arena: Allocator, |
| 14 | 17 | args: []const []const u8, |
| 15 | 18 | ) !void { |
| 16 | _ = gpa; | |
| 17 | 19 | var i: usize = 0; |
| 18 | 20 | var opt_out_fmt: ?std.Target.ObjectFormat = null; |
| 19 | 21 | var opt_input: ?[]const u8 = null; |
| 20 | 22 | var opt_output: ?[]const u8 = null; |
| 21 | 23 | var only_section: ?[]const u8 = null; |
| 22 | 24 | var pad_to: ?u64 = null; |
| 25 | var listen = false; | |
| 23 | 26 | while (i < args.len) : (i += 1) { |
| 24 | 27 | const arg = args[i]; |
| 25 | 28 | if (!mem.startsWith(u8, arg, "-")) { |
| ... | ... | @@ -54,6 +57,8 @@ pub fn cmdObjCopy( |
| 54 | 57 | i += 1; |
| 55 | 58 | if (i >= args.len) fatal("expected another argument after '{s}'", .{arg}); |
| 56 | 59 | only_section = args[i]; |
| 60 | } else if (mem.eql(u8, arg, "--listen=-")) { | |
| 61 | listen = true; | |
| 57 | 62 | } else if (mem.startsWith(u8, arg, "--only-section=")) { |
| 58 | 63 | only_section = arg["--output-target=".len..]; |
| 59 | 64 | } else if (mem.eql(u8, arg, "--pad-to")) { |
| ... | ... | @@ -102,10 +107,44 @@ pub fn cmdObjCopy( |
| 102 | 107 | .only_section = only_section, |
| 103 | 108 | .pad_to = pad_to, |
| 104 | 109 | }); |
| 105 | return cleanExit(); | |
| 106 | 110 | }, |
| 107 | 111 | else => fatal("unsupported output object format: {s}", .{@tagName(out_fmt)}), |
| 108 | 112 | } |
| 113 | ||
| 114 | if (listen) { | |
| 115 | var server = try Server.init(.{ | |
| 116 | .gpa = gpa, | |
| 117 | .in = std.io.getStdIn(), | |
| 118 | .out = std.io.getStdOut(), | |
| 119 | }); | |
| 120 | defer server.deinit(); | |
| 121 | ||
| 122 | var seen_update = false; | |
| 123 | while (true) { | |
| 124 | const hdr = try server.receiveMessage(); | |
| 125 | switch (hdr.tag) { | |
| 126 | .exit => { | |
| 127 | return cleanExit(); | |
| 128 | }, | |
| 129 | .update => { | |
| 130 | if (seen_update) { | |
| 131 | std.debug.print("zig objcopy only supports 1 update for now\n", .{}); | |
| 132 | std.process.exit(1); | |
| 133 | } | |
| 134 | seen_update = true; | |
| 135 | ||
| 136 | try server.serveEmitBinPath(output, .{ | |
| 137 | .flags = .{ .cache_hit = false }, | |
| 138 | }); | |
| 139 | }, | |
| 140 | else => { | |
| 141 | std.debug.print("unsupported message: {s}", .{@tagName(hdr.tag)}); | |
| 142 | std.process.exit(1); | |
| 143 | }, | |
| 144 | } | |
| 145 | } | |
| 146 | } | |
| 147 | return cleanExit(); | |
| 109 | 148 | } |
| 110 | 149 | |
| 111 | 150 | const usage = |
| ... | ... | @@ -417,7 +456,7 @@ const HexWriter = struct { |
| 417 | 456 | } |
| 418 | 457 | |
| 419 | 458 | fn Address(address: u32) Record { |
| 420 | std.debug.assert(address > 0xFFFF); | |
| 459 | assert(address > 0xFFFF); | |
| 421 | 460 | const segment = @intCast(u16, address / 0x10000); |
| 422 | 461 | if (address > 0xFFFFF) { |
| 423 | 462 | return Record{ |
| ... | ... | @@ -460,7 +499,7 @@ const HexWriter = struct { |
| 460 | 499 | const BUFSIZE = 1 + (1 + 2 + 1 + MAX_PAYLOAD_LEN + 1) * 2 + linesep.len; |
| 461 | 500 | var outbuf: [BUFSIZE]u8 = undefined; |
| 462 | 501 | const payload_bytes = self.getPayloadBytes(); |
| 463 | std.debug.assert(payload_bytes.len <= MAX_PAYLOAD_LEN); | |
| 502 | assert(payload_bytes.len <= MAX_PAYLOAD_LEN); | |
| 464 | 503 | |
| 465 | 504 | const line = try std.fmt.bufPrint(&outbuf, ":{0X:0>2}{1X:0>4}{2X:0>2}{3s}{4X:0>2}" ++ linesep, .{ |
| 466 | 505 | @intCast(u8, payload_bytes.len), |