zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

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:
Mlib/compiler/Maker/PkgConfig.zig | 38+++++++++++++++++++++++---------------
Mlib/compiler/Maker/Step.zig | 48+++++++++++++++++++++++++++---------------------
Mlib/compiler/Maker/Step/Fmt.zig | 10+++++++++-
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');