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

closes #6653
This commit is contained in:
Andrew Kelley
2020-10-15 17:19:47 -07:00

View File

@@ -114,15 +114,15 @@ pub fn main() anyerror!void {
return mainArgs(gpa, arena, args);
}
const os_can_execve = std.builtin.os.tag != .windows;
pub fn mainArgs(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !void {
if (args.len <= 1) {
std.log.info("{}", .{usage});
fatal("expected command argument", .{});
}
if (std.Target.current.os.tag != .windows and
std.os.getenvZ("ZIG_IS_DETECTING_LIBC_PATHS") != null)
{
if (os_can_execve and std.os.getenvZ("ZIG_IS_DETECTING_LIBC_PATHS") != null) {
// In this case we have accidentally invoked ourselves as "the system C compiler"
// to figure out where libc is installed. This is essentially infinite recursion
// via child process execution due to the CC environment variable pointing to Zig.
@@ -1710,40 +1710,50 @@ fn buildOutputType(
warn("--watch is not recommended with the stage1 backend; it leaks memory and is not capable of incremental compilation", .{});
}
switch (arg_mode) {
.run, .zig_test => run: {
const exe_loc = emit_bin_loc orelse break :run;
const exe_directory = exe_loc.directory orelse comp.bin_file.options.emit.?.directory;
const exe_path = try fs.path.join(arena, &[_][]const u8{
exe_directory.path orelse ".", exe_loc.basename,
});
const run_or_test = switch (arg_mode) {
.run, .zig_test => true,
else => false,
};
if (run_or_test) run: {
const exe_loc = emit_bin_loc orelse break :run;
const exe_directory = exe_loc.directory orelse comp.bin_file.options.emit.?.directory;
const exe_path = try fs.path.join(arena, &[_][]const u8{
exe_directory.path orelse ".", exe_loc.basename,
});
var argv = std.ArrayList([]const u8).init(gpa);
defer argv.deinit();
var argv = std.ArrayList([]const u8).init(gpa);
defer argv.deinit();
if (test_exec_args.items.len == 0) {
if (!std.Target.current.canExecBinariesOf(target_info.target)) {
switch (arg_mode) {
.zig_test => {
warn("created {s} but skipping execution because it is non-native", .{exe_path});
if (!watch) return cleanExit();
break :run;
},
.run => fatal("unable to execute {s}: non-native", .{exe_path}),
else => unreachable,
}
}
try argv.append(exe_path);
} else {
for (test_exec_args.items) |arg| {
try argv.append(arg orelse exe_path);
if (test_exec_args.items.len == 0) {
if (!std.Target.current.canExecBinariesOf(target_info.target)) {
switch (arg_mode) {
.zig_test => {
warn("created {s} but skipping execution because it is non-native", .{exe_path});
if (!watch) return cleanExit();
break :run;
},
.run => fatal("unable to execute {s}: non-native", .{exe_path}),
else => unreachable,
}
}
if (runtime_args_start) |i| {
try argv.appendSlice(all_args[i..]);
try argv.append(exe_path);
} else {
for (test_exec_args.items) |arg| {
try argv.append(arg orelse exe_path);
}
// TODO On operating systems that support it, do an execve here rather than child process,
// when watch=false and arg_mode == .run
}
if (runtime_args_start) |i| {
try argv.appendSlice(all_args[i..]);
}
// We do not execve for tests because if the test fails we want to print the error message and
// invocation below.
if (os_can_execve and arg_mode == .run and !watch) {
// TODO improve the std lib so that we don't need a call to getEnvMap here.
var env_vars = try process.getEnvMap(arena);
const err = std.os.execvpe(gpa, argv.items, &env_vars);
const cmd = try argvCmd(arena, argv.items);
fatal("the following command failed to execve with '{s}':\n{s}", .{ @errorName(err), cmd });
} else {
const child = try std.ChildProcess.init(argv.items, gpa);
defer child.deinit();
@@ -1784,8 +1794,7 @@ fn buildOutputType(
},
else => unreachable,
}
},
else => {},
}
}
const stdin = std.io.getStdIn().inStream();