authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-09-17 21:04:22-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-09-17 21:04:22-07:00
logc106e2759578e787e5be235c8f6b227623ff2c3b
tree35589932ad26dbc7f28b4e8db6346395863cd5fe
parentb27aacf8207bab54f62bfe78b25d05a0a758d99d

std.Build.Step.Options: add addOptionPathDirectory

Now, when adding an option that is a file path, one must explicitly choose between: * `addOptionPath` (must be a file) * `addOptionPathDirectory` (must be a directory) * `addOptionPathUntracked` (opt out of dependency tracking) closes #35766

4 files changed, 67 insertions(+), 25 deletions(-)

lib/compiler/Maker/Step/Options.zig+16-3
...@@ -30,7 +30,7 @@ pub fn make(...@@ -30,7 +30,7 @@ pub fn make(
30 // generated zig file are observable by dependant steps.30 // generated zig file are observable by dependant steps.
31 // Pathnames added to Options.args are assumed to be generated files whose31 // Pathnames added to Options.args are assumed to be generated files whose
32 // contents are also observable, while pathnames added to32 // contents are also observable, while pathnames added to
33 // Options.args_untracked are treated as pure path string data with no33 // Options.untracked_paths are treated as pure path string data with no
34 // tracking of the path's state or contents.34 // tracking of the path's state or contents.
3535
36 step.clearWatchInputs(maker);36 step.clearWatchInputs(maker);
...@@ -40,7 +40,7 @@ pub fn make(...@@ -40,7 +40,7 @@ pub fn make(
4040
41 var args_bytes: std.ArrayList(u8) = .empty;41 var args_bytes: std.ArrayList(u8) = .empty;
4242
43 for (conf_options.args.slice) |arg| {43 for (conf_options.files.slice) |arg| {
44 const name = arg.name.slice(conf);44 const name = arg.name.slice(conf);
45 const lazy_path = arg.path.get(conf);45 const lazy_path = arg.path.get(conf);
46 try step.addWatchInput(maker, arena, lazy_path);46 try step.addWatchInput(maker, arena, lazy_path);
...@@ -51,7 +51,20 @@ pub fn make(...@@ -51,7 +51,20 @@ pub fn make(
51 });51 });
52 }52 }
5353
54 for (conf_options.args_untracked.slice) |arg| {54 for (conf_options.directories.slice) |arg| {
55 const name = arg.name.slice(conf);
56 const lazy_path = arg.path.get(conf);
57 _ = try step.addDirectoryWatchInput(maker, lazy_path);
58 const arg_path = try maker.resolveLazyPath(arena, lazy_path, step_index);
59 _ = try man.addInputPath(arg_path, .{
60 .handle = .{ .dir = null },
61 });
62 try args_bytes.print(arena, "pub const {f}: []const u8 = \"{f}\";\n", .{
63 std.zig.fmtId(name), arg_path.fmtEscapeString(),
64 });
65 }
66
67 for (conf_options.untracked_paths.slice) |arg| {
55 const name = arg.name.slice(conf);68 const name = arg.name.slice(conf);
56 const lazy_path = arg.path.get(conf);69 const lazy_path = arg.path.get(conf);
57 const arg_path = try maker.resolveLazyPath(arena, lazy_path, step_index);70 const arg_path = try maker.resolveLazyPath(arena, lazy_path, step_index);
lib/std/Build/Configuration.zig+8-6
...@@ -1378,19 +1378,21 @@ pub const Step = extern struct {...@@ -1378,19 +1378,21 @@ pub const Step = extern struct {
1378 flags: @This().Flags,1378 flags: @This().Flags,
1379 generated_file: GeneratedFileIndex,1379 generated_file: GeneratedFileIndex,
1380 contents: Bytes,1380 contents: Bytes,
1381 args: Storage.FlagLengthPrefixedList(.flags, .args, Arg),1381 files: Storage.FlagLengthPrefixedList(.flags, .files, NamedPath),
1382 args_untracked: Storage.FlagLengthPrefixedList(.flags, .args_untracked, Arg),1382 directories: Storage.FlagLengthPrefixedList(.flags, .directories, NamedPath),
1383 untracked_paths: Storage.FlagLengthPrefixedList(.flags, .untracked_paths, NamedPath),
13831384
1384 pub const Arg = extern struct {1385 pub const NamedPath = extern struct {
1385 name: String,1386 name: String,
1386 path: LazyPath.Index,1387 path: LazyPath.Index,
1387 };1388 };
13881389
1389 pub const Flags = packed struct(u32) {1390 pub const Flags = packed struct(u32) {
1390 tag: Tag = .options,1391 tag: Tag = .options,
1391 args: bool,1392 files: bool,
1392 args_untracked: bool,1393 directories: bool,
1393 _: u25 = 0,1394 untracked_paths: bool,
1395 _: u24 = 0,
1394 };1396 };
1395 };1397 };
13961398
lib/std/Build/Serialize.zig+16-8
...@@ -648,27 +648,35 @@ pub fn write(b: *std.Build, wc: *Configuration.Wip, writer: *std.Io.Writer) !voi...@@ -648,27 +648,35 @@ pub fn write(b: *std.Build, wc: *Configuration.Wip, writer: *std.Io.Writer) !voi
648 .options => e: {648 .options => e: {
649 const so: *Step.Options = @fieldParentPtr("step", step);649 const so: *Step.Options = @fieldParentPtr("step", step);
650650
651 const args = try arena.alloc(Configuration.Step.Options.Arg, so.args.items.len);651 const files = try arena.alloc(Configuration.Step.Options.NamedPath, so.files.items.len);
652 for (args, so.args.items) |*dest, src| dest.* = .{652 for (files, so.files.items) |*dest, src| dest.* = .{
653 .name = src.name,653 .name = src.name,
654 .path = try s.addLazyPath(src.path),654 .path = try s.addLazyPath(src.path),
655 };655 };
656656
657 const args_untracked = try arena.alloc(Configuration.Step.Options.Arg, so.args_untracked.items.len);657 const directories = try arena.alloc(Configuration.Step.Options.NamedPath, so.directories.items.len);
658 for (args_untracked, so.args_untracked.items) |*dest, src| dest.* = .{658 for (directories, so.directories.items) |*dest, src| dest.* = .{
659 .name = src.name,
660 .path = try s.addLazyPath(src.path),
661 };
662
663 const untracked_paths = try arena.alloc(Configuration.Step.Options.NamedPath, so.untracked_paths.items.len);
664 for (untracked_paths, so.untracked_paths.items) |*dest, src| dest.* = .{
659 .name = src.name,665 .name = src.name,
660 .path = try s.addLazyPath(src.path),666 .path = try s.addLazyPath(src.path),
661 };667 };
662668
663 break :e try wc.addExtraErased(Configuration.Step.Options, .{669 break :e try wc.addExtraErased(Configuration.Step.Options, .{
664 .flags = .{670 .flags = .{
665 .args = so.args.items.len != 0,671 .files = so.files.items.len != 0,
666 .args_untracked = so.args_untracked.items.len != 0,672 .directories = so.directories.items.len != 0,
673 .untracked_paths = so.untracked_paths.items.len != 0,
667 },674 },
668 .generated_file = so.generated_file,675 .generated_file = so.generated_file,
669 .contents = try wc.addBytes(so.contents.items),676 .contents = try wc.addBytes(so.contents.items),
670 .args = .{ .slice = args },677 .files = .{ .slice = files },
671 .args_untracked = .{ .slice = args_untracked },678 .directories = .{ .slice = directories },
679 .untracked_paths = .{ .slice = untracked_paths },
672 });680 });
673 },681 },
674 })),682 })),
lib/std/Build/Step/Options.zig+27-8
...@@ -12,13 +12,14 @@ const Configuration = std.Build.Configuration;...@@ -12,13 +12,14 @@ const Configuration = std.Build.Configuration;
12step: Step,12step: Step,
13generated_file: Configuration.GeneratedFileIndex,13generated_file: Configuration.GeneratedFileIndex,
14contents: std.ArrayList(u8) = .empty,14contents: std.ArrayList(u8) = .empty,
15args: std.ArrayList(Arg) = .empty,15files: std.ArrayList(NamedPath) = .empty,
16args_untracked: std.ArrayList(Arg) = .empty,16directories: std.ArrayList(NamedPath) = .empty,
17untracked_paths: std.ArrayList(NamedPath) = .empty,
17encountered_types: std.StringHashMapUnmanaged(void),18encountered_types: std.StringHashMapUnmanaged(void),
1819
19pub const base_tag: Step.Tag = .options;20pub const base_tag: Step.Tag = .options;
2021
21pub const Arg = struct {22pub const NamedPath = struct {
22 name: Configuration.String,23 name: Configuration.String,
23 path: LazyPath,24 path: LazyPath,
24};25};
...@@ -421,18 +422,36 @@ fn printStructValue(...@@ -421,18 +422,36 @@ fn printStructValue(
421 }422 }
422}423}
423424
424/// The added option has type `[]const u8` and value of the provided path.425/// The added option has type `[]const u8` and value of the provided file path. If the provided path is a
425/// This interface assumes the provided path is a generated file, and causes a426/// generated file, causes a transitive dependency on the file's contents.
426/// transitive dependency through Options on the file's contents.
427///427///
428/// See also:428/// See also:
429/// * `addOptionPathDirectory`
429/// * `addOptionPathUntracked`430/// * `addOptionPathUntracked`
430pub fn addOptionPath(options: *Options, name: []const u8, path: LazyPath) void {431pub fn addOptionPath(options: *Options, name: []const u8, path: LazyPath) void {
431 const graph = options.step.owner.graph;432 const graph = options.step.owner.graph;
432 const arena = graph.arena;433 const arena = graph.arena;
433 const wc = &graph.wip_configuration;434 const wc = &graph.wip_configuration;
434435
435 options.args.append(arena, .{436 options.files.append(arena, .{
437 .name = wc.addString(name) catch @panic("OOM"),
438 .path = path.dupe(options.step.owner.graph),
439 }) catch @panic("OOM");
440 path.addStepDependencies(&options.step);
441}
442
443/// The added option has type `[]const u8` and value of the provided directory path. Causes a transitive
444/// dependency through Options on the directory's contents.
445///
446/// See also:
447/// * `addOptionPath`
448/// * `addOptionPathUntracked`
449pub fn addOptionPathDirectory(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.directories.append(arena, .{
436 .name = wc.addString(name) catch @panic("OOM"),455 .name = wc.addString(name) catch @panic("OOM"),
437 .path = path.dupe(options.step.owner.graph),456 .path = path.dupe(options.step.owner.graph),
438 }) catch @panic("OOM");457 }) catch @panic("OOM");
...@@ -450,7 +469,7 @@ pub fn addOptionPathUntracked(options: *Options, name: []const u8, path: LazyPat...@@ -450,7 +469,7 @@ pub fn addOptionPathUntracked(options: *Options, name: []const u8, path: LazyPat
450 const arena = graph.arena;469 const arena = graph.arena;
451 const wc = &graph.wip_configuration;470 const wc = &graph.wip_configuration;
452471
453 options.args_untracked.append(arena, .{472 options.untracked_paths.append(arena, .{
454 .name = wc.addString(name) catch @panic("OOM"),473 .name = wc.addString(name) catch @panic("OOM"),
455 .path = path.dupe(options.step.owner.graph),474 .path = path.dupe(options.step.owner.graph),
456 }) catch @panic("OOM");475 }) catch @panic("OOM");