aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2022-02-07 00:31:17 -0500
committerGitHub <noreply@github.com>2022-02-07 00:31:17 -0500
commit21135387fb7c2dbaf70a72f2c97341e9c1307045 (patch)
tree5926ea2d182a76f80429776a5473202738c9b656 /src
parent069dd01ce4ced3cb9664e4f1e09be753cb3ed476 (diff)
parent33fa29601921d88097a1ee3c0d92b93047a5186d (diff)
downloadzig-21135387fb7c2dbaf70a72f2c97341e9c1307045.tar.gz
zig-21135387fb7c2dbaf70a72f2c97341e9c1307045.zip
Merge pull request #10782 from topolarity/gate-child-processes
Avoid depending on child process execution when not supported by host OS
Diffstat (limited to 'src')
-rw-r--r--src/Compilation.zig101
-rw-r--r--src/ThreadPool.zig3
-rw-r--r--src/libc_installation.zig4
-rw-r--r--src/link/Coff.zig116
-rw-r--r--src/link/Elf.zig106
-rw-r--r--src/link/Wasm.zig108
-rw-r--r--src/main.zig166
-rw-r--r--src/mingw.zig57
-rw-r--r--src/test.zig11
9 files changed, 383 insertions, 289 deletions
diff --git a/src/Compilation.zig b/src/Compilation.zig
index 21a0c6fe58..f07a7c9dd7 100644
--- a/src/Compilation.zig
+++ b/src/Compilation.zig
@@ -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(),
- }
- } else {
- child.stdin_behavior = .Ignore;
- child.stdout_behavior = .Ignore;
- child.stderr_behavior = .Pipe;
+ 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();
+ try child.spawn();
- const stderr_reader = child.stderr.?.reader();
+ const stderr_reader = child.stderr.?.reader();
- const stderr = try stderr_reader.readAllAlloc(arena, 10 * 1024 * 1024);
+ 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) });
- };
+ 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", .{});
- },
+ 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 {
+ 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);
}
}
diff --git a/src/ThreadPool.zig b/src/ThreadPool.zig
index 4f9d8dc015..813d67db66 100644
--- a/src/ThreadPool.zig
+++ b/src/ThreadPool.zig
@@ -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();
diff --git a/src/libc_installation.zig b/src/libc_installation.zig
index 4cd43c7567..fe1a2b2ca5 100644
--- a/src/libc_installation.zig
+++ b/src/libc_installation.zig
@@ -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;
}
diff --git a/src/link/Coff.zig b/src/link/Coff.zig
index 894d5dd8f7..bc5837fe47 100644
--- a/src/link/Coff.zig
+++ b/src/link/Coff.zig
@@ -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 (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(),
+ 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;
+
+ 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;
+ }
}
}
}
diff --git a/src/link/Elf.zig b/src/link/Elf.zig
index 37afd68c82..afaf41a2f9 100644
--- a/src/link/Elf.zig
+++ b/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(),
- }
- } else {
- child.stdin_behavior = .Ignore;
- child.stdout_behavior = .Ignore;
- child.stderr_behavior = .Pipe;
+ 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();
+ try child.spawn();
- const stderr = try child.stderr.?.reader().readAllAlloc(arena, 10 * 1024 * 1024);
+ 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;
- };
+ 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;
- },
- }
+ 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});
+ if (stderr.len != 0) {
+ log.warn("unexpected LLD stderr:\n{s}", .{stderr});
+ }
+ }
+ } else {
+ 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;
+ }
}
}
}
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig
index b047e4b68a..e6988e9232 100644
--- a/src/link/Wasm.zig
+++ b/src/link/Wasm.zig
@@ -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 (comp.clang_passthrough_mode) {
- child.stdin_behavior = .Inherit;
- child.stdout_behavior = .Inherit;
- child.stderr_behavior = .Inherit;
+ 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;
+
+ 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;
- 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;
+ try child.spawn();
- try child.spawn();
+ const stderr = try child.stderr.?.reader().readAllAlloc(arena, 10 * 1024 * 1024);
- 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;
+ };
- 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;
+ },
+ }
- 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});
+ }
}
-
- if (stderr.len != 0) {
- log.warn("unexpected LLD stderr:\n{s}", .{stderr});
+ } else {
+ 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;
+ }
}
}
}
diff --git a/src/main.zig b/src/main.zig
index bbdb948c90..3f38fd1f78 100644
--- a/src/main.zig
+++ b/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,41 +3556,36 @@ 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();
-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(' ');
+ 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 });
}
- try cmd.appendSlice(argv[argv.len - 1]);
- return cmd.toOwnedSlice();
}
fn readSourceFileToEndAlloc(
@@ -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;
diff --git a/src/mingw.zig b/src/mingw.zig
index f555634459..84ec0795f1 100644
--- a/src/mingw.zig
+++ b/src/mingw.zig
@@ -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{
diff --git a/src/test.zig b/src/test.zig
index e02ea04f1c..b73e11d7f5 100644
--- a/src/test.zig
+++ b/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);