authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-10-15 17:13:32-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-10-15 17:18:40-07:00
log43c2ce10a1af3e0f4929d2f875e48f8686a6b747
tree40afe85389fbd803accc93783dab5dfad155ea33
parent1c36680928dec40fd607b43050bdeec53b0b0941

fixups

* extract logic into a `os_can_execve` and use it in the other place that we execve * outdent some code by introducing `run_or_test` variable * delete unnecessary and wasteful memory management logic * better error message for when execve fails * add comment to explain why we do not execve for `zig test`

1 files changed, 80 insertions(+), 77 deletions(-)

src/main.zig+80-77
...@@ -2,7 +2,6 @@ const std = @import("std");...@@ -2,7 +2,6 @@ const std = @import("std");
2const assert = std.debug.assert;2const assert = std.debug.assert;
3const io = std.io;3const io = std.io;
4const fs = std.fs;4const fs = std.fs;
5const os = std.os;
6const mem = std.mem;5const mem = std.mem;
7const process = std.process;6const process = std.process;
8const Allocator = mem.Allocator;7const 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}
117116
117const os_can_execve = std.builtin.os.tag != .windows;
118
118pub fn mainArgs(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !void {119pub 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 }
123124
124 if (std.Target.current.os.tag != .windows and125 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 recursion127 // 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 }
17131712
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;
17211720 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();
17541723
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;
17581726
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 }
17961799
1797 const stdin = std.io.getStdIn().inStream();1800 const stdin = std.io.getStdIn().inStream();