| ... | @@ -2,7 +2,6 @@ const std = @import("std"); | ... | @@ -2,7 +2,6 @@ const std = @import("std"); |
| 2 | const assert = std.debug.assert; | 2 | const assert = std.debug.assert; |
| 3 | const io = std.io; | 3 | const io = std.io; |
| 4 | const fs = std.fs; | 4 | const fs = std.fs; |
| 5 | const os = std.os; | | |
| 6 | const mem = std.mem; | 5 | const mem = std.mem; |
| 7 | const process = std.process; | 6 | const process = std.process; |
| 8 | const Allocator = mem.Allocator; | 7 | const Allocator = mem.Allocator; |
| ... | @@ -115,15 +114,15 @@ pub fn main() anyerror!void { | ... | @@ -115,15 +114,15 @@ pub fn main() anyerror!void { |
| 115 | return mainArgs(gpa, arena, args); | 114 | return mainArgs(gpa, arena, args); |
| 116 | } | 115 | } |
| 117 | | 116 | |
| | 117 | const os_can_execve = std.builtin.os.tag != .windows; |
| | 118 | |
| 118 | pub fn mainArgs(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !void { | 119 | pub fn mainArgs(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !void { |
| 119 | if (args.len <= 1) { | 120 | if (args.len <= 1) { |
| 120 | std.log.info("{}", .{usage}); | 121 | std.log.info("{}", .{usage}); |
| 121 | fatal("expected command argument", .{}); | 122 | fatal("expected command argument", .{}); |
| 122 | } | 123 | } |
| 123 | | 124 | |
| 124 | if (std.Target.current.os.tag != .windows and | 125 | if (os_can_execve and std.os.getenvZ("ZIG_IS_DETECTING_LIBC_PATHS") != null) { |
| 125 | std.os.getenvZ("ZIG_IS_DETECTING_LIBC_PATHS") != null) | | |
| 126 | { | | |
| 127 | // In this case we have accidentally invoked ourselves as "the system C compiler" | 126 | // In this case we have accidentally invoked ourselves as "the system C compiler" |
| 128 | // to figure out where libc is installed. This is essentially infinite recursion | 127 | // to figure out where libc is installed. This is essentially infinite recursion |
| 129 | // via child process execution due to the CC environment variable pointing to Zig. | 128 | // via child process execution due to the CC environment variable pointing to Zig. |
| ... | @@ -1711,87 +1710,91 @@ fn buildOutputType( | ... | @@ -1711,87 +1710,91 @@ fn buildOutputType( |
| 1711 | warn("--watch is not recommended with the stage1 backend; it leaks memory and is not capable of incremental compilation", .{}); | 1710 | warn("--watch is not recommended with the stage1 backend; it leaks memory and is not capable of incremental compilation", .{}); |
| 1712 | } | 1711 | } |
| 1713 | | 1712 | |
| 1714 | switch (arg_mode) { | 1713 | const run_or_test = switch (arg_mode) { |
| 1715 | .run, .zig_test => run: { | 1714 | .run, .zig_test => true, |
| 1716 | const exe_loc = emit_bin_loc orelse break :run; | 1715 | else => false, |
| 1717 | const exe_directory = exe_loc.directory orelse comp.bin_file.options.emit.?.directory; | 1716 | }; |
| 1718 | const exe_path = try fs.path.join(arena, &[_][]const u8{ | 1717 | if (run_or_test) run: { |
| 1719 | exe_directory.path orelse ".", exe_loc.basename, | 1718 | const exe_loc = emit_bin_loc orelse break :run; |
| 1720 | }); | 1719 | const exe_directory = exe_loc.directory orelse comp.bin_file.options.emit.?.directory; |
| 1721 | | 1720 | const exe_path = try fs.path.join(arena, &[_][]const u8{ |
| 1722 | var argv = std.ArrayList([]const u8).init(gpa); | 1721 | exe_directory.path orelse ".", exe_loc.basename, |
| 1723 | defer argv.deinit(); | 1722 | }); |
| 1724 | | | |
| 1725 | if (test_exec_args.items.len == 0) { | | |
| 1726 | if (!std.Target.current.canExecBinariesOf(target_info.target)) { | | |
| 1727 | switch (arg_mode) { | | |
| 1728 | .zig_test => { | | |
| 1729 | warn("created {s} but skipping execution because it is non-native", .{exe_path}); | | |
| 1730 | if (!watch) return cleanExit(); | | |
| 1731 | break :run; | | |
| 1732 | }, | | |
| 1733 | .run => fatal("unable to execute {s}: non-native", .{exe_path}), | | |
| 1734 | else => unreachable, | | |
| 1735 | } | | |
| 1736 | } | | |
| 1737 | try argv.append(exe_path); | | |
| 1738 | } else { | | |
| 1739 | for (test_exec_args.items) |arg| { | | |
| 1740 | try argv.append(arg orelse exe_path); | | |
| 1741 | } | | |
| 1742 | } | | |
| 1743 | if (runtime_args_start) |i| { | | |
| 1744 | try argv.appendSlice(all_args[i..]); | | |
| 1745 | } | | |
| 1746 | if (std.builtin.os.tag != .windows and arg_mode == .run and !watch) { | | |
| 1747 | var env_vars = try process.getEnvMap(gpa); | | |
| 1748 | const err = os.execvpe(gpa, argv.items, &env_vars); | | |
| 1749 | env_vars.deinit(); // it would cause a memory leak because a defer would be unreachable because of fatal | | |
| 1750 | fatal("There was an error with `zig run`: {}", .{@errorName(err)}); | | |
| 1751 | } else { | | |
| 1752 | const child = try std.ChildProcess.init(argv.items, gpa); | | |
| 1753 | defer child.deinit(); | | |
| 1754 | | 1723 | |
| 1755 | child.stdin_behavior = .Inherit; | 1724 | var argv = std.ArrayList([]const u8).init(gpa); |
| 1756 | child.stdout_behavior = .Inherit; | 1725 | defer argv.deinit(); |
| 1757 | child.stderr_behavior = .Inherit; | | |
| 1758 | | 1726 | |
| 1759 | const term = try child.spawnAndWait(); | 1727 | if (test_exec_args.items.len == 0) { |
| | 1728 | if (!std.Target.current.canExecBinariesOf(target_info.target)) { |
| 1760 | switch (arg_mode) { | 1729 | switch (arg_mode) { |
| 1761 | .run => { | | |
| 1762 | switch (term) { | | |
| 1763 | .Exited => |code| { | | |
| 1764 | if (code == 0) { | | |
| 1765 | if (!watch) return cleanExit(); | | |
| 1766 | } else { | | |
| 1767 | // TODO https://github.com/ziglang/zig/issues/6342 | | |
| 1768 | process.exit(1); | | |
| 1769 | } | | |
| 1770 | }, | | |
| 1771 | else => process.exit(1), | | |
| 1772 | } | | |
| 1773 | }, | | |
| 1774 | .zig_test => { | 1730 | .zig_test => { |
| 1775 | switch (term) { | 1731 | warn("created {s} but skipping execution because it is non-native", .{exe_path}); |
| 1776 | .Exited => |code| { | 1732 | if (!watch) return cleanExit(); |
| 1777 | if (code == 0) { | 1733 | break :run; |
| 1778 | if (!watch) return cleanExit(); | | |
| 1779 | } else { | | |
| 1780 | const cmd = try argvCmd(arena, argv.items); | | |
| 1781 | fatal("the following test command failed with exit code {}:\n{}", .{ code, cmd }); | | |
| 1782 | } | | |
| 1783 | }, | | |
| 1784 | else => { | | |
| 1785 | const cmd = try argvCmd(arena, argv.items); | | |
| 1786 | fatal("the following test command crashed:\n{}", .{cmd}); | | |
| 1787 | }, | | |
| 1788 | } | | |
| 1789 | }, | 1734 | }, |
| | 1735 | .run => fatal("unable to execute {s}: non-native", .{exe_path}), |
| 1790 | else => unreachable, | 1736 | else => unreachable, |
| 1791 | } | 1737 | } |
| 1792 | } | 1738 | } |
| 1793 | }, | 1739 | try argv.append(exe_path); |
| 1794 | else => {}, | 1740 | } else { |
| | 1741 | for (test_exec_args.items) |arg| { |
| | 1742 | try argv.append(arg orelse exe_path); |
| | 1743 | } |
| | 1744 | } |
| | 1745 | if (runtime_args_start) |i| { |
| | 1746 | try argv.appendSlice(all_args[i..]); |
| | 1747 | } |
| | 1748 | // We do not execve for tests because if the test fails we want to print the error message and |
| | 1749 | // invocation below. |
| | 1750 | if (os_can_execve and arg_mode == .run and !watch) { |
| | 1751 | // TODO improve the std lib so that we don't need a call to getEnvMap here. |
| | 1752 | var env_vars = try process.getEnvMap(arena); |
| | 1753 | const err = std.os.execvpe(gpa, argv.items, &env_vars); |
| | 1754 | const cmd = try argvCmd(arena, argv.items); |
| | 1755 | fatal("the following command failed to execve with '{s}':\n{s}", .{ @errorName(err), cmd }); |
| | 1756 | } else { |
| | 1757 | const child = try std.ChildProcess.init(argv.items, gpa); |
| | 1758 | defer child.deinit(); |
| | 1759 | |
| | 1760 | child.stdin_behavior = .Inherit; |
| | 1761 | child.stdout_behavior = .Inherit; |
| | 1762 | child.stderr_behavior = .Inherit; |
| | 1763 | |
| | 1764 | const term = try child.spawnAndWait(); |
| | 1765 | switch (arg_mode) { |
| | 1766 | .run => { |
| | 1767 | switch (term) { |
| | 1768 | .Exited => |code| { |
| | 1769 | if (code == 0) { |
| | 1770 | if (!watch) return cleanExit(); |
| | 1771 | } else { |
| | 1772 | // TODO https://github.com/ziglang/zig/issues/6342 |
| | 1773 | process.exit(1); |
| | 1774 | } |
| | 1775 | }, |
| | 1776 | else => process.exit(1), |
| | 1777 | } |
| | 1778 | }, |
| | 1779 | .zig_test => { |
| | 1780 | switch (term) { |
| | 1781 | .Exited => |code| { |
| | 1782 | if (code == 0) { |
| | 1783 | if (!watch) return cleanExit(); |
| | 1784 | } else { |
| | 1785 | const cmd = try argvCmd(arena, argv.items); |
| | 1786 | fatal("the following test command failed with exit code {}:\n{}", .{ code, cmd }); |
| | 1787 | } |
| | 1788 | }, |
| | 1789 | else => { |
| | 1790 | const cmd = try argvCmd(arena, argv.items); |
| | 1791 | fatal("the following test command crashed:\n{}", .{cmd}); |
| | 1792 | }, |
| | 1793 | } |
| | 1794 | }, |
| | 1795 | else => unreachable, |
| | 1796 | } |
| | 1797 | } |
| 1795 | } | 1798 | } |
| 1796 | | 1799 | |
| 1797 | const stdin = std.io.getStdIn().inStream(); | 1800 | const stdin = std.io.getStdIn().inStream(); |