authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-09-18 22:02:45+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-09-18 22:02:45+02:00
log3f9fe9e28f83119f8ecf2fdafcd12967417634e9
tree0027863d7bf1aa63d959eb39082e74a1adaf68b4
parent80fe9b2b7fc981166cbfe98165e17dad6107cb34
parentc106e2759578e787e5be235c8f6b227623ff2c3b

Merge pull request 'std.Build.Step.Options: add addOptionPathDirectory' (#36876) from std.Build.Step.Options into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/36876

5 files changed, 78 insertions(+), 32 deletions(-)

lib/compiler/Maker/Step/Options.zig+16-3
......@@ -30,7 +30,7 @@ pub fn make(
3030 // generated zig file are observable by dependant steps.
3131 // Pathnames added to Options.args are assumed to be generated files whose
3232 // contents are also observable, while pathnames added to
33 // Options.args_untracked are treated as pure path string data with no
33 // Options.untracked_paths are treated as pure path string data with no
3434 // tracking of the path's state or contents.
3535
3636 step.clearWatchInputs(maker);
......@@ -40,7 +40,7 @@ pub fn make(
4040
4141 var args_bytes: std.ArrayList(u8) = .empty;
4242
43 for (conf_options.args.slice) |arg| {
43 for (conf_options.files.slice) |arg| {
4444 const name = arg.name.slice(conf);
4545 const lazy_path = arg.path.get(conf);
4646 try step.addWatchInput(maker, arena, lazy_path);
......@@ -51,7 +51,20 @@ pub fn make(
5151 });
5252 }
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| {
5568 const name = arg.name.slice(conf);
5669 const lazy_path = arg.path.get(conf);
5770 const arg_path = try maker.resolveLazyPath(arena, lazy_path, step_index);
lib/std/Build/Cache.zig+8-3
......@@ -514,6 +514,11 @@ pub const Manifest = struct {
514514 pub fn path(off: File.Offset, contents: []const u8) [:0]const u8 {
515515 return pathFallible(off, contents) catch unreachable;
516516 }
517
518 pub fn pathOrDot(off: File.Offset, contents: []const u8) [:0]const u8 {
519 const p = pathFallible(off, contents) catch unreachable;
520 return if (p.len == 0) "." else p;
521 }
517522 };
518523
519524 /// Intentionally matches if the files are different only by flags other than prefix.
......@@ -1176,7 +1181,7 @@ pub const Manifest = struct {
11761181 const io = cache.io;
11771182 const input_file = file_off.get(contents);
11781183 const parent_dir = cache.prefixes()[input_file.flags.prefix].handle;
1179 const file_path = file_off.path(contents);
1184 const file_path = file_off.pathOrDot(contents);
11801185 const gpa = cache.gpa;
11811186
11821187 if (input_path.have_digest) return;
......@@ -1352,7 +1357,7 @@ pub const Manifest = struct {
13521357 const disk_file = file_off.get(disk_contents);
13531358 const input_file = file_off.get(input_contents);
13541359 const parent_dir = cache.prefixes()[disk_file.flags.prefix].handle;
1355 const file_path = file_off.path(disk_contents);
1360 const file_path = file_off.pathOrDot(disk_contents);
13561361
13571362 assert(disk_file.flags == input_file.flags);
13581363
......@@ -1536,7 +1541,7 @@ pub const Manifest = struct {
15361541 const gpa = cache.gpa;
15371542 const io = cache.io;
15381543 const parent_dir = cache.prefixes()[file.flags.prefix].handle;
1539 const file_path = file_off.path(contents);
1544 const file_path = file_off.pathOrDot(contents);
15401545
15411546 if (file.flags.metadata_only) {
15421547 const actual_stat = parent_dir.statFile(io, file_path, .{}) catch |err| switch (err) {
lib/std/Build/Configuration.zig+8-6
......@@ -1378,19 +1378,21 @@ pub const Step = extern struct {
13781378 flags: @This().Flags,
13791379 generated_file: GeneratedFileIndex,
13801380 contents: Bytes,
1381 args: Storage.FlagLengthPrefixedList(.flags, .args, Arg),
1382 args_untracked: Storage.FlagLengthPrefixedList(.flags, .args_untracked, Arg),
1381 files: Storage.FlagLengthPrefixedList(.flags, .files, NamedPath),
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 {
13851386 name: String,
13861387 path: LazyPath.Index,
13871388 };
13881389
13891390 pub const Flags = packed struct(u32) {
13901391 tag: Tag = .options,
1391 args: bool,
1392 args_untracked: bool,
1393 _: u25 = 0,
1392 files: bool,
1393 directories: bool,
1394 untracked_paths: bool,
1395 _: u24 = 0,
13941396 };
13951397 };
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
648648 .options => e: {
649649 const so: *Step.Options = @fieldParentPtr("step", step);
650650
651 const args = try arena.alloc(Configuration.Step.Options.Arg, so.args.items.len);
652 for (args, so.args.items) |*dest, src| dest.* = .{
651 const files = try arena.alloc(Configuration.Step.Options.NamedPath, so.files.items.len);
652 for (files, so.files.items) |*dest, src| dest.* = .{
653653 .name = src.name,
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.* = .{
657 const directories = try arena.alloc(Configuration.Step.Options.NamedPath, so.directories.items.len);
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.* = .{
659665 .name = src.name,
660666 .path = try s.addLazyPath(src.path),
661667 };
662668
663669 break :e try wc.addExtraErased(Configuration.Step.Options, .{
664670 .flags = .{
665 .args = so.args.items.len != 0,
666 .args_untracked = so.args_untracked.items.len != 0,
671 .files = so.files.items.len != 0,
672 .directories = so.directories.items.len != 0,
673 .untracked_paths = so.untracked_paths.items.len != 0,
667674 },
668675 .generated_file = so.generated_file,
669676 .contents = try wc.addBytes(so.contents.items),
670 .args = .{ .slice = args },
671 .args_untracked = .{ .slice = args_untracked },
677 .files = .{ .slice = files },
678 .directories = .{ .slice = directories },
679 .untracked_paths = .{ .slice = untracked_paths },
672680 });
673681 },
674682 })),
lib/std/Build/Step/Options.zig+30-12
......@@ -12,13 +12,14 @@ const Configuration = std.Build.Configuration;
1212step: Step,
1313generated_file: Configuration.GeneratedFileIndex,
1414contents: std.ArrayList(u8) = .empty,
15args: std.ArrayList(Arg) = .empty,
16args_untracked: std.ArrayList(Arg) = .empty,
15files: std.ArrayList(NamedPath) = .empty,
16directories: std.ArrayList(NamedPath) = .empty,
17untracked_paths: std.ArrayList(NamedPath) = .empty,
1718encountered_types: std.StringHashMapUnmanaged(void),
1819
1920pub const base_tag: Step.Tag = .options;
2021
21pub const Arg = struct {
22pub const NamedPath = struct {
2223 name: Configuration.String,
2324 path: LazyPath,
2425};
......@@ -421,28 +422,45 @@ fn printStructValue(
421422 }
422423}
423424
424/// 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.
425/// The added option has type `[]const u8` and value of the provided file path. If the provided path is a
426/// generated file, causes a transitive dependency on the file's contents.
427427///
428428/// See also:
429/// * `addOptionPathDirectory`
429430/// * `addOptionPathUntracked`
430431pub fn addOptionPath(options: *Options, name: []const u8, path: LazyPath) void {
431432 const graph = options.step.owner.graph;
432433 const arena = graph.arena;
433434 const wc = &graph.wip_configuration;
434435
435 options.args.append(arena, .{
436 options.files.append(arena, .{
436437 .name = wc.addString(name) catch @panic("OOM"),
437438 .path = path.dupe(options.step.owner.graph),
438439 }) catch @panic("OOM");
439440 path.addStepDependencies(&options.step);
440441}
441442
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.
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, .{
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
461/// The added option has type `[]const u8` and value of the provided path. The resolved path is interpreted as
462/// a string without tracking anything about the meaning or contents, and therefore may be a file, directory,
463/// not exist, or even be an invalid path, and likewise does not create any file system or `Step` dependencies.
446464///
447465/// See also:
448466/// * `addOptionPath`
......@@ -451,7 +469,7 @@ pub fn addOptionPathUntracked(options: *Options, name: []const u8, path: LazyPat
451469 const arena = graph.arena;
452470 const wc = &graph.wip_configuration;
453471
454 options.args_untracked.append(arena, .{
472 options.untracked_paths.append(arena, .{
455473 .name = wc.addString(name) catch @panic("OOM"),
456474 .path = path.dupe(options.step.owner.graph),
457475 }) catch @panic("OOM");