From fa26566867cddbb0cd067cbc1d41bd41e68002a1 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 1 May 2026 18:26:19 -0700 Subject: [PATCH] configurer: get InstallDir and Options steps compiling --- BRANCH_TODO | 1 - build.zig | 13 +- lib/compiler/Maker/Step/InstallDir.zig | 66 +++++++ lib/compiler/Maker/Step/InstallFile.zig | 1 + lib/compiler/Maker/Step/Options.zig | 84 ++++++++ lib/std/Build.zig | 14 +- lib/std/Build/Configuration.zig | 23 ++- lib/std/Build/Step/InstallDir.zig | 75 ++----- lib/std/Build/Step/InstallFile.zig | 17 +- lib/std/Build/Step/Options.zig | 248 +----------------------- 10 files changed, 215 insertions(+), 327 deletions(-) create mode 100644 lib/compiler/Maker/Step/InstallDir.zig create mode 100644 lib/compiler/Maker/Step/Options.zig diff --git a/BRANCH_TODO b/BRANCH_TODO index 1b5f0d8e3d..10c0b23bae 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -26,7 +26,6 @@ - but artifact install steps also add paths for dyn libs on windows * no more "artifact arg" to run step. if you want to run the post-install binary, get the lazy path from the install step. -* -D options which are files need to be accounted for in the configure cache ## Release Notes diff --git a/build.zig b/build.zig index fcbf1a46dc..1b24707483 100644 --- a/build.zig +++ b/build.zig @@ -208,7 +208,8 @@ pub fn build(b: *std.Build) !void { .single_threaded = single_threaded, }); exe.pie = pie; - exe.entitlements = entitlements; + // https://codeberg.org/ziglang/zig/issues/32173 + exe.entitlements = if (entitlements) |p| .{ .cwd_relative = p } else null; exe.use_new_linker = b.option(bool, "new-linker", "Use the new linker"); const use_llvm = b.option(bool, "use-llvm", "Use the llvm backend"); @@ -1498,11 +1499,13 @@ fn generateLangRef(b: *std.Build) std.Build.LazyPath { }), }); - var dir = b.build_root.handle.openDir(io, "doc/langref", .{ .iterate = true }) catch |err| { - std.debug.panic("unable to open '{f}doc/langref' directory: {s}", .{ - b.build_root, @errorName(err), - }); + const langref_path: std.Build.Cache.Path = .{ + .root_dir = b.build_root, + .sub_path = "doc/langref", }; + + var dir = langref_path.root_dir.handle.openDir(io, langref_path.sub_path, .{ .iterate = true }) catch |err| + std.debug.panic("unable to open directory {f}: {t}", .{ langref_path, err }); defer dir.close(io); var wf = b.addWriteFiles(); diff --git a/lib/compiler/Maker/Step/InstallDir.zig b/lib/compiler/Maker/Step/InstallDir.zig new file mode 100644 index 0000000000..fb5f288c68 --- /dev/null +++ b/lib/compiler/Maker/Step/InstallDir.zig @@ -0,0 +1,66 @@ +const InstallDir = @This(); + +const std = @import("std"); +const Configuration = std.Build.Configuration; + +const Step = @import("../Step.zig"); +const Maker = @import("../../Maker.zig"); + +pub fn make( + install_dir: *InstallDir, + step_index: Configuration.Step.Index, + maker: *Maker, + progress_node: std.Progress.Node, +) !void { + const graph = maker.graph; + const arena = maker.graph.arena; // TODO don't leak into process arena + const io = graph.io; + const step = maker.stepByIndex(step_index); + + step.clearWatchInputs(); + const dest_prefix = b.getInstallPath(install_dir.options.install_dir, install_dir.options.install_subdir); + const src_dir_path = install_dir.options.source_dir.getPath3(b, step); + const need_derived_inputs = try step.addDirectoryWatchInput(install_dir.options.source_dir); + var src_dir = src_dir_path.root_dir.handle.openDir(io, src_dir_path.subPathOrDot(), .{ .iterate = true }) catch |err| { + return step.fail("unable to open source directory '{f}': {t}", .{ src_dir_path, err }); + }; + defer src_dir.close(io); + var it = try src_dir.walk(arena); + var all_cached = true; + next_entry: while (try it.next(io)) |entry| { + for (install_dir.options.exclude_extensions) |ext| { + if (std.mem.endsWith(u8, entry.path, ext)) continue :next_entry; + } + if (install_dir.options.include_extensions) |incs| { + for (incs) |inc| { + if (std.mem.endsWith(u8, entry.path, inc)) break; + } else { + continue :next_entry; + } + } + + const src_path = try install_dir.options.source_dir.join(arena, entry.path); + const dest_path = b.pathJoin(&.{ dest_prefix, entry.path }); + switch (entry.kind) { + .directory => { + if (need_derived_inputs) _ = try step.addDirectoryWatchInput(src_path); + const p = try step.installDir(dest_path); + all_cached = all_cached and p == .existed; + }, + .file => { + for (install_dir.options.blank_extensions) |ext| { + if (std.mem.endsWith(u8, entry.path, ext)) { + try b.truncateFile(dest_path); + continue :next_entry; + } + } + + const p = try step.installFile(src_path, dest_path); + all_cached = all_cached and p == .fresh; + }, + else => continue, + } + } + + step.result_cached = all_cached; +} diff --git a/lib/compiler/Maker/Step/InstallFile.zig b/lib/compiler/Maker/Step/InstallFile.zig index 439c793c6f..eb9547f44e 100644 --- a/lib/compiler/Maker/Step/InstallFile.zig +++ b/lib/compiler/Maker/Step/InstallFile.zig @@ -19,6 +19,7 @@ pub fn make( const conf = &maker.scanned_config.configuration; const conf_step = step_index.ptr(conf); const conf_if = conf_step.extended.get(conf.extra).install_file; + try step.singleUnchangingWatchInput(maker, arena, conf_if.source.get(conf)); const p = try maker.installLazyPathSub(arena, conf_if.source, conf_if.dest_dir, conf_if.dest_sub_path.slice(conf), step_index); step.result_cached = p == .fresh; diff --git a/lib/compiler/Maker/Step/Options.zig b/lib/compiler/Maker/Step/Options.zig new file mode 100644 index 0000000000..dcdc49a4a0 --- /dev/null +++ b/lib/compiler/Maker/Step/Options.zig @@ -0,0 +1,84 @@ +const Options = @This(); + +const std = @import("std"); +const Configuration = std.Build.Configuration; + +const Step = @import("../Step.zig"); +const Maker = @import("../../Maker.zig"); + + +fn make( + options: *Options, + step_index: Configuration.Step.Index, + maker: *Maker, + progress_node: std.Progress.Node, +) !void { + // This step completes so quickly that no progress reporting is necessary. + _ = progress_node; + + const graph = maker.graph; + const step = maker.stepByIndex(step_index); + const io = graph.io; + const cache_root = graph.local_cache_root; + + for (options.args.items) |arg| { + options.addOption( + []const u8, + arg.name, + arg.path.getPath2(b, step), + ); + } + if (!step.inputs.populated()) for (options.args.items) |arg| { + try step.addWatchInput(arg.path); + }; + + const basename = "options.zig"; + + // Hash contents to file name. + var hash = graph.cache.hash; + // Random bytes to make unique. Refresh this with new random bytes when + // implementation is modified in a non-backwards-compatible way. + hash.add(@as(u32, 0xad95e922)); + hash.addBytes(options.contents.items); + const sub_path = "c" ++ fs.path.sep_str ++ hash.final() ++ fs.path.sep_str ++ basename; + + options.generated_file.path = try cache_root.join(arena, &.{sub_path}); + + // Optimize for the hot path. Stat the file, and if it already exists, + // cache hit. + if (cache_root.handle.access(io, sub_path, .{})) |_| { + // This is the hot path, success. + step.result_cached = true; + return; + } else |outer_err| switch (outer_err) { + error.FileNotFound => { + var atomic_file = cache_root.handle.createFileAtomic(io, sub_path, .{ + .replace = false, + .make_path = true, + }) catch |err| return step.fail("failed to create temporary path for '{f}{s}': {t}", .{ + cache_root, sub_path, err, + }); + defer atomic_file.deinit(io); + + atomic_file.file.writeStreamingAll(io, options.contents.items) catch |err| { + return step.fail("failed to write options to temporary path for '{f}{s}': {t}", .{ + cache_root, sub_path, err, + }); + }; + + atomic_file.link(io) catch |err| switch (err) { + error.PathAlreadyExists => { + step.result_cached = true; + return; + }, + else => return step.fail("failed to link temporary file into '{f}{s}': {t}", .{ + cache_root, sub_path, err, + }), + }; + }, + else => |e| return step.fail("unable to access options file '{f}{s}': {t}", .{ + cache_root, sub_path, e, + }), + } +} + diff --git a/lib/std/Build.zig b/lib/std/Build.zig index 3fbc135758..b6b3263bfa 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -99,19 +99,19 @@ pub const Graph = struct { return @enumFromInt(graph.generated_files.items.len - 1); } - pub fn dupeString(graph: *Graph, bytes: []const u8) []const u8 { + pub fn dupeString(graph: *const Graph, bytes: []const u8) []const u8 { return graph.arena.dupe(u8, bytes) catch @panic("OOM"); } - pub fn dupePath(graph: *Graph, bytes: []const u8) []const u8 { + pub fn dupePath(graph: *const Graph, bytes: []const u8) []const u8 { const arena = graph.arena; - if (builtin.os.tag != .windows) return graph.arena.dupe(u8, bytes) catch @panic("OOM"); + if (builtin.os.tag != .windows) return arena.dupe(u8, bytes) catch @panic("OOM"); const the_copy = arena.dupe(u8, bytes) catch @panic("OOM"); mem.replaceScalar(u8, the_copy, '/', '\\'); return the_copy; } - pub fn dupeStrings(graph: *Graph, strings: []const []const u8) []const []const u8 { + pub fn dupeStrings(graph: *const Graph, strings: []const []const u8) []const []const u8 { const arena = graph.arena; const array = arena.alloc([]const u8, strings.len) catch @panic("OOM"); for (array, strings) |*dest, source| dest.* = dupeString(graph, source); @@ -2186,7 +2186,7 @@ pub const LazyPath = union(enum) { /// /// The `b` parameter is only used for its allocator. All *Build instances /// share the same allocator. - pub fn dupe(lazy_path: LazyPath, graph: *Graph) LazyPath { + pub fn dupe(lazy_path: LazyPath, graph: *const Graph) LazyPath { return switch (lazy_path) { .src_path => |sp| .{ .src_path = .{ .owner = sp.owner, .sub_path = sp.owner.dupePath(sp.sub_path) } }, .cwd_relative => |p| .{ .cwd_relative = graph.dupePath(p) }, @@ -2245,9 +2245,9 @@ pub const InstallDir = union(enum) { custom: []const u8, /// Duplicates the install directory including the path if set to custom. - pub fn dupe(dir: InstallDir, builder: *Build) InstallDir { + pub fn dupe(dir: InstallDir, graph: *const Graph) InstallDir { if (dir == .custom) { - return .{ .custom = builder.dupe(dir.custom) }; + return .{ .custom = graph.dupeString(dir.custom) }; } else { return dir; } diff --git a/lib/std/Build/Configuration.zig b/lib/std/Build/Configuration.zig index d3a5a2086b..ca1c82074a 100644 --- a/lib/std/Build/Configuration.zig +++ b/lib/std/Build/Configuration.zig @@ -1039,10 +1039,20 @@ pub const Step = extern struct { pub const InstallDir = struct { flags: @This().Flags, + source_dir: LazyPath.Index, + dest_dir: InstallDestDir, + dest_sub_path: Storage.FlagOptional(.flags, .dest_sub_path, String), + exclude_extensions: Storage.FlagLengthPrefixedList(.flags, .exclude_extensions, String), + include_extensions: Storage.FlagLengthPrefixedList(.flags, .include_extensions, String), + blank_extensions: Storage.FlagLengthPrefixedList(.flags, .blank_extensions, String), pub const Flags = packed struct(u32) { tag: Tag = .install_dir, - _: u27 = 0, + dest_sub_path: bool, + exclude_extensions: bool, + include_extensions: bool, + blank_extensions: bool, + _: u23 = 0, }; }; @@ -1069,10 +1079,19 @@ pub const Step = extern struct { pub const Options = struct { flags: @This().Flags, + generated_file: GeneratedFileIndex, + contents: Bytes, + args: Storage.FlagLengthPrefixedList(.flags, .args, Arg), + + pub const Arg = extern struct { + name: String, + path: LazyPath.Index, + }; pub const Flags = packed struct(u32) { tag: Tag = .options, - _: u27 = 0, + args: bool, + _: u26 = 0, }; }; diff --git a/lib/std/Build/Step/InstallDir.zig b/lib/std/Build/Step/InstallDir.zig index f755a28662..f1a904cba5 100644 --- a/lib/std/Build/Step/InstallDir.zig +++ b/lib/std/Build/Step/InstallDir.zig @@ -1,9 +1,10 @@ +const InstallDir = @This(); + const std = @import("std"); const mem = std.mem; const fs = std.fs; const Step = std.Build.Step; const LazyPath = std.Build.LazyPath; -const InstallDir = @This(); step: Step, options: Options, @@ -28,83 +29,29 @@ pub const Options = struct { /// `@import("test.zig")` would be a compile error. blank_extensions: []const []const u8 = &.{}, - fn dupe(opts: Options, b: *std.Build) Options { + fn dupe(opts: Options, graph: *const std.Build.Graph) Options { return .{ - .source_dir = opts.source_dir.dupe(b), - .install_dir = opts.install_dir.dupe(b), - .install_subdir = b.dupe(opts.install_subdir), - .exclude_extensions = b.dupeStrings(opts.exclude_extensions), - .include_extensions = if (opts.include_extensions) |incs| b.dupeStrings(incs) else null, - .blank_extensions = b.dupeStrings(opts.blank_extensions), + .source_dir = opts.source_dir.dupe(graph), + .install_dir = opts.install_dir.dupe(graph), + .install_subdir = graph.dupeString(opts.install_subdir), + .exclude_extensions = graph.dupeStrings(opts.exclude_extensions), + .include_extensions = if (opts.include_extensions) |incs| graph.dupeStrings(incs) else null, + .blank_extensions = graph.dupeStrings(opts.blank_extensions), }; } }; pub fn create(owner: *std.Build, options: Options) *InstallDir { const install_dir = owner.allocator.create(InstallDir) catch @panic("OOM"); + const graph = owner.graph; install_dir.* = .{ .step = Step.init(.{ .tag = base_tag, .name = owner.fmt("install {s}/", .{options.source_dir.getDisplayName()}), .owner = owner, - .makeFn = make, }), - .options = options.dupe(owner), + .options = options.dupe(graph), }; options.source_dir.addStepDependencies(&install_dir.step); return install_dir; } - -fn make(step: *Step, options: Step.MakeOptions) !void { - _ = options; - const b = step.owner; - const io = b.graph.io; - const install_dir: *InstallDir = @fieldParentPtr("step", step); - step.clearWatchInputs(); - const arena = b.allocator; - const dest_prefix = b.getInstallPath(install_dir.options.install_dir, install_dir.options.install_subdir); - const src_dir_path = install_dir.options.source_dir.getPath3(b, step); - const need_derived_inputs = try step.addDirectoryWatchInput(install_dir.options.source_dir); - var src_dir = src_dir_path.root_dir.handle.openDir(io, src_dir_path.subPathOrDot(), .{ .iterate = true }) catch |err| { - return step.fail("unable to open source directory '{f}': {t}", .{ src_dir_path, err }); - }; - defer src_dir.close(io); - var it = try src_dir.walk(arena); - var all_cached = true; - next_entry: while (try it.next(io)) |entry| { - for (install_dir.options.exclude_extensions) |ext| { - if (mem.endsWith(u8, entry.path, ext)) continue :next_entry; - } - if (install_dir.options.include_extensions) |incs| { - for (incs) |inc| { - if (mem.endsWith(u8, entry.path, inc)) break; - } else { - continue :next_entry; - } - } - - const src_path = try install_dir.options.source_dir.join(b.allocator, entry.path); - const dest_path = b.pathJoin(&.{ dest_prefix, entry.path }); - switch (entry.kind) { - .directory => { - if (need_derived_inputs) _ = try step.addDirectoryWatchInput(src_path); - const p = try step.installDir(dest_path); - all_cached = all_cached and p == .existed; - }, - .file => { - for (install_dir.options.blank_extensions) |ext| { - if (mem.endsWith(u8, entry.path, ext)) { - try b.truncateFile(dest_path); - continue :next_entry; - } - } - - const p = try step.installFile(src_path, dest_path); - all_cached = all_cached and p == .fresh; - }, - else => continue, - } - } - - step.result_cached = all_cached; -} diff --git a/lib/std/Build/Step/InstallFile.zig b/lib/std/Build/Step/InstallFile.zig index 5b80b3d1a1..f143e43e4e 100644 --- a/lib/std/Build/Step/InstallFile.zig +++ b/lib/std/Build/Step/InstallFile.zig @@ -1,17 +1,18 @@ +const InstallFile = @This(); + const std = @import("std"); const Step = std.Build.Step; const LazyPath = std.Build.LazyPath; const InstallDir = std.Build.InstallDir; -const InstallFile = @This(); const assert = std.debug.assert; -pub const base_tag: Step.Tag = .install_file; - step: Step, source: LazyPath, dir: InstallDir, dest_rel_path: []const u8, +pub const base_tag: Step.Tag = .install_file; + pub fn create( owner: *std.Build, source: LazyPath, @@ -19,16 +20,18 @@ pub fn create( dest_rel_path: []const u8, ) *InstallFile { assert(dest_rel_path.len != 0); - const install_file = owner.allocator.create(InstallFile) catch @panic("OOM"); + const graph = owner.graph; + const arena = graph.arena; + const install_file = arena.create(InstallFile) catch @panic("OOM"); install_file.* = .{ .step = Step.init(.{ .tag = base_tag, .name = owner.fmt("install {s} to {s}", .{ source.getDisplayName(), dest_rel_path }), .owner = owner, }), - .source = source.dupe(owner), - .dir = dir.dupe(owner), - .dest_rel_path = owner.dupePath(dest_rel_path), + .source = source.dupe(graph), + .dir = dir.dupe(graph), + .dest_rel_path = graph.dupePath(dest_rel_path), }; source.addStepDependencies(&install_file.step); return install_file; diff --git a/lib/std/Build/Step/Options.zig b/lib/std/Build/Step/Options.zig index 1bf8266ec0..935aec618c 100644 --- a/lib/std/Build/Step/Options.zig +++ b/lib/std/Build/Step/Options.zig @@ -9,15 +9,19 @@ const Step = std.Build.Step; const LazyPath = std.Build.LazyPath; const Configuration = std.Build.Configuration; -pub const base_tag: Step.Tag = .options; - step: Step, generated_file: Configuration.GeneratedFileIndex, - contents: std.ArrayList(u8), args: std.ArrayList(Arg), encountered_types: std.StringHashMapUnmanaged(void), +pub const base_tag: Step.Tag = .options; + +pub const Arg = struct { + name: []const u8, + path: LazyPath, +}; + pub fn create(owner: *std.Build) *Options { const graph = owner.graph; const arena = graph.arena; @@ -28,7 +32,6 @@ pub fn create(owner: *std.Build) *Options { .tag = base_tag, .name = "options", .owner = owner, - .makeFn = make, }), .generated_file = graph.addGeneratedFile(&options.step), .contents = .empty, @@ -439,240 +442,3 @@ pub fn createModule(options: *Options) *std.Build.Module { pub fn getOutput(options: *Options) LazyPath { return .{ .generated = .{ .index = options.generated_file } }; } - -fn make(step: *Step, make_options: Step.MakeOptions) !void { - // This step completes so quickly that no progress reporting is necessary. - _ = make_options; - - const b = step.owner; - const io = b.graph.io; - const options: *Options = @fieldParentPtr("step", step); - - for (options.args.items) |item| { - options.addOption( - []const u8, - item.name, - item.path.getPath2(b, step), - ); - } - if (!step.inputs.populated()) for (options.args.items) |item| { - try step.addWatchInput(item.path); - }; - - const basename = "options.zig"; - - // Hash contents to file name. - var hash = b.graph.cache.hash; - // Random bytes to make unique. Refresh this with new random bytes when - // implementation is modified in a non-backwards-compatible way. - hash.add(@as(u32, 0xad95e922)); - hash.addBytes(options.contents.items); - const sub_path = "c" ++ fs.path.sep_str ++ hash.final() ++ fs.path.sep_str ++ basename; - - options.generated_file.path = try b.cache_root.join(b.allocator, &.{sub_path}); - - // Optimize for the hot path. Stat the file, and if it already exists, - // cache hit. - if (b.cache_root.handle.access(io, sub_path, .{})) |_| { - // This is the hot path, success. - step.result_cached = true; - return; - } else |outer_err| switch (outer_err) { - error.FileNotFound => { - var atomic_file = b.cache_root.handle.createFileAtomic(io, sub_path, .{ - .replace = false, - .make_path = true, - }) catch |err| return step.fail("failed to create temporary path for '{f}{s}': {t}", .{ - b.cache_root, sub_path, err, - }); - defer atomic_file.deinit(io); - - atomic_file.file.writeStreamingAll(io, options.contents.items) catch |err| { - return step.fail("failed to write options to temporary path for '{f}{s}': {t}", .{ - b.cache_root, sub_path, err, - }); - }; - - atomic_file.link(io) catch |err| switch (err) { - error.PathAlreadyExists => { - step.result_cached = true; - return; - }, - else => return step.fail("failed to link temporary file into '{f}{s}': {t}", .{ - b.cache_root, sub_path, err, - }), - }; - }, - else => |e| return step.fail("unable to access options file '{f}{s}': {t}", .{ - b.cache_root, sub_path, e, - }), - } -} - -const Arg = struct { - name: []const u8, - path: LazyPath, -}; - -test Options { - if (builtin.os.tag == .wasi) return error.SkipZigTest; - - const io = std.testing.io; - - var arena = std.heap.ArenaAllocator.init(std.testing.allocator); - defer arena.deinit(); - - const cwd = try std.process.currentPathAlloc(io, std.testing.allocator); - defer std.testing.allocator.free(cwd); - - var graph: std.Build.Graph = .{ - .io = io, - .arena = arena.allocator(), - .cache = .{ - .io = io, - .gpa = arena.allocator(), - .manifest_dir = Io.Dir.cwd(), - .cwd = cwd, - }, - .zig_exe = "test", - .environ_map = std.process.Environ.Map.init(arena.allocator()), - .global_cache_root = .{ .path = "test", .handle = Io.Dir.cwd() }, - .host = .{ - .query = .{}, - .result = try std.zig.system.resolveTargetQuery(io, .{}), - }, - .zig_lib_directory = std.Build.Cache.Directory.cwd(), - .time_report = false, - }; - - var builder = try std.Build.create( - &graph, - .{ .path = "test", .handle = Io.Dir.cwd() }, - .{ .path = "test", .handle = Io.Dir.cwd() }, - &.{}, - ); - - const options = builder.addOptions(); - - const KeywordEnum = enum { - @"0.8.1", - }; - - const NormalEnum = enum { - foo, - bar, - }; - - const nested_array = [2][2]u16{ - [2]u16{ 300, 200 }, - [2]u16{ 300, 200 }, - }; - const nested_slice: []const []const u16 = &[_][]const u16{ &nested_array[0], &nested_array[1] }; - - const NormalStruct = struct { - hello: ?[]const u8, - world: bool = true, - }; - - const NestedStruct = struct { - normal_struct: NormalStruct, - normal_enum: NormalEnum = .foo, - }; - - options.addOption(usize, "option1", 1); - options.addOption(?usize, "option2", null); - options.addOption(?usize, "option3", 3); - options.addOption(comptime_int, "option4", 4); - options.addOption(comptime_float, "option5", 5.01); - options.addOption([]const u8, "string", "zigisthebest"); - options.addOption(?[]const u8, "optional_string", null); - options.addOption([2][2]u16, "nested_array", nested_array); - options.addOption([]const []const u16, "nested_slice", nested_slice); - options.addOption(KeywordEnum, "keyword_enum", .@"0.8.1"); - options.addOption(std.SemanticVersion, "semantic_version", try std.SemanticVersion.parse("0.1.2-foo+bar")); - options.addOption(NormalEnum, "normal1_enum", NormalEnum.foo); - options.addOption(NormalEnum, "normal2_enum", NormalEnum.bar); - options.addOption(NormalStruct, "normal1_struct", NormalStruct{ - .hello = "foo", - }); - options.addOption(NormalStruct, "normal2_struct", NormalStruct{ - .hello = null, - .world = false, - }); - options.addOption(NestedStruct, "nested_struct", NestedStruct{ - .normal_struct = .{ .hello = "bar" }, - }); - - try std.testing.expectEqualStrings( - \\pub const option1: usize = 1; - \\pub const option2: ?usize = null; - \\pub const option3: ?usize = 3; - \\pub const option4: comptime_int = 4; - \\pub const option5: comptime_float = 5.01; - \\pub const string: []const u8 = "zigisthebest"; - \\pub const optional_string: ?[]const u8 = null; - \\pub const nested_array: [2][2]u16 = [2][2]u16 { - \\ [2]u16 { - \\ 300, - \\ 200, - \\ }, - \\ [2]u16 { - \\ 300, - \\ 200, - \\ }, - \\}; - \\pub const nested_slice: []const []const u16 = &[_][]const u16 { - \\ &[_]u16 { - \\ 300, - \\ 200, - \\ }, - \\ &[_]u16 { - \\ 300, - \\ 200, - \\ }, - \\}; - \\pub const @"Build.Step.Options.decltest.Options.KeywordEnum" = enum (u0) { - \\ @"0.8.1" = 0, - \\}; - \\pub const keyword_enum: @"Build.Step.Options.decltest.Options.KeywordEnum" = .@"0.8.1"; - \\pub const semantic_version: @import("std").SemanticVersion = .{ - \\ .major = 0, - \\ .minor = 1, - \\ .patch = 2, - \\ .pre = "foo", - \\ .build = "bar", - \\}; - \\pub const @"Build.Step.Options.decltest.Options.NormalEnum" = enum (u1) { - \\ foo = 0, - \\ bar = 1, - \\}; - \\pub const normal1_enum: @"Build.Step.Options.decltest.Options.NormalEnum" = .foo; - \\pub const normal2_enum: @"Build.Step.Options.decltest.Options.NormalEnum" = .bar; - \\pub const @"Build.Step.Options.decltest.Options.NormalStruct" = struct { - \\ hello: ?[]const u8, - \\ world: bool = true, - \\}; - \\pub const normal1_struct: @"Build.Step.Options.decltest.Options.NormalStruct" = .{ - \\ .hello = "foo", - \\ .world = true, - \\}; - \\pub const normal2_struct: @"Build.Step.Options.decltest.Options.NormalStruct" = .{ - \\ .hello = null, - \\ .world = false, - \\}; - \\pub const @"Build.Step.Options.decltest.Options.NestedStruct" = struct { - \\ normal_struct: @"Build.Step.Options.decltest.Options.NormalStruct", - \\ normal_enum: @"Build.Step.Options.decltest.Options.NormalEnum" = .foo, - \\}; - \\pub const nested_struct: @"Build.Step.Options.decltest.Options.NestedStruct" = .{ - \\ .normal_struct = .{ - \\ .hello = "bar", - \\ .world = true, - \\ }, - \\ .normal_enum = .foo, - \\}; - \\ - , options.contents.items); - - _ = try std.zig.Ast.parse(arena.allocator(), try options.contents.toOwnedSliceSentinel(arena.allocator(), 0), .zig); -}