commit 4aa8fa898de3847f3a0469edf4484f60c3ecf051 (tree)
parent d9881466382093f3c29ebe3f36a7d09d72407837
Author: Andrew Kelley <andrew@ziglang.org>
Date: Sun, 17 May 2026 21:00:11 -0700
Maker.PkgConfig: fix regression when pkg-config not found
unless pkg_config == .force, this is supposed to be allowed
Diffstat:
3 files changed, 59 insertions(+), 37 deletions(-)
diff --git a/lib/compiler/Maker/PkgConfig.zig b/lib/compiler/Maker/PkgConfig.zig
@@ -1,6 +1,7 @@
const std = @import("std");
const Io = std.Io;
const mem = std.mem;
+const assert = std.debug.assert;
const Maker = @import("../Maker.zig");
const Step = @import("Step.zig");
@@ -92,14 +93,15 @@ pub fn run(
};
const pkg_config_exe = getExe(graph);
- const captured = try step.captureChildProcess(maker, progress_node, &.{
- pkg_config_exe, pkg_name, "--cflags", "--libs",
+ const stdout = try captureChildProcess(maker, step, .{
+ .argv = &.{ pkg_config_exe, pkg_name, "--cflags", "--libs" },
+ .progress_node = progress_node,
+ .allow_failure = !force,
});
- try step.handleChildProcessTerm(maker, captured.term);
var zig_cflags: std.ArrayList([]const u8) = .empty;
var zig_libs: std.ArrayList([]const u8) = .empty;
- var arg_it = mem.tokenizeAny(u8, captured.stdout, " \r\n\t");
+ var arg_it = mem.tokenizeAny(u8, stdout, " \r\n\t");
while (arg_it.next()) |arg| {
if (mem.eql(u8, arg, "-I")) {
@@ -168,19 +170,14 @@ fn getList(maker: *Maker, step: *Step, progress_node: std.Progress.Node, force:
if (pc.list) |list| return list;
const pkg_config_exe = getExe(graph);
- const captured = try step.captureChildProcess(maker, progress_node, &.{ pkg_config_exe, "--list-all" });
- if (force) {
- try step.handleChildProcessTerm(maker, captured.term);
- } else switch (captured.term) {
- .exited => |code| if (code != 0) return error.PkgConfigUnavailable,
- else => {
- try step.handleChildProcessTerm(maker, captured.term);
- unreachable;
- },
- }
+ const stdout = try captureChildProcess(maker, step, .{
+ .argv = &.{ pkg_config_exe, "--list-all" },
+ .progress_node = progress_node,
+ .allow_failure = !force,
+ });
var list: std.ArrayList(Pkg) = .empty;
- var line_it = mem.tokenizeAny(u8, captured.stdout, "\r\n");
+ var line_it = mem.tokenizeAny(u8, stdout, "\r\n");
while (line_it.next()) |line| {
if (mem.trim(u8, line, " \t").len == 0) continue;
var tok_it = mem.tokenizeAny(u8, line, " \t");
@@ -200,3 +197,14 @@ fn getList(maker: *Maker, step: *Step, progress_node: std.Progress.Node, force:
pc.list = result;
return result;
}
+
+fn captureChildProcess(maker: *Maker, step: *Step, options: Step.CaptureChildProcessOptions) ![]const u8 {
+ const captured = step.captureChildProcess(maker, options) catch |err| switch (err) {
+ error.FileNotFound => return error.PkgConfigUnavailable,
+ else => |e| return e,
+ };
+ assert(step.result_failed_command != null);
+ if (captured.term.success()) return captured.stdout;
+ if (!options.allow_failure) return step.fail(maker, "{s} {f}", .{ options.argv[0], captured.term });
+ return error.PkgConfigUnavailable;
+}
diff --git a/lib/compiler/Maker/Step.zig b/lib/compiler/Maker/Step.zig
@@ -329,13 +329,19 @@ pub fn reset(step: *Step, maker: *Maker) void {
step.result_error_bundle = std.zig.ErrorBundle.empty;
}
-/// Populates `s.result_failed_command`.
-pub fn captureChildProcess(
- s: *Step,
- maker: *Maker,
- progress_node: std.Progress.Node,
+pub const CaptureChildProcessError = error{
+ FileNotFound,
+} || ExtendedMakeError;
+
+pub const CaptureChildProcessOptions = struct {
argv: []const []const u8,
-) !std.process.RunResult {
+ progress_node: std.Progress.Node = .none,
+ environ_map: ?*const std.process.Environ.Map = null,
+ allow_failure: bool = false,
+};
+
+/// Populates `s.result_failed_command`.
+pub fn captureChildProcess(s: *Step, maker: *Maker, options: CaptureChildProcessOptions) !std.process.RunResult {
const gpa = maker.gpa;
const graph = maker.graph;
const arena = graph.arena; // TODO stop leaking into process arena
@@ -343,20 +349,25 @@ pub fn captureChildProcess(
// If an error occurs, it's happened in this command:
assert(s.result_failed_command == null);
- s.result_failed_command = try std.zig.allocPrintCmd(gpa, argv, .{});
+ s.result_failed_command = try std.zig.allocPrintCmd(gpa, options.argv, .{});
try handleChildProcUnsupported(s, maker);
- try graph.handleVerbose(.inherit, null, argv);
+ try graph.handleVerbose(.inherit, null, options.argv);
const result = std.process.run(arena, io, .{
- .argv = argv,
- .environ_map = &graph.environ_map,
- .progress_node = progress_node,
- }) catch |err| return s.fail(maker, "failed to run {s}: {t}", .{ argv[0], err });
+ .argv = options.argv,
+ .environ_map = options.environ_map orelse &graph.environ_map,
+ .progress_node = options.progress_node,
+ }) catch |err| {
+ switch (err) {
+ error.OutOfMemory, error.Canceled => |e| return e,
+ error.FileNotFound => |e| if (options.allow_failure) return e,
+ else => {},
+ }
+ return s.fail(maker, "failed to run {s}: {t}", .{ options.argv[0], err });
+ };
- if (result.stderr.len > 0) {
- try s.result_error_msgs.append(arena, result.stderr);
- }
+ if (result.stderr.len > 0) try s.result_error_msgs.append(arena, result.stderr);
return result;
}
@@ -679,12 +690,7 @@ pub inline fn handleChildProcUnsupported(s: *Step, maker: *Maker) FailError!void
/// Asserts that the caller has already populated `s.result_failed_command`.
pub fn handleChildProcessTerm(s: *Step, maker: *Maker, term: std.process.Child.Term) FailError!void {
assert(s.result_failed_command != null);
- return switch (term) {
- .exited => |code| if (code != 0) s.fail(maker, "process exited with error code {d}", .{code}),
- .signal => |sig| s.fail(maker, "process terminated with signal {t}", .{sig}),
- .stopped => |sig| s.fail(maker, "process stopped with signal {t}", .{sig}),
- .unknown => s.fail(maker, "process terminated unexpectedly", .{}),
- };
+ if (!term.success()) return s.fail(maker, "process {f}", .{term});
}
/// Prefer `cacheHitAndWatch` unless you already added watch inputs
diff --git a/lib/compiler/Maker/Step/Fmt.zig b/lib/compiler/Maker/Step/Fmt.zig
@@ -43,7 +43,15 @@ pub fn make(
argv.appendAssumeCapacity(try maker.resolveLazyPathIndexAbs(arena, lp, step_index));
}
- const run_result = try step.captureChildProcess(maker, progress_node, argv.items);
+ const run_result = step.captureChildProcess(maker, .{
+ .progress_node = progress_node,
+ .argv = argv.items,
+ .allow_failure = false,
+ }) catch |err| switch (err) {
+ error.FileNotFound => unreachable,
+ else => |e| return e,
+ };
+
if (conf_fmt.flags.check) switch (run_result.term) {
.exited => |code| if (code != 0 and run_result.stdout.len != 0) {
var it = std.mem.tokenizeScalar(u8, run_result.stdout, '\n');