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 {
114114 return mainArgs(gpa, arena, args);
115115}
116116
117const os_can_execve = std.builtin.os.tag != .windows;
118
117119pub fn mainArgs(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !void {
118120 if (args.len <= 1) {
119121 std.log.info("{}", .{usage});
120122 fatal("expected command argument", .{});
121123 }
122124
123 if (std.Target.current.os.tag != .windows and
124 std.os.getenvZ("ZIG_IS_DETECTING_LIBC_PATHS") != null)
125 {
125 if (os_can_execve and std.os.getenvZ("ZIG_IS_DETECTING_LIBC_PATHS") != null) {
126126 // In this case we have accidentally invoked ourselves as "the system C compiler"
127127 // to figure out where libc is installed. This is essentially infinite recursion
128128 // via child process execution due to the CC environment variable pointing to Zig.
......@@ -1710,40 +1710,50 @@ fn buildOutputType(
17101710 warn("--watch is not recommended with the stage1 backend; it leaks memory and is not capable of incremental compilation", .{});
17111711 }
17121712
1713 switch (arg_mode) {
1714 .run, .zig_test => run: {
1715 const exe_loc = emit_bin_loc orelse break :run;
1716 const exe_directory = exe_loc.directory orelse comp.bin_file.options.emit.?.directory;
1717 const exe_path = try fs.path.join(arena, &[_][]const u8{
1718 exe_directory.path orelse ".", exe_loc.basename,
1719 });
1720
1721 var argv = std.ArrayList([]const u8).init(gpa);
1722 defer argv.deinit();
1723
1724 if (test_exec_args.items.len == 0) {
1725 if (!std.Target.current.canExecBinariesOf(target_info.target)) {
1726 switch (arg_mode) {
1727 .zig_test => {
1728 warn("created {s} but skipping execution because it is non-native", .{exe_path});
1729 if (!watch) return cleanExit();
1730 break :run;
1731 },
1732 .run => fatal("unable to execute {s}: non-native", .{exe_path}),
1733 else => unreachable,
1734 }
1735 }
1736 try argv.append(exe_path);
1737 } else {
1738 for (test_exec_args.items) |arg| {
1739 try argv.append(arg orelse exe_path);
1713 const run_or_test = switch (arg_mode) {
1714 .run, .zig_test => true,
1715 else => false,
1716 };
1717 if (run_or_test) run: {
1718 const exe_loc = emit_bin_loc orelse break :run;
1719 const exe_directory = exe_loc.directory orelse comp.bin_file.options.emit.?.directory;
1720 const exe_path = try fs.path.join(arena, &[_][]const u8{
1721 exe_directory.path orelse ".", exe_loc.basename,
1722 });
1723
1724 var argv = std.ArrayList([]const u8).init(gpa);
1725 defer argv.deinit();
1726
1727 if (test_exec_args.items.len == 0) {
1728 if (!std.Target.current.canExecBinariesOf(target_info.target)) {
1729 switch (arg_mode) {
1730 .zig_test => {
1731 warn("created {s} but skipping execution because it is non-native", .{exe_path});
1732 if (!watch) return cleanExit();
1733 break :run;
1734 },
1735 .run => fatal("unable to execute {s}: non-native", .{exe_path}),
1736 else => unreachable,
17401737 }
17411738 }
1742 if (runtime_args_start) |i| {
1743 try argv.appendSlice(all_args[i..]);
1739 try argv.append(exe_path);
1740 } else {
1741 for (test_exec_args.items) |arg| {
1742 try argv.append(arg orelse exe_path);
17441743 }
1745 // TODO On operating systems that support it, do an execve here rather than child process,
1746 // when watch=false and arg_mode == .run
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 {
17471757 const child = try std.ChildProcess.init(argv.items, gpa);
17481758 defer child.deinit();
17491759
......@@ -1784,8 +1794,7 @@ fn buildOutputType(
17841794 },
17851795 else => unreachable,
17861796 }
1787 },
1788 else => {},
1797 }
17891798 }
17901799
17911800 const stdin = std.io.getStdIn().inStream();