aboutsummaryrefslogtreecommitdiff
path: root/lib
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 /lib
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 'lib')
-rw-r--r--lib/std/build.zig38
-rw-r--r--lib/std/build/RunStep.zig9
-rw-r--r--lib/std/child_process.zig4
-rw-r--r--lib/std/process.zig8
4 files changed, 54 insertions, 5 deletions
diff --git a/lib/std/build.zig b/lib/std/build.zig
index 05f36f5714..fcaa115ccb 100644
--- a/lib/std/build.zig
+++ b/lib/std/build.zig
@@ -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,
diff --git a/lib/std/build/RunStep.zig b/lib/std/build/RunStep.zig
index 4e18d5d738..e8544921d9 100644
--- a/lib/std/build/RunStep.zig
+++ b/lib/std/build/RunStep.zig
@@ -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();
diff --git a/lib/std/child_process.zig b/lib/std/child_process.zig
index 7808dcd1e5..4cbe840bba 100644
--- a/lib/std/child_process.zig
+++ b/lib/std/child_process.zig
@@ -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 {
diff --git a/lib/std/process.zig b/lib/std/process.zig
index 699c994abf..c0f11b22ce 100644
--- a/lib/std/process.zig
+++ b/lib/std/process.zig
@@ -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,
};