| author | |
| committer | |
| log | 5065830aa007c374c382be9e80ba924df6cecc78 |
| tree | b8f8b3b601ded5d48cac007c52bd23592a62c206 |
| parent | 069dd01ce4ced3cb9664e4f1e09be753cb3ed476 |
In accordance with the requesting issue (#10750):
- `zig test` skips any tests that it cannot spawn, returning success
- `zig run` and `zig build` exit with failure, reporting the command the cannot be run
- `zig clang`, `zig ar`, etc. already punt directly to the appropriate clang/lld main(), even before this change
- Native `libc` Detection is not supported
Additionally, `exec()` and related Builder functions error at run-time, reporting the command that cannot be run15 files changed, 464 insertions(+), 276 deletions(-)
build.zig+7| ... | @@ -229,6 +229,10 @@ pub fn build(b: *Builder) !void { | ... | @@ -229,6 +229,10 @@ pub fn build(b: *Builder) !void { |
| 229 | const version = if (opt_version_string) |version| version else v: { | 229 | const version = if (opt_version_string) |version| version else v: { |
| 230 | const version_string = b.fmt("{d}.{d}.{d}", .{ zig_version.major, zig_version.minor, zig_version.patch }); | 230 | const version_string = b.fmt("{d}.{d}.{d}", .{ zig_version.major, zig_version.minor, zig_version.patch }); |
| 231 | 231 | ||
| 232 | if (!std.process.can_spawn) { | ||
| 233 | std.debug.print("error: version info cannot be retrieved from git. Zig version must be provided using -Dversion-string\n", .{}); | ||
| 234 | std.process.exit(1); | ||
| 235 | } | ||
| 232 | var code: u8 = undefined; | 236 | var code: u8 = undefined; |
| 233 | const git_describe_untrimmed = b.execAllowFail(&[_][]const u8{ | 237 | const git_describe_untrimmed = b.execAllowFail(&[_][]const u8{ |
| 234 | "git", "-C", b.build_root, "describe", "--match", "*.*.*", "--tags", | 238 | "git", "-C", b.build_root, "describe", "--match", "*.*.*", "--tags", |
| ... | @@ -542,6 +546,9 @@ fn addCxxKnownPath( | ... | @@ -542,6 +546,9 @@ fn addCxxKnownPath( |
| 542 | errtxt: ?[]const u8, | 546 | errtxt: ?[]const u8, |
| 543 | need_cpp_includes: bool, | 547 | need_cpp_includes: bool, |
| 544 | ) !void { | 548 | ) !void { |
| 549 | if (!std.process.can_spawn) | ||
| 550 | return error.RequiredLibraryNotFound; | ||
| 551 | |||
| 545 | const path_padded = try b.exec(&[_][]const u8{ | 552 | const path_padded = try b.exec(&[_][]const u8{ |
| 546 | ctx.cxx_compiler, | 553 | ctx.cxx_compiler, |
| 547 | b.fmt("-print-file-name={s}", .{objname}), | 554 | b.fmt("-print-file-name={s}", .{objname}), |
lib/std/build.zig+34-4| ... | @@ -88,7 +88,14 @@ pub const Builder = struct { | ... | @@ -88,7 +88,14 @@ pub const Builder = struct { |
| 88 | /// Information about the native target. Computed before build() is invoked. | 88 | /// Information about the native target. Computed before build() is invoked. |
| 89 | host: NativeTargetInfo, | 89 | host: NativeTargetInfo, |
| 90 | 90 | ||
| 91 | const PkgConfigError = error{ | 91 | pub const ExecError = error{ |
| 92 | ReadFailure, | ||
| 93 | ExitCodeFailure, | ||
| 94 | ProcessTerminated, | ||
| 95 | ExecNotSupported, | ||
| 96 | } || std.ChildProcess.SpawnError; | ||
| 97 | |||
| 98 | pub const PkgConfigError = error{ | ||
| 92 | PkgConfigCrashed, | 99 | PkgConfigCrashed, |
| 93 | PkgConfigFailed, | 100 | PkgConfigFailed, |
| 94 | PkgConfigNotInstalled, | 101 | PkgConfigNotInstalled, |
| ... | @@ -959,6 +966,9 @@ pub const Builder = struct { | ... | @@ -959,6 +966,9 @@ pub const Builder = struct { |
| 959 | printCmd(cwd, argv); | 966 | printCmd(cwd, argv); |
| 960 | } | 967 | } |
| 961 | 968 | ||
| 969 | if (!std.process.can_spawn) | ||
| 970 | return error.ExecNotSupported; | ||
| 971 | |||
| 962 | const child = std.ChildProcess.init(argv, self.allocator) catch unreachable; | 972 | const child = std.ChildProcess.init(argv, self.allocator) catch unreachable; |
| 963 | defer child.deinit(); | 973 | defer child.deinit(); |
| 964 | 974 | ||
| ... | @@ -1168,9 +1178,12 @@ pub const Builder = struct { | ... | @@ -1168,9 +1178,12 @@ pub const Builder = struct { |
| 1168 | argv: []const []const u8, | 1178 | argv: []const []const u8, |
| 1169 | out_code: *u8, | 1179 | out_code: *u8, |
| 1170 | stderr_behavior: std.ChildProcess.StdIo, | 1180 | stderr_behavior: std.ChildProcess.StdIo, |
| 1171 | ) ![]u8 { | 1181 | ) ExecError![]u8 { |
| 1172 | assert(argv.len != 0); | 1182 | assert(argv.len != 0); |
| 1173 | 1183 | ||
| 1184 | if (!std.process.can_spawn) | ||
| 1185 | return error.ExecNotSupported; | ||
| 1186 | |||
| 1174 | const max_output_size = 400 * 1024; | 1187 | const max_output_size = 400 * 1024; |
| 1175 | const child = try std.ChildProcess.init(argv, self.allocator); | 1188 | const child = try std.ChildProcess.init(argv, self.allocator); |
| 1176 | defer child.deinit(); | 1189 | defer child.deinit(); |
| ... | @@ -1182,7 +1195,9 @@ pub const Builder = struct { | ... | @@ -1182,7 +1195,9 @@ pub const Builder = struct { |
| 1182 | 1195 | ||
| 1183 | try child.spawn(); | 1196 | try child.spawn(); |
| 1184 | 1197 | ||
| 1185 | const stdout = try child.stdout.?.reader().readAllAlloc(self.allocator, max_output_size); | 1198 | const stdout = child.stdout.?.reader().readAllAlloc(self.allocator, max_output_size) catch { |
| 1199 | return error.ReadFailure; | ||
| 1200 | }; | ||
| 1186 | errdefer self.allocator.free(stdout); | 1201 | errdefer self.allocator.free(stdout); |
| 1187 | 1202 | ||
| 1188 | const term = try child.wait(); | 1203 | const term = try child.wait(); |
| ... | @@ -1208,8 +1223,21 @@ pub const Builder = struct { | ... | @@ -1208,8 +1223,21 @@ pub const Builder = struct { |
| 1208 | printCmd(null, argv); | 1223 | printCmd(null, argv); |
| 1209 | } | 1224 | } |
| 1210 | 1225 | ||
| 1226 | if (!std.process.can_spawn) { | ||
| 1227 | if (src_step) |s| warn("{s}...", .{s.name}); | ||
| 1228 | warn("Unable to spawn the following command: cannot spawn child process\n", .{}); | ||
| 1229 | printCmd(null, argv); | ||
| 1230 | std.os.abort(); | ||
| 1231 | } | ||
| 1232 | |||
| 1211 | var code: u8 = undefined; | 1233 | var code: u8 = undefined; |
| 1212 | return self.execAllowFail(argv, &code, .Inherit) catch |err| switch (err) { | 1234 | return self.execAllowFail(argv, &code, .Inherit) catch |err| switch (err) { |
| 1235 | error.ExecNotSupported => { | ||
| 1236 | if (src_step) |s| warn("{s}...", .{s.name}); | ||
| 1237 | warn("Unable to spawn the following command: cannot spawn child process\n", .{}); | ||
| 1238 | printCmd(null, argv); | ||
| 1239 | std.os.abort(); | ||
| 1240 | }, | ||
| 1213 | error.FileNotFound => { | 1241 | error.FileNotFound => { |
| 1214 | if (src_step) |s| warn("{s}...", .{s.name}); | 1242 | if (src_step) |s| warn("{s}...", .{s.name}); |
| 1215 | warn("Unable to spawn the following command: file not found\n", .{}); | 1243 | warn("Unable to spawn the following command: file not found\n", .{}); |
| ... | @@ -1260,7 +1288,7 @@ pub const Builder = struct { | ... | @@ -1260,7 +1288,7 @@ pub const Builder = struct { |
| 1260 | ) catch unreachable; | 1288 | ) catch unreachable; |
| 1261 | } | 1289 | } |
| 1262 | 1290 | ||
| 1263 | fn execPkgConfigList(self: *Builder, out_code: *u8) ![]const PkgConfigPkg { | 1291 | fn execPkgConfigList(self: *Builder, out_code: *u8) (PkgConfigError || ExecError)![]const PkgConfigPkg { |
| 1264 | const stdout = try self.execAllowFail(&[_][]const u8{ "pkg-config", "--list-all" }, out_code, .Ignore); | 1292 | const stdout = try self.execAllowFail(&[_][]const u8{ "pkg-config", "--list-all" }, out_code, .Ignore); |
| 1265 | var list = ArrayList(PkgConfigPkg).init(self.allocator); | 1293 | var list = ArrayList(PkgConfigPkg).init(self.allocator); |
| 1266 | errdefer list.deinit(); | 1294 | errdefer list.deinit(); |
| ... | @@ -1287,6 +1315,7 @@ pub const Builder = struct { | ... | @@ -1287,6 +1315,7 @@ pub const Builder = struct { |
| 1287 | } else |err| { | 1315 | } else |err| { |
| 1288 | const result = switch (err) { | 1316 | const result = switch (err) { |
| 1289 | error.ProcessTerminated => error.PkgConfigCrashed, | 1317 | error.ProcessTerminated => error.PkgConfigCrashed, |
| 1318 | error.ExecNotSupported => error.PkgConfigFailed, | ||
| 1290 | error.ExitCodeFailure => error.PkgConfigFailed, | 1319 | error.ExitCodeFailure => error.PkgConfigFailed, |
| 1291 | error.FileNotFound => error.PkgConfigNotInstalled, | 1320 | error.FileNotFound => error.PkgConfigNotInstalled, |
| 1292 | error.InvalidName => error.PkgConfigNotInstalled, | 1321 | error.InvalidName => error.PkgConfigNotInstalled, |
| ... | @@ -1929,6 +1958,7 @@ pub const LibExeObjStep = struct { | ... | @@ -1929,6 +1958,7 @@ pub const LibExeObjStep = struct { |
| 1929 | "--libs", | 1958 | "--libs", |
| 1930 | }, &code, .Ignore)) |stdout| stdout else |err| switch (err) { | 1959 | }, &code, .Ignore)) |stdout| stdout else |err| switch (err) { |
| 1931 | error.ProcessTerminated => return error.PkgConfigCrashed, | 1960 | error.ProcessTerminated => return error.PkgConfigCrashed, |
| 1961 | error.ExecNotSupported => return error.PkgConfigFailed, | ||
| 1932 | error.ExitCodeFailure => return error.PkgConfigFailed, | 1962 | error.ExitCodeFailure => return error.PkgConfigFailed, |
| 1933 | error.FileNotFound => return error.PkgConfigNotInstalled, | 1963 | error.FileNotFound => return error.PkgConfigNotInstalled, |
| 1934 | else => return err, | 1964 | else => return err, |
lib/std/build/RunStep.zig+20| ... | @@ -10,6 +10,8 @@ const mem = std.mem; | ... | @@ -10,6 +10,8 @@ const mem = std.mem; |
| 10 | const process = std.process; | 10 | const process = std.process; |
| 11 | const ArrayList = std.ArrayList; | 11 | const ArrayList = std.ArrayList; |
| 12 | const BufMap = std.BufMap; | 12 | const BufMap = std.BufMap; |
| 13 | const Allocator = mem.Allocator; | ||
| 14 | const ExecError = build.Builder.ExecError; | ||
| 13 | 15 | ||
| 14 | const max_stdout_size = 1 * 1024 * 1024; // 1 MiB | 16 | const max_stdout_size = 1 * 1024 * 1024; // 1 MiB |
| 15 | 17 | ||
| ... | @@ -136,6 +138,17 @@ pub fn setEnvironmentVariable(self: *RunStep, key: []const u8, value: []const u8 | ... | @@ -136,6 +138,17 @@ pub fn setEnvironmentVariable(self: *RunStep, key: []const u8, value: []const u8 |
| 136 | ) catch unreachable; | 138 | ) catch unreachable; |
| 137 | } | 139 | } |
| 138 | 140 | ||
| 141 | fn argvCmd(allocator: Allocator, argv: []const []const u8) ![]u8 { | ||
| 142 | var cmd = std.ArrayList(u8).init(allocator); | ||
| 143 | defer cmd.deinit(); | ||
| 144 | for (argv[0 .. argv.len - 1]) |arg| { | ||
| 145 | try cmd.appendSlice(arg); | ||
| 146 | try cmd.append(' '); | ||
| 147 | } | ||
| 148 | try cmd.appendSlice(argv[argv.len - 1]); | ||
| 149 | return cmd.toOwnedSlice(); | ||
| 150 | } | ||
| 151 | |||
| 139 | pub fn expectStdErrEqual(self: *RunStep, bytes: []const u8) void { | 152 | pub fn expectStdErrEqual(self: *RunStep, bytes: []const u8) void { |
| 140 | self.stderr_action = .{ .expect_exact = self.builder.dupe(bytes) }; | 153 | self.stderr_action = .{ .expect_exact = self.builder.dupe(bytes) }; |
| 141 | } | 154 | } |
| ... | @@ -175,6 +188,13 @@ fn make(step: *Step) !void { | ... | @@ -175,6 +188,13 @@ fn make(step: *Step) !void { |
| 175 | 188 | ||
| 176 | const argv = argv_list.items; | 189 | const argv = argv_list.items; |
| 177 | 190 | ||
| 191 | if (!std.process.can_spawn) { | ||
| 192 | const cmd = try argvCmd(self.builder.allocator, argv); | ||
| 193 | std.debug.print("the following command cannot be executed ({s} does not support spawning a child process):\n{s}", .{ @tagName(builtin.os.tag), cmd }); | ||
| 194 | self.builder.allocator.free(cmd); | ||
| 195 | return ExecError.ExecNotSupported; | ||
| 196 | } | ||
| 197 | |||
| 178 | const child = std.ChildProcess.init(argv, self.builder.allocator) catch unreachable; | 198 | const child = std.ChildProcess.init(argv, self.builder.allocator) catch unreachable; |
| 179 | defer child.deinit(); | 199 | defer child.deinit(); |
| 180 | 200 |
lib/std/child_process.zig+4| ... | @@ -124,6 +124,10 @@ pub const ChildProcess = struct { | ... | @@ -124,6 +124,10 @@ pub const ChildProcess = struct { |
| 124 | 124 | ||
| 125 | /// On success must call `kill` or `wait`. | 125 | /// On success must call `kill` or `wait`. |
| 126 | pub fn spawn(self: *ChildProcess) SpawnError!void { | 126 | pub fn spawn(self: *ChildProcess) SpawnError!void { |
| 127 | if (!std.process.can_spawn) { | ||
| 128 | @compileError("the target operating system cannot spawn processes"); | ||
| 129 | } | ||
| 130 | |||
| 127 | if (builtin.os.tag == .windows) { | 131 | if (builtin.os.tag == .windows) { |
| 128 | return self.spawnWindows(); | 132 | return self.spawnWindows(); |
| 129 | } else { | 133 | } else { |
lib/std/process.zig+7-1| ... | @@ -950,7 +950,13 @@ pub fn getSelfExeSharedLibPaths(allocator: Allocator) error{OutOfMemory}![][:0]u | ... | @@ -950,7 +950,13 @@ pub fn getSelfExeSharedLibPaths(allocator: Allocator) error{OutOfMemory}![][:0]u |
| 950 | 950 | ||
| 951 | /// Tells whether calling the `execv` or `execve` functions will be a compile error. | 951 | /// Tells whether calling the `execv` or `execve` functions will be a compile error. |
| 952 | pub const can_execv = switch (builtin.os.tag) { | 952 | pub const can_execv = switch (builtin.os.tag) { |
| 953 | .windows, .haiku => false, | 953 | .windows, .haiku, .wasi => false, |
| 954 | else => true, | ||
| 955 | }; | ||
| 956 | |||
| 957 | /// Tells whether spawning child processes is supported (e.g. via ChildProcess) | ||
| 958 | pub const can_spawn = switch (builtin.os.tag) { | ||
| 959 | .wasi => false, | ||
| 954 | else => true, | 960 | else => true, |
| 955 | }; | 961 | }; |
| 956 | 962 |
src/Compilation.zig+59-42| ... | @@ -25,6 +25,7 @@ const libunwind = @import("libunwind.zig"); | ... | @@ -25,6 +25,7 @@ const libunwind = @import("libunwind.zig"); |
| 25 | const libcxx = @import("libcxx.zig"); | 25 | const libcxx = @import("libcxx.zig"); |
| 26 | const wasi_libc = @import("wasi_libc.zig"); | 26 | const wasi_libc = @import("wasi_libc.zig"); |
| 27 | const fatal = @import("main.zig").fatal; | 27 | const fatal = @import("main.zig").fatal; |
| 28 | const clangMain = @import("main.zig").clangMain; | ||
| 28 | const Module = @import("Module.zig"); | 29 | const Module = @import("Module.zig"); |
| 29 | const Cache = @import("Cache.zig"); | 30 | const Cache = @import("Cache.zig"); |
| 30 | const stage1 = @import("stage1.zig"); | 31 | const stage1 = @import("stage1.zig"); |
| ... | @@ -3667,55 +3668,71 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P | ... | @@ -3667,55 +3668,71 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P |
| 3667 | dump_argv(argv.items); | 3668 | dump_argv(argv.items); |
| 3668 | } | 3669 | } |
| 3669 | 3670 | ||
| 3670 | const child = try std.ChildProcess.init(argv.items, arena); | 3671 | if (std.process.can_spawn) { |
| 3671 | defer child.deinit(); | 3672 | const child = try std.ChildProcess.init(argv.items, arena); |
| 3673 | defer child.deinit(); | ||
| 3672 | 3674 | ||
| 3673 | if (comp.clang_passthrough_mode) { | 3675 | if (comp.clang_passthrough_mode) { |
| 3674 | child.stdin_behavior = .Inherit; | 3676 | child.stdin_behavior = .Inherit; |
| 3675 | child.stdout_behavior = .Inherit; | 3677 | child.stdout_behavior = .Inherit; |
| 3676 | child.stderr_behavior = .Inherit; | 3678 | child.stderr_behavior = .Inherit; |
| 3677 | 3679 | ||
| 3678 | const term = child.spawnAndWait() catch |err| { | 3680 | const term = child.spawnAndWait() catch |err| { |
| 3679 | return comp.failCObj(c_object, "unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); | 3681 | return comp.failCObj(c_object, "unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); |
| 3680 | }; | 3682 | }; |
| 3681 | switch (term) { | 3683 | switch (term) { |
| 3682 | .Exited => |code| { | 3684 | .Exited => |code| { |
| 3683 | if (code != 0) { | 3685 | if (code != 0) { |
| 3684 | std.process.exit(code); | 3686 | std.process.exit(code); |
| 3685 | } | 3687 | } |
| 3686 | if (comp.clang_preprocessor_mode == .stdout) | 3688 | if (comp.clang_preprocessor_mode == .stdout) |
| 3687 | std.process.exit(0); | 3689 | std.process.exit(0); |
| 3688 | }, | 3690 | }, |
| 3689 | else => std.process.abort(), | 3691 | else => std.process.abort(), |
| 3690 | } | 3692 | } |
| 3691 | } else { | 3693 | } else { |
| 3692 | child.stdin_behavior = .Ignore; | 3694 | child.stdin_behavior = .Ignore; |
| 3693 | child.stdout_behavior = .Ignore; | 3695 | child.stdout_behavior = .Ignore; |
| 3694 | child.stderr_behavior = .Pipe; | 3696 | child.stderr_behavior = .Pipe; |
| 3695 | 3697 | ||
| 3696 | try child.spawn(); | 3698 | try child.spawn(); |
| 3697 | 3699 | ||
| 3698 | const stderr_reader = child.stderr.?.reader(); | 3700 | const stderr_reader = child.stderr.?.reader(); |
| 3699 | 3701 | ||
| 3700 | const stderr = try stderr_reader.readAllAlloc(arena, 10 * 1024 * 1024); | 3702 | const stderr = try stderr_reader.readAllAlloc(arena, 10 * 1024 * 1024); |
| 3701 | 3703 | ||
| 3702 | const term = child.wait() catch |err| { | 3704 | const term = child.wait() catch |err| { |
| 3703 | return comp.failCObj(c_object, "unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); | 3705 | return comp.failCObj(c_object, "unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); |
| 3704 | }; | 3706 | }; |
| 3705 | 3707 | ||
| 3706 | switch (term) { | 3708 | switch (term) { |
| 3707 | .Exited => |code| { | 3709 | .Exited => |code| { |
| 3708 | if (code != 0) { | 3710 | if (code != 0) { |
| 3709 | // TODO parse clang stderr and turn it into an error message | 3711 | // TODO parse clang stderr and turn it into an error message |
| 3710 | // and then call failCObjWithOwnedErrorMsg | 3712 | // and then call failCObjWithOwnedErrorMsg |
| 3711 | log.err("clang failed with stderr: {s}", .{stderr}); | 3713 | log.err("clang failed with stderr: {s}", .{stderr}); |
| 3712 | return comp.failCObj(c_object, "clang exited with code {d}", .{code}); | 3714 | return comp.failCObj(c_object, "clang exited with code {d}", .{code}); |
| 3713 | } | 3715 | } |
| 3714 | }, | 3716 | }, |
| 3715 | else => { | 3717 | else => { |
| 3716 | log.err("clang terminated with stderr: {s}", .{stderr}); | 3718 | log.err("clang terminated with stderr: {s}", .{stderr}); |
| 3717 | return comp.failCObj(c_object, "clang terminated unexpectedly", .{}); | 3719 | return comp.failCObj(c_object, "clang terminated unexpectedly", .{}); |
| 3718 | }, | 3720 | }, |
| 3721 | } | ||
| 3722 | } | ||
| 3723 | } else { | ||
| 3724 | const exit_code = try clangMain(arena, argv.items); | ||
| 3725 | if (exit_code != 0) { | ||
| 3726 | if (comp.clang_passthrough_mode) { | ||
| 3727 | std.process.exit(exit_code); | ||
| 3728 | } else { | ||
| 3729 | return comp.failCObj(c_object, "clang exited with code {d}", .{exit_code}); | ||
| 3730 | } | ||
| 3731 | } | ||
| 3732 | if (comp.clang_passthrough_mode and | ||
| 3733 | comp.clang_preprocessor_mode == .stdout) | ||
| 3734 | { | ||
| 3735 | std.process.exit(0); | ||
| 3719 | } | 3736 | } |
| 3720 | } | 3737 | } |
| 3721 | 3738 |
src/ThreadPool.zig+3| ... | @@ -82,6 +82,9 @@ pub fn init(self: *ThreadPool, allocator: std.mem.Allocator) !void { | ... | @@ -82,6 +82,9 @@ pub fn init(self: *ThreadPool, allocator: std.mem.Allocator) !void { |
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | fn destroyWorkers(self: *ThreadPool, spawned: usize) void { | 84 | fn destroyWorkers(self: *ThreadPool, spawned: usize) void { |
| 85 | if (builtin.single_threaded) | ||
| 86 | return; | ||
| 87 | |||
| 85 | for (self.workers[0..spawned]) |*worker| { | 88 | for (self.workers[0..spawned]) |*worker| { |
| 86 | worker.thread.join(); | 89 | worker.thread.join(); |
| 87 | worker.idle_node.data.deinit(); | 90 | worker.idle_node.data.deinit(); |
src/libc_installation.zig+3-1| ... | @@ -216,7 +216,7 @@ pub const LibCInstallation = struct { | ... | @@ -216,7 +216,7 @@ pub const LibCInstallation = struct { |
| 216 | self.crt_dir = try args.allocator.dupeZ(u8, "/system/develop/lib"); | 216 | self.crt_dir = try args.allocator.dupeZ(u8, "/system/develop/lib"); |
| 217 | break :blk batch.wait(); | 217 | break :blk batch.wait(); |
| 218 | }; | 218 | }; |
| 219 | } else { | 219 | } else if (std.process.can_spawn) { |
| 220 | try blk: { | 220 | try blk: { |
| 221 | var batch = Batch(FindError!void, 2, .auto_async).init(); | 221 | var batch = Batch(FindError!void, 2, .auto_async).init(); |
| 222 | errdefer batch.wait() catch {}; | 222 | errdefer batch.wait() catch {}; |
| ... | @@ -229,6 +229,8 @@ pub const LibCInstallation = struct { | ... | @@ -229,6 +229,8 @@ pub const LibCInstallation = struct { |
| 229 | } | 229 | } |
| 230 | break :blk batch.wait(); | 230 | break :blk batch.wait(); |
| 231 | }; | 231 | }; |
| 232 | } else { | ||
| 233 | return error.LibCRuntimeNotFound; | ||
| 232 | } | 234 | } |
| 233 | return self; | 235 | return self; |
| 234 | } | 236 | } |
src/link/Coff.zig+64-52| ... | @@ -9,6 +9,7 @@ const fs = std.fs; | ... | @@ -9,6 +9,7 @@ const fs = std.fs; |
| 9 | const allocPrint = std.fmt.allocPrint; | 9 | const allocPrint = std.fmt.allocPrint; |
| 10 | const mem = std.mem; | 10 | const mem = std.mem; |
| 11 | 11 | ||
| 12 | const lldMain = @import("../main.zig").lldMain; | ||
| 12 | const trace = @import("../tracy.zig").trace; | 13 | const trace = @import("../tracy.zig").trace; |
| 13 | const Module = @import("../Module.zig"); | 14 | const Module = @import("../Module.zig"); |
| 14 | const Compilation = @import("../Compilation.zig"); | 15 | const Compilation = @import("../Compilation.zig"); |
| ... | @@ -1358,60 +1359,71 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void { | ... | @@ -1358,60 +1359,71 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void { |
| 1358 | Compilation.dump_argv(argv.items[1..]); | 1359 | Compilation.dump_argv(argv.items[1..]); |
| 1359 | } | 1360 | } |
| 1360 | 1361 | ||
| 1361 | // Sadly, we must run LLD as a child process because it does not behave | 1362 | if (std.process.can_spawn) { |
| 1362 | // properly as a library. | 1363 | // If possible, we run LLD as a child process because it does not always |
| 1363 | const child = try std.ChildProcess.init(argv.items, arena); | 1364 | // behave properly as a library, unfortunately. |
| 1364 | defer child.deinit(); | 1365 | // https://github.com/ziglang/zig/issues/3825 |
| 1365 | 1366 | const child = try std.ChildProcess.init(argv.items, arena); | |
| 1366 | if (comp.clang_passthrough_mode) { | 1367 | defer child.deinit(); |
| 1367 | child.stdin_behavior = .Inherit; | 1368 | |
| 1368 | child.stdout_behavior = .Inherit; | 1369 | if (comp.clang_passthrough_mode) { |
| 1369 | child.stderr_behavior = .Inherit; | 1370 | child.stdin_behavior = .Inherit; |
| 1370 | 1371 | child.stdout_behavior = .Inherit; | |
| 1371 | const term = child.spawnAndWait() catch |err| { | 1372 | child.stderr_behavior = .Inherit; |
| 1372 | log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); | 1373 | |
| 1373 | return error.UnableToSpawnSelf; | 1374 | const term = child.spawnAndWait() catch |err| { |
| 1374 | }; | 1375 | log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); |
| 1375 | switch (term) { | 1376 | return error.UnableToSpawnSelf; |
| 1376 | .Exited => |code| { | 1377 | }; |
| 1377 | if (code != 0) { | 1378 | switch (term) { |
| 1378 | // TODO https://github.com/ziglang/zig/issues/6342 | 1379 | .Exited => |code| { |
| 1379 | std.process.exit(1); | 1380 | if (code != 0) { |
| 1380 | } | 1381 | std.process.exit(code); |
| 1381 | }, | 1382 | } |
| 1382 | else => std.process.abort(), | 1383 | }, |
| 1384 | else => std.process.abort(), | ||
| 1385 | } | ||
| 1386 | } else { | ||
| 1387 | child.stdin_behavior = .Ignore; | ||
| 1388 | child.stdout_behavior = .Ignore; | ||
| 1389 | child.stderr_behavior = .Pipe; | ||
| 1390 | |||
| 1391 | try child.spawn(); | ||
| 1392 | |||
| 1393 | const stderr = try child.stderr.?.reader().readAllAlloc(arena, 10 * 1024 * 1024); | ||
| 1394 | |||
| 1395 | const term = child.wait() catch |err| { | ||
| 1396 | log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); | ||
| 1397 | return error.UnableToSpawnSelf; | ||
| 1398 | }; | ||
| 1399 | |||
| 1400 | switch (term) { | ||
| 1401 | .Exited => |code| { | ||
| 1402 | if (code != 0) { | ||
| 1403 | // TODO parse this output and surface with the Compilation API rather than | ||
| 1404 | // directly outputting to stderr here. | ||
| 1405 | std.debug.print("{s}", .{stderr}); | ||
| 1406 | return error.LLDReportedFailure; | ||
| 1407 | } | ||
| 1408 | }, | ||
| 1409 | else => { | ||
| 1410 | log.err("{s} terminated with stderr:\n{s}", .{ argv.items[0], stderr }); | ||
| 1411 | return error.LLDCrashed; | ||
| 1412 | }, | ||
| 1413 | } | ||
| 1414 | |||
| 1415 | if (stderr.len != 0) { | ||
| 1416 | log.warn("unexpected LLD stderr:\n{s}", .{stderr}); | ||
| 1417 | } | ||
| 1383 | } | 1418 | } |
| 1384 | } else { | 1419 | } else { |
| 1385 | child.stdin_behavior = .Ignore; | 1420 | const exit_code = try lldMain(arena, argv.items); |
| 1386 | child.stdout_behavior = .Ignore; | 1421 | if (exit_code != 0) { |
| 1387 | child.stderr_behavior = .Pipe; | 1422 | if (comp.clang_passthrough_mode) { |
| 1388 | 1423 | std.process.exit(exit_code); | |
| 1389 | try child.spawn(); | 1424 | } else { |
| 1390 | 1425 | return error.LLDReportedFailure; | |
| 1391 | const stderr = try child.stderr.?.reader().readAllAlloc(arena, 10 * 1024 * 1024); | 1426 | } |
| 1392 | |||
| 1393 | const term = child.wait() catch |err| { | ||
| 1394 | log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); | ||
| 1395 | return error.UnableToSpawnSelf; | ||
| 1396 | }; | ||
| 1397 | |||
| 1398 | switch (term) { | ||
| 1399 | .Exited => |code| { | ||
| 1400 | if (code != 0) { | ||
| 1401 | // TODO parse this output and surface with the Compilation API rather than | ||
| 1402 | // directly outputting to stderr here. | ||
| 1403 | std.debug.print("{s}", .{stderr}); | ||
| 1404 | return error.LLDReportedFailure; | ||
| 1405 | } | ||
| 1406 | }, | ||
| 1407 | else => { | ||
| 1408 | log.err("{s} terminated with stderr:\n{s}", .{ argv.items[0], stderr }); | ||
| 1409 | return error.LLDCrashed; | ||
| 1410 | }, | ||
| 1411 | } | ||
| 1412 | |||
| 1413 | if (stderr.len != 0) { | ||
| 1414 | log.warn("unexpected LLD stderr:\n{s}", .{stderr}); | ||
| 1415 | } | 1427 | } |
| 1416 | } | 1428 | } |
| 1417 | } | 1429 | } |
src/link/Elf.zig+59-47| ... | @@ -14,6 +14,7 @@ const leb128 = std.leb; | ... | @@ -14,6 +14,7 @@ const leb128 = std.leb; |
| 14 | const Module = @import("../Module.zig"); | 14 | const Module = @import("../Module.zig"); |
| 15 | const Compilation = @import("../Compilation.zig"); | 15 | const Compilation = @import("../Compilation.zig"); |
| 16 | const codegen = @import("../codegen.zig"); | 16 | const codegen = @import("../codegen.zig"); |
| 17 | const lldMain = @import("../main.zig").lldMain; | ||
| 17 | const trace = @import("../tracy.zig").trace; | 18 | const trace = @import("../tracy.zig").trace; |
| 18 | const Package = @import("../Package.zig"); | 19 | const Package = @import("../Package.zig"); |
| 19 | const Value = @import("../value.zig").Value; | 20 | const Value = @import("../value.zig").Value; |
| ... | @@ -1950,60 +1951,71 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { | ... | @@ -1950,60 +1951,71 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { |
| 1950 | Compilation.dump_argv(argv.items[1..]); | 1951 | Compilation.dump_argv(argv.items[1..]); |
| 1951 | } | 1952 | } |
| 1952 | 1953 | ||
| 1953 | // Sadly, we must run LLD as a child process because it does not behave | 1954 | if (std.process.can_spawn) { |
| 1954 | // properly as a library. | 1955 | // If possible, we run LLD as a child process because it does not always |
| 1955 | const child = try std.ChildProcess.init(argv.items, arena); | 1956 | // behave properly as a library, unfortunately. |
| 1956 | defer child.deinit(); | 1957 | // https://github.com/ziglang/zig/issues/3825 |
| 1958 | const child = try std.ChildProcess.init(argv.items, arena); | ||
| 1959 | defer child.deinit(); | ||
| 1957 | 1960 | ||
| 1958 | if (comp.clang_passthrough_mode) { | 1961 | if (comp.clang_passthrough_mode) { |
| 1959 | child.stdin_behavior = .Inherit; | 1962 | child.stdin_behavior = .Inherit; |
| 1960 | child.stdout_behavior = .Inherit; | 1963 | child.stdout_behavior = .Inherit; |
| 1961 | child.stderr_behavior = .Inherit; | 1964 | child.stderr_behavior = .Inherit; |
| 1962 | 1965 | ||
| 1963 | const term = child.spawnAndWait() catch |err| { | 1966 | const term = child.spawnAndWait() catch |err| { |
| 1964 | log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); | 1967 | log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); |
| 1965 | return error.UnableToSpawnSelf; | 1968 | return error.UnableToSpawnSelf; |
| 1966 | }; | 1969 | }; |
| 1967 | switch (term) { | 1970 | switch (term) { |
| 1968 | .Exited => |code| { | 1971 | .Exited => |code| { |
| 1969 | if (code != 0) { | 1972 | if (code != 0) { |
| 1970 | // TODO https://github.com/ziglang/zig/issues/6342 | 1973 | std.process.exit(code); |
| 1971 | std.process.exit(1); | 1974 | } |
| 1972 | } | 1975 | }, |
| 1973 | }, | 1976 | else => std.process.abort(), |
| 1974 | else => std.process.abort(), | 1977 | } |
| 1975 | } | 1978 | } else { |
| 1976 | } else { | 1979 | child.stdin_behavior = .Ignore; |
| 1977 | child.stdin_behavior = .Ignore; | 1980 | child.stdout_behavior = .Ignore; |
| 1978 | child.stdout_behavior = .Ignore; | 1981 | child.stderr_behavior = .Pipe; |
| 1979 | child.stderr_behavior = .Pipe; | ||
| 1980 | 1982 | ||
| 1981 | try child.spawn(); | 1983 | try child.spawn(); |
| 1982 | 1984 | ||
| 1983 | const stderr = try child.stderr.?.reader().readAllAlloc(arena, 10 * 1024 * 1024); | 1985 | const stderr = try child.stderr.?.reader().readAllAlloc(arena, 10 * 1024 * 1024); |
| 1984 | 1986 | ||
| 1985 | const term = child.wait() catch |err| { | 1987 | const term = child.wait() catch |err| { |
| 1986 | log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); | 1988 | log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); |
| 1987 | return error.UnableToSpawnSelf; | 1989 | return error.UnableToSpawnSelf; |
| 1988 | }; | 1990 | }; |
| 1989 | 1991 | ||
| 1990 | switch (term) { | 1992 | switch (term) { |
| 1991 | .Exited => |code| { | 1993 | .Exited => |code| { |
| 1992 | if (code != 0) { | 1994 | if (code != 0) { |
| 1993 | // TODO parse this output and surface with the Compilation API rather than | 1995 | // TODO parse this output and surface with the Compilation API rather than |
| 1994 | // directly outputting to stderr here. | 1996 | // directly outputting to stderr here. |
| 1995 | std.debug.print("{s}", .{stderr}); | 1997 | std.debug.print("{s}", .{stderr}); |
| 1996 | return error.LLDReportedFailure; | 1998 | return error.LLDReportedFailure; |
| 1997 | } | 1999 | } |
| 1998 | }, | 2000 | }, |
| 1999 | else => { | 2001 | else => { |
| 2000 | log.err("{s} terminated with stderr:\n{s}", .{ argv.items[0], stderr }); | 2002 | log.err("{s} terminated with stderr:\n{s}", .{ argv.items[0], stderr }); |
| 2001 | return error.LLDCrashed; | 2003 | return error.LLDCrashed; |
| 2002 | }, | 2004 | }, |
| 2003 | } | 2005 | } |
| 2004 | 2006 | ||
| 2005 | if (stderr.len != 0) { | 2007 | if (stderr.len != 0) { |
| 2006 | log.warn("unexpected LLD stderr:\n{s}", .{stderr}); | 2008 | log.warn("unexpected LLD stderr:\n{s}", .{stderr}); |
| 2009 | } | ||
| 2010 | } | ||
| 2011 | } else { | ||
| 2012 | const exit_code = try lldMain(arena, argv.items); | ||
| 2013 | if (exit_code != 0) { | ||
| 2014 | if (comp.clang_passthrough_mode) { | ||
| 2015 | std.process.exit(exit_code); | ||
| 2016 | } else { | ||
| 2017 | return error.LLDReportedFailure; | ||
| 2018 | } | ||
| 2007 | } | 2019 | } |
| 2008 | } | 2020 | } |
| 2009 | } | 2021 | } |
src/link/Wasm.zig+60-48| ... | @@ -15,6 +15,7 @@ const Module = @import("../Module.zig"); | ... | @@ -15,6 +15,7 @@ const Module = @import("../Module.zig"); |
| 15 | const Compilation = @import("../Compilation.zig"); | 15 | const Compilation = @import("../Compilation.zig"); |
| 16 | const CodeGen = @import("../arch/wasm/CodeGen.zig"); | 16 | const CodeGen = @import("../arch/wasm/CodeGen.zig"); |
| 17 | const link = @import("../link.zig"); | 17 | const link = @import("../link.zig"); |
| 18 | const lldMain = @import("../main.zig").lldMain; | ||
| 18 | const trace = @import("../tracy.zig").trace; | 19 | const trace = @import("../tracy.zig").trace; |
| 19 | const build_options = @import("build_options"); | 20 | const build_options = @import("build_options"); |
| 20 | const wasi_libc = @import("../wasi_libc.zig"); | 21 | const wasi_libc = @import("../wasi_libc.zig"); |
| ... | @@ -1486,60 +1487,71 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { | ... | @@ -1486,60 +1487,71 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { |
| 1486 | Compilation.dump_argv(argv.items[1..]); | 1487 | Compilation.dump_argv(argv.items[1..]); |
| 1487 | } | 1488 | } |
| 1488 | 1489 | ||
| 1489 | // Sadly, we must run LLD as a child process because it does not behave | 1490 | if (std.process.can_spawn) { |
| 1490 | // properly as a library. | 1491 | // If possible, we run LLD as a child process because it does not always |
| 1491 | const child = try std.ChildProcess.init(argv.items, arena); | 1492 | // behave properly as a library, unfortunately. |
| 1492 | defer child.deinit(); | 1493 | // https://github.com/ziglang/zig/issues/3825 |
| 1493 | 1494 | const child = try std.ChildProcess.init(argv.items, arena); | |
| 1494 | if (comp.clang_passthrough_mode) { | 1495 | defer child.deinit(); |
| 1495 | child.stdin_behavior = .Inherit; | 1496 | |
| 1496 | child.stdout_behavior = .Inherit; | 1497 | if (comp.clang_passthrough_mode) { |
| 1497 | child.stderr_behavior = .Inherit; | 1498 | child.stdin_behavior = .Inherit; |
| 1499 | child.stdout_behavior = .Inherit; | ||
| 1500 | child.stderr_behavior = .Inherit; | ||
| 1501 | |||
| 1502 | const term = child.spawnAndWait() catch |err| { | ||
| 1503 | log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); | ||
| 1504 | return error.UnableToSpawnSelf; | ||
| 1505 | }; | ||
| 1506 | switch (term) { | ||
| 1507 | .Exited => |code| { | ||
| 1508 | if (code != 0) { | ||
| 1509 | std.process.exit(code); | ||
| 1510 | } | ||
| 1511 | }, | ||
| 1512 | else => std.process.abort(), | ||
| 1513 | } | ||
| 1514 | } else { | ||
| 1515 | child.stdin_behavior = .Ignore; | ||
| 1516 | child.stdout_behavior = .Ignore; | ||
| 1517 | child.stderr_behavior = .Pipe; | ||
| 1498 | 1518 | ||
| 1499 | const term = child.spawnAndWait() catch |err| { | 1519 | try child.spawn(); |
| 1500 | log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); | ||
| 1501 | return error.UnableToSpawnSelf; | ||
| 1502 | }; | ||
| 1503 | switch (term) { | ||
| 1504 | .Exited => |code| { | ||
| 1505 | if (code != 0) { | ||
| 1506 | // TODO https://github.com/ziglang/zig/issues/6342 | ||
| 1507 | std.process.exit(1); | ||
| 1508 | } | ||
| 1509 | }, | ||
| 1510 | else => std.process.abort(), | ||
| 1511 | } | ||
| 1512 | } else { | ||
| 1513 | child.stdin_behavior = .Ignore; | ||
| 1514 | child.stdout_behavior = .Ignore; | ||
| 1515 | child.stderr_behavior = .Pipe; | ||
| 1516 | 1520 | ||
| 1517 | try child.spawn(); | 1521 | const stderr = try child.stderr.?.reader().readAllAlloc(arena, 10 * 1024 * 1024); |
| 1518 | 1522 | ||
| 1519 | const stderr = try child.stderr.?.reader().readAllAlloc(arena, 10 * 1024 * 1024); | 1523 | const term = child.wait() catch |err| { |
| 1524 | log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); | ||
| 1525 | return error.UnableToSpawnSelf; | ||
| 1526 | }; | ||
| 1520 | 1527 | ||
| 1521 | const term = child.wait() catch |err| { | 1528 | switch (term) { |
| 1522 | log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); | 1529 | .Exited => |code| { |
| 1523 | return error.UnableToSpawnSelf; | 1530 | if (code != 0) { |
| 1524 | }; | 1531 | // TODO parse this output and surface with the Compilation API rather than |
| 1532 | // directly outputting to stderr here. | ||
| 1533 | std.debug.print("{s}", .{stderr}); | ||
| 1534 | return error.LLDReportedFailure; | ||
| 1535 | } | ||
| 1536 | }, | ||
| 1537 | else => { | ||
| 1538 | log.err("{s} terminated with stderr:\n{s}", .{ argv.items[0], stderr }); | ||
| 1539 | return error.LLDCrashed; | ||
| 1540 | }, | ||
| 1541 | } | ||
| 1525 | 1542 | ||
| 1526 | switch (term) { | 1543 | if (stderr.len != 0) { |
| 1527 | .Exited => |code| { | 1544 | log.warn("unexpected LLD stderr:\n{s}", .{stderr}); |
| 1528 | if (code != 0) { | 1545 | } |
| 1529 | // TODO parse this output and surface with the Compilation API rather than | ||
| 1530 | // directly outputting to stderr here. | ||
| 1531 | std.debug.print("{s}", .{stderr}); | ||
| 1532 | return error.LLDReportedFailure; | ||
| 1533 | } | ||
| 1534 | }, | ||
| 1535 | else => { | ||
| 1536 | log.err("{s} terminated with stderr:\n{s}", .{ argv.items[0], stderr }); | ||
| 1537 | return error.LLDCrashed; | ||
| 1538 | }, | ||
| 1539 | } | 1546 | } |
| 1540 | 1547 | } else { | |
| 1541 | if (stderr.len != 0) { | 1548 | const exit_code = try lldMain(arena, argv.items); |
| 1542 | log.warn("unexpected LLD stderr:\n{s}", .{stderr}); | 1549 | if (exit_code != 0) { |
| 1550 | if (comp.clang_passthrough_mode) { | ||
| 1551 | std.process.exit(exit_code); | ||
| 1552 | } else { | ||
| 1553 | return error.LLDReportedFailure; | ||
| 1554 | } | ||
| 1543 | } | 1555 | } |
| 1544 | } | 1556 | } |
| 1545 | } | 1557 | } |
src/main.zig+82-55| ... | @@ -221,7 +221,7 @@ pub fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi | ... | @@ -221,7 +221,7 @@ pub fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi |
| 221 | mem.eql(u8, cmd, "lib") or | 221 | mem.eql(u8, cmd, "lib") or |
| 222 | mem.eql(u8, cmd, "ar")) | 222 | mem.eql(u8, cmd, "ar")) |
| 223 | { | 223 | { |
| 224 | return punt_to_llvm_ar(arena, args); | 224 | return process.exit(try llvmArMain(arena, args)); |
| 225 | } else if (mem.eql(u8, cmd, "cc")) { | 225 | } else if (mem.eql(u8, cmd, "cc")) { |
| 226 | return buildOutputType(gpa, arena, args, .cc); | 226 | return buildOutputType(gpa, arena, args, .cc); |
| 227 | } else if (mem.eql(u8, cmd, "c++")) { | 227 | } else if (mem.eql(u8, cmd, "c++")) { |
| ... | @@ -231,12 +231,12 @@ pub fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi | ... | @@ -231,12 +231,12 @@ pub fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi |
| 231 | } else if (mem.eql(u8, cmd, "clang") or | 231 | } else if (mem.eql(u8, cmd, "clang") or |
| 232 | mem.eql(u8, cmd, "-cc1") or mem.eql(u8, cmd, "-cc1as")) | 232 | mem.eql(u8, cmd, "-cc1") or mem.eql(u8, cmd, "-cc1as")) |
| 233 | { | 233 | { |
| 234 | return punt_to_clang(arena, args); | 234 | return process.exit(try clangMain(arena, args)); |
| 235 | } else if (mem.eql(u8, cmd, "ld.lld") or | 235 | } else if (mem.eql(u8, cmd, "ld.lld") or |
| 236 | mem.eql(u8, cmd, "lld-link") or | 236 | mem.eql(u8, cmd, "lld-link") or |
| 237 | mem.eql(u8, cmd, "wasm-ld")) | 237 | mem.eql(u8, cmd, "wasm-ld")) |
| 238 | { | 238 | { |
| 239 | return punt_to_lld(arena, args); | 239 | return process.exit(try lldMain(arena, args)); |
| 240 | } else if (mem.eql(u8, cmd, "build")) { | 240 | } else if (mem.eql(u8, cmd, "build")) { |
| 241 | return cmdBuild(gpa, arena, cmd_args); | 241 | return cmdBuild(gpa, arena, cmd_args); |
| 242 | } else if (mem.eql(u8, cmd, "fmt")) { | 242 | } else if (mem.eql(u8, cmd, "fmt")) { |
| ... | @@ -1347,7 +1347,7 @@ fn buildOutputType( | ... | @@ -1347,7 +1347,7 @@ fn buildOutputType( |
| 1347 | .ignore => {}, | 1347 | .ignore => {}, |
| 1348 | .driver_punt => { | 1348 | .driver_punt => { |
| 1349 | // Never mind what we're doing, just pass the args directly. For example --help. | 1349 | // Never mind what we're doing, just pass the args directly. For example --help. |
| 1350 | return punt_to_clang(arena, all_args); | 1350 | return process.exit(try clangMain(arena, all_args)); |
| 1351 | }, | 1351 | }, |
| 1352 | .pic => want_pic = true, | 1352 | .pic => want_pic = true, |
| 1353 | .no_pic => want_pic = false, | 1353 | .no_pic => want_pic = false, |
| ... | @@ -1866,7 +1866,7 @@ fn buildOutputType( | ... | @@ -1866,7 +1866,7 @@ fn buildOutputType( |
| 1866 | // An error message is generated when there is more than 1 C source file. | 1866 | // An error message is generated when there is more than 1 C source file. |
| 1867 | if (c_source_files.items.len != 1) { | 1867 | if (c_source_files.items.len != 1) { |
| 1868 | // For example `zig cc` and no args should print the "no input files" message. | 1868 | // For example `zig cc` and no args should print the "no input files" message. |
| 1869 | return punt_to_clang(arena, all_args); | 1869 | return process.exit(try clangMain(arena, all_args)); |
| 1870 | } | 1870 | } |
| 1871 | if (out_path) |p| { | 1871 | if (out_path) |p| { |
| 1872 | emit_bin = .{ .yes = p }; | 1872 | emit_bin = .{ .yes = p }; |
| ... | @@ -1882,7 +1882,7 @@ fn buildOutputType( | ... | @@ -1882,7 +1882,7 @@ fn buildOutputType( |
| 1882 | { | 1882 | { |
| 1883 | // For example `zig cc` and no args should print the "no input files" message. | 1883 | // For example `zig cc` and no args should print the "no input files" message. |
| 1884 | // There could be other reasons to punt to clang, for example, --help. | 1884 | // There could be other reasons to punt to clang, for example, --help. |
| 1885 | return punt_to_clang(arena, all_args); | 1885 | return process.exit(try clangMain(arena, all_args)); |
| 1886 | } | 1886 | } |
| 1887 | }, | 1887 | }, |
| 1888 | } | 1888 | } |
| ... | @@ -2883,7 +2883,7 @@ fn runOrTest( | ... | @@ -2883,7 +2883,7 @@ fn runOrTest( |
| 2883 | try warnAboutForeignBinaries(gpa, arena, arg_mode, target_info, link_libc); | 2883 | try warnAboutForeignBinaries(gpa, arena, arg_mode, target_info, link_libc); |
| 2884 | const cmd = try argvCmd(arena, argv.items); | 2884 | const cmd = try argvCmd(arena, argv.items); |
| 2885 | fatal("the following command failed to execve with '{s}':\n{s}", .{ @errorName(err), cmd }); | 2885 | fatal("the following command failed to execve with '{s}':\n{s}", .{ @errorName(err), cmd }); |
| 2886 | } else { | 2886 | } else if (std.process.can_spawn) { |
| 2887 | const child = try std.ChildProcess.init(argv.items, gpa); | 2887 | const child = try std.ChildProcess.init(argv.items, gpa); |
| 2888 | defer child.deinit(); | 2888 | defer child.deinit(); |
| 2889 | 2889 | ||
| ... | @@ -2943,6 +2943,9 @@ fn runOrTest( | ... | @@ -2943,6 +2943,9 @@ fn runOrTest( |
| 2943 | }, | 2943 | }, |
| 2944 | else => unreachable, | 2944 | else => unreachable, |
| 2945 | } | 2945 | } |
| 2946 | } else { | ||
| 2947 | const cmd = try argvCmd(arena, argv.items); | ||
| 2948 | fatal("the following command cannot be executed ({s} does not support spawning a child process):\n{s}", .{ @tagName(builtin.os.tag), cmd }); | ||
| 2946 | } | 2949 | } |
| 2947 | } | 2950 | } |
| 2948 | 2951 | ||
| ... | @@ -3553,29 +3556,35 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi | ... | @@ -3553,29 +3556,35 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi |
| 3553 | 3556 | ||
| 3554 | break :argv child_argv.items; | 3557 | break :argv child_argv.items; |
| 3555 | }; | 3558 | }; |
| 3556 | const child = try std.ChildProcess.init(child_argv, gpa); | ||
| 3557 | defer child.deinit(); | ||
| 3558 | 3559 | ||
| 3559 | child.stdin_behavior = .Inherit; | 3560 | if (std.process.can_spawn) { |
| 3560 | child.stdout_behavior = .Inherit; | 3561 | const child = try std.ChildProcess.init(child_argv, gpa); |
| 3561 | child.stderr_behavior = .Inherit; | 3562 | defer child.deinit(); |
| 3563 | |||
| 3564 | child.stdin_behavior = .Inherit; | ||
| 3565 | child.stdout_behavior = .Inherit; | ||
| 3566 | child.stderr_behavior = .Inherit; | ||
| 3562 | 3567 | ||
| 3563 | const term = try child.spawnAndWait(); | 3568 | const term = try child.spawnAndWait(); |
| 3564 | switch (term) { | 3569 | switch (term) { |
| 3565 | .Exited => |code| { | 3570 | .Exited => |code| { |
| 3566 | if (code == 0) return cleanExit(); | 3571 | if (code == 0) return cleanExit(); |
| 3567 | 3572 | ||
| 3568 | if (prominent_compile_errors) { | 3573 | if (prominent_compile_errors) { |
| 3569 | fatal("the build command failed with exit code {d}", .{code}); | 3574 | fatal("the build command failed with exit code {d}", .{code}); |
| 3570 | } else { | 3575 | } else { |
| 3576 | const cmd = try argvCmd(arena, child_argv); | ||
| 3577 | fatal("the following build command failed with exit code {d}:\n{s}", .{ code, cmd }); | ||
| 3578 | } | ||
| 3579 | }, | ||
| 3580 | else => { | ||
| 3571 | const cmd = try argvCmd(arena, child_argv); | 3581 | const cmd = try argvCmd(arena, child_argv); |
| 3572 | fatal("the following build command failed with exit code {d}:\n{s}", .{ code, cmd }); | 3582 | fatal("the following build command crashed:\n{s}", .{cmd}); |
| 3573 | } | 3583 | }, |
| 3574 | }, | 3584 | } |
| 3575 | else => { | 3585 | } else { |
| 3576 | const cmd = try argvCmd(arena, child_argv); | 3586 | const cmd = try argvCmd(arena, child_argv); |
| 3577 | fatal("the following build command crashed:\n{s}", .{cmd}); | 3587 | fatal("the following command cannot be executed ({s} does not support spawning a child process):\n{s}", .{ @tagName(builtin.os.tag), cmd }); |
| 3578 | }, | ||
| 3579 | } | 3588 | } |
| 3580 | } | 3589 | } |
| 3581 | 3590 | ||
| ... | @@ -4080,51 +4089,69 @@ pub const info_zen = | ... | @@ -4080,51 +4089,69 @@ pub const info_zen = |
| 4080 | extern "c" fn ZigClang_main(argc: c_int, argv: [*:null]?[*:0]u8) c_int; | 4089 | extern "c" fn ZigClang_main(argc: c_int, argv: [*:null]?[*:0]u8) c_int; |
| 4081 | extern "c" fn ZigLlvmAr_main(argc: c_int, argv: [*:null]?[*:0]u8) c_int; | 4090 | extern "c" fn ZigLlvmAr_main(argc: c_int, argv: [*:null]?[*:0]u8) c_int; |
| 4082 | 4091 | ||
| 4083 | /// TODO https://github.com/ziglang/zig/issues/3257 | 4092 | fn argsCopyZ(alloc: Allocator, args: []const []const u8) ![:null]?[*:0]u8 { |
| 4084 | fn punt_to_clang(arena: Allocator, args: []const []const u8) error{OutOfMemory} { | 4093 | var argv = try alloc.allocSentinel(?[*:0]u8, args.len, null); |
| 4085 | if (!build_options.have_llvm) | ||
| 4086 | fatal("`zig cc` and `zig c++` unavailable: compiler built without LLVM extensions", .{}); | ||
| 4087 | // Convert the args to the format Clang expects. | ||
| 4088 | const argv = try arena.alloc(?[*:0]u8, args.len + 1); | ||
| 4089 | for (args) |arg, i| { | 4094 | for (args) |arg, i| { |
| 4090 | argv[i] = try arena.dupeZ(u8, arg); // TODO If there was an argsAllocZ we could avoid this allocation. | 4095 | argv[i] = try alloc.dupeZ(u8, arg); // TODO If there was an argsAllocZ we could avoid this allocation. |
| 4091 | } | 4096 | } |
| 4092 | argv[args.len] = null; | 4097 | return argv; |
| 4093 | const exit_code = ZigClang_main(@intCast(c_int, args.len), argv[0..args.len :null].ptr); | 4098 | } |
| 4094 | process.exit(@bitCast(u8, @truncate(i8, exit_code))); | 4099 | |
| 4100 | pub fn clangMain(alloc: Allocator, args: []const []const u8) error{OutOfMemory}!u8 { | ||
| 4101 | if (!build_options.have_llvm) | ||
| 4102 | fatal("`zig cc` and `zig c++` unavailable: compiler built without LLVM extensions", .{}); | ||
| 4103 | |||
| 4104 | var arena_instance = std.heap.ArenaAllocator.init(alloc); | ||
| 4105 | defer arena_instance.deinit(); | ||
| 4106 | const arena = arena_instance.allocator(); | ||
| 4107 | |||
| 4108 | // Convert the args to the null-terminated format Clang expects. | ||
| 4109 | const argv = try argsCopyZ(arena, args); | ||
| 4110 | const exit_code = ZigClang_main(@intCast(c_int, argv.len), argv.ptr); | ||
| 4111 | return @bitCast(u8, @truncate(i8, exit_code)); | ||
| 4095 | } | 4112 | } |
| 4096 | 4113 | ||
| 4097 | /// TODO https://github.com/ziglang/zig/issues/3257 | 4114 | pub fn llvmArMain(alloc: Allocator, args: []const []const u8) error{OutOfMemory}!u8 { |
| 4098 | fn punt_to_llvm_ar(arena: Allocator, args: []const []const u8) error{OutOfMemory} { | ||
| 4099 | if (!build_options.have_llvm) | 4115 | if (!build_options.have_llvm) |
| 4100 | fatal("`zig ar`, `zig dlltool`, `zig ranlib', and `zig lib` unavailable: compiler built without LLVM extensions", .{}); | 4116 | fatal("`zig ar`, `zig dlltool`, `zig ranlib', and `zig lib` unavailable: compiler built without LLVM extensions", .{}); |
| 4101 | 4117 | ||
| 4118 | var arena_instance = std.heap.ArenaAllocator.init(alloc); | ||
| 4119 | defer arena_instance.deinit(); | ||
| 4120 | const arena = arena_instance.allocator(); | ||
| 4121 | |||
| 4102 | // Convert the args to the format llvm-ar expects. | 4122 | // Convert the args to the format llvm-ar expects. |
| 4103 | // We subtract 1 to shave off the zig binary from args[0]. | 4123 | // We intentionally shave off the zig binary at args[0]. |
| 4104 | const argv = try arena.allocSentinel(?[*:0]u8, args.len - 1, null); | 4124 | const argv = try argsCopyZ(arena, args[1..]); |
| 4105 | for (args[1..]) |arg, i| { | 4125 | const exit_code = ZigLlvmAr_main(@intCast(c_int, argv.len), argv.ptr); |
| 4106 | // TODO If there was an argsAllocZ we could avoid this allocation. | 4126 | return @bitCast(u8, @truncate(i8, exit_code)); |
| 4107 | argv[i] = try arena.dupeZ(u8, arg); | ||
| 4108 | } | ||
| 4109 | const argc = @intCast(c_int, argv.len); | ||
| 4110 | const exit_code = ZigLlvmAr_main(argc, argv.ptr); | ||
| 4111 | process.exit(@bitCast(u8, @truncate(i8, exit_code))); | ||
| 4112 | } | 4127 | } |
| 4113 | 4128 | ||
| 4114 | /// The first argument determines which backend is invoked. The options are: | 4129 | /// The first argument determines which backend is invoked. The options are: |
| 4115 | /// * `ld.lld` - ELF | 4130 | /// * `ld.lld` - ELF |
| 4116 | /// * `lld-link` - COFF | 4131 | /// * `lld-link` - COFF |
| 4117 | /// * `wasm-ld` - WebAssembly | 4132 | /// * `wasm-ld` - WebAssembly |
| 4118 | /// TODO https://github.com/ziglang/zig/issues/3257 | 4133 | pub fn lldMain(alloc: Allocator, args: []const []const u8) error{OutOfMemory}!u8 { |
| 4119 | pub fn punt_to_lld(arena: Allocator, args: []const []const u8) error{OutOfMemory} { | ||
| 4120 | if (!build_options.have_llvm) | 4134 | if (!build_options.have_llvm) |
| 4121 | fatal("`zig {s}` unavailable: compiler built without LLVM extensions", .{args[0]}); | 4135 | fatal("`zig {s}` unavailable: compiler built without LLVM extensions", .{args[0]}); |
| 4122 | // Convert the args to the format LLD expects. | 4136 | |
| 4123 | // We subtract 1 to shave off the zig binary from args[0]. | 4137 | // Print a warning if lld is called multiple times in the same process, |
| 4124 | const argv = try arena.allocSentinel(?[*:0]const u8, args.len - 1, null); | 4138 | // since it may misbehave |
| 4125 | for (args[1..]) |arg, i| { | 4139 | // https://github.com/ziglang/zig/issues/3825 |
| 4126 | argv[i] = try arena.dupeZ(u8, arg); // TODO If there was an argsAllocZ we could avoid this allocation. | 4140 | const CallCounter = struct { |
| 4141 | var count: usize = 0; | ||
| 4142 | }; | ||
| 4143 | if (CallCounter.count == 1) { // Issue the warning on the first repeat call | ||
| 4144 | warn("calling lldMain repeatedly within the same process can have side effects (https://github.com/ziglang/zig/issues/3825)", .{}); | ||
| 4127 | } | 4145 | } |
| 4146 | CallCounter.count += 1; | ||
| 4147 | |||
| 4148 | var arena_instance = std.heap.ArenaAllocator.init(alloc); | ||
| 4149 | defer arena_instance.deinit(); | ||
| 4150 | const arena = arena_instance.allocator(); | ||
| 4151 | |||
| 4152 | // Convert the args to the format llvm-ar expects. | ||
| 4153 | // We intentionally shave off the zig binary at args[0]. | ||
| 4154 | const argv = try argsCopyZ(arena, args[1..]); | ||
| 4128 | const exit_code = rc: { | 4155 | const exit_code = rc: { |
| 4129 | const llvm = @import("codegen/llvm/bindings.zig"); | 4156 | const llvm = @import("codegen/llvm/bindings.zig"); |
| 4130 | const argc = @intCast(c_int, argv.len); | 4157 | const argc = @intCast(c_int, argv.len); |
| ... | @@ -4138,7 +4165,7 @@ pub fn punt_to_lld(arena: Allocator, args: []const []const u8) error{OutOfMemory | ... | @@ -4138,7 +4165,7 @@ pub fn punt_to_lld(arena: Allocator, args: []const []const u8) error{OutOfMemory |
| 4138 | unreachable; | 4165 | unreachable; |
| 4139 | } | 4166 | } |
| 4140 | }; | 4167 | }; |
| 4141 | process.exit(@bitCast(u8, @truncate(i8, exit_code))); | 4168 | return @bitCast(u8, @truncate(i8, exit_code)); |
| 4142 | } | 4169 | } |
| 4143 | 4170 | ||
| 4144 | const clang_args = @import("clang_options.zig").list; | 4171 | const clang_args = @import("clang_options.zig").list; |
src/mingw.zig+31-26| ... | @@ -5,6 +5,7 @@ const path = std.fs.path; | ... | @@ -5,6 +5,7 @@ const path = std.fs.path; |
| 5 | const assert = std.debug.assert; | 5 | const assert = std.debug.assert; |
| 6 | const log = std.log.scoped(.mingw); | 6 | const log = std.log.scoped(.mingw); |
| 7 | 7 | ||
| 8 | const builtin = @import("builtin"); | ||
| 8 | const target_util = @import("target.zig"); | 9 | const target_util = @import("target.zig"); |
| 9 | const Compilation = @import("Compilation.zig"); | 10 | const Compilation = @import("Compilation.zig"); |
| 10 | const build_options = @import("build_options"); | 11 | const build_options = @import("build_options"); |
| ... | @@ -367,39 +368,43 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void { | ... | @@ -367,39 +368,43 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void { |
| 367 | Compilation.dump_argv(&args); | 368 | Compilation.dump_argv(&args); |
| 368 | } | 369 | } |
| 369 | 370 | ||
| 370 | const child = try std.ChildProcess.init(&args, arena); | 371 | if (std.process.can_spawn) { |
| 371 | defer child.deinit(); | 372 | const child = try std.ChildProcess.init(&args, arena); |
| 373 | defer child.deinit(); | ||
| 372 | 374 | ||
| 373 | child.stdin_behavior = .Ignore; | 375 | child.stdin_behavior = .Ignore; |
| 374 | child.stdout_behavior = .Pipe; | 376 | child.stdout_behavior = .Pipe; |
| 375 | child.stderr_behavior = .Pipe; | 377 | child.stderr_behavior = .Pipe; |
| 376 | 378 | ||
| 377 | try child.spawn(); | 379 | try child.spawn(); |
| 378 | 380 | ||
| 379 | const stderr_reader = child.stderr.?.reader(); | 381 | const stderr_reader = child.stderr.?.reader(); |
| 380 | 382 | ||
| 381 | // TODO https://github.com/ziglang/zig/issues/6343 | 383 | // TODO https://github.com/ziglang/zig/issues/6343 |
| 382 | const stderr = try stderr_reader.readAllAlloc(arena, 10 * 1024 * 1024); | 384 | const stderr = try stderr_reader.readAllAlloc(arena, 10 * 1024 * 1024); |
| 383 | 385 | ||
| 384 | const term = child.wait() catch |err| { | 386 | const term = child.wait() catch |err| { |
| 385 | // TODO surface a proper error here | ||
| 386 | log.err("unable to spawn {s}: {s}", .{ args[0], @errorName(err) }); | ||
| 387 | return error.ClangPreprocessorFailed; | ||
| 388 | }; | ||
| 389 | |||
| 390 | switch (term) { | ||
| 391 | .Exited => |code| { | ||
| 392 | if (code != 0) { | ||
| 393 | // TODO surface a proper error here | ||
| 394 | log.err("clang exited with code {d} and stderr: {s}", .{ code, stderr }); | ||
| 395 | return error.ClangPreprocessorFailed; | ||
| 396 | } | ||
| 397 | }, | ||
| 398 | else => { | ||
| 399 | // TODO surface a proper error here | 387 | // TODO surface a proper error here |
| 400 | log.err("clang terminated unexpectedly with stderr: {s}", .{stderr}); | 388 | log.err("unable to spawn {s}: {s}", .{ args[0], @errorName(err) }); |
| 401 | return error.ClangPreprocessorFailed; | 389 | return error.ClangPreprocessorFailed; |
| 402 | }, | 390 | }; |
| 391 | switch (term) { | ||
| 392 | .Exited => |code| { | ||
| 393 | if (code != 0) { | ||
| 394 | // TODO surface a proper error here | ||
| 395 | log.err("clang exited with code {d} and stderr: {s}", .{ code, stderr }); | ||
| 396 | return error.ClangPreprocessorFailed; | ||
| 397 | } | ||
| 398 | }, | ||
| 399 | else => { | ||
| 400 | // TODO surface a proper error here | ||
| 401 | log.err("clang terminated unexpectedly with stderr: {s}", .{stderr}); | ||
| 402 | return error.ClangPreprocessorFailed; | ||
| 403 | }, | ||
| 404 | } | ||
| 405 | } else { | ||
| 406 | log.err("unable to spawn {s}: spawning child process not supported on {s}", .{ args[0], @tagName(builtin.os.tag) }); | ||
| 407 | return error.ClangPreprocessorFailed; | ||
| 403 | } | 408 | } |
| 404 | 409 | ||
| 405 | const lib_final_path = try comp.global_cache_directory.join(comp.gpa, &[_][]const u8{ | 410 | const lib_final_path = try comp.global_cache_directory.join(comp.gpa, &[_][]const u8{ |
src/test.zig+11| ... | @@ -730,6 +730,12 @@ pub const TestContext = struct { | ... | @@ -730,6 +730,12 @@ pub const TestContext = struct { |
| 730 | // * cannot handle updates | 730 | // * cannot handle updates |
| 731 | // because of this we must spawn a child process rather than | 731 | // because of this we must spawn a child process rather than |
| 732 | // using Compilation directly. | 732 | // using Compilation directly. |
| 733 | |||
| 734 | if (!std.process.can_spawn) { | ||
| 735 | print("Unable to spawn child processes on {s}, skipping test.\n", .{@tagName(builtin.os.tag)}); | ||
| 736 | return; // Pass test. | ||
| 737 | } | ||
| 738 | |||
| 733 | assert(case.updates.items.len == 1); | 739 | assert(case.updates.items.len == 1); |
| 734 | const update = case.updates.items[0]; | 740 | const update = case.updates.items[0]; |
| 735 | try tmp.dir.writeFile(tmp_src_path, update.src); | 741 | try tmp.dir.writeFile(tmp_src_path, update.src); |
| ... | @@ -1104,6 +1110,11 @@ pub const TestContext = struct { | ... | @@ -1104,6 +1110,11 @@ pub const TestContext = struct { |
| 1104 | } | 1110 | } |
| 1105 | }, | 1111 | }, |
| 1106 | .Execution => |expected_stdout| { | 1112 | .Execution => |expected_stdout| { |
| 1113 | if (!std.process.can_spawn) { | ||
| 1114 | print("Unable to spawn child processes on {s}, skipping test.\n", .{@tagName(builtin.os.tag)}); | ||
| 1115 | return; // Pass test. | ||
| 1116 | } | ||
| 1117 | |||
| 1107 | update_node.setEstimatedTotalItems(4); | 1118 | update_node.setEstimatedTotalItems(4); |
| 1108 | 1119 | ||
| 1109 | var argv = std.ArrayList([]const u8).init(allocator); | 1120 | var argv = std.ArrayList([]const u8).init(allocator); |
test/tests.zig+20| ... | @@ -10,6 +10,8 @@ const fmt = std.fmt; | ... | @@ -10,6 +10,8 @@ const fmt = std.fmt; |
| 10 | const ArrayList = std.ArrayList; | 10 | const ArrayList = std.ArrayList; |
| 11 | const Mode = std.builtin.Mode; | 11 | const Mode = std.builtin.Mode; |
| 12 | const LibExeObjStep = build.LibExeObjStep; | 12 | const LibExeObjStep = build.LibExeObjStep; |
| 13 | const Allocator = mem.Allocator; | ||
| 14 | const ExecError = build.Builder.ExecError; | ||
| 13 | 15 | ||
| 14 | // Cases | 16 | // Cases |
| 15 | const compare_output = @import("compare_output.zig"); | 17 | const compare_output = @import("compare_output.zig"); |
| ... | @@ -26,6 +28,17 @@ pub const TranslateCContext = @import("src/translate_c.zig").TranslateCContext; | ... | @@ -26,6 +28,17 @@ pub const TranslateCContext = @import("src/translate_c.zig").TranslateCContext; |
| 26 | pub const RunTranslatedCContext = @import("src/run_translated_c.zig").RunTranslatedCContext; | 28 | pub const RunTranslatedCContext = @import("src/run_translated_c.zig").RunTranslatedCContext; |
| 27 | pub const CompareOutputContext = @import("src/compare_output.zig").CompareOutputContext; | 29 | pub const CompareOutputContext = @import("src/compare_output.zig").CompareOutputContext; |
| 28 | 30 | ||
| 31 | fn argvCmd(allocator: Allocator, argv: []const []const u8) ![]u8 { | ||
| 32 | var cmd = std.ArrayList(u8).init(allocator); | ||
| 33 | defer cmd.deinit(); | ||
| 34 | for (argv[0 .. argv.len - 1]) |arg| { | ||
| 35 | try cmd.appendSlice(arg); | ||
| 36 | try cmd.append(' '); | ||
| 37 | } | ||
| 38 | try cmd.appendSlice(argv[argv.len - 1]); | ||
| 39 | return cmd.toOwnedSlice(); | ||
| 40 | } | ||
| 41 | |||
| 29 | const TestTarget = struct { | 42 | const TestTarget = struct { |
| 30 | target: CrossTarget = @as(CrossTarget, .{}), | 43 | target: CrossTarget = @as(CrossTarget, .{}), |
| 31 | mode: std.builtin.Mode = .Debug, | 44 | mode: std.builtin.Mode = .Debug, |
| ... | @@ -722,6 +735,13 @@ pub const StackTracesContext = struct { | ... | @@ -722,6 +735,13 @@ pub const StackTracesContext = struct { |
| 722 | 735 | ||
| 723 | std.debug.print("Test {d}/{d} {s}...", .{ self.test_index + 1, self.context.test_index, self.name }); | 736 | std.debug.print("Test {d}/{d} {s}...", .{ self.test_index + 1, self.context.test_index, self.name }); |
| 724 | 737 | ||
| 738 | if (!std.process.can_spawn) { | ||
| 739 | const cmd = try argvCmd(b.allocator, args.items); | ||
| 740 | std.debug.print("the following command cannot be executed ({s} does not support spawning a child process):\n{s}", .{ @tagName(builtin.os.tag), cmd }); | ||
| 741 | b.allocator.free(cmd); | ||
| 742 | return ExecError.ExecNotSupported; | ||
| 743 | } | ||
| 744 | |||
| 725 | const child = std.ChildProcess.init(args.items, b.allocator) catch unreachable; | 745 | const child = std.ChildProcess.init(args.items, b.allocator) catch unreachable; |
| 726 | defer child.deinit(); | 746 | defer child.deinit(); |
| 727 | 747 |