authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-05-17 18:17:49-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-05-25 18:54:35-07:00
log9709efce98289f393ae496921ba30123ea6123f5
treeb8f3e0f8fe1abfed0a50153d9f399b1c6e6b3748
parente2dbf6f48ffe09b01c701887b8eb77b326cfe7b2

std.Build.Step.Run: introduce Arg.cc_args

provides a way for the build system to append -target and -isystem/-I flags to a Run step. needed by translate-c package to avoid doing naughty stuff in the configure phase.

6 files changed, 132 insertions(+), 29 deletions(-)

BRANCH_TODO+3
......@@ -1,3 +1,4 @@
1* double check when targets get resolved (should be at configure time)
12* pass overridden pkg-dir to maker
23* finish migrating the rest of the build steps
34* inspect b4ffb402c082605c4b324e88120306fc8fb3cf32 diff and apply changes as needed (merge conflict)
......@@ -7,6 +8,7 @@
78* solve the TODOs added in this branch
89* get zig tests passing
910* test a bunch of third party projects / help people migrate
11 * tetris
1012
1113* get the target from the parent process instead
1214* [handle missing cache hits when chaining two run steps](https://codeberg.org/ziglang/zig/pulls/30762)
......@@ -80,6 +82,7 @@ closes #31397
8082
8183* `b.build_root` (Directory) -> `b.root` (Path)
8284* `ConfigHeader.Options`: `include_guard_override` -> `include_guard`
85* `LazyPath`: `getDisplayName` -> `format` or `fmt`
8386
8487### Perf Data Point: `zig build -h` (cached)
8588
lib/compiler/Maker/Step/Run.zig+3
......@@ -184,6 +184,9 @@ pub fn make(
184184 man.hash.addListOfBytes(run_args);
185185 }
186186 },
187 .cc_args => {
188 @panic("TODO Run make cc_args");
189 },
187190 }
188191 }
189192
lib/compiler/configurer.zig+46-1
......@@ -312,6 +312,8 @@ const Serialize = struct {
312312 .producer = true,
313313 .generated = false,
314314 .dep_file = false,
315 .target_query = false,
316 .link_libc = false,
315317 },
316318 .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null },
317319 .suffix = .{ .value = null },
......@@ -319,6 +321,7 @@ const Serialize = struct {
319321 .path = .{ .value = null },
320322 .producer = .{ .value = stepIndex(s, &a.artifact.step) },
321323 .generated = .{ .value = null },
324 .target_query = .{ .value = null },
322325 },
323326 .lazy_path => |a| .{
324327 .flags = .{
......@@ -330,6 +333,8 @@ const Serialize = struct {
330333 .producer = false,
331334 .generated = false,
332335 .dep_file = false,
336 .target_query = false,
337 .link_libc = false,
333338 },
334339 .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null },
335340 .suffix = .{ .value = null },
......@@ -337,6 +342,7 @@ const Serialize = struct {
337342 .path = .{ .value = try addLazyPath(s, a.lazy_path) },
338343 .producer = .{ .value = null },
339344 .generated = .{ .value = null },
345 .target_query = .{ .value = null },
340346 },
341347 .decorated_directory => |a| .{
342348 .flags = .{
......@@ -348,6 +354,8 @@ const Serialize = struct {
348354 .producer = false,
349355 .generated = false,
350356 .dep_file = false,
357 .target_query = false,
358 .link_libc = false,
351359 },
352360 .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null },
353361 .suffix = .{ .value = try addOptionalString(s, a.suffix) },
......@@ -355,6 +363,7 @@ const Serialize = struct {
355363 .path = .{ .value = try addLazyPath(s, a.lazy_path) },
356364 .producer = .{ .value = null },
357365 .generated = .{ .value = null },
366 .target_query = .{ .value = null },
358367 },
359368 .file_content => |a| .{
360369 .flags = .{
......@@ -366,6 +375,8 @@ const Serialize = struct {
366375 .producer = false,
367376 .generated = false,
368377 .dep_file = false,
378 .target_query = false,
379 .link_libc = false,
369380 },
370381 .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null },
371382 .suffix = .{ .value = null },
......@@ -373,6 +384,7 @@ const Serialize = struct {
373384 .path = .{ .value = try addLazyPath(s, a.lazy_path) },
374385 .producer = .{ .value = null },
375386 .generated = .{ .value = null },
387 .target_query = .{ .value = null },
376388 },
377389 .bytes => |a| .{
378390 .flags = .{
......@@ -384,6 +396,8 @@ const Serialize = struct {
384396 .producer = false,
385397 .generated = false,
386398 .dep_file = false,
399 .target_query = false,
400 .link_libc = false,
387401 },
388402 .prefix = .{ .value = try wc.addString(a) },
389403 .suffix = .{ .value = null },
......@@ -391,6 +405,7 @@ const Serialize = struct {
391405 .path = .{ .value = null },
392406 .producer = .{ .value = null },
393407 .generated = .{ .value = null },
408 .target_query = .{ .value = null },
394409 },
395410 .output_file, .output_file_dep => |a, tag| .{
396411 .flags = .{
......@@ -402,6 +417,8 @@ const Serialize = struct {
402417 .producer = false,
403418 .generated = true,
404419 .dep_file = tag == .output_file_dep,
420 .target_query = false,
421 .link_libc = false,
405422 },
406423 .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null },
407424 .suffix = .{ .value = null },
......@@ -409,6 +426,7 @@ const Serialize = struct {
409426 .path = .{ .value = null },
410427 .producer = .{ .value = null },
411428 .generated = .{ .value = a.generated_file },
429 .target_query = .{ .value = null },
412430 },
413431 .output_directory => |a| .{
414432 .flags = .{
......@@ -420,6 +438,8 @@ const Serialize = struct {
420438 .producer = false,
421439 .generated = true,
422440 .dep_file = false,
441 .target_query = false,
442 .link_libc = false,
423443 },
424444 .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null },
425445 .suffix = .{ .value = null },
......@@ -427,6 +447,7 @@ const Serialize = struct {
427447 .path = .{ .value = null },
428448 .producer = .{ .value = null },
429449 .generated = .{ .value = a.generated_file },
450 .target_query = .{ .value = null },
430451 },
431452 .passthru => .{
432453 .flags = .{
......@@ -438,6 +459,8 @@ const Serialize = struct {
438459 .producer = false,
439460 .generated = false,
440461 .dep_file = false,
462 .target_query = false,
463 .link_libc = false,
441464 },
442465 .prefix = .{ .value = null },
443466 .suffix = .{ .value = null },
......@@ -445,6 +468,28 @@ const Serialize = struct {
445468 .path = .{ .value = null },
446469 .producer = .{ .value = null },
447470 .generated = .{ .value = null },
471 .target_query = .{ .value = null },
472 },
473 .cc_args => |a| .{
474 .flags = .{
475 .tag = .cc_args,
476 .prefix = false,
477 .suffix = false,
478 .basename = false,
479 .path = false,
480 .producer = false,
481 .generated = false,
482 .dep_file = false,
483 .target_query = a.target_query != .none,
484 .link_libc = a.link_libc,
485 },
486 .prefix = .{ .value = null },
487 .suffix = .{ .value = null },
488 .basename = .{ .value = null },
489 .path = .{ .value = null },
490 .producer = .{ .value = null },
491 .generated = .{ .value = null },
492 .target_query = .{ .value = a.target_query.unwrap() },
448493 },
449494 })));
450495 }
......@@ -1234,7 +1279,7 @@ fn addOptionalResolvedTarget(
12341279) !Configuration.ResolvedTarget.OptionalIndex {
12351280 const resolved_target = optional_resolved_target orelse return .none;
12361281 return @enumFromInt(try wc.addDeduped(@as(Configuration.ResolvedTarget, .{
1237 .query = try wc.addTargetQuery(resolved_target.query),
1282 .query = try wc.addTargetQuery(&resolved_target.query),
12381283 .result = try wc.addTarget(resolved_target.result),
12391284 })));
12401285}
lib/std/Build.zig+50-25
......@@ -129,13 +129,17 @@ pub const Graph = struct {
129129 ///
130130 /// Use of this function indicates a dependency on the host system.
131131 pub fn cwdRelativePath(graph: *Graph, sub_path: []const u8) LazyPath {
132 return @This().path(graph, .cwd, sub_path);
133 }
134
135 /// A path whose components and contents are known at some point during
136 /// `Step` resolution, relative to the provided base directory.
137 pub fn path(graph: *Graph, base: Configuration.Path.Base, sub_path: []const u8) LazyPath {
132138 const wc = &graph.wip_configuration;
133 return .{
134 .relative = .{
135 .base = .cwd,
136 .sub_path = wc.addString(sub_path) catch @panic("OOM"),
137 },
138 };
139 return .{ .relative = .{
140 .base = base,
141 .sub_path = wc.addString(sub_path) catch @panic("OOM"),
142 } };
139143 }
140144
141145 /// Allocates using the global process arena, failing the build on
......@@ -780,8 +784,10 @@ pub const AssemblyOptions = struct {
780784/// it available to other packages which depend on this one.
781785/// `createModule` can be used instead to create a private module.
782786pub fn addModule(b: *Build, name: []const u8, options: Module.CreateOptions) *Module {
787 const graph = b.graph;
788 const arena = graph.arena;
783789 const module = Module.create(b, options);
784 b.modules.put(b.graph.arena, b.dupe(name), module) catch @panic("OOM");
790 b.modules.put(arena, graph.dupeString(name), module) catch @panic("OOM");
785791 return module;
786792}
787793
......@@ -913,13 +919,15 @@ pub fn addWriteFile(b: *Build, file_path: []const u8, data: []const u8) *Step.Wr
913919}
914920
915921pub fn addNamedWriteFiles(b: *Build, name: []const u8) *Step.WriteFile {
922 const graph = b.graph;
916923 const wf = Step.WriteFile.create(b);
917 b.named_writefiles.put(b.graph.arena, b.dupe(name), wf) catch @panic("OOM");
924 b.named_writefiles.put(graph.arena, graph.dupeString(name), wf) catch @panic("OOM");
918925 return wf;
919926}
920927
921928pub fn addNamedLazyPath(b: *Build, name: []const u8, lp: LazyPath) void {
922 b.named_lazy_paths.put(b.graph.arena, b.dupe(name), lp.dupe(b)) catch @panic("OOM");
929 const graph = b.graph;
930 b.named_lazy_paths.put(graph.arena, graph.dupeString(name), lp.dupe(graph)) catch @panic("OOM");
923931}
924932
925933/// Creates a step for mutating files inside a temporary directory created lazily
......@@ -1183,16 +1191,18 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw
11831191}
11841192
11851193pub fn step(b: *Build, name: []const u8, description: []const u8) *Step {
1186 const step_info = b.allocator.create(Step.TopLevel) catch @panic("OOM");
1194 const graph = b.graph;
1195 const arena = graph.arena;
1196 const step_info = arena.create(Step.TopLevel) catch @panic("OOM");
11871197 step_info.* = .{
11881198 .step = .init(.{
11891199 .tag = .top_level,
11901200 .name = name,
11911201 .owner = b,
11921202 }),
1193 .description = b.dupe(description),
1203 .description = graph.dupeString(description),
11941204 };
1195 const gop = b.top_level_steps.getOrPut(b.allocator, name) catch @panic("OOM");
1205 const gop = b.top_level_steps.getOrPut(arena, name) catch @panic("OOM");
11961206 if (gop.found_existing) panic("A top-level step with name \"{s}\" already exists", .{name});
11971207
11981208 gop.key_ptr.* = step_info.step.name;
......@@ -1302,6 +1312,9 @@ pub fn parseTargetQuery(options: std.Target.Query.ParseOptions) error{ParseFaile
13021312
13031313/// Exposes standard `zig build` options for choosing a target.
13041314pub fn standardTargetOptionsQueryOnly(b: *Build, args: StandardTargetOptionsArgs) Target.Query {
1315 const graph = b.graph;
1316 const arena = graph.arena;
1317
13051318 const maybe_triple = b.option(
13061319 []const u8,
13071320 "target",
......@@ -1350,20 +1363,22 @@ pub fn standardTargetOptionsQueryOnly(b: *Build, args: StandardTargetOptionsArgs
13501363
13511364 for (whitelist) |q| {
13521365 log.info("allowed target: -Dtarget={s} -Dcpu={s}", .{
1353 q.zigTriple(b.allocator) catch @panic("OOM"),
1354 q.serializeCpuAlloc(b.allocator) catch @panic("OOM"),
1366 q.zigTriple(arena) catch @panic("OOM"),
1367 q.serializeCpuAlloc(arena) catch @panic("OOM"),
13551368 });
13561369 }
13571370 log.err("chosen target '{s}' does not match one of the allowed targets", .{
1358 selected_target.zigTriple(b.allocator) catch @panic("OOM"),
1371 selected_target.zigTriple(arena) catch @panic("OOM"),
13591372 });
13601373 b.markInvalidUserInput();
13611374 return args.default_target;
13621375}
13631376
13641377pub fn addUserInputOption(b: *Build, name_raw: []const u8, value_raw: []const u8) error{OutOfMemory}!bool {
1365 const name = b.dupe(name_raw);
1366 const value = b.dupe(value_raw);
1378 const graph = b.graph;
1379 const arena = graph.arena;
1380 const name = graph.dupeString(name_raw);
1381 const value = graph.dupeString(value_raw);
13671382 const gop = try b.user_input_options.getOrPut(name);
13681383 if (!gop.found_existing) {
13691384 gop.value_ptr.* = UserInputOption{
......@@ -1378,7 +1393,7 @@ pub fn addUserInputOption(b: *Build, name_raw: []const u8, value_raw: []const u8
13781393 switch (gop.value_ptr.value) {
13791394 .scalar => |s| {
13801395 // turn it into a list
1381 var list = std.array_list.Managed([]const u8).init(b.allocator);
1396 var list = std.array_list.Managed([]const u8).init(arena);
13821397 try list.append(s);
13831398 try list.append(value);
13841399 try b.user_input_options.put(name, .{
......@@ -1608,15 +1623,21 @@ pub fn pathList(b: *Build, sub_paths: []const []const u8) []const LazyPath {
16081623}
16091624
16101625pub fn pathJoin(b: *Build, paths: []const []const u8) []u8 {
1611 return fs.path.join(b.allocator, paths) catch @panic("OOM");
1626 const graph = b.graph;
1627 const arena = graph.arena;
1628 return fs.path.join(arena, paths) catch @panic("OOM");
16121629}
16131630
16141631pub fn pathResolve(b: *Build, paths: []const []const u8) []u8 {
1615 return fs.path.resolve(b.allocator, paths) catch @panic("OOM");
1632 const graph = b.graph;
1633 const arena = graph.arena;
1634 return fs.path.resolve(arena, paths) catch @panic("OOM");
16161635}
16171636
16181637pub fn fmt(b: *Build, comptime format: []const u8, args: anytype) []u8 {
1619 return std.fmt.allocPrint(b.allocator, format, args) catch @panic("OOM");
1638 const graph = b.graph;
1639 const arena = graph.arena;
1640 return std.fmt.allocPrint(arena, format, args) catch @panic("OOM");
16201641}
16211642
16221643/// Creates an anonymous `Step` that searches for an executable on the host that
......@@ -2264,7 +2285,9 @@ pub const LazyPath = union(enum) {
22642285 }
22652286
22662287 pub fn path(lazy_path: LazyPath, b: *Build, sub_path: []const u8) LazyPath {
2267 return lazy_path.join(b.allocator, sub_path) catch @panic("OOM");
2288 const graph = b.graph;
2289 const arena = graph.arena;
2290 return lazy_path.join(arena, sub_path) catch @panic("OOM");
22682291 }
22692292
22702293 pub fn join(lazy_path: LazyPath, arena: Allocator, sub_path: []const u8) Allocator.Error!LazyPath {
......@@ -2460,7 +2483,9 @@ pub fn systemIntegrationOption(
24602483 name: []const u8,
24612484 config: SystemIntegrationOptionConfig,
24622485) bool {
2463 const gop = b.graph.system_integration_options.getOrPut(b.allocator, name) catch @panic("OOM");
2486 const graph = b.graph;
2487 const arena = graph.arena;
2488 const gop = graph.system_integration_options.getOrPut(arena, name) catch @panic("OOM");
24642489 if (gop.found_existing) switch (gop.value_ptr.*) {
24652490 .user_disabled => {
24662491 gop.value_ptr.* = .declared_disabled;
......@@ -2473,8 +2498,8 @@ pub fn systemIntegrationOption(
24732498 .declared_disabled => return false,
24742499 .declared_enabled => return true,
24752500 } else {
2476 gop.key_ptr.* = b.dupe(name);
2477 if (config.default orelse b.graph.system_package_mode) {
2501 gop.key_ptr.* = graph.dupeString(name);
2502 if (config.default orelse graph.system_package_mode) {
24782503 gop.value_ptr.* = .declared_enabled;
24792504 return true;
24802505 } else {
lib/std/Build/Configuration.zig+7-3
......@@ -230,7 +230,7 @@ pub const Wip = struct {
230230 return addString(wip, writer.buffered());
231231 }
232232
233 pub fn addTargetQuery(wip: *Wip, q: std.Target.Query) !TargetQuery.OptionalIndex {
233 pub fn addTargetQuery(wip: *Wip, q: *const std.Target.Query) !TargetQuery.OptionalIndex {
234234 if (q.isNative()) return .none;
235235 const gpa = wip.gpa;
236236 const cpu_name: ?String = switch (q.cpu_model) {
......@@ -575,6 +575,7 @@ pub const Step = extern struct {
575575 /// Always a compile step.
576576 producer: Storage.FlagOptional(.flags, .producer, Step.Index),
577577 generated: Storage.FlagOptional(.flags, .generated, GeneratedFileIndex),
578 target_query: Storage.FlagOptional(.flags, .target_query, TargetQuery.Index),
578579
579580 pub const Flags = packed struct(u32) {
580581 tag: Arg.Tag,
......@@ -585,10 +586,12 @@ pub const Step = extern struct {
585586 producer: bool,
586587 generated: bool,
587588 dep_file: bool,
588 _: u22 = 0,
589 target_query: bool,
590 link_libc: bool,
591 _: u19 = 0,
589592 };
590593
591 pub const Tag = enum(u3) {
594 pub const Tag = enum(u4) {
592595 artifact,
593596 /// `path` contains the file.
594597 path_file,
......@@ -599,6 +602,7 @@ pub const Step = extern struct {
599602 output_file,
600603 output_directory,
601604 passthru,
605 cc_args,
602606 };
603607
604608 pub const Index = IndexType(@This());
lib/std/Build/Step/Run.zig+23
......@@ -143,6 +143,13 @@ pub const Arg = union(enum) {
143143 output_directory: *Output,
144144 /// The arguments passed after "--" on the "zig build" CLI.
145145 passthru,
146 /// Adds standard "-isystem" and "-iframework" arguments corresponding to the libc of the target.
147 cc_args: CcArgs,
148};
149
150pub const CcArgs = struct {
151 link_libc: bool,
152 target_query: Configuration.TargetQuery.OptionalIndex,
146153};
147154
148155pub const PrefixedArtifact = struct {
......@@ -529,6 +536,22 @@ pub fn addPassthruArgs(run: *Run) void {
529536 run.argv.append(arena, .passthru) catch @panic("OOM");
530537}
531538
539pub const AddCcArgs = struct {
540 link_libc: bool = false,
541 target_query: ?*const std.Target.Query = null,
542};
543
544/// Appends C compiler flags for the target and for including libc.
545pub fn addCcArgs(run: *Run, options: AddCcArgs) void {
546 const graph = run.step.owner.graph;
547 const arena = graph.arena;
548 const wc = &graph.wip_configuration;
549 run.argv.append(arena, .{ .cc_args = .{
550 .link_libc = options.link_libc,
551 .target_query = if (options.target_query) |q| wc.addTargetQuery(q) catch @panic("OOM") else .none,
552 } }) catch @panic("OOM");
553}
554
532555pub fn setStdIn(run: *Run, stdin: StdIn) void {
533556 switch (stdin) {
534557 .lazy_path => |lazy_path| lazy_path.addStepDependencies(&run.step),