From 7dd4afb224f4ca747b8eb462c28337ce9a63d38c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 8 Dec 2020 22:37:01 -0700 Subject: [PATCH] stage2: link: properly implement passthrough mode for LLD child proc passthrough mode does not mean always exit - it just means to pass through stdio and exit if the child process exits, without doing any special error reporting. --- src/Compilation.zig | 2 +- src/link/Coff.zig | 78 ++++++++++++++++++++++++++------------------- src/link/Elf.zig | 78 ++++++++++++++++++++++++++------------------- src/link/MachO.zig | 78 ++++++++++++++++++++++++++------------------- src/link/Wasm.zig | 78 ++++++++++++++++++++++++++------------------- 5 files changed, 185 insertions(+), 129 deletions(-) diff --git a/src/Compilation.zig b/src/Compilation.zig index fbccb21557..572dc1e0d7 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -1804,7 +1804,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_comp_progress_node: * if (comp.clang_preprocessor_mode == .stdout) std.process.exit(0); }, - else => std.process.exit(1), + else => std.process.abort(), } } else { child.stdin_behavior = .Ignore; diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 0d620ba12f..b5eb645e5c 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -1153,46 +1153,60 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void { } // Sadly, we must run LLD as a child process because it does not behave - // properly as a library. One exception is if we are running in passthrough - // mode, which means Clang / LLD should inherit stdio and are allowed to - // crash zig directly. - if (comp.clang_passthrough_mode) { - return @import("../main.zig").punt_to_lld(arena, argv.items); - } - + // properly as a library. const child = try std.ChildProcess.init(argv.items, arena); defer child.deinit(); - child.stdin_behavior = .Ignore; - child.stdout_behavior = .Ignore; - child.stderr_behavior = .Pipe; + if (comp.clang_passthrough_mode) { + child.stdin_behavior = .Inherit; + child.stdout_behavior = .Inherit; + child.stderr_behavior = .Inherit; - try child.spawn(); + const term = child.spawnAndWait() catch |err| { + log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); + return error.UnableToSpawnSelf; + }; + switch (term) { + .Exited => |code| { + if (code != 0) { + // TODO https://github.com/ziglang/zig/issues/6342 + std.process.exit(1); + } + }, + else => std.process.abort(), + } + } else { + child.stdin_behavior = .Ignore; + child.stdout_behavior = .Ignore; + child.stderr_behavior = .Pipe; - const stderr = try child.stderr.?.reader().readAllAlloc(arena, 10 * 1024 * 1024); + try child.spawn(); - const term = child.wait() catch |err| { - log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); - return error.UnableToSpawnSelf; - }; + const stderr = try child.stderr.?.reader().readAllAlloc(arena, 10 * 1024 * 1024); - switch (term) { - .Exited => |code| { - if (code != 0) { - // TODO parse this output and surface with the Compilation API rather than - // directly outputting to stderr here. - std.debug.print("{s}", .{stderr}); - return error.LLDReportedFailure; - } - }, - else => { - log.err("{s} terminated with stderr:\n{s}", .{ argv.items[0], stderr }); - return error.LLDCrashed; - }, - } + const term = child.wait() catch |err| { + log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); + return error.UnableToSpawnSelf; + }; - if (stderr.len != 0) { - std.log.warn("unexpected LLD stderr:\n{s}", .{stderr}); + switch (term) { + .Exited => |code| { + if (code != 0) { + // TODO parse this output and surface with the Compilation API rather than + // directly outputting to stderr here. + std.debug.print("{s}", .{stderr}); + return error.LLDReportedFailure; + } + }, + else => { + log.err("{s} terminated with stderr:\n{s}", .{ argv.items[0], stderr }); + return error.LLDCrashed; + }, + } + + if (stderr.len != 0) { + std.log.warn("unexpected LLD stderr:\n{s}", .{stderr}); + } } } diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 24219d3c44..ba1a9f824d 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1632,46 +1632,60 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { } // Sadly, we must run LLD as a child process because it does not behave - // properly as a library. One exception is if we are running in passthrough - // mode, which means Clang / LLD should inherit stdio and are allowed to - // crash zig directly. - if (comp.clang_passthrough_mode) { - return @import("../main.zig").punt_to_lld(arena, argv.items); - } - + // properly as a library. const child = try std.ChildProcess.init(argv.items, arena); defer child.deinit(); - child.stdin_behavior = .Ignore; - child.stdout_behavior = .Ignore; - child.stderr_behavior = .Pipe; + if (comp.clang_passthrough_mode) { + child.stdin_behavior = .Inherit; + child.stdout_behavior = .Inherit; + child.stderr_behavior = .Inherit; - try child.spawn(); + const term = child.spawnAndWait() catch |err| { + log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); + return error.UnableToSpawnSelf; + }; + switch (term) { + .Exited => |code| { + if (code != 0) { + // TODO https://github.com/ziglang/zig/issues/6342 + std.process.exit(1); + } + }, + else => std.process.abort(), + } + } else { + child.stdin_behavior = .Ignore; + child.stdout_behavior = .Ignore; + child.stderr_behavior = .Pipe; - const stderr = try child.stderr.?.reader().readAllAlloc(arena, 10 * 1024 * 1024); + try child.spawn(); - const term = child.wait() catch |err| { - log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); - return error.UnableToSpawnSelf; - }; + const stderr = try child.stderr.?.reader().readAllAlloc(arena, 10 * 1024 * 1024); - switch (term) { - .Exited => |code| { - if (code != 0) { - // TODO parse this output and surface with the Compilation API rather than - // directly outputting to stderr here. - std.debug.print("{s}", .{stderr}); - return error.LLDReportedFailure; - } - }, - else => { - log.err("{s} terminated with stderr:\n{s}", .{ argv.items[0], stderr }); - return error.LLDCrashed; - }, - } + const term = child.wait() catch |err| { + log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); + return error.UnableToSpawnSelf; + }; - if (stderr.len != 0) { - std.log.warn("unexpected LLD stderr:\n{s}", .{stderr}); + switch (term) { + .Exited => |code| { + if (code != 0) { + // TODO parse this output and surface with the Compilation API rather than + // directly outputting to stderr here. + std.debug.print("{s}", .{stderr}); + return error.LLDReportedFailure; + } + }, + else => { + log.err("{s} terminated with stderr:\n{s}", .{ argv.items[0], stderr }); + return error.LLDCrashed; + }, + } + + if (stderr.len != 0) { + std.log.warn("unexpected LLD stderr:\n{s}", .{stderr}); + } } if (!self.base.options.disable_lld_caching) { diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 35a6a7d24a..0767ad149f 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -686,46 +686,60 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { } } else { // Sadly, we must run LLD as a child process because it does not behave - // properly as a library. One exception is if we are running in passthrough - // mode, which means Clang / LLD should inherit stdio and are allowed to - // crash zig directly. - if (comp.clang_passthrough_mode) { - return @import("../main.zig").punt_to_lld(arena, argv.items); - } - + // properly as a library. const child = try std.ChildProcess.init(argv.items, arena); defer child.deinit(); - child.stdin_behavior = .Ignore; - child.stdout_behavior = .Ignore; - child.stderr_behavior = .Pipe; + if (comp.clang_passthrough_mode) { + child.stdin_behavior = .Inherit; + child.stdout_behavior = .Inherit; + child.stderr_behavior = .Inherit; - try child.spawn(); + const term = child.spawnAndWait() catch |err| { + log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); + return error.UnableToSpawnSelf; + }; + switch (term) { + .Exited => |code| { + if (code != 0) { + // TODO https://github.com/ziglang/zig/issues/6342 + std.process.exit(1); + } + }, + else => std.process.abort(), + } + } else { + child.stdin_behavior = .Ignore; + child.stdout_behavior = .Ignore; + child.stderr_behavior = .Pipe; - const stderr = try child.stderr.?.reader().readAllAlloc(arena, 10 * 1024 * 1024); + try child.spawn(); - const term = child.wait() catch |err| { - log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); - return error.UnableToSpawnSelf; - }; + const stderr = try child.stderr.?.reader().readAllAlloc(arena, 10 * 1024 * 1024); - switch (term) { - .Exited => |code| { - if (code != 0) { - // TODO parse this output and surface with the Compilation API rather than - // directly outputting to stderr here. - std.debug.print("{s}", .{stderr}); - return error.LLDReportedFailure; - } - }, - else => { - log.err("{s} terminated with stderr:\n{s}", .{ argv.items[0], stderr }); - return error.LLDCrashed; - }, - } + const term = child.wait() catch |err| { + log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); + return error.UnableToSpawnSelf; + }; - if (stderr.len != 0) { - std.log.warn("unexpected LLD stderr:\n{s}", .{stderr}); + switch (term) { + .Exited => |code| { + if (code != 0) { + // TODO parse this output and surface with the Compilation API rather than + // directly outputting to stderr here. + std.debug.print("{s}", .{stderr}); + return error.LLDReportedFailure; + } + }, + else => { + log.err("{s} terminated with stderr:\n{s}", .{ argv.items[0], stderr }); + return error.LLDCrashed; + }, + } + + if (stderr.len != 0) { + std.log.warn("unexpected LLD stderr:\n{s}", .{stderr}); + } } // At this stage, LLD has done its job. It is time to patch the resultant diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 41f43a08fd..cc57aee03d 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -403,46 +403,60 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { } // Sadly, we must run LLD as a child process because it does not behave - // properly as a library. One exception is if we are running in passthrough - // mode, which means Clang / LLD should inherit stdio and are allowed to - // crash zig directly. - if (comp.clang_passthrough_mode) { - return @import("../main.zig").punt_to_lld(arena, argv.items); - } - + // properly as a library. const child = try std.ChildProcess.init(argv.items, arena); defer child.deinit(); - child.stdin_behavior = .Ignore; - child.stdout_behavior = .Ignore; - child.stderr_behavior = .Pipe; + if (comp.clang_passthrough_mode) { + child.stdin_behavior = .Inherit; + child.stdout_behavior = .Inherit; + child.stderr_behavior = .Inherit; - try child.spawn(); + const term = child.spawnAndWait() catch |err| { + log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); + return error.UnableToSpawnSelf; + }; + switch (term) { + .Exited => |code| { + if (code != 0) { + // TODO https://github.com/ziglang/zig/issues/6342 + std.process.exit(1); + } + }, + else => std.process.abort(), + } + } else { + child.stdin_behavior = .Ignore; + child.stdout_behavior = .Ignore; + child.stderr_behavior = .Pipe; - const stderr = try child.stderr.?.reader().readAllAlloc(arena, 10 * 1024 * 1024); + try child.spawn(); - const term = child.wait() catch |err| { - log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); - return error.UnableToSpawnSelf; - }; + const stderr = try child.stderr.?.reader().readAllAlloc(arena, 10 * 1024 * 1024); - switch (term) { - .Exited => |code| { - if (code != 0) { - // TODO parse this output and surface with the Compilation API rather than - // directly outputting to stderr here. - std.debug.print("{s}", .{stderr}); - return error.LLDReportedFailure; - } - }, - else => { - log.err("{s} terminated with stderr:\n{s}", .{ argv.items[0], stderr }); - return error.LLDCrashed; - }, - } + const term = child.wait() catch |err| { + log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); + return error.UnableToSpawnSelf; + }; - if (stderr.len != 0) { - std.log.warn("unexpected LLD stderr:\n{s}", .{stderr}); + switch (term) { + .Exited => |code| { + if (code != 0) { + // TODO parse this output and surface with the Compilation API rather than + // directly outputting to stderr here. + std.debug.print("{s}", .{stderr}); + return error.LLDReportedFailure; + } + }, + else => { + log.err("{s} terminated with stderr:\n{s}", .{ argv.items[0], stderr }); + return error.LLDCrashed; + }, + } + + if (stderr.len != 0) { + std.log.warn("unexpected LLD stderr:\n{s}", .{stderr}); + } } if (!self.base.options.disable_lld_caching) {