authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-03-13 19:11:36-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-03-15 10:48:15-07:00
logbde12930939c50fbfa344c3701a01885e6dd06d4
treee0dee4ad74167e03bd5ec10e587925741d183067
parent0f88ad8c72797b1bc8899e2eb1d1c1c07a39addf

CLI: remove the experimental --watch flag

The compiler REPL will move to an external process that communicates with the compiler over the binary protocol.

1 files changed, 9 insertions(+), 133 deletions(-)

src/main.zig+9-133
...@@ -365,7 +365,6 @@ const usage_build_generic =...@@ -365,7 +365,6 @@ const usage_build_generic =
365 \\365 \\
366 \\General Options:366 \\General Options:
367 \\ -h, --help Print this help and exit367 \\ -h, --help Print this help and exit
368 \\ --watch Enable compiler REPL
369 \\ --color [auto|off|on] Enable or disable colored error messages368 \\ --color [auto|off|on] Enable or disable colored error messages
370 \\ -femit-bin[=path] (default) Output machine code369 \\ -femit-bin[=path] (default) Output machine code
371 \\ -fno-emit-bin Do not output machine code370 \\ -fno-emit-bin Do not output machine code
...@@ -700,7 +699,6 @@ fn buildOutputType(...@@ -700,7 +699,6 @@ fn buildOutputType(
700 var formatted_panics: ?bool = null;699 var formatted_panics: ?bool = null;
701 var function_sections = false;700 var function_sections = false;
702 var no_builtin = false;701 var no_builtin = false;
703 var watch = false;
704 var listen: Listen = .none;702 var listen: Listen = .none;
705 var debug_compile_errors = false;703 var debug_compile_errors = false;
706 var verbose_link = (builtin.os.tag != .wasi or builtin.link_libc) and std.process.hasEnvVarConstant("ZIG_VERBOSE_LINK");704 var verbose_link = (builtin.os.tag != .wasi or builtin.link_libc) and std.process.hasEnvVarConstant("ZIG_VERBOSE_LINK");
...@@ -1163,7 +1161,6 @@ fn buildOutputType(...@@ -1163,7 +1161,6 @@ fn buildOutputType(
1163 const next_arg = args_iter.nextOrFatal();1161 const next_arg = args_iter.nextOrFatal();
1164 if (mem.eql(u8, next_arg, "-")) {1162 if (mem.eql(u8, next_arg, "-")) {
1165 listen = .stdio;1163 listen = .stdio;
1166 watch = true;
1167 } else {1164 } else {
1168 if (build_options.omit_pkg_fetching_code) unreachable;1165 if (build_options.omit_pkg_fetching_code) unreachable;
1169 // example: --listen 127.0.0.1:90001166 // example: --listen 127.0.0.1:9000
...@@ -1174,11 +1171,9 @@ fn buildOutputType(...@@ -1174,11 +1171,9 @@ fn buildOutputType(
1174 fatal("invalid port number: '{s}': {s}", .{ port_text, @errorName(err) });1171 fatal("invalid port number: '{s}': {s}", .{ port_text, @errorName(err) });
1175 listen = .{ .ip4 = std.net.Ip4Address.parse(host, port) catch |err|1172 listen = .{ .ip4 = std.net.Ip4Address.parse(host, port) catch |err|
1176 fatal("invalid host: '{s}': {s}", .{ host, @errorName(err) }) };1173 fatal("invalid host: '{s}': {s}", .{ host, @errorName(err) }) };
1177 watch = true;
1178 }1174 }
1179 } else if (mem.eql(u8, arg, "--listen=-")) {1175 } else if (mem.eql(u8, arg, "--listen=-")) {
1180 listen = .stdio;1176 listen = .stdio;
1181 watch = true;
1182 } else if (mem.eql(u8, arg, "--debug-link-snapshot")) {1177 } else if (mem.eql(u8, arg, "--debug-link-snapshot")) {
1183 if (!build_options.enable_link_snapshots) {1178 if (!build_options.enable_link_snapshots) {
1184 std.log.warn("Zig was compiled without linker snapshots enabled (-Dlink-snapshot). --debug-link-snapshot has no effect.", .{});1179 std.log.warn("Zig was compiled without linker snapshots enabled (-Dlink-snapshot). --debug-link-snapshot has no effect.", .{});
...@@ -1207,8 +1202,6 @@ fn buildOutputType(...@@ -1207,8 +1202,6 @@ fn buildOutputType(
1207 test_evented_io = true;1202 test_evented_io = true;
1208 } else if (mem.eql(u8, arg, "--test-no-exec")) {1203 } else if (mem.eql(u8, arg, "--test-no-exec")) {
1209 test_no_exec = true;1204 test_no_exec = true;
1210 } else if (mem.eql(u8, arg, "--watch")) {
1211 watch = true;
1212 } else if (mem.eql(u8, arg, "-ftime-report")) {1205 } else if (mem.eql(u8, arg, "-ftime-report")) {
1213 time_report = true;1206 time_report = true;
1214 } else if (mem.eql(u8, arg, "-fstack-report")) {1207 } else if (mem.eql(u8, arg, "-fstack-report")) {
...@@ -3355,7 +3348,7 @@ fn buildOutputType(...@@ -3355,7 +3348,7 @@ fn buildOutputType(
3355 };3348 };
33563349
3357 updateModule(gpa, comp, hook) catch |err| switch (err) {3350 updateModule(gpa, comp, hook) catch |err| switch (err) {
3358 error.SemanticAnalyzeFail => if (!watch) process.exit(1),3351 error.SemanticAnalyzeFail => if (listen == .none) process.exit(1),
3359 else => |e| return e,3352 else => |e| return e,
3360 };3353 };
3361 if (build_options.only_c) return cleanExit();3354 if (build_options.only_c) return cleanExit();
...@@ -3411,7 +3404,6 @@ fn buildOutputType(...@@ -3411,7 +3404,6 @@ fn buildOutputType(
3411 self_exe_path.?,3404 self_exe_path.?,
3412 arg_mode,3405 arg_mode,
3413 target_info,3406 target_info,
3414 watch,
3415 &comp_destroyed,3407 &comp_destroyed,
3416 all_args,3408 all_args,
3417 runtime_args_start,3409 runtime_args_start,
...@@ -3419,113 +3411,6 @@ fn buildOutputType(...@@ -3419,113 +3411,6 @@ fn buildOutputType(
3419 );3411 );
3420 }3412 }
34213413
3422 // TODO move this REPL implementation to the standard library / build
3423 // system and have it be a CLI abstraction layer on top of the real, actual
3424 // binary protocol of the compiler. Make it actually interface through the
3425 // server protocol. This way the REPL does not have any special powers that
3426 // an IDE couldn't also have.
3427
3428 const stdin = std.io.getStdIn().reader();
3429 const stderr = std.io.getStdErr().writer();
3430 var repl_buf: [1024]u8 = undefined;
3431
3432 const ReplCmd = enum {
3433 update,
3434 help,
3435 run,
3436 update_and_run,
3437 };
3438
3439 var last_cmd: ReplCmd = .help;
3440
3441 while (watch) {
3442 try stderr.print("(zig) ", .{});
3443 try comp.makeBinFileExecutable();
3444 if (stdin.readUntilDelimiterOrEof(&repl_buf, '\n') catch |err| {
3445 try stderr.print("\nUnable to parse command: {s}\n", .{@errorName(err)});
3446 continue;
3447 }) |line| {
3448 const actual_line = mem.trimRight(u8, line, "\r\n ");
3449 const cmd: ReplCmd = blk: {
3450 if (mem.eql(u8, actual_line, "update")) {
3451 break :blk .update;
3452 } else if (mem.eql(u8, actual_line, "exit")) {
3453 break;
3454 } else if (mem.eql(u8, actual_line, "help")) {
3455 break :blk .help;
3456 } else if (mem.eql(u8, actual_line, "run")) {
3457 break :blk .run;
3458 } else if (mem.eql(u8, actual_line, "update-and-run")) {
3459 break :blk .update_and_run;
3460 } else if (actual_line.len == 0) {
3461 break :blk last_cmd;
3462 } else {
3463 try stderr.print("unknown command: {s}\n", .{actual_line});
3464 continue;
3465 }
3466 };
3467 last_cmd = cmd;
3468 switch (cmd) {
3469 .update => {
3470 tracy.frameMark();
3471 if (output_mode == .Exe) {
3472 try comp.makeBinFileWritable();
3473 }
3474 updateModule(gpa, comp, hook) catch |err| switch (err) {
3475 error.SemanticAnalyzeFail => continue,
3476 else => |e| return e,
3477 };
3478 },
3479 .help => {
3480 try stderr.writeAll(repl_help);
3481 },
3482 .run => {
3483 tracy.frameMark();
3484 try runOrTest(
3485 comp,
3486 gpa,
3487 arena,
3488 test_exec_args.items,
3489 self_exe_path.?,
3490 arg_mode,
3491 target_info,
3492 watch,
3493 &comp_destroyed,
3494 all_args,
3495 runtime_args_start,
3496 link_libc,
3497 );
3498 },
3499 .update_and_run => {
3500 tracy.frameMark();
3501 if (output_mode == .Exe) {
3502 try comp.makeBinFileWritable();
3503 }
3504 updateModule(gpa, comp, hook) catch |err| switch (err) {
3505 error.SemanticAnalyzeFail => continue,
3506 else => |e| return e,
3507 };
3508 try comp.makeBinFileExecutable();
3509 try runOrTest(
3510 comp,
3511 gpa,
3512 arena,
3513 test_exec_args.items,
3514 self_exe_path.?,
3515 arg_mode,
3516 target_info,
3517 watch,
3518 &comp_destroyed,
3519 all_args,
3520 runtime_args_start,
3521 link_libc,
3522 );
3523 },
3524 }
3525 } else {
3526 break;
3527 }
3528 }
3529 // Skip resource deallocation in release builds; let the OS do it.3414 // Skip resource deallocation in release builds; let the OS do it.
3530 return cleanExit();3415 return cleanExit();
3531}3416}
...@@ -3822,7 +3707,6 @@ fn runOrTest(...@@ -3822,7 +3707,6 @@ fn runOrTest(
3822 self_exe_path: []const u8,3707 self_exe_path: []const u8,
3823 arg_mode: ArgMode,3708 arg_mode: ArgMode,
3824 target_info: std.zig.system.NativeTargetInfo,3709 target_info: std.zig.system.NativeTargetInfo,
3825 watch: bool,
3826 comp_destroyed: *bool,3710 comp_destroyed: *bool,
3827 all_args: []const []const u8,3711 all_args: []const []const u8,
3828 runtime_args_start: ?usize,3712 runtime_args_start: ?usize,
...@@ -3853,7 +3737,7 @@ fn runOrTest(...@@ -3853,7 +3737,7 @@ fn runOrTest(
38533737
3854 // We do not execve for tests because if the test fails we want to print3738 // We do not execve for tests because if the test fails we want to print
3855 // the error message and invocation below.3739 // the error message and invocation below.
3856 if (std.process.can_execv and arg_mode == .run and !watch) {3740 if (std.process.can_execv and arg_mode == .run) {
3857 // execv releases the locks; no need to destroy the Compilation here.3741 // execv releases the locks; no need to destroy the Compilation here.
3858 const err = std.process.execve(gpa, argv.items, &env_map);3742 const err = std.process.execve(gpa, argv.items, &env_map);
3859 try warnAboutForeignBinaries(arena, arg_mode, target_info, link_libc);3743 try warnAboutForeignBinaries(arena, arg_mode, target_info, link_libc);
...@@ -3866,12 +3750,10 @@ fn runOrTest(...@@ -3866,12 +3750,10 @@ fn runOrTest(
3866 child.stdout_behavior = .Inherit;3750 child.stdout_behavior = .Inherit;
3867 child.stderr_behavior = .Inherit;3751 child.stderr_behavior = .Inherit;
38683752
3869 if (!watch) {3753 // Here we release all the locks associated with the Compilation so
3870 // Here we release all the locks associated with the Compilation so3754 // that whatever this child process wants to do won't deadlock.
3871 // that whatever this child process wants to do won't deadlock.3755 comp.destroy();
3872 comp.destroy();3756 comp_destroyed.* = true;
3873 comp_destroyed.* = true;
3874 }
38753757
3876 const term = child.spawnAndWait() catch |err| {3758 const term = child.spawnAndWait() catch |err| {
3877 try warnAboutForeignBinaries(arena, arg_mode, target_info, link_libc);3759 try warnAboutForeignBinaries(arena, arg_mode, target_info, link_libc);
...@@ -3883,19 +3765,13 @@ fn runOrTest(...@@ -3883,19 +3765,13 @@ fn runOrTest(
3883 switch (term) {3765 switch (term) {
3884 .Exited => |code| {3766 .Exited => |code| {
3885 if (code == 0) {3767 if (code == 0) {
3886 if (!watch) return cleanExit();3768 return cleanExit();
3887 } else if (watch) {
3888 warn("process exited with code {d}", .{code});
3889 } else {3769 } else {
3890 process.exit(code);3770 process.exit(code);
3891 }3771 }
3892 },3772 },
3893 else => {3773 else => {
3894 if (watch) {3774 process.exit(1);
3895 warn("process aborted abnormally", .{});
3896 } else {
3897 process.exit(1);
3898 }
3899 },3775 },
3900 }3776 }
3901 },3777 },
...@@ -3903,7 +3779,7 @@ fn runOrTest(...@@ -3903,7 +3779,7 @@ fn runOrTest(
3903 switch (term) {3779 switch (term) {
3904 .Exited => |code| {3780 .Exited => |code| {
3905 if (code == 0) {3781 if (code == 0) {
3906 if (!watch) return cleanExit();3782 return cleanExit();
3907 } else {3783 } else {
3908 const cmd = try std.mem.join(arena, " ", argv.items);3784 const cmd = try std.mem.join(arena, " ", argv.items);
3909 fatal("the following test command failed with exit code {d}:\n{s}", .{ code, cmd });3785 fatal("the following test command failed with exit code {d}:\n{s}", .{ code, cmd });