authorgravatar for bblack@wikimedia.orgBrandon Black <bblack@wikimedia.org> 2026-05-29 13:14:49-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-09-18 04:31:03+02:00
log5ede6a167eef1835f6fb6c768a82d977269dafe5
tree63caa43d668a66ef5049921f67146127d93b9041
parentaeb55668ba2b23ffc99524ff28b25cec2b0fc356

Build.Step.Options: addOptionPathUntracked

This interface is like `addOptionPath`, but does not assume that the provided `LazyPath` represents a generated file, and does not set up any further dependencies on whatever the path represents. This supports use-cases like setting an `.install_prefix` -based default directory path option for the application to use as a fallback when the user does not provide an override. Example: options.addOptionPathUntracked( "DefaultConfigDir", b.graph.path( .install_prefix, b.pathJoin(&.{ "etc", "myapp" }), ), );

4 files changed, 50 insertions(+), 3 deletions(-)

lib/compiler/Maker/Step/Options.zig+14-2
......@@ -27,8 +27,11 @@ pub fn make(
2727 const contents = conf_options.contents.slice(conf);
2828
2929 // This step operates under the assumption that all contents of the
30 // generated zig file are observable by dependant steps, as well as the
31 // contents of files added via Options.Arg.
30 // generated zig file are observable by dependant steps.
31 // Pathnames added to Options.args are assumed to be generated files whose
32 // contents are also observable, while pathnames added to
33 // Options.args_untracked are treated as pure path string data with no
34 // tracking of the path's state or contents.
3235
3336 step.clearWatchInputs(maker);
3437
......@@ -48,6 +51,15 @@ pub fn make(
4851 });
4952 }
5053
54 for (conf_options.args_untracked.slice) |arg| {
55 const name = arg.name.slice(conf);
56 const lazy_path = arg.path.get(conf);
57 const arg_path = try maker.resolveLazyPath(arena, lazy_path, step_index);
58 try args_bytes.print(arena, "pub const {f}: []const u8 = \"{f}\";\n", .{
59 std.zig.fmtId(name), arg_path.fmtEscapeString(),
60 });
61 }
62
5163 man.hash.addBytes(contents);
5264 man.hash.addBytes(args_bytes.items);
5365
lib/std/Build/Configuration.zig+3-1
......@@ -1379,6 +1379,7 @@ pub const Step = extern struct {
13791379 generated_file: GeneratedFileIndex,
13801380 contents: Bytes,
13811381 args: Storage.FlagLengthPrefixedList(.flags, .args, Arg),
1382 args_untracked: Storage.FlagLengthPrefixedList(.flags, .args_untracked, Arg),
13821383
13831384 pub const Arg = extern struct {
13841385 name: String,
......@@ -1388,7 +1389,8 @@ pub const Step = extern struct {
13881389 pub const Flags = packed struct(u32) {
13891390 tag: Tag = .options,
13901391 args: bool,
1391 _: u26 = 0,
1392 args_untracked: bool,
1393 _: u25 = 0,
13921394 };
13931395 };
13941396
lib/std/Build/Serialize.zig+8
......@@ -654,13 +654,21 @@ pub fn write(b: *std.Build, wc: *Configuration.Wip, writer: *std.Io.Writer) !voi
654654 .path = try s.addLazyPath(src.path),
655655 };
656656
657 const args_untracked = try arena.alloc(Configuration.Step.Options.Arg, so.args_untracked.items.len);
658 for (args_untracked, so.args_untracked.items) |*dest, src| dest.* = .{
659 .name = src.name,
660 .path = try s.addLazyPath(src.path),
661 };
662
657663 break :e try wc.addExtraErased(Configuration.Step.Options, .{
658664 .flags = .{
659665 .args = so.args.items.len != 0,
666 .args_untracked = so.args_untracked.items.len != 0,
660667 },
661668 .generated_file = so.generated_file,
662669 .contents = try wc.addBytes(so.contents.items),
663670 .args = .{ .slice = args },
671 .args_untracked = .{ .slice = args_untracked },
664672 });
665673 },
666674 })),
lib/std/Build/Step/Options.zig+25
......@@ -13,6 +13,7 @@ step: Step,
1313generated_file: Configuration.GeneratedFileIndex,
1414contents: std.ArrayList(u8) = .empty,
1515args: std.ArrayList(Arg) = .empty,
16args_untracked: std.ArrayList(Arg) = .empty,
1617encountered_types: std.StringHashMapUnmanaged(void),
1718
1819pub const base_tag: Step.Tag = .options;
......@@ -421,6 +422,11 @@ fn printStructValue(
421422}
422423
423424/// The added option has type `[]const u8` and value of the provided path.
425/// This interface assumes the provided path is a generated file, and causes a
426/// transitive dependency through Options on the file's contents.
427///
428/// See also:
429/// * `addOptionPathUntracked`
424430pub fn addOptionPath(options: *Options, name: []const u8, path: LazyPath) void {
425431 const graph = options.step.owner.graph;
426432 const arena = graph.arena;
......@@ -433,6 +439,25 @@ pub fn addOptionPath(options: *Options, name: []const u8, path: LazyPath) void {
433439 path.addStepDependencies(&options.step);
434440}
435441
442/// The added option has type `[]const u8` and value of the provided path.
443/// This interface treats the resolved path string as pure data, meaning it
444/// does not track anything about the meaning or contents of this path, and
445/// therefore also does not create any related dependencies.
446///
447/// See also:
448/// * `addOptionPath`
449pub fn addOptionPathUntracked(options: *Options, name: []const u8, path: LazyPath) void {
450 const graph = options.step.owner.graph;
451 const arena = graph.arena;
452 const wc = &graph.wip_configuration;
453
454 options.args_untracked.append(arena, .{
455 .name = wc.addString(name) catch @panic("OOM"),
456 .path = path.dupe(options.step.owner.graph),
457 }) catch @panic("OOM");
458 path.addStepDependencies(&options.step);
459}
460
436461pub fn createModule(options: *Options) *std.Build.Module {
437462 return options.step.owner.createModule(.{
438463 .root_source_file = options.getOutput(),