diff --git a/lib/compiler/Maker/Step/Options.zig b/lib/compiler/Maker/Step/Options.zig index 9639dffa5bc9b6976bd19bbafff09c803f2fadf0..26ac62db41b7390e30e454738ce8a326abf06bf4 100644 --- a/lib/compiler/Maker/Step/Options.zig +++ b/lib/compiler/Maker/Step/Options.zig @@ -30,7 +30,7 @@ pub fn make( // generated zig file are observable by dependant steps. // Pathnames added to Options.args are assumed to be generated files whose // contents are also observable, while pathnames added to - // Options.args_untracked are treated as pure path string data with no + // Options.untracked_paths are treated as pure path string data with no // tracking of the path's state or contents. step.clearWatchInputs(maker); @@ -40,7 +40,7 @@ pub fn make( var args_bytes: std.ArrayList(u8) = .empty; - for (conf_options.args.slice) |arg| { + for (conf_options.files.slice) |arg| { const name = arg.name.slice(conf); const lazy_path = arg.path.get(conf); try step.addWatchInput(maker, arena, lazy_path); @@ -51,7 +51,20 @@ pub fn make( }); } - for (conf_options.args_untracked.slice) |arg| { + for (conf_options.directories.slice) |arg| { + const name = arg.name.slice(conf); + const lazy_path = arg.path.get(conf); + _ = try step.addDirectoryWatchInput(maker, lazy_path); + const arg_path = try maker.resolveLazyPath(arena, lazy_path, step_index); + _ = try man.addInputPath(arg_path, .{ + .handle = .{ .dir = null }, + }); + try args_bytes.print(arena, "pub const {f}: []const u8 = \"{f}\";\n", .{ + std.zig.fmtId(name), arg_path.fmtEscapeString(), + }); + } + + for (conf_options.untracked_paths.slice) |arg| { const name = arg.name.slice(conf); const lazy_path = arg.path.get(conf); const arg_path = try maker.resolveLazyPath(arena, lazy_path, step_index); diff --git a/lib/std/Build/Cache.zig b/lib/std/Build/Cache.zig index d0a7d93e16b1207429222ee77a96361a345290e4..003c892cf3ac3be18151a5f9a6713714203b7f49 100644 --- a/lib/std/Build/Cache.zig +++ b/lib/std/Build/Cache.zig @@ -514,6 +514,11 @@ pub const Manifest = struct { pub fn path(off: File.Offset, contents: []const u8) [:0]const u8 { return pathFallible(off, contents) catch unreachable; } + + pub fn pathOrDot(off: File.Offset, contents: []const u8) [:0]const u8 { + const p = pathFallible(off, contents) catch unreachable; + return if (p.len == 0) "." else p; + } }; /// Intentionally matches if the files are different only by flags other than prefix. @@ -1176,7 +1181,7 @@ pub const Manifest = struct { const io = cache.io; const input_file = file_off.get(contents); const parent_dir = cache.prefixes()[input_file.flags.prefix].handle; - const file_path = file_off.path(contents); + const file_path = file_off.pathOrDot(contents); const gpa = cache.gpa; if (input_path.have_digest) return; @@ -1352,7 +1357,7 @@ pub const Manifest = struct { const disk_file = file_off.get(disk_contents); const input_file = file_off.get(input_contents); const parent_dir = cache.prefixes()[disk_file.flags.prefix].handle; - const file_path = file_off.path(disk_contents); + const file_path = file_off.pathOrDot(disk_contents); assert(disk_file.flags == input_file.flags); @@ -1536,7 +1541,7 @@ pub const Manifest = struct { const gpa = cache.gpa; const io = cache.io; const parent_dir = cache.prefixes()[file.flags.prefix].handle; - const file_path = file_off.path(contents); + const file_path = file_off.pathOrDot(contents); if (file.flags.metadata_only) { const actual_stat = parent_dir.statFile(io, file_path, .{}) catch |err| switch (err) { diff --git a/lib/std/Build/Configuration.zig b/lib/std/Build/Configuration.zig index 9fb44c80d89336542fe91fdc7d58f9696a18b40f..a902374974e43dba5cac3bf2653b067d1f1c2956 100644 --- a/lib/std/Build/Configuration.zig +++ b/lib/std/Build/Configuration.zig @@ -1378,19 +1378,21 @@ pub const Step = extern struct { flags: @This().Flags, generated_file: GeneratedFileIndex, contents: Bytes, - args: Storage.FlagLengthPrefixedList(.flags, .args, Arg), - args_untracked: Storage.FlagLengthPrefixedList(.flags, .args_untracked, Arg), + files: Storage.FlagLengthPrefixedList(.flags, .files, NamedPath), + directories: Storage.FlagLengthPrefixedList(.flags, .directories, NamedPath), + untracked_paths: Storage.FlagLengthPrefixedList(.flags, .untracked_paths, NamedPath), - pub const Arg = extern struct { + pub const NamedPath = extern struct { name: String, path: LazyPath.Index, }; pub const Flags = packed struct(u32) { tag: Tag = .options, - args: bool, - args_untracked: bool, - _: u25 = 0, + files: bool, + directories: bool, + untracked_paths: bool, + _: u24 = 0, }; }; diff --git a/lib/std/Build/Serialize.zig b/lib/std/Build/Serialize.zig index b61cc49fd55885a4ca1d450eafcf0c3eae916be0..053cf86924dafc3c5e929b487f408d0b9c5482df 100644 --- a/lib/std/Build/Serialize.zig +++ b/lib/std/Build/Serialize.zig @@ -648,27 +648,35 @@ pub fn write(b: *std.Build, wc: *Configuration.Wip, writer: *std.Io.Writer) !voi .options => e: { const so: *Step.Options = @fieldParentPtr("step", step); - const args = try arena.alloc(Configuration.Step.Options.Arg, so.args.items.len); - for (args, so.args.items) |*dest, src| dest.* = .{ + const files = try arena.alloc(Configuration.Step.Options.NamedPath, so.files.items.len); + for (files, so.files.items) |*dest, src| dest.* = .{ .name = src.name, .path = try s.addLazyPath(src.path), }; - const args_untracked = try arena.alloc(Configuration.Step.Options.Arg, so.args_untracked.items.len); - for (args_untracked, so.args_untracked.items) |*dest, src| dest.* = .{ + const directories = try arena.alloc(Configuration.Step.Options.NamedPath, so.directories.items.len); + for (directories, so.directories.items) |*dest, src| dest.* = .{ + .name = src.name, + .path = try s.addLazyPath(src.path), + }; + + const untracked_paths = try arena.alloc(Configuration.Step.Options.NamedPath, so.untracked_paths.items.len); + for (untracked_paths, so.untracked_paths.items) |*dest, src| dest.* = .{ .name = src.name, .path = try s.addLazyPath(src.path), }; break :e try wc.addExtraErased(Configuration.Step.Options, .{ .flags = .{ - .args = so.args.items.len != 0, - .args_untracked = so.args_untracked.items.len != 0, + .files = so.files.items.len != 0, + .directories = so.directories.items.len != 0, + .untracked_paths = so.untracked_paths.items.len != 0, }, .generated_file = so.generated_file, .contents = try wc.addBytes(so.contents.items), - .args = .{ .slice = args }, - .args_untracked = .{ .slice = args_untracked }, + .files = .{ .slice = files }, + .directories = .{ .slice = directories }, + .untracked_paths = .{ .slice = untracked_paths }, }); }, })), diff --git a/lib/std/Build/Step/Options.zig b/lib/std/Build/Step/Options.zig index b616306dbe755cce5855295aead29935e4ff31cd..1d49670df9196608abf0b416525a3c394e1d7aa7 100644 --- a/lib/std/Build/Step/Options.zig +++ b/lib/std/Build/Step/Options.zig @@ -12,13 +12,14 @@ const Configuration = std.Build.Configuration; step: Step, generated_file: Configuration.GeneratedFileIndex, contents: std.ArrayList(u8) = .empty, -args: std.ArrayList(Arg) = .empty, -args_untracked: std.ArrayList(Arg) = .empty, +files: std.ArrayList(NamedPath) = .empty, +directories: std.ArrayList(NamedPath) = .empty, +untracked_paths: std.ArrayList(NamedPath) = .empty, encountered_types: std.StringHashMapUnmanaged(void), pub const base_tag: Step.Tag = .options; -pub const Arg = struct { +pub const NamedPath = struct { name: Configuration.String, path: LazyPath, }; @@ -421,28 +422,45 @@ fn printStructValue( } } -/// The added option has type `[]const u8` and value of the provided path. -/// This interface assumes the provided path is a generated file, and causes a -/// transitive dependency through Options on the file's contents. +/// The added option has type `[]const u8` and value of the provided file path. If the provided path is a +/// generated file, causes a transitive dependency on the file's contents. /// /// See also: +/// * `addOptionPathDirectory` /// * `addOptionPathUntracked` pub fn addOptionPath(options: *Options, name: []const u8, path: LazyPath) void { const graph = options.step.owner.graph; const arena = graph.arena; const wc = &graph.wip_configuration; - options.args.append(arena, .{ + options.files.append(arena, .{ .name = wc.addString(name) catch @panic("OOM"), .path = path.dupe(options.step.owner.graph), }) catch @panic("OOM"); path.addStepDependencies(&options.step); } -/// The added option has type `[]const u8` and value of the provided path. -/// This interface treats the resolved path string as pure data, meaning it -/// does not track anything about the meaning or contents of this path, and -/// therefore also does not create any related dependencies. +/// The added option has type `[]const u8` and value of the provided directory path. Causes a transitive +/// dependency through Options on the directory's contents. +/// +/// See also: +/// * `addOptionPath` +/// * `addOptionPathUntracked` +pub fn addOptionPathDirectory(options: *Options, name: []const u8, path: LazyPath) void { + const graph = options.step.owner.graph; + const arena = graph.arena; + const wc = &graph.wip_configuration; + + options.directories.append(arena, .{ + .name = wc.addString(name) catch @panic("OOM"), + .path = path.dupe(options.step.owner.graph), + }) catch @panic("OOM"); + path.addStepDependencies(&options.step); +} + +/// The added option has type `[]const u8` and value of the provided path. The resolved path is interpreted as +/// a string without tracking anything about the meaning or contents, and therefore may be a file, directory, +/// not exist, or even be an invalid path, and likewise does not create any file system or `Step` dependencies. /// /// See also: /// * `addOptionPath` @@ -451,7 +469,7 @@ pub fn addOptionPathUntracked(options: *Options, name: []const u8, path: LazyPat const arena = graph.arena; const wc = &graph.wip_configuration; - options.args_untracked.append(arena, .{ + options.untracked_paths.append(arena, .{ .name = wc.addString(name) catch @panic("OOM"), .path = path.dupe(options.step.owner.graph), }) catch @panic("OOM");