| ... | @@ -2,7 +2,7 @@ const std = @import("std"); | ... | @@ -2,7 +2,7 @@ const std = @import("std"); |
| 2 | const fatal = std.process.fatal; | 2 | const fatal = std.process.fatal; |
| 3 | const Allocator = std.mem.Allocator; | 3 | const Allocator = std.mem.Allocator; |
| 4 | | 4 | |
| 5 | const usage = "usage: incr-check <zig binary path> <input file> [-fno-emit-bin] [--zig-lib-dir lib]"; | 5 | const usage = "usage: incr-check <zig binary path> <input file> [-fno-emit-bin] [--zig-lib-dir lib] [--debug-zcu]"; |
| 6 | | 6 | |
| 7 | pub fn main() !void { | 7 | pub fn main() !void { |
| 8 | var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator); | 8 | var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator); |
| ... | @@ -13,6 +13,7 @@ pub fn main() !void { | ... | @@ -13,6 +13,7 @@ pub fn main() !void { |
| 13 | var opt_input_file_name: ?[]const u8 = null; | 13 | var opt_input_file_name: ?[]const u8 = null; |
| 14 | var opt_lib_dir: ?[]const u8 = null; | 14 | var opt_lib_dir: ?[]const u8 = null; |
| 15 | var no_bin = false; | 15 | var no_bin = false; |
| | 16 | var debug_zcu = false; |
| 16 | | 17 | |
| 17 | var arg_it = try std.process.argsWithAllocator(arena); | 18 | var arg_it = try std.process.argsWithAllocator(arena); |
| 18 | _ = arg_it.skip(); | 19 | _ = arg_it.skip(); |
| ... | @@ -20,6 +21,8 @@ pub fn main() !void { | ... | @@ -20,6 +21,8 @@ pub fn main() !void { |
| 20 | if (arg.len > 0 and arg[0] == '-') { | 21 | if (arg.len > 0 and arg[0] == '-') { |
| 21 | if (std.mem.eql(u8, arg, "-fno-emit-bin")) { | 22 | if (std.mem.eql(u8, arg, "-fno-emit-bin")) { |
| 22 | no_bin = true; | 23 | no_bin = true; |
| | 24 | } else if (std.mem.eql(u8, arg, "--debug-zcu")) { |
| | 25 | debug_zcu = true; |
| 23 | } else if (std.mem.eql(u8, arg, "--zig-lib-dir")) { | 26 | } else if (std.mem.eql(u8, arg, "--zig-lib-dir")) { |
| 24 | opt_lib_dir = arg_it.next() orelse fatal("expected arg after '--zig-lib-dir'\n{s}", .{usage}); | 27 | opt_lib_dir = arg_it.next() orelse fatal("expected arg after '--zig-lib-dir'\n{s}", .{usage}); |
| 25 | } else { | 28 | } else { |
| ... | @@ -48,6 +51,13 @@ pub fn main() !void { | ... | @@ -48,6 +51,13 @@ pub fn main() !void { |
| 48 | const tmp_dir_path = "tmp_" ++ std.fmt.hex(rand_int); | 51 | const tmp_dir_path = "tmp_" ++ std.fmt.hex(rand_int); |
| 49 | const tmp_dir = try std.fs.cwd().makeOpenPath(tmp_dir_path, .{}); | 52 | const tmp_dir = try std.fs.cwd().makeOpenPath(tmp_dir_path, .{}); |
| 50 | | 53 | |
| | 54 | if (opt_lib_dir) |lib_dir| { |
| | 55 | if (!std.fs.path.isAbsolute(lib_dir)) { |
| | 56 | // The cwd of the subprocess is within the tmp dir, so prepend `..` to the path. |
| | 57 | opt_lib_dir = try std.fs.path.join(arena, &.{ "..", lib_dir }); |
| | 58 | } |
| | 59 | } |
| | 60 | |
| 51 | const child_prog_node = prog_node.start("zig build-exe", 0); | 61 | const child_prog_node = prog_node.start("zig build-exe", 0); |
| 52 | defer child_prog_node.end(); | 62 | defer child_prog_node.end(); |
| 53 | | 63 | |
| ... | @@ -74,6 +84,9 @@ pub fn main() !void { | ... | @@ -74,6 +84,9 @@ pub fn main() !void { |
| 74 | } else { | 84 | } else { |
| 75 | try child_args.appendSlice(arena, &.{ "-fno-llvm", "-fno-lld" }); | 85 | try child_args.appendSlice(arena, &.{ "-fno-llvm", "-fno-lld" }); |
| 76 | } | 86 | } |
| | 87 | if (debug_zcu) { |
| | 88 | try child_args.appendSlice(arena, &.{ "--debug-log", "zcu" }); |
| | 89 | } |
| 77 | | 90 | |
| 78 | var child = std.process.Child.init(child_args.items, arena); | 91 | var child = std.process.Child.init(child_args.items, arena); |
| 79 | child.stdin_behavior = .Pipe; | 92 | child.stdin_behavior = .Pipe; |
| ... | @@ -89,6 +102,7 @@ pub fn main() !void { | ... | @@ -89,6 +102,7 @@ pub fn main() !void { |
| 89 | .tmp_dir = tmp_dir, | 102 | .tmp_dir = tmp_dir, |
| 90 | .tmp_dir_path = tmp_dir_path, | 103 | .tmp_dir_path = tmp_dir_path, |
| 91 | .child = &child, | 104 | .child = &child, |
| | 105 | .allow_stderr = debug_zcu, |
| 92 | }; | 106 | }; |
| 93 | | 107 | |
| 94 | try child.spawn(); | 108 | try child.spawn(); |
| ... | @@ -102,6 +116,11 @@ pub fn main() !void { | ... | @@ -102,6 +116,11 @@ pub fn main() !void { |
| 102 | for (case.updates) |update| { | 116 | for (case.updates) |update| { |
| 103 | var update_node = prog_node.start(update.name, 0); | 117 | var update_node = prog_node.start(update.name, 0); |
| 104 | defer update_node.end(); | 118 | defer update_node.end(); |
| | 119 | |
| | 120 | if (debug_zcu) { |
| | 121 | std.log.info("=== START UPDATE '{s}' ===", .{update.name}); |
| | 122 | } |
| | 123 | |
| 105 | eval.write(update); | 124 | eval.write(update); |
| 106 | try eval.requestUpdate(); | 125 | try eval.requestUpdate(); |
| 107 | try eval.check(&poller, update); | 126 | try eval.check(&poller, update); |
| ... | @@ -118,6 +137,7 @@ const Eval = struct { | ... | @@ -118,6 +137,7 @@ const Eval = struct { |
| 118 | tmp_dir: std.fs.Dir, | 137 | tmp_dir: std.fs.Dir, |
| 119 | tmp_dir_path: []const u8, | 138 | tmp_dir_path: []const u8, |
| 120 | child: *std.process.Child, | 139 | child: *std.process.Child, |
| | 140 | allow_stderr: bool, |
| 121 | | 141 | |
| 122 | const StreamEnum = enum { stdout, stderr }; | 142 | const StreamEnum = enum { stdout, stderr }; |
| 123 | const Poller = std.io.Poller(StreamEnum); | 143 | const Poller = std.io.Poller(StreamEnum); |
| ... | @@ -173,7 +193,11 @@ const Eval = struct { | ... | @@ -173,7 +193,11 @@ const Eval = struct { |
| 173 | }; | 193 | }; |
| 174 | if (stderr.readableLength() > 0) { | 194 | if (stderr.readableLength() > 0) { |
| 175 | const stderr_data = try stderr.toOwnedSlice(); | 195 | const stderr_data = try stderr.toOwnedSlice(); |
| 176 | fatal("error_bundle included unexpected stderr:\n{s}", .{stderr_data}); | 196 | if (eval.allow_stderr) { |
| | 197 | std.log.info("error_bundle included stderr:\n{s}", .{stderr_data}); |
| | 198 | } else { |
| | 199 | fatal("error_bundle included unexpected stderr:\n{s}", .{stderr_data}); |
| | 200 | } |
| 177 | } | 201 | } |
| 178 | if (result_error_bundle.errorMessageCount() == 0) { | 202 | if (result_error_bundle.errorMessageCount() == 0) { |
| 179 | // Empty bundle indicates successful update in a `-fno-emit-bin` build. | 203 | // Empty bundle indicates successful update in a `-fno-emit-bin` build. |
| ... | @@ -197,7 +221,11 @@ const Eval = struct { | ... | @@ -197,7 +221,11 @@ const Eval = struct { |
| 197 | const result_binary = try arena.dupe(u8, body[@sizeOf(EbpHdr)..]); | 221 | const result_binary = try arena.dupe(u8, body[@sizeOf(EbpHdr)..]); |
| 198 | if (stderr.readableLength() > 0) { | 222 | if (stderr.readableLength() > 0) { |
| 199 | const stderr_data = try stderr.toOwnedSlice(); | 223 | const stderr_data = try stderr.toOwnedSlice(); |
| 200 | fatal("emit_bin_path included unexpected stderr:\n{s}", .{stderr_data}); | 224 | if (eval.allow_stderr) { |
| | 225 | std.log.info("emit_bin_path included stderr:\n{s}", .{stderr_data}); |
| | 226 | } else { |
| | 227 | fatal("emit_bin_path included unexpected stderr:\n{s}", .{stderr_data}); |
| | 228 | } |
| 201 | } | 229 | } |
| 202 | try eval.checkSuccessOutcome(update, result_binary); | 230 | try eval.checkSuccessOutcome(update, result_binary); |
| 203 | // This message indicates the end of the update. | 231 | // This message indicates the end of the update. |
| ... | @@ -213,7 +241,11 @@ const Eval = struct { | ... | @@ -213,7 +241,11 @@ const Eval = struct { |
| 213 | | 241 | |
| 214 | if (stderr.readableLength() > 0) { | 242 | if (stderr.readableLength() > 0) { |
| 215 | const stderr_data = try stderr.toOwnedSlice(); | 243 | const stderr_data = try stderr.toOwnedSlice(); |
| 216 | fatal("update '{s}' failed:\n{s}", .{ update.name, stderr_data }); | 244 | if (eval.allow_stderr) { |
| | 245 | std.log.info("update '{s}' included stderr:\n{s}", .{ update.name, stderr_data }); |
| | 246 | } else { |
| | 247 | fatal("update '{s}' failed:\n{s}", .{ update.name, stderr_data }); |
| | 248 | } |
| 217 | } | 249 | } |
| 218 | | 250 | |
| 219 | waitChild(eval.child); | 251 | waitChild(eval.child); |