diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2022-02-07 00:31:17 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-02-07 00:31:17 -0500 |
| commit | 21135387fb7c2dbaf70a72f2c97341e9c1307045 (patch) | |
| tree | 5926ea2d182a76f80429776a5473202738c9b656 /lib/std | |
| parent | 069dd01ce4ced3cb9664e4f1e09be753cb3ed476 (diff) | |
| parent | 33fa29601921d88097a1ee3c0d92b93047a5186d (diff) | |
| download | zig-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/std')
| -rw-r--r-- | lib/std/build.zig | 38 | ||||
| -rw-r--r-- | lib/std/build/RunStep.zig | 9 | ||||
| -rw-r--r-- | lib/std/child_process.zig | 4 | ||||
| -rw-r--r-- | lib/std/process.zig | 8 |
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, }; |
