authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-05-17 21:00:11-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-05-25 18:54:35-07:00
log4aa8fa898de3847f3a0469edf4484f60c3ecf051
tree09cd8a615231a24c19e1d86040b84f5c93d444d2
parentd9881466382093f3c29ebe3f36a7d09d72407837

Maker.PkgConfig: fix regression when pkg-config not found

unless pkg_config == .force, this is supposed to be allowed

3 files changed, 59 insertions(+), 37 deletions(-)

lib/compiler/Maker/PkgConfig.zig+23-15
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1const std = @import("std");1const std = @import("std");
2const Io = std.Io;2const Io = std.Io;
3const mem = std.mem;3const mem = std.mem;
4const assert = std.debug.assert;
45
5const Maker = @import("../Maker.zig");6const Maker = @import("../Maker.zig");
6const Step = @import("Step.zig");7const Step = @import("Step.zig");
...@@ -92,14 +93,15 @@ pub fn run(...@@ -92,14 +93,15 @@ pub fn run(
92 };93 };
9394
94 const pkg_config_exe = getExe(graph);95 const pkg_config_exe = getExe(graph);
95 const captured = try step.captureChildProcess(maker, progress_node, &.{96 const stdout = try captureChildProcess(maker, step, .{
96 pkg_config_exe, pkg_name, "--cflags", "--libs",97 .argv = &.{ pkg_config_exe, pkg_name, "--cflags", "--libs" },
98 .progress_node = progress_node,
99 .allow_failure = !force,
97 });100 });
98 try step.handleChildProcessTerm(maker, captured.term);
99101
100 var zig_cflags: std.ArrayList([]const u8) = .empty;102 var zig_cflags: std.ArrayList([]const u8) = .empty;
101 var zig_libs: std.ArrayList([]const u8) = .empty;103 var zig_libs: std.ArrayList([]const u8) = .empty;
102 var arg_it = mem.tokenizeAny(u8, captured.stdout, " \r\n\t");104 var arg_it = mem.tokenizeAny(u8, stdout, " \r\n\t");
103105
104 while (arg_it.next()) |arg| {106 while (arg_it.next()) |arg| {
105 if (mem.eql(u8, arg, "-I")) {107 if (mem.eql(u8, arg, "-I")) {
...@@ -168,19 +170,14 @@ fn getList(maker: *Maker, step: *Step, progress_node: std.Progress.Node, force:...@@ -168,19 +170,14 @@ fn getList(maker: *Maker, step: *Step, progress_node: std.Progress.Node, force:
168 if (pc.list) |list| return list;170 if (pc.list) |list| return list;
169171
170 const pkg_config_exe = getExe(graph);172 const pkg_config_exe = getExe(graph);
171 const captured = try step.captureChildProcess(maker, progress_node, &.{ pkg_config_exe, "--list-all" });173 const stdout = try captureChildProcess(maker, step, .{
172 if (force) {174 .argv = &.{ pkg_config_exe, "--list-all" },
173 try step.handleChildProcessTerm(maker, captured.term);175 .progress_node = progress_node,
174 } else switch (captured.term) {176 .allow_failure = !force,
175 .exited => |code| if (code != 0) return error.PkgConfigUnavailable,177 });
176 else => {
177 try step.handleChildProcessTerm(maker, captured.term);
178 unreachable;
179 },
180 }
181178
182 var list: std.ArrayList(Pkg) = .empty;179 var list: std.ArrayList(Pkg) = .empty;
183 var line_it = mem.tokenizeAny(u8, captured.stdout, "\r\n");180 var line_it = mem.tokenizeAny(u8, stdout, "\r\n");
184 while (line_it.next()) |line| {181 while (line_it.next()) |line| {
185 if (mem.trim(u8, line, " \t").len == 0) continue;182 if (mem.trim(u8, line, " \t").len == 0) continue;
186 var tok_it = mem.tokenizeAny(u8, line, " \t");183 var tok_it = mem.tokenizeAny(u8, line, " \t");
...@@ -200,3 +197,14 @@ fn getList(maker: *Maker, step: *Step, progress_node: std.Progress.Node, force:...@@ -200,3 +197,14 @@ fn getList(maker: *Maker, step: *Step, progress_node: std.Progress.Node, force:
200 pc.list = result;197 pc.list = result;
201 return result;198 return result;
202}199}
200
201fn captureChildProcess(maker: *Maker, step: *Step, options: Step.CaptureChildProcessOptions) ![]const u8 {
202 const captured = step.captureChildProcess(maker, options) catch |err| switch (err) {
203 error.FileNotFound => return error.PkgConfigUnavailable,
204 else => |e| return e,
205 };
206 assert(step.result_failed_command != null);
207 if (captured.term.success()) return captured.stdout;
208 if (!options.allow_failure) return step.fail(maker, "{s} {f}", .{ options.argv[0], captured.term });
209 return error.PkgConfigUnavailable;
210}
lib/compiler/Maker/Step.zig+27-21
...@@ -329,13 +329,19 @@ pub fn reset(step: *Step, maker: *Maker) void {...@@ -329,13 +329,19 @@ pub fn reset(step: *Step, maker: *Maker) void {
329 step.result_error_bundle = std.zig.ErrorBundle.empty;329 step.result_error_bundle = std.zig.ErrorBundle.empty;
330}330}
331331
332/// Populates `s.result_failed_command`.332pub const CaptureChildProcessError = error{
333pub fn captureChildProcess(333 FileNotFound,
334 s: *Step,334} || ExtendedMakeError;
335 maker: *Maker,335
336 progress_node: std.Progress.Node,336pub const CaptureChildProcessOptions = struct {
337 argv: []const []const u8,337 argv: []const []const u8,
338) !std.process.RunResult {338 progress_node: std.Progress.Node = .none,
339 environ_map: ?*const std.process.Environ.Map = null,
340 allow_failure: bool = false,
341};
342
343/// Populates `s.result_failed_command`.
344pub fn captureChildProcess(s: *Step, maker: *Maker, options: CaptureChildProcessOptions) !std.process.RunResult {
339 const gpa = maker.gpa;345 const gpa = maker.gpa;
340 const graph = maker.graph;346 const graph = maker.graph;
341 const arena = graph.arena; // TODO stop leaking into process arena347 const arena = graph.arena; // TODO stop leaking into process arena
...@@ -343,20 +349,25 @@ pub fn captureChildProcess(...@@ -343,20 +349,25 @@ pub fn captureChildProcess(
343349
344 // If an error occurs, it's happened in this command:350 // If an error occurs, it's happened in this command:
345 assert(s.result_failed_command == null);351 assert(s.result_failed_command == null);
346 s.result_failed_command = try std.zig.allocPrintCmd(gpa, argv, .{});352 s.result_failed_command = try std.zig.allocPrintCmd(gpa, options.argv, .{});
347353
348 try handleChildProcUnsupported(s, maker);354 try handleChildProcUnsupported(s, maker);
349 try graph.handleVerbose(.inherit, null, argv);355 try graph.handleVerbose(.inherit, null, options.argv);
350356
351 const result = std.process.run(arena, io, .{357 const result = std.process.run(arena, io, .{
352 .argv = argv,358 .argv = options.argv,
353 .environ_map = &graph.environ_map,359 .environ_map = options.environ_map orelse &graph.environ_map,
354 .progress_node = progress_node,360 .progress_node = options.progress_node,
355 }) catch |err| return s.fail(maker, "failed to run {s}: {t}", .{ argv[0], err });361 }) catch |err| {
362 switch (err) {
363 error.OutOfMemory, error.Canceled => |e| return e,
364 error.FileNotFound => |e| if (options.allow_failure) return e,
365 else => {},
366 }
367 return s.fail(maker, "failed to run {s}: {t}", .{ options.argv[0], err });
368 };
356369
357 if (result.stderr.len > 0) {370 if (result.stderr.len > 0) try s.result_error_msgs.append(arena, result.stderr);
358 try s.result_error_msgs.append(arena, result.stderr);
359 }
360371
361 return result;372 return result;
362}373}
...@@ -679,12 +690,7 @@ pub inline fn handleChildProcUnsupported(s: *Step, maker: *Maker) FailError!void...@@ -679,12 +690,7 @@ pub inline fn handleChildProcUnsupported(s: *Step, maker: *Maker) FailError!void
679/// Asserts that the caller has already populated `s.result_failed_command`.690/// Asserts that the caller has already populated `s.result_failed_command`.
680pub fn handleChildProcessTerm(s: *Step, maker: *Maker, term: std.process.Child.Term) FailError!void {691pub fn handleChildProcessTerm(s: *Step, maker: *Maker, term: std.process.Child.Term) FailError!void {
681 assert(s.result_failed_command != null);692 assert(s.result_failed_command != null);
682 return switch (term) {693 if (!term.success()) return s.fail(maker, "process {f}", .{term});
683 .exited => |code| if (code != 0) s.fail(maker, "process exited with error code {d}", .{code}),
684 .signal => |sig| s.fail(maker, "process terminated with signal {t}", .{sig}),
685 .stopped => |sig| s.fail(maker, "process stopped with signal {t}", .{sig}),
686 .unknown => s.fail(maker, "process terminated unexpectedly", .{}),
687 };
688}694}
689695
690/// Prefer `cacheHitAndWatch` unless you already added watch inputs696/// Prefer `cacheHitAndWatch` unless you already added watch inputs
lib/compiler/Maker/Step/Fmt.zig+9-1
...@@ -43,7 +43,15 @@ pub fn make(...@@ -43,7 +43,15 @@ pub fn make(
43 argv.appendAssumeCapacity(try maker.resolveLazyPathIndexAbs(arena, lp, step_index));43 argv.appendAssumeCapacity(try maker.resolveLazyPathIndexAbs(arena, lp, step_index));
44 }44 }
4545
46 const run_result = try step.captureChildProcess(maker, progress_node, argv.items);46 const run_result = step.captureChildProcess(maker, .{
47 .progress_node = progress_node,
48 .argv = argv.items,
49 .allow_failure = false,
50 }) catch |err| switch (err) {
51 error.FileNotFound => unreachable,
52 else => |e| return e,
53 };
54
47 if (conf_fmt.flags.check) switch (run_result.term) {55 if (conf_fmt.flags.check) switch (run_result.term) {
48 .exited => |code| if (code != 0 and run_result.stdout.len != 0) {56 .exited => |code| if (code != 0 and run_result.stdout.len != 0) {
49 var it = std.mem.tokenizeScalar(u8, run_result.stdout, '\n');57 var it = std.mem.tokenizeScalar(u8, run_result.stdout, '\n');