authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-10-15 17:19:47-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-10-15 17:19:47-07:00
log0da027f07819657b6a93da6658e734eb1bdfe74f
tree40afe85389fbd803accc93783dab5dfad155ea33
parente17297102a14620c8d53a3d1f4137314880a28ce
parent43c2ce10a1af3e0f4929d2f875e48f8686a6b747

Merge branch 'g-w1-zig-test-zig-run-execve'

closes #6653

1 files changed, 45 insertions(+), 36 deletions(-)

src/main.zig+45-36
...@@ -114,15 +114,15 @@ pub fn main() anyerror!void {...@@ -114,15 +114,15 @@ pub fn main() anyerror!void {
114 return mainArgs(gpa, arena, args);114 return mainArgs(gpa, arena, args);
115}115}
116116
117const os_can_execve = std.builtin.os.tag != .windows;
118
117pub fn mainArgs(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !void {119pub fn mainArgs(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !void {
118 if (args.len <= 1) {120 if (args.len <= 1) {
119 std.log.info("{}", .{usage});121 std.log.info("{}", .{usage});
120 fatal("expected command argument", .{});122 fatal("expected command argument", .{});
121 }123 }
122124
123 if (std.Target.current.os.tag != .windows and125 if (os_can_execve and std.os.getenvZ("ZIG_IS_DETECTING_LIBC_PATHS") != null) {
124 std.os.getenvZ("ZIG_IS_DETECTING_LIBC_PATHS") != null)
125 {
126 // 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"
127 // to figure out where libc is installed. This is essentially infinite recursion127 // to figure out where libc is installed. This is essentially infinite recursion
128 // 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.
...@@ -1710,40 +1710,50 @@ fn buildOutputType(...@@ -1710,40 +1710,50 @@ fn buildOutputType(
1710 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", .{});
1711 }1711 }
17121712
1713 switch (arg_mode) {1713 const run_or_test = switch (arg_mode) {
1714 .run, .zig_test => run: {1714 .run, .zig_test => true,
1715 const exe_loc = emit_bin_loc orelse break :run;1715 else => false,
1716 const exe_directory = exe_loc.directory orelse comp.bin_file.options.emit.?.directory;1716 };
1717 const exe_path = try fs.path.join(arena, &[_][]const u8{1717 if (run_or_test) run: {
1718 exe_directory.path orelse ".", exe_loc.basename,1718 const exe_loc = emit_bin_loc orelse break :run;
1719 });1719 const exe_directory = exe_loc.directory orelse comp.bin_file.options.emit.?.directory;
17201720 const exe_path = try fs.path.join(arena, &[_][]const u8{
1721 var argv = std.ArrayList([]const u8).init(gpa);1721 exe_directory.path orelse ".", exe_loc.basename,
1722 defer argv.deinit();1722 });
17231723
1724 if (test_exec_args.items.len == 0) {1724 var argv = std.ArrayList([]const u8).init(gpa);
1725 if (!std.Target.current.canExecBinariesOf(target_info.target)) {1725 defer argv.deinit();
1726 switch (arg_mode) {1726
1727 .zig_test => {1727 if (test_exec_args.items.len == 0) {
1728 warn("created {s} but skipping execution because it is non-native", .{exe_path});1728 if (!std.Target.current.canExecBinariesOf(target_info.target)) {
1729 if (!watch) return cleanExit();1729 switch (arg_mode) {
1730 break :run;1730 .zig_test => {
1731 },1731 warn("created {s} but skipping execution because it is non-native", .{exe_path});
1732 .run => fatal("unable to execute {s}: non-native", .{exe_path}),1732 if (!watch) return cleanExit();
1733 else => unreachable,1733 break :run;
1734 }1734 },
1735 }1735 .run => fatal("unable to execute {s}: non-native", .{exe_path}),
1736 try argv.append(exe_path);1736 else => unreachable,
1737 } else {
1738 for (test_exec_args.items) |arg| {
1739 try argv.append(arg orelse exe_path);
1740 }1737 }
1741 }1738 }
1742 if (runtime_args_start) |i| {1739 try argv.append(exe_path);
1743 try argv.appendSlice(all_args[i..]);1740 } else {
1741 for (test_exec_args.items) |arg| {
1742 try argv.append(arg orelse exe_path);
1744 }1743 }
1745 // TODO On operating systems that support it, do an execve here rather than child process,1744 }
1746 // when watch=false and arg_mode == .run1745 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 {
1747 const child = try std.ChildProcess.init(argv.items, gpa);1757 const child = try std.ChildProcess.init(argv.items, gpa);
1748 defer child.deinit();1758 defer child.deinit();
17491759
...@@ -1784,8 +1794,7 @@ fn buildOutputType(...@@ -1784,8 +1794,7 @@ fn buildOutputType(
1784 },1794 },
1785 else => unreachable,1795 else => unreachable,
1786 }1796 }
1787 },1797 }
1788 else => {},
1789 }1798 }
17901799
1791 const stdin = std.io.getStdIn().inStream();1800 const stdin = std.io.getStdIn().inStream();