Merge pull request #10782 from topolarity/gate-child-processes
Avoid depending on child process execution when not supported by host OS
This commit is contained in:
@@ -229,6 +229,10 @@ pub fn build(b: *Builder) !void {
|
||||
const version = if (opt_version_string) |version| version else v: {
|
||||
const version_string = b.fmt("{d}.{d}.{d}", .{ zig_version.major, zig_version.minor, zig_version.patch });
|
||||
|
||||
if (!std.process.can_spawn) {
|
||||
std.debug.print("error: version info cannot be retrieved from git. Zig version must be provided using -Dversion-string\n", .{});
|
||||
std.process.exit(1);
|
||||
}
|
||||
var code: u8 = undefined;
|
||||
const git_describe_untrimmed = b.execAllowFail(&[_][]const u8{
|
||||
"git", "-C", b.build_root, "describe", "--match", "*.*.*", "--tags",
|
||||
@@ -542,6 +546,9 @@ fn addCxxKnownPath(
|
||||
errtxt: ?[]const u8,
|
||||
need_cpp_includes: bool,
|
||||
) !void {
|
||||
if (!std.process.can_spawn)
|
||||
return error.RequiredLibraryNotFound;
|
||||
|
||||
const path_padded = try b.exec(&[_][]const u8{
|
||||
ctx.cxx_compiler,
|
||||
b.fmt("-print-file-name={s}", .{objname}),
|
||||
|
||||
@@ -88,7 +88,14 @@ pub const Builder = struct {
|
||||
/// Information about the native target. Computed before build() is invoked.
|
||||
host: NativeTargetInfo,
|
||||
|
||||
const PkgConfigError = error{
|
||||
pub const ExecError = error{
|
||||
ReadFailure,
|
||||
ExitCodeFailure,
|
||||
ProcessTerminated,
|
||||
ExecNotSupported,
|
||||
} || std.ChildProcess.SpawnError;
|
||||
|
||||
pub const PkgConfigError = error{
|
||||
PkgConfigCrashed,
|
||||
PkgConfigFailed,
|
||||
PkgConfigNotInstalled,
|
||||
@@ -959,6 +966,9 @@ pub const Builder = struct {
|
||||
printCmd(cwd, argv);
|
||||
}
|
||||
|
||||
if (!std.process.can_spawn)
|
||||
return error.ExecNotSupported;
|
||||
|
||||
const child = std.ChildProcess.init(argv, self.allocator) catch unreachable;
|
||||
defer child.deinit();
|
||||
|
||||
@@ -1168,9 +1178,12 @@ pub const Builder = struct {
|
||||
argv: []const []const u8,
|
||||
out_code: *u8,
|
||||
stderr_behavior: std.ChildProcess.StdIo,
|
||||
) ![]u8 {
|
||||
) ExecError![]u8 {
|
||||
assert(argv.len != 0);
|
||||
|
||||
if (!std.process.can_spawn)
|
||||
return error.ExecNotSupported;
|
||||
|
||||
const max_output_size = 400 * 1024;
|
||||
const child = try std.ChildProcess.init(argv, self.allocator);
|
||||
defer child.deinit();
|
||||
@@ -1182,7 +1195,9 @@ pub const Builder = struct {
|
||||
|
||||
try child.spawn();
|
||||
|
||||
const stdout = try child.stdout.?.reader().readAllAlloc(self.allocator, max_output_size);
|
||||
const stdout = child.stdout.?.reader().readAllAlloc(self.allocator, max_output_size) catch {
|
||||
return error.ReadFailure;
|
||||
};
|
||||
errdefer self.allocator.free(stdout);
|
||||
|
||||
const term = try child.wait();
|
||||
@@ -1208,8 +1223,21 @@ pub const Builder = struct {
|
||||
printCmd(null, argv);
|
||||
}
|
||||
|
||||
if (!std.process.can_spawn) {
|
||||
if (src_step) |s| warn("{s}...", .{s.name});
|
||||
warn("Unable to spawn the following command: cannot spawn child process\n", .{});
|
||||
printCmd(null, argv);
|
||||
std.os.abort();
|
||||
}
|
||||
|
||||
var code: u8 = undefined;
|
||||
return self.execAllowFail(argv, &code, .Inherit) catch |err| switch (err) {
|
||||
error.ExecNotSupported => {
|
||||
if (src_step) |s| warn("{s}...", .{s.name});
|
||||
warn("Unable to spawn the following command: cannot spawn child process\n", .{});
|
||||
printCmd(null, argv);
|
||||
std.os.abort();
|
||||
},
|
||||
error.FileNotFound => {
|
||||
if (src_step) |s| warn("{s}...", .{s.name});
|
||||
warn("Unable to spawn the following command: file not found\n", .{});
|
||||
@@ -1260,7 +1288,7 @@ pub const Builder = struct {
|
||||
) catch unreachable;
|
||||
}
|
||||
|
||||
fn execPkgConfigList(self: *Builder, out_code: *u8) ![]const PkgConfigPkg {
|
||||
fn execPkgConfigList(self: *Builder, out_code: *u8) (PkgConfigError || ExecError)![]const PkgConfigPkg {
|
||||
const stdout = try self.execAllowFail(&[_][]const u8{ "pkg-config", "--list-all" }, out_code, .Ignore);
|
||||
var list = ArrayList(PkgConfigPkg).init(self.allocator);
|
||||
errdefer list.deinit();
|
||||
@@ -1287,6 +1315,7 @@ pub const Builder = struct {
|
||||
} else |err| {
|
||||
const result = switch (err) {
|
||||
error.ProcessTerminated => error.PkgConfigCrashed,
|
||||
error.ExecNotSupported => error.PkgConfigFailed,
|
||||
error.ExitCodeFailure => error.PkgConfigFailed,
|
||||
error.FileNotFound => error.PkgConfigNotInstalled,
|
||||
error.InvalidName => error.PkgConfigNotInstalled,
|
||||
@@ -1929,6 +1958,7 @@ pub const LibExeObjStep = struct {
|
||||
"--libs",
|
||||
}, &code, .Ignore)) |stdout| stdout else |err| switch (err) {
|
||||
error.ProcessTerminated => return error.PkgConfigCrashed,
|
||||
error.ExecNotSupported => return error.PkgConfigFailed,
|
||||
error.ExitCodeFailure => return error.PkgConfigFailed,
|
||||
error.FileNotFound => return error.PkgConfigNotInstalled,
|
||||
else => return err,
|
||||
|
||||
@@ -10,6 +10,8 @@ const mem = std.mem;
|
||||
const process = std.process;
|
||||
const ArrayList = std.ArrayList;
|
||||
const BufMap = std.BufMap;
|
||||
const Allocator = mem.Allocator;
|
||||
const ExecError = build.Builder.ExecError;
|
||||
|
||||
const max_stdout_size = 1 * 1024 * 1024; // 1 MiB
|
||||
|
||||
@@ -175,6 +177,13 @@ fn make(step: *Step) !void {
|
||||
|
||||
const argv = argv_list.items;
|
||||
|
||||
if (!std.process.can_spawn) {
|
||||
const cmd = try std.mem.join(self.builder.allocator, " ", argv);
|
||||
std.debug.print("the following command cannot be executed ({s} does not support spawning a child process):\n{s}", .{ @tagName(builtin.os.tag), cmd });
|
||||
self.builder.allocator.free(cmd);
|
||||
return ExecError.ExecNotSupported;
|
||||
}
|
||||
|
||||
const child = std.ChildProcess.init(argv, self.builder.allocator) catch unreachable;
|
||||
defer child.deinit();
|
||||
|
||||
|
||||
@@ -124,6 +124,10 @@ pub const ChildProcess = struct {
|
||||
|
||||
/// On success must call `kill` or `wait`.
|
||||
pub fn spawn(self: *ChildProcess) SpawnError!void {
|
||||
if (!std.process.can_spawn) {
|
||||
@compileError("the target operating system cannot spawn processes");
|
||||
}
|
||||
|
||||
if (builtin.os.tag == .windows) {
|
||||
return self.spawnWindows();
|
||||
} else {
|
||||
|
||||
@@ -950,7 +950,13 @@ pub fn getSelfExeSharedLibPaths(allocator: Allocator) error{OutOfMemory}![][:0]u
|
||||
|
||||
/// Tells whether calling the `execv` or `execve` functions will be a compile error.
|
||||
pub const can_execv = switch (builtin.os.tag) {
|
||||
.windows, .haiku => false,
|
||||
.windows, .haiku, .wasi => false,
|
||||
else => true,
|
||||
};
|
||||
|
||||
/// Tells whether spawning child processes is supported (e.g. via ChildProcess)
|
||||
pub const can_spawn = switch (builtin.os.tag) {
|
||||
.wasi => false,
|
||||
else => true,
|
||||
};
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ const libunwind = @import("libunwind.zig");
|
||||
const libcxx = @import("libcxx.zig");
|
||||
const wasi_libc = @import("wasi_libc.zig");
|
||||
const fatal = @import("main.zig").fatal;
|
||||
const clangMain = @import("main.zig").clangMain;
|
||||
const Module = @import("Module.zig");
|
||||
const Cache = @import("Cache.zig");
|
||||
const stage1 = @import("stage1.zig");
|
||||
@@ -3667,55 +3668,71 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P
|
||||
dump_argv(argv.items);
|
||||
}
|
||||
|
||||
const child = try std.ChildProcess.init(argv.items, arena);
|
||||
defer child.deinit();
|
||||
if (std.process.can_spawn) {
|
||||
const child = try std.ChildProcess.init(argv.items, arena);
|
||||
defer child.deinit();
|
||||
|
||||
if (comp.clang_passthrough_mode) {
|
||||
child.stdin_behavior = .Inherit;
|
||||
child.stdout_behavior = .Inherit;
|
||||
child.stderr_behavior = .Inherit;
|
||||
if (comp.clang_passthrough_mode) {
|
||||
child.stdin_behavior = .Inherit;
|
||||
child.stdout_behavior = .Inherit;
|
||||
child.stderr_behavior = .Inherit;
|
||||
|
||||
const term = child.spawnAndWait() catch |err| {
|
||||
return comp.failCObj(c_object, "unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) });
|
||||
};
|
||||
switch (term) {
|
||||
.Exited => |code| {
|
||||
if (code != 0) {
|
||||
std.process.exit(code);
|
||||
}
|
||||
if (comp.clang_preprocessor_mode == .stdout)
|
||||
std.process.exit(0);
|
||||
},
|
||||
else => std.process.abort(),
|
||||
const term = child.spawnAndWait() catch |err| {
|
||||
return comp.failCObj(c_object, "unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) });
|
||||
};
|
||||
switch (term) {
|
||||
.Exited => |code| {
|
||||
if (code != 0) {
|
||||
std.process.exit(code);
|
||||
}
|
||||
if (comp.clang_preprocessor_mode == .stdout)
|
||||
std.process.exit(0);
|
||||
},
|
||||
else => std.process.abort(),
|
||||
}
|
||||
} else {
|
||||
child.stdin_behavior = .Ignore;
|
||||
child.stdout_behavior = .Ignore;
|
||||
child.stderr_behavior = .Pipe;
|
||||
|
||||
try child.spawn();
|
||||
|
||||
const stderr_reader = child.stderr.?.reader();
|
||||
|
||||
const stderr = try stderr_reader.readAllAlloc(arena, 10 * 1024 * 1024);
|
||||
|
||||
const term = child.wait() catch |err| {
|
||||
return comp.failCObj(c_object, "unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) });
|
||||
};
|
||||
|
||||
switch (term) {
|
||||
.Exited => |code| {
|
||||
if (code != 0) {
|
||||
// TODO parse clang stderr and turn it into an error message
|
||||
// and then call failCObjWithOwnedErrorMsg
|
||||
log.err("clang failed with stderr: {s}", .{stderr});
|
||||
return comp.failCObj(c_object, "clang exited with code {d}", .{code});
|
||||
}
|
||||
},
|
||||
else => {
|
||||
log.err("clang terminated with stderr: {s}", .{stderr});
|
||||
return comp.failCObj(c_object, "clang terminated unexpectedly", .{});
|
||||
},
|
||||
}
|
||||
}
|
||||
} else {
|
||||
child.stdin_behavior = .Ignore;
|
||||
child.stdout_behavior = .Ignore;
|
||||
child.stderr_behavior = .Pipe;
|
||||
|
||||
try child.spawn();
|
||||
|
||||
const stderr_reader = child.stderr.?.reader();
|
||||
|
||||
const stderr = try stderr_reader.readAllAlloc(arena, 10 * 1024 * 1024);
|
||||
|
||||
const term = child.wait() catch |err| {
|
||||
return comp.failCObj(c_object, "unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) });
|
||||
};
|
||||
|
||||
switch (term) {
|
||||
.Exited => |code| {
|
||||
if (code != 0) {
|
||||
// TODO parse clang stderr and turn it into an error message
|
||||
// and then call failCObjWithOwnedErrorMsg
|
||||
log.err("clang failed with stderr: {s}", .{stderr});
|
||||
return comp.failCObj(c_object, "clang exited with code {d}", .{code});
|
||||
}
|
||||
},
|
||||
else => {
|
||||
log.err("clang terminated with stderr: {s}", .{stderr});
|
||||
return comp.failCObj(c_object, "clang terminated unexpectedly", .{});
|
||||
},
|
||||
const exit_code = try clangMain(arena, argv.items);
|
||||
if (exit_code != 0) {
|
||||
if (comp.clang_passthrough_mode) {
|
||||
std.process.exit(exit_code);
|
||||
} else {
|
||||
return comp.failCObj(c_object, "clang exited with code {d}", .{exit_code});
|
||||
}
|
||||
}
|
||||
if (comp.clang_passthrough_mode and
|
||||
comp.clang_preprocessor_mode == .stdout)
|
||||
{
|
||||
std.process.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -82,6 +82,9 @@ pub fn init(self: *ThreadPool, allocator: std.mem.Allocator) !void {
|
||||
}
|
||||
|
||||
fn destroyWorkers(self: *ThreadPool, spawned: usize) void {
|
||||
if (builtin.single_threaded)
|
||||
return;
|
||||
|
||||
for (self.workers[0..spawned]) |*worker| {
|
||||
worker.thread.join();
|
||||
worker.idle_node.data.deinit();
|
||||
|
||||
@@ -216,7 +216,7 @@ pub const LibCInstallation = struct {
|
||||
self.crt_dir = try args.allocator.dupeZ(u8, "/system/develop/lib");
|
||||
break :blk batch.wait();
|
||||
};
|
||||
} else {
|
||||
} else if (std.process.can_spawn) {
|
||||
try blk: {
|
||||
var batch = Batch(FindError!void, 2, .auto_async).init();
|
||||
errdefer batch.wait() catch {};
|
||||
@@ -229,6 +229,8 @@ pub const LibCInstallation = struct {
|
||||
}
|
||||
break :blk batch.wait();
|
||||
};
|
||||
} else {
|
||||
return error.LibCRuntimeNotFound;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ const fs = std.fs;
|
||||
const allocPrint = std.fmt.allocPrint;
|
||||
const mem = std.mem;
|
||||
|
||||
const lldMain = @import("../main.zig").lldMain;
|
||||
const trace = @import("../tracy.zig").trace;
|
||||
const Module = @import("../Module.zig");
|
||||
const Compilation = @import("../Compilation.zig");
|
||||
@@ -1358,60 +1359,71 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void {
|
||||
Compilation.dump_argv(argv.items[1..]);
|
||||
}
|
||||
|
||||
// Sadly, we must run LLD as a child process because it does not behave
|
||||
// properly as a library.
|
||||
const child = try std.ChildProcess.init(argv.items, arena);
|
||||
defer child.deinit();
|
||||
if (std.process.can_spawn) {
|
||||
// If possible, we run LLD as a child process because it does not always
|
||||
// behave properly as a library, unfortunately.
|
||||
// https://github.com/ziglang/zig/issues/3825
|
||||
const child = try std.ChildProcess.init(argv.items, arena);
|
||||
defer child.deinit();
|
||||
|
||||
if (comp.clang_passthrough_mode) {
|
||||
child.stdin_behavior = .Inherit;
|
||||
child.stdout_behavior = .Inherit;
|
||||
child.stderr_behavior = .Inherit;
|
||||
if (comp.clang_passthrough_mode) {
|
||||
child.stdin_behavior = .Inherit;
|
||||
child.stdout_behavior = .Inherit;
|
||||
child.stderr_behavior = .Inherit;
|
||||
|
||||
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(),
|
||||
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) {
|
||||
std.process.exit(code);
|
||||
}
|
||||
},
|
||||
else => std.process.abort(),
|
||||
}
|
||||
} else {
|
||||
child.stdin_behavior = .Ignore;
|
||||
child.stdout_behavior = .Ignore;
|
||||
child.stderr_behavior = .Pipe;
|
||||
|
||||
try child.spawn();
|
||||
|
||||
const stderr = try child.stderr.?.reader().readAllAlloc(arena, 10 * 1024 * 1024);
|
||||
|
||||
const term = child.wait() 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 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) {
|
||||
log.warn("unexpected LLD stderr:\n{s}", .{stderr});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
child.stdin_behavior = .Ignore;
|
||||
child.stdout_behavior = .Ignore;
|
||||
child.stderr_behavior = .Pipe;
|
||||
|
||||
try child.spawn();
|
||||
|
||||
const stderr = try child.stderr.?.reader().readAllAlloc(arena, 10 * 1024 * 1024);
|
||||
|
||||
const term = child.wait() 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 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) {
|
||||
log.warn("unexpected LLD stderr:\n{s}", .{stderr});
|
||||
const exit_code = try lldMain(arena, argv.items, false);
|
||||
if (exit_code != 0) {
|
||||
if (comp.clang_passthrough_mode) {
|
||||
std.process.exit(exit_code);
|
||||
} else {
|
||||
return error.LLDReportedFailure;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
112
src/link/Elf.zig
112
src/link/Elf.zig
@@ -14,6 +14,7 @@ const leb128 = std.leb;
|
||||
const Module = @import("../Module.zig");
|
||||
const Compilation = @import("../Compilation.zig");
|
||||
const codegen = @import("../codegen.zig");
|
||||
const lldMain = @import("../main.zig").lldMain;
|
||||
const trace = @import("../tracy.zig").trace;
|
||||
const Package = @import("../Package.zig");
|
||||
const Value = @import("../value.zig").Value;
|
||||
@@ -1950,60 +1951,71 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
|
||||
Compilation.dump_argv(argv.items[1..]);
|
||||
}
|
||||
|
||||
// Sadly, we must run LLD as a child process because it does not behave
|
||||
// properly as a library.
|
||||
const child = try std.ChildProcess.init(argv.items, arena);
|
||||
defer child.deinit();
|
||||
if (std.process.can_spawn) {
|
||||
// If possible, we run LLD as a child process because it does not always
|
||||
// behave properly as a library, unfortunately.
|
||||
// https://github.com/ziglang/zig/issues/3825
|
||||
const child = try std.ChildProcess.init(argv.items, arena);
|
||||
defer child.deinit();
|
||||
|
||||
if (comp.clang_passthrough_mode) {
|
||||
child.stdin_behavior = .Inherit;
|
||||
child.stdout_behavior = .Inherit;
|
||||
child.stderr_behavior = .Inherit;
|
||||
if (comp.clang_passthrough_mode) {
|
||||
child.stdin_behavior = .Inherit;
|
||||
child.stdout_behavior = .Inherit;
|
||||
child.stderr_behavior = .Inherit;
|
||||
|
||||
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(),
|
||||
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) {
|
||||
std.process.exit(code);
|
||||
}
|
||||
},
|
||||
else => std.process.abort(),
|
||||
}
|
||||
} else {
|
||||
child.stdin_behavior = .Ignore;
|
||||
child.stdout_behavior = .Ignore;
|
||||
child.stderr_behavior = .Pipe;
|
||||
|
||||
try child.spawn();
|
||||
|
||||
const stderr = try child.stderr.?.reader().readAllAlloc(arena, 10 * 1024 * 1024);
|
||||
|
||||
const term = child.wait() 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 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) {
|
||||
log.warn("unexpected LLD stderr:\n{s}", .{stderr});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
child.stdin_behavior = .Ignore;
|
||||
child.stdout_behavior = .Ignore;
|
||||
child.stderr_behavior = .Pipe;
|
||||
|
||||
try child.spawn();
|
||||
|
||||
const stderr = try child.stderr.?.reader().readAllAlloc(arena, 10 * 1024 * 1024);
|
||||
|
||||
const term = child.wait() 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 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) {
|
||||
log.warn("unexpected LLD stderr:\n{s}", .{stderr});
|
||||
const exit_code = try lldMain(arena, argv.items, false);
|
||||
if (exit_code != 0) {
|
||||
if (comp.clang_passthrough_mode) {
|
||||
std.process.exit(exit_code);
|
||||
} else {
|
||||
return error.LLDReportedFailure;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ const Module = @import("../Module.zig");
|
||||
const Compilation = @import("../Compilation.zig");
|
||||
const CodeGen = @import("../arch/wasm/CodeGen.zig");
|
||||
const link = @import("../link.zig");
|
||||
const lldMain = @import("../main.zig").lldMain;
|
||||
const trace = @import("../tracy.zig").trace;
|
||||
const build_options = @import("build_options");
|
||||
const wasi_libc = @import("../wasi_libc.zig");
|
||||
@@ -1486,60 +1487,71 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
|
||||
Compilation.dump_argv(argv.items[1..]);
|
||||
}
|
||||
|
||||
// Sadly, we must run LLD as a child process because it does not behave
|
||||
// properly as a library.
|
||||
const child = try std.ChildProcess.init(argv.items, arena);
|
||||
defer child.deinit();
|
||||
if (std.process.can_spawn) {
|
||||
// If possible, we run LLD as a child process because it does not always
|
||||
// behave properly as a library, unfortunately.
|
||||
// https://github.com/ziglang/zig/issues/3825
|
||||
const child = try std.ChildProcess.init(argv.items, arena);
|
||||
defer child.deinit();
|
||||
|
||||
if (comp.clang_passthrough_mode) {
|
||||
child.stdin_behavior = .Inherit;
|
||||
child.stdout_behavior = .Inherit;
|
||||
child.stderr_behavior = .Inherit;
|
||||
if (comp.clang_passthrough_mode) {
|
||||
child.stdin_behavior = .Inherit;
|
||||
child.stdout_behavior = .Inherit;
|
||||
child.stderr_behavior = .Inherit;
|
||||
|
||||
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(),
|
||||
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) {
|
||||
std.process.exit(code);
|
||||
}
|
||||
},
|
||||
else => std.process.abort(),
|
||||
}
|
||||
} else {
|
||||
child.stdin_behavior = .Ignore;
|
||||
child.stdout_behavior = .Ignore;
|
||||
child.stderr_behavior = .Pipe;
|
||||
|
||||
try child.spawn();
|
||||
|
||||
const stderr = try child.stderr.?.reader().readAllAlloc(arena, 10 * 1024 * 1024);
|
||||
|
||||
const term = child.wait() 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 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) {
|
||||
log.warn("unexpected LLD stderr:\n{s}", .{stderr});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
child.stdin_behavior = .Ignore;
|
||||
child.stdout_behavior = .Ignore;
|
||||
child.stderr_behavior = .Pipe;
|
||||
|
||||
try child.spawn();
|
||||
|
||||
const stderr = try child.stderr.?.reader().readAllAlloc(arena, 10 * 1024 * 1024);
|
||||
|
||||
const term = child.wait() 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 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) {
|
||||
log.warn("unexpected LLD stderr:\n{s}", .{stderr});
|
||||
const exit_code = try lldMain(arena, argv.items, false);
|
||||
if (exit_code != 0) {
|
||||
if (comp.clang_passthrough_mode) {
|
||||
std.process.exit(exit_code);
|
||||
} else {
|
||||
return error.LLDReportedFailure;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
168
src/main.zig
168
src/main.zig
@@ -221,7 +221,7 @@ pub fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
|
||||
mem.eql(u8, cmd, "lib") or
|
||||
mem.eql(u8, cmd, "ar"))
|
||||
{
|
||||
return punt_to_llvm_ar(arena, args);
|
||||
return process.exit(try llvmArMain(arena, args));
|
||||
} else if (mem.eql(u8, cmd, "cc")) {
|
||||
return buildOutputType(gpa, arena, args, .cc);
|
||||
} else if (mem.eql(u8, cmd, "c++")) {
|
||||
@@ -231,12 +231,12 @@ pub fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
|
||||
} else if (mem.eql(u8, cmd, "clang") or
|
||||
mem.eql(u8, cmd, "-cc1") or mem.eql(u8, cmd, "-cc1as"))
|
||||
{
|
||||
return punt_to_clang(arena, args);
|
||||
return process.exit(try clangMain(arena, args));
|
||||
} else if (mem.eql(u8, cmd, "ld.lld") or
|
||||
mem.eql(u8, cmd, "lld-link") or
|
||||
mem.eql(u8, cmd, "wasm-ld"))
|
||||
{
|
||||
return punt_to_lld(arena, args);
|
||||
return process.exit(try lldMain(arena, args, true));
|
||||
} else if (mem.eql(u8, cmd, "build")) {
|
||||
return cmdBuild(gpa, arena, cmd_args);
|
||||
} else if (mem.eql(u8, cmd, "fmt")) {
|
||||
@@ -1347,7 +1347,7 @@ fn buildOutputType(
|
||||
.ignore => {},
|
||||
.driver_punt => {
|
||||
// Never mind what we're doing, just pass the args directly. For example --help.
|
||||
return punt_to_clang(arena, all_args);
|
||||
return process.exit(try clangMain(arena, all_args));
|
||||
},
|
||||
.pic => want_pic = true,
|
||||
.no_pic => want_pic = false,
|
||||
@@ -1866,7 +1866,7 @@ fn buildOutputType(
|
||||
// An error message is generated when there is more than 1 C source file.
|
||||
if (c_source_files.items.len != 1) {
|
||||
// For example `zig cc` and no args should print the "no input files" message.
|
||||
return punt_to_clang(arena, all_args);
|
||||
return process.exit(try clangMain(arena, all_args));
|
||||
}
|
||||
if (out_path) |p| {
|
||||
emit_bin = .{ .yes = p };
|
||||
@@ -1882,7 +1882,7 @@ fn buildOutputType(
|
||||
{
|
||||
// For example `zig cc` and no args should print the "no input files" message.
|
||||
// There could be other reasons to punt to clang, for example, --help.
|
||||
return punt_to_clang(arena, all_args);
|
||||
return process.exit(try clangMain(arena, all_args));
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -2881,9 +2881,9 @@ fn runOrTest(
|
||||
// execv releases the locks; no need to destroy the Compilation here.
|
||||
const err = std.process.execv(gpa, argv.items);
|
||||
try warnAboutForeignBinaries(gpa, arena, arg_mode, target_info, link_libc);
|
||||
const cmd = try argvCmd(arena, argv.items);
|
||||
const cmd = try std.mem.join(arena, " ", argv.items);
|
||||
fatal("the following command failed to execve with '{s}':\n{s}", .{ @errorName(err), cmd });
|
||||
} else {
|
||||
} else if (std.process.can_spawn) {
|
||||
const child = try std.ChildProcess.init(argv.items, gpa);
|
||||
defer child.deinit();
|
||||
|
||||
@@ -2900,7 +2900,7 @@ fn runOrTest(
|
||||
|
||||
const term = child.spawnAndWait() catch |err| {
|
||||
try warnAboutForeignBinaries(gpa, arena, arg_mode, target_info, link_libc);
|
||||
const cmd = try argvCmd(arena, argv.items);
|
||||
const cmd = try std.mem.join(arena, " ", argv.items);
|
||||
fatal("the following command failed with '{s}':\n{s}", .{ @errorName(err), cmd });
|
||||
};
|
||||
switch (arg_mode) {
|
||||
@@ -2931,18 +2931,21 @@ fn runOrTest(
|
||||
if (code == 0) {
|
||||
if (!watch) return cleanExit();
|
||||
} else {
|
||||
const cmd = try argvCmd(arena, argv.items);
|
||||
const cmd = try std.mem.join(arena, " ", argv.items);
|
||||
fatal("the following test command failed with exit code {d}:\n{s}", .{ code, cmd });
|
||||
}
|
||||
},
|
||||
else => {
|
||||
const cmd = try argvCmd(arena, argv.items);
|
||||
const cmd = try std.mem.join(arena, " ", argv.items);
|
||||
fatal("the following test command crashed:\n{s}", .{cmd});
|
||||
},
|
||||
}
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
} else {
|
||||
const cmd = try std.mem.join(arena, " ", argv.items);
|
||||
fatal("the following command cannot be executed ({s} does not support spawning a child process):\n{s}", .{ @tagName(builtin.os.tag), cmd });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3553,43 +3556,38 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
|
||||
|
||||
break :argv child_argv.items;
|
||||
};
|
||||
const child = try std.ChildProcess.init(child_argv, gpa);
|
||||
defer child.deinit();
|
||||
|
||||
child.stdin_behavior = .Inherit;
|
||||
child.stdout_behavior = .Inherit;
|
||||
child.stderr_behavior = .Inherit;
|
||||
if (std.process.can_spawn) {
|
||||
const child = try std.ChildProcess.init(child_argv, gpa);
|
||||
defer child.deinit();
|
||||
|
||||
const term = try child.spawnAndWait();
|
||||
switch (term) {
|
||||
.Exited => |code| {
|
||||
if (code == 0) return cleanExit();
|
||||
child.stdin_behavior = .Inherit;
|
||||
child.stdout_behavior = .Inherit;
|
||||
child.stderr_behavior = .Inherit;
|
||||
|
||||
if (prominent_compile_errors) {
|
||||
fatal("the build command failed with exit code {d}", .{code});
|
||||
} else {
|
||||
const cmd = try argvCmd(arena, child_argv);
|
||||
fatal("the following build command failed with exit code {d}:\n{s}", .{ code, cmd });
|
||||
}
|
||||
},
|
||||
else => {
|
||||
const cmd = try argvCmd(arena, child_argv);
|
||||
fatal("the following build command crashed:\n{s}", .{cmd});
|
||||
},
|
||||
const term = try child.spawnAndWait();
|
||||
switch (term) {
|
||||
.Exited => |code| {
|
||||
if (code == 0) return cleanExit();
|
||||
|
||||
if (prominent_compile_errors) {
|
||||
fatal("the build command failed with exit code {d}", .{code});
|
||||
} else {
|
||||
const cmd = try std.mem.join(arena, " ", child_argv);
|
||||
fatal("the following build command failed with exit code {d}:\n{s}", .{ code, cmd });
|
||||
}
|
||||
},
|
||||
else => {
|
||||
const cmd = try std.mem.join(arena, " ", child_argv);
|
||||
fatal("the following build command crashed:\n{s}", .{cmd});
|
||||
},
|
||||
}
|
||||
} else {
|
||||
const cmd = try std.mem.join(arena, " ", child_argv);
|
||||
fatal("the following command cannot be executed ({s} does not support spawning a child process):\n{s}", .{ @tagName(builtin.os.tag), cmd });
|
||||
}
|
||||
}
|
||||
|
||||
fn argvCmd(allocator: Allocator, argv: []const []const u8) ![]u8 {
|
||||
var cmd = std.ArrayList(u8).init(allocator);
|
||||
defer cmd.deinit();
|
||||
for (argv[0 .. argv.len - 1]) |arg| {
|
||||
try cmd.appendSlice(arg);
|
||||
try cmd.append(' ');
|
||||
}
|
||||
try cmd.appendSlice(argv[argv.len - 1]);
|
||||
return cmd.toOwnedSlice();
|
||||
}
|
||||
|
||||
fn readSourceFileToEndAlloc(
|
||||
allocator: mem.Allocator,
|
||||
input: *const fs.File,
|
||||
@@ -4080,65 +4078,87 @@ pub const info_zen =
|
||||
extern "c" fn ZigClang_main(argc: c_int, argv: [*:null]?[*:0]u8) c_int;
|
||||
extern "c" fn ZigLlvmAr_main(argc: c_int, argv: [*:null]?[*:0]u8) c_int;
|
||||
|
||||
/// TODO https://github.com/ziglang/zig/issues/3257
|
||||
fn punt_to_clang(arena: Allocator, args: []const []const u8) error{OutOfMemory} {
|
||||
if (!build_options.have_llvm)
|
||||
fatal("`zig cc` and `zig c++` unavailable: compiler built without LLVM extensions", .{});
|
||||
// Convert the args to the format Clang expects.
|
||||
const argv = try arena.alloc(?[*:0]u8, args.len + 1);
|
||||
fn argsCopyZ(alloc: Allocator, args: []const []const u8) ![:null]?[*:0]u8 {
|
||||
var argv = try alloc.allocSentinel(?[*:0]u8, args.len, null);
|
||||
for (args) |arg, i| {
|
||||
argv[i] = try arena.dupeZ(u8, arg); // TODO If there was an argsAllocZ we could avoid this allocation.
|
||||
argv[i] = try alloc.dupeZ(u8, arg); // TODO If there was an argsAllocZ we could avoid this allocation.
|
||||
}
|
||||
argv[args.len] = null;
|
||||
const exit_code = ZigClang_main(@intCast(c_int, args.len), argv[0..args.len :null].ptr);
|
||||
process.exit(@bitCast(u8, @truncate(i8, exit_code)));
|
||||
return argv;
|
||||
}
|
||||
|
||||
/// TODO https://github.com/ziglang/zig/issues/3257
|
||||
fn punt_to_llvm_ar(arena: Allocator, args: []const []const u8) error{OutOfMemory} {
|
||||
pub fn clangMain(alloc: Allocator, args: []const []const u8) error{OutOfMemory}!u8 {
|
||||
if (!build_options.have_llvm)
|
||||
fatal("`zig cc` and `zig c++` unavailable: compiler built without LLVM extensions", .{});
|
||||
|
||||
var arena_instance = std.heap.ArenaAllocator.init(alloc);
|
||||
defer arena_instance.deinit();
|
||||
const arena = arena_instance.allocator();
|
||||
|
||||
// Convert the args to the null-terminated format Clang expects.
|
||||
const argv = try argsCopyZ(arena, args);
|
||||
const exit_code = ZigClang_main(@intCast(c_int, argv.len), argv.ptr);
|
||||
return @bitCast(u8, @truncate(i8, exit_code));
|
||||
}
|
||||
|
||||
pub fn llvmArMain(alloc: Allocator, args: []const []const u8) error{OutOfMemory}!u8 {
|
||||
if (!build_options.have_llvm)
|
||||
fatal("`zig ar`, `zig dlltool`, `zig ranlib', and `zig lib` unavailable: compiler built without LLVM extensions", .{});
|
||||
|
||||
var arena_instance = std.heap.ArenaAllocator.init(alloc);
|
||||
defer arena_instance.deinit();
|
||||
const arena = arena_instance.allocator();
|
||||
|
||||
// Convert the args to the format llvm-ar expects.
|
||||
// We subtract 1 to shave off the zig binary from args[0].
|
||||
const argv = try arena.allocSentinel(?[*:0]u8, args.len - 1, null);
|
||||
for (args[1..]) |arg, i| {
|
||||
// TODO If there was an argsAllocZ we could avoid this allocation.
|
||||
argv[i] = try arena.dupeZ(u8, arg);
|
||||
}
|
||||
const argc = @intCast(c_int, argv.len);
|
||||
const exit_code = ZigLlvmAr_main(argc, argv.ptr);
|
||||
process.exit(@bitCast(u8, @truncate(i8, exit_code)));
|
||||
// We intentionally shave off the zig binary at args[0].
|
||||
const argv = try argsCopyZ(arena, args[1..]);
|
||||
const exit_code = ZigLlvmAr_main(@intCast(c_int, argv.len), argv.ptr);
|
||||
return @bitCast(u8, @truncate(i8, exit_code));
|
||||
}
|
||||
|
||||
/// The first argument determines which backend is invoked. The options are:
|
||||
/// * `ld.lld` - ELF
|
||||
/// * `lld-link` - COFF
|
||||
/// * `wasm-ld` - WebAssembly
|
||||
/// TODO https://github.com/ziglang/zig/issues/3257
|
||||
pub fn punt_to_lld(arena: Allocator, args: []const []const u8) error{OutOfMemory} {
|
||||
pub fn lldMain(
|
||||
alloc: Allocator,
|
||||
args: []const []const u8,
|
||||
can_exit_early: bool,
|
||||
) error{OutOfMemory}!u8 {
|
||||
if (!build_options.have_llvm)
|
||||
fatal("`zig {s}` unavailable: compiler built without LLVM extensions", .{args[0]});
|
||||
// Convert the args to the format LLD expects.
|
||||
// We subtract 1 to shave off the zig binary from args[0].
|
||||
const argv = try arena.allocSentinel(?[*:0]const u8, args.len - 1, null);
|
||||
for (args[1..]) |arg, i| {
|
||||
argv[i] = try arena.dupeZ(u8, arg); // TODO If there was an argsAllocZ we could avoid this allocation.
|
||||
|
||||
// Print a warning if lld is called multiple times in the same process,
|
||||
// since it may misbehave
|
||||
// https://github.com/ziglang/zig/issues/3825
|
||||
const CallCounter = struct {
|
||||
var count: usize = 0;
|
||||
};
|
||||
if (CallCounter.count == 1) { // Issue the warning on the first repeat call
|
||||
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)});
|
||||
}
|
||||
CallCounter.count += 1;
|
||||
|
||||
var arena_instance = std.heap.ArenaAllocator.init(alloc);
|
||||
defer arena_instance.deinit();
|
||||
const arena = arena_instance.allocator();
|
||||
|
||||
// Convert the args to the format llvm-ar expects.
|
||||
// We intentionally shave off the zig binary at args[0].
|
||||
const argv = try argsCopyZ(arena, args[1..]);
|
||||
const exit_code = rc: {
|
||||
const llvm = @import("codegen/llvm/bindings.zig");
|
||||
const argc = @intCast(c_int, argv.len);
|
||||
if (mem.eql(u8, args[1], "ld.lld")) {
|
||||
break :rc llvm.LinkELF(argc, argv.ptr, true);
|
||||
break :rc llvm.LinkELF(argc, argv.ptr, can_exit_early);
|
||||
} else if (mem.eql(u8, args[1], "lld-link")) {
|
||||
break :rc llvm.LinkCOFF(argc, argv.ptr, true);
|
||||
break :rc llvm.LinkCOFF(argc, argv.ptr, can_exit_early);
|
||||
} else if (mem.eql(u8, args[1], "wasm-ld")) {
|
||||
break :rc llvm.LinkWasm(argc, argv.ptr, true);
|
||||
break :rc llvm.LinkWasm(argc, argv.ptr, can_exit_early);
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
};
|
||||
process.exit(@bitCast(u8, @truncate(i8, exit_code)));
|
||||
return @bitCast(u8, @truncate(i8, exit_code));
|
||||
}
|
||||
|
||||
const clang_args = @import("clang_options.zig").list;
|
||||
|
||||
@@ -5,6 +5,7 @@ const path = std.fs.path;
|
||||
const assert = std.debug.assert;
|
||||
const log = std.log.scoped(.mingw);
|
||||
|
||||
const builtin = @import("builtin");
|
||||
const target_util = @import("target.zig");
|
||||
const Compilation = @import("Compilation.zig");
|
||||
const build_options = @import("build_options");
|
||||
@@ -367,39 +368,43 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
|
||||
Compilation.dump_argv(&args);
|
||||
}
|
||||
|
||||
const child = try std.ChildProcess.init(&args, arena);
|
||||
defer child.deinit();
|
||||
if (std.process.can_spawn) {
|
||||
const child = try std.ChildProcess.init(&args, arena);
|
||||
defer child.deinit();
|
||||
|
||||
child.stdin_behavior = .Ignore;
|
||||
child.stdout_behavior = .Pipe;
|
||||
child.stderr_behavior = .Pipe;
|
||||
child.stdin_behavior = .Ignore;
|
||||
child.stdout_behavior = .Pipe;
|
||||
child.stderr_behavior = .Pipe;
|
||||
|
||||
try child.spawn();
|
||||
try child.spawn();
|
||||
|
||||
const stderr_reader = child.stderr.?.reader();
|
||||
const stderr_reader = child.stderr.?.reader();
|
||||
|
||||
// TODO https://github.com/ziglang/zig/issues/6343
|
||||
const stderr = try stderr_reader.readAllAlloc(arena, 10 * 1024 * 1024);
|
||||
// TODO https://github.com/ziglang/zig/issues/6343
|
||||
const stderr = try stderr_reader.readAllAlloc(arena, 10 * 1024 * 1024);
|
||||
|
||||
const term = child.wait() catch |err| {
|
||||
// TODO surface a proper error here
|
||||
log.err("unable to spawn {s}: {s}", .{ args[0], @errorName(err) });
|
||||
return error.ClangPreprocessorFailed;
|
||||
};
|
||||
|
||||
switch (term) {
|
||||
.Exited => |code| {
|
||||
if (code != 0) {
|
||||
// TODO surface a proper error here
|
||||
log.err("clang exited with code {d} and stderr: {s}", .{ code, stderr });
|
||||
return error.ClangPreprocessorFailed;
|
||||
}
|
||||
},
|
||||
else => {
|
||||
const term = child.wait() catch |err| {
|
||||
// TODO surface a proper error here
|
||||
log.err("clang terminated unexpectedly with stderr: {s}", .{stderr});
|
||||
log.err("unable to spawn {s}: {s}", .{ args[0], @errorName(err) });
|
||||
return error.ClangPreprocessorFailed;
|
||||
},
|
||||
};
|
||||
switch (term) {
|
||||
.Exited => |code| {
|
||||
if (code != 0) {
|
||||
// TODO surface a proper error here
|
||||
log.err("clang exited with code {d} and stderr: {s}", .{ code, stderr });
|
||||
return error.ClangPreprocessorFailed;
|
||||
}
|
||||
},
|
||||
else => {
|
||||
// TODO surface a proper error here
|
||||
log.err("clang terminated unexpectedly with stderr: {s}", .{stderr});
|
||||
return error.ClangPreprocessorFailed;
|
||||
},
|
||||
}
|
||||
} else {
|
||||
log.err("unable to spawn {s}: spawning child process not supported on {s}", .{ args[0], @tagName(builtin.os.tag) });
|
||||
return error.ClangPreprocessorFailed;
|
||||
}
|
||||
|
||||
const lib_final_path = try comp.global_cache_directory.join(comp.gpa, &[_][]const u8{
|
||||
|
||||
11
src/test.zig
11
src/test.zig
@@ -730,6 +730,12 @@ pub const TestContext = struct {
|
||||
// * cannot handle updates
|
||||
// because of this we must spawn a child process rather than
|
||||
// using Compilation directly.
|
||||
|
||||
if (!std.process.can_spawn) {
|
||||
print("Unable to spawn child processes on {s}, skipping test.\n", .{@tagName(builtin.os.tag)});
|
||||
return; // Pass test.
|
||||
}
|
||||
|
||||
assert(case.updates.items.len == 1);
|
||||
const update = case.updates.items[0];
|
||||
try tmp.dir.writeFile(tmp_src_path, update.src);
|
||||
@@ -1104,6 +1110,11 @@ pub const TestContext = struct {
|
||||
}
|
||||
},
|
||||
.Execution => |expected_stdout| {
|
||||
if (!std.process.can_spawn) {
|
||||
print("Unable to spawn child processes on {s}, skipping test.\n", .{@tagName(builtin.os.tag)});
|
||||
return; // Pass test.
|
||||
}
|
||||
|
||||
update_node.setEstimatedTotalItems(4);
|
||||
|
||||
var argv = std.ArrayList([]const u8).init(allocator);
|
||||
|
||||
@@ -10,6 +10,8 @@ const fmt = std.fmt;
|
||||
const ArrayList = std.ArrayList;
|
||||
const Mode = std.builtin.Mode;
|
||||
const LibExeObjStep = build.LibExeObjStep;
|
||||
const Allocator = mem.Allocator;
|
||||
const ExecError = build.Builder.ExecError;
|
||||
|
||||
// Cases
|
||||
const compare_output = @import("compare_output.zig");
|
||||
@@ -722,6 +724,13 @@ pub const StackTracesContext = struct {
|
||||
|
||||
std.debug.print("Test {d}/{d} {s}...", .{ self.test_index + 1, self.context.test_index, self.name });
|
||||
|
||||
if (!std.process.can_spawn) {
|
||||
const cmd = try std.mem.join(b.allocator, " ", args.items);
|
||||
std.debug.print("the following command cannot be executed ({s} does not support spawning a child process):\n{s}", .{ @tagName(builtin.os.tag), cmd });
|
||||
b.allocator.free(cmd);
|
||||
return ExecError.ExecNotSupported;
|
||||
}
|
||||
|
||||
const child = std.ChildProcess.init(args.items, b.allocator) catch unreachable;
|
||||
defer child.deinit();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user