| author | |
| committer | |
| log | 21135387fb7c2dbaf70a72f2c97341e9c1307045 |
| tree | 5926ea2d182a76f80429776a5473202738c9b656 |
| parent | 069dd01ce4ced3cb9664e4f1e09be753cb3ed476 |
| parent | 33fa29601921d88097a1ee3c0d92b93047a5186d |
| signature |
Avoid depending on child process execution when not supported by host OS15 files changed, 453 insertions(+), 294 deletions(-)
build.zig+7| ... | ... | @@ -229,6 +229,10 @@ pub fn build(b: *Builder) !void { |
| 229 | 229 | const version = if (opt_version_string) |version| version else v: { |
| 230 | 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 | 236 | var code: u8 = undefined; |
| 233 | 237 | const git_describe_untrimmed = b.execAllowFail(&[_][]const u8{ |
| 234 | 238 | "git", "-C", b.build_root, "describe", "--match", "*.*.*", "--tags", |
| ... | ... | @@ -542,6 +546,9 @@ fn addCxxKnownPath( |
| 542 | 546 | errtxt: ?[]const u8, |
| 543 | 547 | need_cpp_includes: bool, |
| 544 | 548 | ) !void { |
| 549 | if (!std.process.can_spawn) | |
| 550 | return error.RequiredLibraryNotFound; | |
| 551 | ||
| 545 | 552 | const path_padded = try b.exec(&[_][]const u8{ |
| 546 | 553 | ctx.cxx_compiler, |
| 547 | 554 | b.fmt("-print-file-name={s}", .{objname}), |
lib/std/build.zig+34-4| ... | ... | @@ -88,7 +88,14 @@ pub const Builder = struct { |
| 88 | 88 | /// Information about the native target. Computed before build() is invoked. |
| 89 | 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 | 99 | PkgConfigCrashed, |
| 93 | 100 | PkgConfigFailed, |
| 94 | 101 | PkgConfigNotInstalled, |
| ... | ... | @@ -959,6 +966,9 @@ pub const Builder = struct { |
| 959 | 966 | printCmd(cwd, argv); |
| 960 | 967 | } |
| 961 | 968 | |
| 969 | if (!std.process.can_spawn) | |
| 970 | return error.ExecNotSupported; | |
| 971 | ||
| 962 | 972 | const child = std.ChildProcess.init(argv, self.allocator) catch unreachable; |
| 963 | 973 | defer child.deinit(); |
| 964 | 974 | |
| ... | ... | @@ -1168,9 +1178,12 @@ pub const Builder = struct { |
| 1168 | 1178 | argv: []const []const u8, |
| 1169 | 1179 | out_code: *u8, |
| 1170 | 1180 | stderr_behavior: std.ChildProcess.StdIo, |
| 1171 | ) ![]u8 { | |
| 1181 | ) ExecError![]u8 { | |
| 1172 | 1182 | assert(argv.len != 0); |
| 1173 | 1183 | |
| 1184 | if (!std.process.can_spawn) | |
| 1185 | return error.ExecNotSupported; | |
| 1186 | ||
| 1174 | 1187 | const max_output_size = 400 * 1024; |
| 1175 | 1188 | const child = try std.ChildProcess.init(argv, self.allocator); |
| 1176 | 1189 | defer child.deinit(); |
| ... | ... | @@ -1182,7 +1195,9 @@ pub const Builder = struct { |
| 1182 | 1195 | |
| 1183 | 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 | 1201 | errdefer self.allocator.free(stdout); |
| 1187 | 1202 | |
| 1188 | 1203 | const term = try child.wait(); |
| ... | ... | @@ -1208,8 +1223,21 @@ pub const Builder = struct { |
| 1208 | 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 | 1233 | var code: u8 = undefined; |
| 1212 | 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 | 1241 | error.FileNotFound => { |
| 1214 | 1242 | if (src_step) |s| warn("{s}...", .{s.name}); |
| 1215 | 1243 | warn("Unable to spawn the following command: file not found\n", .{}); |
| ... | ... | @@ -1260,7 +1288,7 @@ pub const Builder = struct { |
| 1260 | 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 | 1292 | const stdout = try self.execAllowFail(&[_][]const u8{ "pkg-config", "--list-all" }, out_code, .Ignore); |
| 1265 | 1293 | var list = ArrayList(PkgConfigPkg).init(self.allocator); |
| 1266 | 1294 | errdefer list.deinit(); |
| ... | ... | @@ -1287,6 +1315,7 @@ pub const Builder = struct { |
| 1287 | 1315 | } else |err| { |
| 1288 | 1316 | const result = switch (err) { |
| 1289 | 1317 | error.ProcessTerminated => error.PkgConfigCrashed, |
| 1318 | error.ExecNotSupported => error.PkgConfigFailed, | |
| 1290 | 1319 | error.ExitCodeFailure => error.PkgConfigFailed, |
| 1291 | 1320 | error.FileNotFound => error.PkgConfigNotInstalled, |
| 1292 | 1321 | error.InvalidName => error.PkgConfigNotInstalled, |
| ... | ... | @@ -1929,6 +1958,7 @@ pub const LibExeObjStep = struct { |
| 1929 | 1958 | "--libs", |
| 1930 | 1959 | }, &code, .Ignore)) |stdout| stdout else |err| switch (err) { |
| 1931 | 1960 | error.ProcessTerminated => return error.PkgConfigCrashed, |
| 1961 | error.ExecNotSupported => return error.PkgConfigFailed, | |
| 1932 | 1962 | error.ExitCodeFailure => return error.PkgConfigFailed, |
| 1933 | 1963 | error.FileNotFound => return error.PkgConfigNotInstalled, |
| 1934 | 1964 | else => return err, |
lib/std/build/RunStep.zig+9| ... | ... | @@ -10,6 +10,8 @@ const mem = std.mem; |
| 10 | 10 | const process = std.process; |
| 11 | 11 | const ArrayList = std.ArrayList; |
| 12 | 12 | const BufMap = std.BufMap; |
| 13 | const Allocator = mem.Allocator; | |
| 14 | const ExecError = build.Builder.ExecError; | |
| 13 | 15 | |
| 14 | 16 | const max_stdout_size = 1 * 1024 * 1024; // 1 MiB |
| 15 | 17 | |
| ... | ... | @@ -175,6 +177,13 @@ fn make(step: *Step) !void { |
| 175 | 177 | |
| 176 | 178 | const argv = argv_list.items; |
| 177 | 179 | |
| 180 | if (!std.process.can_spawn) { | |
| 181 | const cmd = try std.mem.join(self.builder.allocator, " ", argv); | |
| 182 | std.debug.print("the following command cannot be executed ({s} does not support spawning a child process):\n{s}", .{ @tagName(builtin.os.tag), cmd }); | |
| 183 | self.builder.allocator.free(cmd); | |
| 184 | return ExecError.ExecNotSupported; | |
| 185 | } | |
| 186 | ||
| 178 | 187 | const child = std.ChildProcess.init(argv, self.builder.allocator) catch unreachable; |
| 179 | 188 | defer child.deinit(); |
| 180 | 189 |
lib/std/child_process.zig+4| ... | ... | @@ -124,6 +124,10 @@ pub const ChildProcess = struct { |
| 124 | 124 | |
| 125 | 125 | /// On success must call `kill` or `wait`. |
| 126 | 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 | 131 | if (builtin.os.tag == .windows) { |
| 128 | 132 | return self.spawnWindows(); |
| 129 | 133 | } else { |
lib/std/process.zig+7-1| ... | ... | @@ -950,7 +950,13 @@ pub fn getSelfExeSharedLibPaths(allocator: Allocator) error{OutOfMemory}![][:0]u |
| 950 | 950 | |
| 951 | 951 | /// Tells whether calling the `execv` or `execve` functions will be a compile error. |
| 952 | 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 | 960 | else => true, |
| 955 | 961 | }; |
| 956 | 962 |
src/Compilation.zig+59-42| ... | ... | @@ -25,6 +25,7 @@ const libunwind = @import("libunwind.zig"); |
| 25 | 25 | const libcxx = @import("libcxx.zig"); |
| 26 | 26 | const wasi_libc = @import("wasi_libc.zig"); |
| 27 | 27 | const fatal = @import("main.zig").fatal; |
| 28 | const clangMain = @import("main.zig").clangMain; | |
| 28 | 29 | const Module = @import("Module.zig"); |
| 29 | 30 | const Cache = @import("Cache.zig"); |
| 30 | 31 | const stage1 = @import("stage1.zig"); |
| ... | ... | @@ -3667,55 +3668,71 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P |
| 3667 | 3668 | dump_argv(argv.items); |
| 3668 | 3669 | } |
| 3669 | 3670 | |
| 3670 | const child = try std.ChildProcess.init(argv.items, arena); | |
| 3671 | defer child.deinit(); | |
| 3671 | if (std.process.can_spawn) { | |
| 3672 | const child = try std.ChildProcess.init(argv.items, arena); | |
| 3673 | defer child.deinit(); | |
| 3672 | 3674 | |
| 3673 | if (comp.clang_passthrough_mode) { | |
| 3674 | child.stdin_behavior = .Inherit; | |
| 3675 | child.stdout_behavior = .Inherit; | |
| 3676 | child.stderr_behavior = .Inherit; | |
| 3675 | if (comp.clang_passthrough_mode) { | |
| 3676 | child.stdin_behavior = .Inherit; | |
| 3677 | child.stdout_behavior = .Inherit; | |
| 3678 | child.stderr_behavior = .Inherit; | |
| 3677 | 3679 | |
| 3678 | const term = child.spawnAndWait() catch |err| { | |
| 3679 | return comp.failCObj(c_object, "unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); | |
| 3680 | }; | |
| 3681 | switch (term) { | |
| 3682 | .Exited => |code| { | |
| 3683 | if (code != 0) { | |
| 3684 | std.process.exit(code); | |
| 3685 | } | |
| 3686 | if (comp.clang_preprocessor_mode == .stdout) | |
| 3687 | std.process.exit(0); | |
| 3688 | }, | |
| 3689 | else => std.process.abort(), | |
| 3690 | } | |
| 3691 | } else { | |
| 3692 | child.stdin_behavior = .Ignore; | |
| 3693 | child.stdout_behavior = .Ignore; | |
| 3694 | child.stderr_behavior = .Pipe; | |
| 3680 | const term = child.spawnAndWait() catch |err| { | |
| 3681 | return comp.failCObj(c_object, "unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); | |
| 3682 | }; | |
| 3683 | switch (term) { | |
| 3684 | .Exited => |code| { | |
| 3685 | if (code != 0) { | |
| 3686 | std.process.exit(code); | |
| 3687 | } | |
| 3688 | if (comp.clang_preprocessor_mode == .stdout) | |
| 3689 | std.process.exit(0); | |
| 3690 | }, | |
| 3691 | else => std.process.abort(), | |
| 3692 | } | |
| 3693 | } else { | |
| 3694 | child.stdin_behavior = .Ignore; | |
| 3695 | child.stdout_behavior = .Ignore; | |
| 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| { | |
| 3703 | return comp.failCObj(c_object, "unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); | |
| 3704 | }; | |
| 3704 | const term = child.wait() catch |err| { | |
| 3705 | return comp.failCObj(c_object, "unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); | |
| 3706 | }; | |
| 3705 | 3707 | |
| 3706 | switch (term) { | |
| 3707 | .Exited => |code| { | |
| 3708 | if (code != 0) { | |
| 3709 | // TODO parse clang stderr and turn it into an error message | |
| 3710 | // and then call failCObjWithOwnedErrorMsg | |
| 3711 | log.err("clang failed with stderr: {s}", .{stderr}); | |
| 3712 | return comp.failCObj(c_object, "clang exited with code {d}", .{code}); | |
| 3713 | } | |
| 3714 | }, | |
| 3715 | else => { | |
| 3716 | log.err("clang terminated with stderr: {s}", .{stderr}); | |
| 3717 | return comp.failCObj(c_object, "clang terminated unexpectedly", .{}); | |
| 3718 | }, | |
| 3708 | switch (term) { | |
| 3709 | .Exited => |code| { | |
| 3710 | if (code != 0) { | |
| 3711 | // TODO parse clang stderr and turn it into an error message | |
| 3712 | // and then call failCObjWithOwnedErrorMsg | |
| 3713 | log.err("clang failed with stderr: {s}", .{stderr}); | |
| 3714 | return comp.failCObj(c_object, "clang exited with code {d}", .{code}); | |
| 3715 | } | |
| 3716 | }, | |
| 3717 | else => { | |
| 3718 | log.err("clang terminated with stderr: {s}", .{stderr}); | |
| 3719 | return comp.failCObj(c_object, "clang terminated unexpectedly", .{}); | |
| 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 | 82 | } |
| 83 | 83 | |
| 84 | 84 | fn destroyWorkers(self: *ThreadPool, spawned: usize) void { |
| 85 | if (builtin.single_threaded) | |
| 86 | return; | |
| 87 | ||
| 85 | 88 | for (self.workers[0..spawned]) |*worker| { |
| 86 | 89 | worker.thread.join(); |
| 87 | 90 | worker.idle_node.data.deinit(); |
src/libc_installation.zig+3-1| ... | ... | @@ -216,7 +216,7 @@ pub const LibCInstallation = struct { |
| 216 | 216 | self.crt_dir = try args.allocator.dupeZ(u8, "/system/develop/lib"); |
| 217 | 217 | break :blk batch.wait(); |
| 218 | 218 | }; |
| 219 | } else { | |
| 219 | } else if (std.process.can_spawn) { | |
| 220 | 220 | try blk: { |
| 221 | 221 | var batch = Batch(FindError!void, 2, .auto_async).init(); |
| 222 | 222 | errdefer batch.wait() catch {}; |
| ... | ... | @@ -229,6 +229,8 @@ pub const LibCInstallation = struct { |
| 229 | 229 | } |
| 230 | 230 | break :blk batch.wait(); |
| 231 | 231 | }; |
| 232 | } else { | |
| 233 | return error.LibCRuntimeNotFound; | |
| 232 | 234 | } |
| 233 | 235 | return self; |
| 234 | 236 | } |
src/link/Coff.zig+64-52| ... | ... | @@ -9,6 +9,7 @@ const fs = std.fs; |
| 9 | 9 | const allocPrint = std.fmt.allocPrint; |
| 10 | 10 | const mem = std.mem; |
| 11 | 11 | |
| 12 | const lldMain = @import("../main.zig").lldMain; | |
| 12 | 13 | const trace = @import("../tracy.zig").trace; |
| 13 | 14 | const Module = @import("../Module.zig"); |
| 14 | 15 | const Compilation = @import("../Compilation.zig"); |
| ... | ... | @@ -1358,60 +1359,71 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void { |
| 1358 | 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 | // properly as a library. | |
| 1363 | const child = try std.ChildProcess.init(argv.items, arena); | |
| 1364 | defer child.deinit(); | |
| 1365 | ||
| 1366 | if (comp.clang_passthrough_mode) { | |
| 1367 | child.stdin_behavior = .Inherit; | |
| 1368 | child.stdout_behavior = .Inherit; | |
| 1369 | child.stderr_behavior = .Inherit; | |
| 1370 | ||
| 1371 | const term = child.spawnAndWait() catch |err| { | |
| 1372 | log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); | |
| 1373 | return error.UnableToSpawnSelf; | |
| 1374 | }; | |
| 1375 | switch (term) { | |
| 1376 | .Exited => |code| { | |
| 1377 | if (code != 0) { | |
| 1378 | // TODO https://github.com/ziglang/zig/issues/6342 | |
| 1379 | std.process.exit(1); | |
| 1380 | } | |
| 1381 | }, | |
| 1382 | else => std.process.abort(), | |
| 1362 | if (std.process.can_spawn) { | |
| 1363 | // If possible, we run LLD as a child process because it does not always | |
| 1364 | // behave properly as a library, unfortunately. | |
| 1365 | // https://github.com/ziglang/zig/issues/3825 | |
| 1366 | const child = try std.ChildProcess.init(argv.items, arena); | |
| 1367 | defer child.deinit(); | |
| 1368 | ||
| 1369 | if (comp.clang_passthrough_mode) { | |
| 1370 | child.stdin_behavior = .Inherit; | |
| 1371 | child.stdout_behavior = .Inherit; | |
| 1372 | child.stderr_behavior = .Inherit; | |
| 1373 | ||
| 1374 | const term = child.spawnAndWait() catch |err| { | |
| 1375 | log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); | |
| 1376 | return error.UnableToSpawnSelf; | |
| 1377 | }; | |
| 1378 | switch (term) { | |
| 1379 | .Exited => |code| { | |
| 1380 | if (code != 0) { | |
| 1381 | std.process.exit(code); | |
| 1382 | } | |
| 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 | 1419 | } else { |
| 1385 | child.stdin_behavior = .Ignore; | |
| 1386 | child.stdout_behavior = .Ignore; | |
| 1387 | child.stderr_behavior = .Pipe; | |
| 1388 | ||
| 1389 | try child.spawn(); | |
| 1390 | ||
| 1391 | const stderr = try child.stderr.?.reader().readAllAlloc(arena, 10 * 1024 * 1024); | |
| 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}); | |
| 1420 | const exit_code = try lldMain(arena, argv.items, false); | |
| 1421 | if (exit_code != 0) { | |
| 1422 | if (comp.clang_passthrough_mode) { | |
| 1423 | std.process.exit(exit_code); | |
| 1424 | } else { | |
| 1425 | return error.LLDReportedFailure; | |
| 1426 | } | |
| 1415 | 1427 | } |
| 1416 | 1428 | } |
| 1417 | 1429 | } |
src/link/Elf.zig+59-47| ... | ... | @@ -14,6 +14,7 @@ const leb128 = std.leb; |
| 14 | 14 | const Module = @import("../Module.zig"); |
| 15 | 15 | const Compilation = @import("../Compilation.zig"); |
| 16 | 16 | const codegen = @import("../codegen.zig"); |
| 17 | const lldMain = @import("../main.zig").lldMain; | |
| 17 | 18 | const trace = @import("../tracy.zig").trace; |
| 18 | 19 | const Package = @import("../Package.zig"); |
| 19 | 20 | const Value = @import("../value.zig").Value; |
| ... | ... | @@ -1950,60 +1951,71 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { |
| 1950 | 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 | // properly as a library. | |
| 1955 | const child = try std.ChildProcess.init(argv.items, arena); | |
| 1956 | defer child.deinit(); | |
| 1954 | if (std.process.can_spawn) { | |
| 1955 | // If possible, we run LLD as a child process because it does not always | |
| 1956 | // behave properly as a library, unfortunately. | |
| 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) { | |
| 1959 | child.stdin_behavior = .Inherit; | |
| 1960 | child.stdout_behavior = .Inherit; | |
| 1961 | child.stderr_behavior = .Inherit; | |
| 1961 | if (comp.clang_passthrough_mode) { | |
| 1962 | child.stdin_behavior = .Inherit; | |
| 1963 | child.stdout_behavior = .Inherit; | |
| 1964 | child.stderr_behavior = .Inherit; | |
| 1962 | 1965 | |
| 1963 | const term = child.spawnAndWait() catch |err| { | |
| 1964 | log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); | |
| 1965 | return error.UnableToSpawnSelf; | |
| 1966 | }; | |
| 1967 | switch (term) { | |
| 1968 | .Exited => |code| { | |
| 1969 | if (code != 0) { | |
| 1970 | // TODO https://github.com/ziglang/zig/issues/6342 | |
| 1971 | std.process.exit(1); | |
| 1972 | } | |
| 1973 | }, | |
| 1974 | else => std.process.abort(), | |
| 1975 | } | |
| 1976 | } else { | |
| 1977 | child.stdin_behavior = .Ignore; | |
| 1978 | child.stdout_behavior = .Ignore; | |
| 1979 | child.stderr_behavior = .Pipe; | |
| 1966 | const term = child.spawnAndWait() catch |err| { | |
| 1967 | log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); | |
| 1968 | return error.UnableToSpawnSelf; | |
| 1969 | }; | |
| 1970 | switch (term) { | |
| 1971 | .Exited => |code| { | |
| 1972 | if (code != 0) { | |
| 1973 | std.process.exit(code); | |
| 1974 | } | |
| 1975 | }, | |
| 1976 | else => std.process.abort(), | |
| 1977 | } | |
| 1978 | } else { | |
| 1979 | child.stdin_behavior = .Ignore; | |
| 1980 | child.stdout_behavior = .Ignore; | |
| 1981 | 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| { | |
| 1986 | log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); | |
| 1987 | return error.UnableToSpawnSelf; | |
| 1988 | }; | |
| 1987 | const term = child.wait() catch |err| { | |
| 1988 | log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); | |
| 1989 | return error.UnableToSpawnSelf; | |
| 1990 | }; | |
| 1989 | 1991 | |
| 1990 | switch (term) { | |
| 1991 | .Exited => |code| { | |
| 1992 | if (code != 0) { | |
| 1993 | // TODO parse this output and surface with the Compilation API rather than | |
| 1994 | // directly outputting to stderr here. | |
| 1995 | std.debug.print("{s}", .{stderr}); | |
| 1996 | return error.LLDReportedFailure; | |
| 1997 | } | |
| 1998 | }, | |
| 1999 | else => { | |
| 2000 | log.err("{s} terminated with stderr:\n{s}", .{ argv.items[0], stderr }); | |
| 2001 | return error.LLDCrashed; | |
| 2002 | }, | |
| 2003 | } | |
| 1992 | switch (term) { | |
| 1993 | .Exited => |code| { | |
| 1994 | if (code != 0) { | |
| 1995 | // TODO parse this output and surface with the Compilation API rather than | |
| 1996 | // directly outputting to stderr here. | |
| 1997 | std.debug.print("{s}", .{stderr}); | |
| 1998 | return error.LLDReportedFailure; | |
| 1999 | } | |
| 2000 | }, | |
| 2001 | else => { | |
| 2002 | log.err("{s} terminated with stderr:\n{s}", .{ argv.items[0], stderr }); | |
| 2003 | return error.LLDCrashed; | |
| 2004 | }, | |
| 2005 | } | |
| 2004 | 2006 | |
| 2005 | if (stderr.len != 0) { | |
| 2006 | log.warn("unexpected LLD stderr:\n{s}", .{stderr}); | |
| 2007 | if (stderr.len != 0) { | |
| 2008 | log.warn("unexpected LLD stderr:\n{s}", .{stderr}); | |
| 2009 | } | |
| 2010 | } | |
| 2011 | } else { | |
| 2012 | const exit_code = try lldMain(arena, argv.items, false); | |
| 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 | 15 | const Compilation = @import("../Compilation.zig"); |
| 16 | 16 | const CodeGen = @import("../arch/wasm/CodeGen.zig"); |
| 17 | 17 | const link = @import("../link.zig"); |
| 18 | const lldMain = @import("../main.zig").lldMain; | |
| 18 | 19 | const trace = @import("../tracy.zig").trace; |
| 19 | 20 | const build_options = @import("build_options"); |
| 20 | 21 | const wasi_libc = @import("../wasi_libc.zig"); |
| ... | ... | @@ -1486,60 +1487,71 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { |
| 1486 | 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 | // properly as a library. | |
| 1491 | const child = try std.ChildProcess.init(argv.items, arena); | |
| 1492 | defer child.deinit(); | |
| 1493 | ||
| 1494 | if (comp.clang_passthrough_mode) { | |
| 1495 | child.stdin_behavior = .Inherit; | |
| 1496 | child.stdout_behavior = .Inherit; | |
| 1497 | child.stderr_behavior = .Inherit; | |
| 1490 | if (std.process.can_spawn) { | |
| 1491 | // If possible, we run LLD as a child process because it does not always | |
| 1492 | // behave properly as a library, unfortunately. | |
| 1493 | // https://github.com/ziglang/zig/issues/3825 | |
| 1494 | const child = try std.ChildProcess.init(argv.items, arena); | |
| 1495 | defer child.deinit(); | |
| 1496 | ||
| 1497 | if (comp.clang_passthrough_mode) { | |
| 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| { | |
| 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; | |
| 1519 | try child.spawn(); | |
| 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| { | |
| 1522 | log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); | |
| 1523 | return error.UnableToSpawnSelf; | |
| 1524 | }; | |
| 1528 | switch (term) { | |
| 1529 | .Exited => |code| { | |
| 1530 | if (code != 0) { | |
| 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) { | |
| 1527 | .Exited => |code| { | |
| 1528 | if (code != 0) { | |
| 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 | }, | |
| 1543 | if (stderr.len != 0) { | |
| 1544 | log.warn("unexpected LLD stderr:\n{s}", .{stderr}); | |
| 1545 | } | |
| 1539 | 1546 | } |
| 1540 | ||
| 1541 | if (stderr.len != 0) { | |
| 1542 | log.warn("unexpected LLD stderr:\n{s}", .{stderr}); | |
| 1547 | } else { | |
| 1548 | const exit_code = try lldMain(arena, argv.items, false); | |
| 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+93-73| ... | ... | @@ -221,7 +221,7 @@ pub fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi |
| 221 | 221 | mem.eql(u8, cmd, "lib") or |
| 222 | 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 | 225 | } else if (mem.eql(u8, cmd, "cc")) { |
| 226 | 226 | return buildOutputType(gpa, arena, args, .cc); |
| 227 | 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 | 231 | } else if (mem.eql(u8, cmd, "clang") or |
| 232 | 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 | 235 | } else if (mem.eql(u8, cmd, "ld.lld") or |
| 236 | 236 | mem.eql(u8, cmd, "lld-link") or |
| 237 | 237 | mem.eql(u8, cmd, "wasm-ld")) |
| 238 | 238 | { |
| 239 | return punt_to_lld(arena, args); | |
| 239 | return process.exit(try lldMain(arena, args, true)); | |
| 240 | 240 | } else if (mem.eql(u8, cmd, "build")) { |
| 241 | 241 | return cmdBuild(gpa, arena, cmd_args); |
| 242 | 242 | } else if (mem.eql(u8, cmd, "fmt")) { |
| ... | ... | @@ -1347,7 +1347,7 @@ fn buildOutputType( |
| 1347 | 1347 | .ignore => {}, |
| 1348 | 1348 | .driver_punt => { |
| 1349 | 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 | 1352 | .pic => want_pic = true, |
| 1353 | 1353 | .no_pic => want_pic = false, |
| ... | ... | @@ -1866,7 +1866,7 @@ fn buildOutputType( |
| 1866 | 1866 | // An error message is generated when there is more than 1 C source file. |
| 1867 | 1867 | if (c_source_files.items.len != 1) { |
| 1868 | 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 | 1871 | if (out_path) |p| { |
| 1872 | 1872 | emit_bin = .{ .yes = p }; |
| ... | ... | @@ -1882,7 +1882,7 @@ fn buildOutputType( |
| 1882 | 1882 | { |
| 1883 | 1883 | // For example `zig cc` and no args should print the "no input files" message. |
| 1884 | 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 | } |
| ... | ... | @@ -2881,9 +2881,9 @@ fn runOrTest( |
| 2881 | 2881 | // execv releases the locks; no need to destroy the Compilation here. |
| 2882 | 2882 | const err = std.process.execv(gpa, argv.items); |
| 2883 | 2883 | try warnAboutForeignBinaries(gpa, arena, arg_mode, target_info, link_libc); |
| 2884 | const cmd = try argvCmd(arena, argv.items); | |
| 2884 | const cmd = try std.mem.join(arena, " ", argv.items); | |
| 2885 | 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 | 2887 | const child = try std.ChildProcess.init(argv.items, gpa); |
| 2888 | 2888 | defer child.deinit(); |
| 2889 | 2889 | |
| ... | ... | @@ -2900,7 +2900,7 @@ fn runOrTest( |
| 2900 | 2900 | |
| 2901 | 2901 | const term = child.spawnAndWait() catch |err| { |
| 2902 | 2902 | try warnAboutForeignBinaries(gpa, arena, arg_mode, target_info, link_libc); |
| 2903 | const cmd = try argvCmd(arena, argv.items); | |
| 2903 | const cmd = try std.mem.join(arena, " ", argv.items); | |
| 2904 | 2904 | fatal("the following command failed with '{s}':\n{s}", .{ @errorName(err), cmd }); |
| 2905 | 2905 | }; |
| 2906 | 2906 | switch (arg_mode) { |
| ... | ... | @@ -2931,18 +2931,21 @@ fn runOrTest( |
| 2931 | 2931 | if (code == 0) { |
| 2932 | 2932 | if (!watch) return cleanExit(); |
| 2933 | 2933 | } else { |
| 2934 | const cmd = try argvCmd(arena, argv.items); | |
| 2934 | const cmd = try std.mem.join(arena, " ", argv.items); | |
| 2935 | 2935 | fatal("the following test command failed with exit code {d}:\n{s}", .{ code, cmd }); |
| 2936 | 2936 | } |
| 2937 | 2937 | }, |
| 2938 | 2938 | else => { |
| 2939 | const cmd = try argvCmd(arena, argv.items); | |
| 2939 | const cmd = try std.mem.join(arena, " ", argv.items); | |
| 2940 | 2940 | fatal("the following test command crashed:\n{s}", .{cmd}); |
| 2941 | 2941 | }, |
| 2942 | 2942 | } |
| 2943 | 2943 | }, |
| 2944 | 2944 | else => unreachable, |
| 2945 | 2945 | } |
| 2946 | } else { | |
| 2947 | const cmd = try std.mem.join(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,41 +3556,36 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi |
| 3553 | 3556 | |
| 3554 | 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 | child.stdout_behavior = .Inherit; | |
| 3561 | child.stderr_behavior = .Inherit; | |
| 3560 | if (std.process.can_spawn) { | |
| 3561 | const child = try std.ChildProcess.init(child_argv, gpa); | |
| 3562 | defer child.deinit(); | |
| 3562 | 3563 | |
| 3563 | const term = try child.spawnAndWait(); | |
| 3564 | switch (term) { | |
| 3565 | .Exited => |code| { | |
| 3566 | if (code == 0) return cleanExit(); | |
| 3564 | child.stdin_behavior = .Inherit; | |
| 3565 | child.stdout_behavior = .Inherit; | |
| 3566 | child.stderr_behavior = .Inherit; | |
| 3567 | 3567 | |
| 3568 | if (prominent_compile_errors) { | |
| 3569 | fatal("the build command failed with exit code {d}", .{code}); | |
| 3570 | } else { | |
| 3571 | const cmd = try argvCmd(arena, child_argv); | |
| 3572 | fatal("the following build command failed with exit code {d}:\n{s}", .{ code, cmd }); | |
| 3573 | } | |
| 3574 | }, | |
| 3575 | else => { | |
| 3576 | const cmd = try argvCmd(arena, child_argv); | |
| 3577 | fatal("the following build command crashed:\n{s}", .{cmd}); | |
| 3578 | }, | |
| 3579 | } | |
| 3580 | } | |
| 3568 | const term = try child.spawnAndWait(); | |
| 3569 | switch (term) { | |
| 3570 | .Exited => |code| { | |
| 3571 | if (code == 0) return cleanExit(); | |
| 3581 | 3572 | |
| 3582 | fn argvCmd(allocator: Allocator, argv: []const []const u8) ![]u8 { | |
| 3583 | var cmd = std.ArrayList(u8).init(allocator); | |
| 3584 | defer cmd.deinit(); | |
| 3585 | for (argv[0 .. argv.len - 1]) |arg| { | |
| 3586 | try cmd.appendSlice(arg); | |
| 3587 | try cmd.append(' '); | |
| 3573 | if (prominent_compile_errors) { | |
| 3574 | fatal("the build command failed with exit code {d}", .{code}); | |
| 3575 | } else { | |
| 3576 | const cmd = try std.mem.join(arena, " ", child_argv); | |
| 3577 | fatal("the following build command failed with exit code {d}:\n{s}", .{ code, cmd }); | |
| 3578 | } | |
| 3579 | }, | |
| 3580 | else => { | |
| 3581 | const cmd = try std.mem.join(arena, " ", child_argv); | |
| 3582 | fatal("the following build command crashed:\n{s}", .{cmd}); | |
| 3583 | }, | |
| 3584 | } | |
| 3585 | } else { | |
| 3586 | const cmd = try std.mem.join(arena, " ", child_argv); | |
| 3587 | fatal("the following command cannot be executed ({s} does not support spawning a child process):\n{s}", .{ @tagName(builtin.os.tag), cmd }); | |
| 3588 | 3588 | } |
| 3589 | try cmd.appendSlice(argv[argv.len - 1]); | |
| 3590 | return cmd.toOwnedSlice(); | |
| 3591 | 3589 | } |
| 3592 | 3590 | |
| 3593 | 3591 | fn readSourceFileToEndAlloc( |
| ... | ... | @@ -4080,65 +4078,87 @@ pub const info_zen = |
| 4080 | 4078 | extern "c" fn ZigClang_main(argc: c_int, argv: [*:null]?[*:0]u8) c_int; |
| 4081 | 4079 | extern "c" fn ZigLlvmAr_main(argc: c_int, argv: [*:null]?[*:0]u8) c_int; |
| 4082 | 4080 | |
| 4083 | /// TODO https://github.com/ziglang/zig/issues/3257 | |
| 4084 | fn punt_to_clang(arena: Allocator, args: []const []const u8) error{OutOfMemory} { | |
| 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); | |
| 4081 | fn argsCopyZ(alloc: Allocator, args: []const []const u8) ![:null]?[*:0]u8 { | |
| 4082 | var argv = try alloc.allocSentinel(?[*:0]u8, args.len, null); | |
| 4089 | 4083 | for (args) |arg, i| { |
| 4090 | argv[i] = try arena.dupeZ(u8, arg); // TODO If there was an argsAllocZ we could avoid this allocation. | |
| 4084 | argv[i] = try alloc.dupeZ(u8, arg); // TODO If there was an argsAllocZ we could avoid this allocation. | |
| 4091 | 4085 | } |
| 4092 | argv[args.len] = null; | |
| 4093 | const exit_code = ZigClang_main(@intCast(c_int, args.len), argv[0..args.len :null].ptr); | |
| 4094 | process.exit(@bitCast(u8, @truncate(i8, exit_code))); | |
| 4086 | return argv; | |
| 4095 | 4087 | } |
| 4096 | 4088 | |
| 4097 | /// TODO https://github.com/ziglang/zig/issues/3257 | |
| 4098 | fn punt_to_llvm_ar(arena: Allocator, args: []const []const u8) error{OutOfMemory} { | |
| 4089 | pub fn clangMain(alloc: Allocator, args: []const []const u8) error{OutOfMemory}!u8 { | |
| 4090 | if (!build_options.have_llvm) | |
| 4091 | fatal("`zig cc` and `zig c++` unavailable: compiler built without LLVM extensions", .{}); | |
| 4092 | ||
| 4093 | var arena_instance = std.heap.ArenaAllocator.init(alloc); | |
| 4094 | defer arena_instance.deinit(); | |
| 4095 | const arena = arena_instance.allocator(); | |
| 4096 | ||
| 4097 | // Convert the args to the null-terminated format Clang expects. | |
| 4098 | const argv = try argsCopyZ(arena, args); | |
| 4099 | const exit_code = ZigClang_main(@intCast(c_int, argv.len), argv.ptr); | |
| 4100 | return @bitCast(u8, @truncate(i8, exit_code)); | |
| 4101 | } | |
| 4102 | ||
| 4103 | pub fn llvmArMain(alloc: Allocator, args: []const []const u8) error{OutOfMemory}!u8 { | |
| 4099 | 4104 | if (!build_options.have_llvm) |
| 4100 | 4105 | fatal("`zig ar`, `zig dlltool`, `zig ranlib', and `zig lib` unavailable: compiler built without LLVM extensions", .{}); |
| 4101 | 4106 | |
| 4107 | var arena_instance = std.heap.ArenaAllocator.init(alloc); | |
| 4108 | defer arena_instance.deinit(); | |
| 4109 | const arena = arena_instance.allocator(); | |
| 4110 | ||
| 4102 | 4111 | // Convert the args to the format llvm-ar expects. |
| 4103 | // We subtract 1 to shave off the zig binary from args[0]. | |
| 4104 | const argv = try arena.allocSentinel(?[*:0]u8, args.len - 1, null); | |
| 4105 | for (args[1..]) |arg, i| { | |
| 4106 | // TODO If there was an argsAllocZ we could avoid this allocation. | |
| 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 | // We intentionally shave off the zig binary at args[0]. | |
| 4113 | const argv = try argsCopyZ(arena, args[1..]); | |
| 4114 | const exit_code = ZigLlvmAr_main(@intCast(c_int, argv.len), argv.ptr); | |
| 4115 | return @bitCast(u8, @truncate(i8, exit_code)); | |
| 4112 | 4116 | } |
| 4113 | 4117 | |
| 4114 | 4118 | /// The first argument determines which backend is invoked. The options are: |
| 4115 | 4119 | /// * `ld.lld` - ELF |
| 4116 | 4120 | /// * `lld-link` - COFF |
| 4117 | 4121 | /// * `wasm-ld` - WebAssembly |
| 4118 | /// TODO https://github.com/ziglang/zig/issues/3257 | |
| 4119 | pub fn punt_to_lld(arena: Allocator, args: []const []const u8) error{OutOfMemory} { | |
| 4122 | pub fn lldMain( | |
| 4123 | alloc: Allocator, | |
| 4124 | args: []const []const u8, | |
| 4125 | can_exit_early: bool, | |
| 4126 | ) error{OutOfMemory}!u8 { | |
| 4120 | 4127 | if (!build_options.have_llvm) |
| 4121 | 4128 | fatal("`zig {s}` unavailable: compiler built without LLVM extensions", .{args[0]}); |
| 4122 | // Convert the args to the format LLD expects. | |
| 4123 | // We subtract 1 to shave off the zig binary from args[0]. | |
| 4124 | const argv = try arena.allocSentinel(?[*:0]const u8, args.len - 1, null); | |
| 4125 | for (args[1..]) |arg, i| { | |
| 4126 | argv[i] = try arena.dupeZ(u8, arg); // TODO If there was an argsAllocZ we could avoid this allocation. | |
| 4129 | ||
| 4130 | // Print a warning if lld is called multiple times in the same process, | |
| 4131 | // since it may misbehave | |
| 4132 | // https://github.com/ziglang/zig/issues/3825 | |
| 4133 | const CallCounter = struct { | |
| 4134 | var count: usize = 0; | |
| 4135 | }; | |
| 4136 | if (CallCounter.count == 1) { // Issue the warning on the first repeat call | |
| 4137 | warn("invoking LLD for the second time within the same process because the host OS ({s}) does not support spawning child processes. This sometimes activates LLD bugs", .{@tagName(builtin.os.tag)}); | |
| 4127 | 4138 | } |
| 4139 | CallCounter.count += 1; | |
| 4140 | ||
| 4141 | var arena_instance = std.heap.ArenaAllocator.init(alloc); | |
| 4142 | defer arena_instance.deinit(); | |
| 4143 | const arena = arena_instance.allocator(); | |
| 4144 | ||
| 4145 | // Convert the args to the format llvm-ar expects. | |
| 4146 | // We intentionally shave off the zig binary at args[0]. | |
| 4147 | const argv = try argsCopyZ(arena, args[1..]); | |
| 4128 | 4148 | const exit_code = rc: { |
| 4129 | 4149 | const llvm = @import("codegen/llvm/bindings.zig"); |
| 4130 | 4150 | const argc = @intCast(c_int, argv.len); |
| 4131 | 4151 | if (mem.eql(u8, args[1], "ld.lld")) { |
| 4132 | break :rc llvm.LinkELF(argc, argv.ptr, true); | |
| 4152 | break :rc llvm.LinkELF(argc, argv.ptr, can_exit_early); | |
| 4133 | 4153 | } else if (mem.eql(u8, args[1], "lld-link")) { |
| 4134 | break :rc llvm.LinkCOFF(argc, argv.ptr, true); | |
| 4154 | break :rc llvm.LinkCOFF(argc, argv.ptr, can_exit_early); | |
| 4135 | 4155 | } else if (mem.eql(u8, args[1], "wasm-ld")) { |
| 4136 | break :rc llvm.LinkWasm(argc, argv.ptr, true); | |
| 4156 | break :rc llvm.LinkWasm(argc, argv.ptr, can_exit_early); | |
| 4137 | 4157 | } else { |
| 4138 | 4158 | unreachable; |
| 4139 | 4159 | } |
| 4140 | 4160 | }; |
| 4141 | process.exit(@bitCast(u8, @truncate(i8, exit_code))); | |
| 4161 | return @bitCast(u8, @truncate(i8, exit_code)); | |
| 4142 | 4162 | } |
| 4143 | 4163 | |
| 4144 | 4164 | const clang_args = @import("clang_options.zig").list; |
src/mingw.zig+31-26| ... | ... | @@ -5,6 +5,7 @@ const path = std.fs.path; |
| 5 | 5 | const assert = std.debug.assert; |
| 6 | 6 | const log = std.log.scoped(.mingw); |
| 7 | 7 | |
| 8 | const builtin = @import("builtin"); | |
| 8 | 9 | const target_util = @import("target.zig"); |
| 9 | 10 | const Compilation = @import("Compilation.zig"); |
| 10 | 11 | const build_options = @import("build_options"); |
| ... | ... | @@ -367,39 +368,43 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void { |
| 367 | 368 | Compilation.dump_argv(&args); |
| 368 | 369 | } |
| 369 | 370 | |
| 370 | const child = try std.ChildProcess.init(&args, arena); | |
| 371 | defer child.deinit(); | |
| 371 | if (std.process.can_spawn) { | |
| 372 | const child = try std.ChildProcess.init(&args, arena); | |
| 373 | defer child.deinit(); | |
| 372 | 374 | |
| 373 | child.stdin_behavior = .Ignore; | |
| 374 | child.stdout_behavior = .Pipe; | |
| 375 | child.stderr_behavior = .Pipe; | |
| 375 | child.stdin_behavior = .Ignore; | |
| 376 | child.stdout_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 | |
| 382 | const stderr = try stderr_reader.readAllAlloc(arena, 10 * 1024 * 1024); | |
| 383 | // TODO https://github.com/ziglang/zig/issues/6343 | |
| 384 | const stderr = try stderr_reader.readAllAlloc(arena, 10 * 1024 * 1024); | |
| 383 | 385 | |
| 384 | 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 => { | |
| 386 | const term = child.wait() catch |err| { | |
| 399 | 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 | 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 | 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 | 730 | // * cannot handle updates |
| 731 | 731 | // because of this we must spawn a child process rather than |
| 732 | 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 | 739 | assert(case.updates.items.len == 1); |
| 734 | 740 | const update = case.updates.items[0]; |
| 735 | 741 | try tmp.dir.writeFile(tmp_src_path, update.src); |
| ... | ... | @@ -1104,6 +1110,11 @@ pub const TestContext = struct { |
| 1104 | 1110 | } |
| 1105 | 1111 | }, |
| 1106 | 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 | 1118 | update_node.setEstimatedTotalItems(4); |
| 1108 | 1119 | |
| 1109 | 1120 | var argv = std.ArrayList([]const u8).init(allocator); |
test/tests.zig+9| ... | ... | @@ -10,6 +10,8 @@ const fmt = std.fmt; |
| 10 | 10 | const ArrayList = std.ArrayList; |
| 11 | 11 | const Mode = std.builtin.Mode; |
| 12 | 12 | const LibExeObjStep = build.LibExeObjStep; |
| 13 | const Allocator = mem.Allocator; | |
| 14 | const ExecError = build.Builder.ExecError; | |
| 13 | 15 | |
| 14 | 16 | // Cases |
| 15 | 17 | const compare_output = @import("compare_output.zig"); |
| ... | ... | @@ -722,6 +724,13 @@ pub const StackTracesContext = struct { |
| 722 | 724 | |
| 723 | 725 | std.debug.print("Test {d}/{d} {s}...", .{ self.test_index + 1, self.context.test_index, self.name }); |
| 724 | 726 | |
| 727 | if (!std.process.can_spawn) { | |
| 728 | const cmd = try std.mem.join(b.allocator, " ", args.items); | |
| 729 | std.debug.print("the following command cannot be executed ({s} does not support spawning a child process):\n{s}", .{ @tagName(builtin.os.tag), cmd }); | |
| 730 | b.allocator.free(cmd); | |
| 731 | return ExecError.ExecNotSupported; | |
| 732 | } | |
| 733 | ||
| 725 | 734 | const child = std.ChildProcess.init(args.items, b.allocator) catch unreachable; |
| 726 | 735 | defer child.deinit(); |
| 727 | 736 |