| ... | ... | @@ -488,18 +488,20 @@ fn optionalStringEnvVar(arena: *Allocator, name: []const u8) !?[]const u8 { |
| 488 | 488 | } |
| 489 | 489 | } |
| 490 | 490 | |
| 491 | const ArgMode = union(enum) { |
| 492 | build: std.builtin.OutputMode, |
| 493 | cc, |
| 494 | cpp, |
| 495 | translate_c, |
| 496 | zig_test, |
| 497 | run, |
| 498 | }; |
| 499 | |
| 491 | 500 | fn buildOutputType( |
| 492 | 501 | gpa: *Allocator, |
| 493 | 502 | arena: *Allocator, |
| 494 | 503 | all_args: []const []const u8, |
| 495 | | arg_mode: union(enum) { |
| 496 | | build: std.builtin.OutputMode, |
| 497 | | cc, |
| 498 | | cpp, |
| 499 | | translate_c, |
| 500 | | zig_test, |
| 501 | | run, |
| 502 | | }, |
| 504 | arg_mode: ArgMode, |
| 503 | 505 | ) !void { |
| 504 | 506 | var color: Color = .auto; |
| 505 | 507 | var optimize_mode: std.builtin.Mode = .Debug; |
| ... | ... | @@ -1967,108 +1969,21 @@ fn buildOutputType( |
| 1967 | 1969 | .run, .zig_test => true, |
| 1968 | 1970 | else => false, |
| 1969 | 1971 | }; |
| 1970 | | if (run_or_test) run: { |
| 1971 | | const exe_loc = emit_bin_loc orelse break :run; |
| 1972 | | const exe_directory = exe_loc.directory orelse comp.bin_file.options.emit.?.directory; |
| 1973 | | const exe_path = try fs.path.join(arena, &[_][]const u8{ |
| 1974 | | exe_directory.path orelse ".", exe_loc.basename, |
| 1975 | | }); |
| 1976 | | |
| 1977 | | var argv = std.ArrayList([]const u8).init(gpa); |
| 1978 | | defer argv.deinit(); |
| 1979 | | |
| 1980 | | if (test_exec_args.items.len == 0) { |
| 1981 | | if (!std.Target.current.canExecBinariesOf(target_info.target)) { |
| 1982 | | switch (arg_mode) { |
| 1983 | | .zig_test => { |
| 1984 | | warn("created {s} but skipping execution because it is non-native", .{exe_path}); |
| 1985 | | if (!watch) return cleanExit(); |
| 1986 | | break :run; |
| 1987 | | }, |
| 1988 | | .run => fatal("unable to execute {s}: non-native", .{exe_path}), |
| 1989 | | else => unreachable, |
| 1990 | | } |
| 1991 | | } |
| 1992 | | // when testing pass the zig_exe_path to argv |
| 1993 | | if (arg_mode == .zig_test) |
| 1994 | | try argv.appendSlice(&[_][]const u8{ |
| 1995 | | exe_path, self_exe_path, |
| 1996 | | }) |
| 1997 | | // when running just pass the current exe |
| 1998 | | else |
| 1999 | | try argv.appendSlice(&[_][]const u8{ |
| 2000 | | exe_path, |
| 2001 | | }); |
| 2002 | | } else { |
| 2003 | | for (test_exec_args.items) |arg| { |
| 2004 | | if (arg) |a| { |
| 2005 | | try argv.append(a); |
| 2006 | | } else { |
| 2007 | | try argv.appendSlice(&[_][]const u8{ |
| 2008 | | exe_path, self_exe_path, |
| 2009 | | }); |
| 2010 | | } |
| 2011 | | } |
| 2012 | | } |
| 2013 | | if (runtime_args_start) |i| { |
| 2014 | | try argv.appendSlice(all_args[i..]); |
| 2015 | | } |
| 2016 | | // We do not execve for tests because if the test fails we want to print |
| 2017 | | // the error message and invocation below. |
| 2018 | | if (std.process.can_execv and arg_mode == .run and !watch) { |
| 2019 | | // execv releases the locks; no need to destroy the Compilation here. |
| 2020 | | const err = std.process.execv(gpa, argv.items); |
| 2021 | | const cmd = try argvCmd(arena, argv.items); |
| 2022 | | fatal("the following command failed to execve with '{s}':\n{s}", .{ @errorName(err), cmd }); |
| 2023 | | } else { |
| 2024 | | const child = try std.ChildProcess.init(argv.items, gpa); |
| 2025 | | defer child.deinit(); |
| 2026 | | |
| 2027 | | child.stdin_behavior = .Inherit; |
| 2028 | | child.stdout_behavior = .Inherit; |
| 2029 | | child.stderr_behavior = .Inherit; |
| 2030 | | |
| 2031 | | if (!watch) { |
| 2032 | | // Here we release all the locks associated with the Compilation so |
| 2033 | | // that whatever this child process wants to do won't deadlock. |
| 2034 | | comp.destroy(); |
| 2035 | | comp_destroyed = true; |
| 2036 | | } |
| 2037 | | |
| 2038 | | const term = try child.spawnAndWait(); |
| 2039 | | switch (arg_mode) { |
| 2040 | | .run => { |
| 2041 | | switch (term) { |
| 2042 | | .Exited => |code| { |
| 2043 | | if (code == 0) { |
| 2044 | | if (!watch) return cleanExit(); |
| 2045 | | } else { |
| 2046 | | // TODO https://github.com/ziglang/zig/issues/6342 |
| 2047 | | process.exit(1); |
| 2048 | | } |
| 2049 | | }, |
| 2050 | | else => process.exit(1), |
| 2051 | | } |
| 2052 | | }, |
| 2053 | | .zig_test => { |
| 2054 | | switch (term) { |
| 2055 | | .Exited => |code| { |
| 2056 | | if (code == 0) { |
| 2057 | | if (!watch) return cleanExit(); |
| 2058 | | } else { |
| 2059 | | const cmd = try argvCmd(arena, argv.items); |
| 2060 | | fatal("the following test command failed with exit code {d}:\n{s}", .{ code, cmd }); |
| 2061 | | } |
| 2062 | | }, |
| 2063 | | else => { |
| 2064 | | const cmd = try argvCmd(arena, argv.items); |
| 2065 | | fatal("the following test command crashed:\n{s}", .{cmd}); |
| 2066 | | }, |
| 2067 | | } |
| 2068 | | }, |
| 2069 | | else => unreachable, |
| 2070 | | } |
| 2071 | | } |
| 1972 | if (run_or_test) { |
| 1973 | try runOrTest( |
| 1974 | comp, |
| 1975 | gpa, |
| 1976 | arena, |
| 1977 | emit_bin_loc, |
| 1978 | test_exec_args.items, |
| 1979 | self_exe_path, |
| 1980 | arg_mode, |
| 1981 | target_info.target, |
| 1982 | watch, |
| 1983 | &comp_destroyed, |
| 1984 | all_args, |
| 1985 | runtime_args_start, |
| 1986 | ); |
| 2072 | 1987 | } |
| 2073 | 1988 | |
| 2074 | 1989 | const stdin = std.io.getStdIn().reader(); |
| ... | ... | @@ -2096,6 +2011,21 @@ fn buildOutputType( |
| 2096 | 2011 | break; |
| 2097 | 2012 | } else if (mem.eql(u8, actual_line, "help")) { |
| 2098 | 2013 | try stderr.writeAll(repl_help); |
| 2014 | } else if (mem.eql(u8, actual_line, "run")) { |
| 2015 | try runOrTest( |
| 2016 | comp, |
| 2017 | gpa, |
| 2018 | arena, |
| 2019 | emit_bin_loc, |
| 2020 | test_exec_args.items, |
| 2021 | self_exe_path, |
| 2022 | arg_mode, |
| 2023 | target_info.target, |
| 2024 | watch, |
| 2025 | &comp_destroyed, |
| 2026 | all_args, |
| 2027 | runtime_args_start, |
| 2028 | ); |
| 2099 | 2029 | } else { |
| 2100 | 2030 | try stderr.print("unknown command: {s}\n", .{actual_line}); |
| 2101 | 2031 | } |
| ... | ... | @@ -2105,6 +2035,131 @@ fn buildOutputType( |
| 2105 | 2035 | } |
| 2106 | 2036 | } |
| 2107 | 2037 | |
| 2038 | fn runOrTest( |
| 2039 | comp: *Compilation, |
| 2040 | gpa: *Allocator, |
| 2041 | arena: *Allocator, |
| 2042 | emit_bin_loc: ?Compilation.EmitLoc, |
| 2043 | test_exec_args: []const ?[]const u8, |
| 2044 | self_exe_path: []const u8, |
| 2045 | arg_mode: ArgMode, |
| 2046 | target: std.Target, |
| 2047 | watch: bool, |
| 2048 | comp_destroyed: *bool, |
| 2049 | all_args: []const []const u8, |
| 2050 | runtime_args_start: ?usize, |
| 2051 | ) !void { |
| 2052 | const exe_loc = emit_bin_loc orelse return; |
| 2053 | const exe_directory = exe_loc.directory orelse comp.bin_file.options.emit.?.directory; |
| 2054 | const exe_path = try fs.path.join(arena, &[_][]const u8{ |
| 2055 | exe_directory.path orelse ".", exe_loc.basename, |
| 2056 | }); |
| 2057 | |
| 2058 | var argv = std.ArrayList([]const u8).init(gpa); |
| 2059 | defer argv.deinit(); |
| 2060 | |
| 2061 | if (test_exec_args.len == 0) { |
| 2062 | if (!std.Target.current.canExecBinariesOf(target)) { |
| 2063 | switch (arg_mode) { |
| 2064 | .zig_test => { |
| 2065 | warn("created {s} but skipping execution because it is non-native", .{exe_path}); |
| 2066 | if (!watch) return cleanExit(); |
| 2067 | return; |
| 2068 | }, |
| 2069 | .run => fatal("unable to execute {s}: non-native", .{exe_path}), |
| 2070 | else => unreachable, |
| 2071 | } |
| 2072 | } |
| 2073 | // when testing pass the zig_exe_path to argv |
| 2074 | if (arg_mode == .zig_test) |
| 2075 | try argv.appendSlice(&[_][]const u8{ |
| 2076 | exe_path, self_exe_path, |
| 2077 | }) |
| 2078 | // when running just pass the current exe |
| 2079 | else |
| 2080 | try argv.appendSlice(&[_][]const u8{ |
| 2081 | exe_path, |
| 2082 | }); |
| 2083 | } else { |
| 2084 | for (test_exec_args) |arg| { |
| 2085 | if (arg) |a| { |
| 2086 | try argv.append(a); |
| 2087 | } else { |
| 2088 | try argv.appendSlice(&[_][]const u8{ |
| 2089 | exe_path, self_exe_path, |
| 2090 | }); |
| 2091 | } |
| 2092 | } |
| 2093 | } |
| 2094 | if (runtime_args_start) |i| { |
| 2095 | try argv.appendSlice(all_args[i..]); |
| 2096 | } |
| 2097 | // We do not execve for tests because if the test fails we want to print |
| 2098 | // the error message and invocation below. |
| 2099 | if (std.process.can_execv and arg_mode == .run and !watch) { |
| 2100 | // execv releases the locks; no need to destroy the Compilation here. |
| 2101 | const err = std.process.execv(gpa, argv.items); |
| 2102 | const cmd = try argvCmd(arena, argv.items); |
| 2103 | fatal("the following command failed to execve with '{s}':\n{s}", .{ @errorName(err), cmd }); |
| 2104 | } else { |
| 2105 | const child = try std.ChildProcess.init(argv.items, gpa); |
| 2106 | defer child.deinit(); |
| 2107 | |
| 2108 | child.stdin_behavior = .Inherit; |
| 2109 | child.stdout_behavior = .Inherit; |
| 2110 | child.stderr_behavior = .Inherit; |
| 2111 | |
| 2112 | if (!watch) { |
| 2113 | // Here we release all the locks associated with the Compilation so |
| 2114 | // that whatever this child process wants to do won't deadlock. |
| 2115 | comp.destroy(); |
| 2116 | comp_destroyed.* = true; |
| 2117 | } |
| 2118 | |
| 2119 | const term = try child.spawnAndWait(); |
| 2120 | switch (arg_mode) { |
| 2121 | .run, .build => { |
| 2122 | switch (term) { |
| 2123 | .Exited => |code| { |
| 2124 | if (code == 0) { |
| 2125 | if (!watch) return cleanExit(); |
| 2126 | } else if (watch) { |
| 2127 | warn("process exited with code {d}", .{code}); |
| 2128 | } else { |
| 2129 | // TODO https://github.com/ziglang/zig/issues/6342 |
| 2130 | process.exit(1); |
| 2131 | } |
| 2132 | }, |
| 2133 | else => { |
| 2134 | if (watch) { |
| 2135 | warn("process aborted abnormally", .{}); |
| 2136 | } else { |
| 2137 | process.exit(1); |
| 2138 | } |
| 2139 | }, |
| 2140 | } |
| 2141 | }, |
| 2142 | .zig_test => { |
| 2143 | switch (term) { |
| 2144 | .Exited => |code| { |
| 2145 | if (code == 0) { |
| 2146 | if (!watch) return cleanExit(); |
| 2147 | } else { |
| 2148 | const cmd = try argvCmd(arena, argv.items); |
| 2149 | fatal("the following test command failed with exit code {d}:\n{s}", .{ code, cmd }); |
| 2150 | } |
| 2151 | }, |
| 2152 | else => { |
| 2153 | const cmd = try argvCmd(arena, argv.items); |
| 2154 | fatal("the following test command crashed:\n{s}", .{cmd}); |
| 2155 | }, |
| 2156 | } |
| 2157 | }, |
| 2158 | else => unreachable, |
| 2159 | } |
| 2160 | } |
| 2161 | } |
| 2162 | |
| 2108 | 2163 | const AfterUpdateHook = union(enum) { |
| 2109 | 2164 | none, |
| 2110 | 2165 | print: []const u8, |