From 800fc5d25a5ed386910dc36c81ae200a19a1d01b Mon Sep 17 00:00:00 2001 From: hemisputnik Date: Wed, 5 Aug 2026 06:50:26 +0300 Subject: [PATCH 1/2] std.Build.Configuration: use inline else to simplify long switches --- lib/std/Build/Configuration.zig | 323 ++------------------------------ 1 file changed, 12 insertions(+), 311 deletions(-) diff --git a/lib/std/Build/Configuration.zig b/lib/std/Build/Configuration.zig index 5743d9800ced11e00ff61ce5a122c6c5bca83b3f..3b0e6c2e7f7ee9e95bae247bb8e952850f4d9e7a 100644 --- a/lib/std/Build/Configuration.zig +++ b/lib/std/Build/Configuration.zig @@ -2120,27 +2120,18 @@ pub const OptionalCSourceLanguage = enum(u3) { objective_cpp, assembly, assembly_with_preprocessor, + default, pub fn init(x: ?std.Build.Module.CSourceLanguage) @This() { return switch (x orelse return .default) { - .c => .c, - .cpp => .cpp, - .objective_c => .objective_c, - .objective_cpp => .objective_cpp, - .assembly => .assembly, - .assembly_with_preprocessor => .assembly_with_preprocessor, + inline else => |tag| @field(@This(), @tagName(tag)), }; } pub fn get(this: @This()) ?std.Build.Module.CSourceLanguage { return switch (this) { - .c => .c, - .cpp => .cpp, - .objective_c => .objective_c, - .objective_cpp => .objective_cpp, - .assembly => .assembly, - .assembly_with_preprocessor => .assembly_with_preprocessor, + inline else => |tag| @field(std.Build.Module.CSourceLanguage, @tagName(tag)), .default => null, }; } @@ -2268,10 +2259,7 @@ pub const TargetQuery = struct { pub fn init(x: std.Target.Query.CpuModel) @This() { return switch (x) { - .native => .native, - .baseline => .baseline, - .determined_by_arch_os => .determined_by_arch_os, - .explicit => .explicit, + inline else => |_, tag| @field(@This(), @tagName(tag)), }; } }; @@ -2329,71 +2317,13 @@ pub const TargetQuery = struct { pub fn init(x: ?std.Target.Abi) @This() { return switch (x orelse return .default) { - .none => .none, - .gnu => .gnu, - .gnuabin32 => .gnuabin32, - .gnuabi64 => .gnuabi64, - .gnueabi => .gnueabi, - .gnueabihf => .gnueabihf, - .gnuf32 => .gnuf32, - .gnusf => .gnusf, - .gnux32 => .gnux32, - .eabi => .eabi, - .eabihf => .eabihf, - .abin32 => .abin32, - .x32 => .x32, - .ilp32 => .ilp32, - .android => .android, - .androideabi => .androideabi, - .musl => .musl, - .muslabin32 => .muslabin32, - .muslabi64 => .muslabi64, - .musleabi => .musleabi, - .musleabihf => .musleabihf, - .muslf32 => .muslf32, - .muslsf => .muslsf, - .muslx32 => .muslx32, - .msvc => .msvc, - .itanium => .itanium, - .simulator => .simulator, - .ohos => .ohos, - .ohoseabi => .ohoseabi, - .call0 => .call0, + inline else => |tag| @field(@This(), @tagName(tag)), }; } pub fn unwrap(this: @This()) ?std.Target.Abi { return switch (this) { - .none => .none, - .gnu => .gnu, - .gnuabin32 => .gnuabin32, - .gnuabi64 => .gnuabi64, - .gnueabi => .gnueabi, - .gnueabihf => .gnueabihf, - .gnuf32 => .gnuf32, - .gnusf => .gnusf, - .gnux32 => .gnux32, - .eabi => .eabi, - .eabihf => .eabihf, - .abin32 => .abin32, - .x32 => .x32, - .ilp32 => .ilp32, - .android => .android, - .androideabi => .androideabi, - .musl => .musl, - .muslabin32 => .muslabin32, - .muslabi64 => .muslabi64, - .musleabi => .musleabi, - .musleabihf => .musleabihf, - .muslf32 => .muslf32, - .muslsf => .muslsf, - .muslx32 => .muslx32, - .msvc => .msvc, - .itanium => .itanium, - .simulator => .simulator, - .ohos => .ohos, - .ohoseabi => .ohoseabi, - .call0 => .call0, + inline else => |tag| @field(std.Target.Abi, @tagName(tag)), .default => null, }; } @@ -2465,132 +2395,13 @@ pub const TargetQuery = struct { pub fn init(x: ?std.Target.Cpu.Arch) @This() { return switch (x orelse return .default) { - .aarch64 => .aarch64, - .aarch64_be => .aarch64_be, - .alpha => .alpha, - .amdgcn => .amdgcn, - .arc => .arc, - .arceb => .arceb, - .arm => .arm, - .armeb => .armeb, - .avr => .avr, - .bpfeb => .bpfeb, - .bpfel => .bpfel, - .csky => .csky, - .ez80 => .ez80, - .hexagon => .hexagon, - .hppa => .hppa, - .hppa64 => .hppa64, - .kalimba => .kalimba, - .kvx => .kvx, - .lanai => .lanai, - .loongarch32 => .loongarch32, - .loongarch64 => .loongarch64, - .m68k => .m68k, - .m88k => .m88k, - .microblaze => .microblaze, - .microblazeel => .microblazeel, - .mips => .mips, - .mipsel => .mipsel, - .mips64 => .mips64, - .mips64el => .mips64el, - .msp430 => .msp430, - .nvptx => .nvptx, - .nvptx64 => .nvptx64, - .or1k => .or1k, - .powerpc => .powerpc, - .powerpcle => .powerpcle, - .powerpc64 => .powerpc64, - .powerpc64le => .powerpc64le, - .propeller => .propeller, - .riscv32 => .riscv32, - .riscv32be => .riscv32be, - .riscv64 => .riscv64, - .riscv64be => .riscv64be, - .s390x => .s390x, - .sh => .sh, - .sheb => .sheb, - .sparc => .sparc, - .sparc64 => .sparc64, - .spirv32 => .spirv32, - .spirv64 => .spirv64, - .thumb => .thumb, - .thumbeb => .thumbeb, - .ve => .ve, - .wasm32 => .wasm32, - .wasm64 => .wasm64, - .x86_16 => .x86_16, - .x86 => .x86, - .x86_64 => .x86_64, - .xcore => .xcore, - .xtensa => .xtensa, - .xtensaeb => .xtensaeb, + inline else => |tag| @field(@This(), @tagName(tag)), }; } pub fn unwrap(this: @This()) ?std.Target.Cpu.Arch { return switch (this) { - .aarch64 => .aarch64, - .aarch64_be => .aarch64_be, - .alpha => .alpha, - .amdgcn => .amdgcn, - .arc => .arc, - .arceb => .arceb, - .arm => .arm, - .armeb => .armeb, - .avr => .avr, - .bpfeb => .bpfeb, - .bpfel => .bpfel, - .csky => .csky, - .ez80 => .ez80, - .hexagon => .hexagon, - .hppa => .hppa, - .hppa64 => .hppa64, - .kalimba => .kalimba, - .kvx => .kvx, - .lanai => .lanai, - .loongarch32 => .loongarch32, - .loongarch64 => .loongarch64, - .m68k => .m68k, - .m88k => .m88k, - .microblaze => .microblaze, - .microblazeel => .microblazeel, - .mips => .mips, - .mipsel => .mipsel, - .mips64 => .mips64, - .mips64el => .mips64el, - .msp430 => .msp430, - .nvptx => .nvptx, - .nvptx64 => .nvptx64, - .or1k => .or1k, - .powerpc => .powerpc, - .powerpcle => .powerpcle, - .powerpc64 => .powerpc64, - .powerpc64le => .powerpc64le, - .propeller => .propeller, - .riscv32 => .riscv32, - .riscv32be => .riscv32be, - .riscv64 => .riscv64, - .riscv64be => .riscv64be, - .s390x => .s390x, - .sh => .sh, - .sheb => .sheb, - .sparc => .sparc, - .sparc64 => .sparc64, - .spirv32 => .spirv32, - .spirv64 => .spirv64, - .thumb => .thumb, - .thumbeb => .thumbeb, - .ve => .ve, - .wasm32 => .wasm32, - .wasm64 => .wasm64, - .x86_16 => .x86_16, - .x86 => .x86, - .x86_64 => .x86_64, - .xcore => .xcore, - .xtensa => .xtensa, - .xtensaeb => .xtensaeb, - + inline else => |tag| @field(std.Target.Cpu.Arch, @tagName(tag)), .default => null, }; } @@ -2649,106 +2460,13 @@ pub const TargetQuery = struct { pub fn init(x: ?std.Target.Os.Tag) @This() { return switch (x orelse return .default) { - .freestanding => .freestanding, - .other => .other, - .contiki => .contiki, - .fuchsia => .fuchsia, - .hermit => .hermit, - .managarm => .managarm, - .haiku => .haiku, - .hurd => .hurd, - .illumos => .illumos, - .linux => .linux, - .plan9 => .plan9, - .rtems => .rtems, - .serenity => .serenity, - .dragonfly => .dragonfly, - .freebsd => .freebsd, - .netbsd => .netbsd, - .openbsd => .openbsd, - .driverkit => .driverkit, - .ios => .ios, - .maccatalyst => .maccatalyst, - .macos => .macos, - .tvos => .tvos, - .visionos => .visionos, - .watchos => .watchos, - .windows => .windows, - .uefi => .uefi, - .@"3ds" => .@"3ds", - .wiiu => .wiiu, - .@"switch" => .@"switch", - .psx => .psx, - .ps3 => .ps3, - .ps4 => .ps4, - .ps5 => .ps5, - .psp => .psp, - .vita => .vita, - .emscripten => .emscripten, - .wasi => .wasi, - .amdhsa => .amdhsa, - .amdpal => .amdpal, - .cuda => .cuda, - .mesa3d => .mesa3d, - .nvcl => .nvcl, - .opencl => .opencl, - .opengl => .opengl, - .vulkan => .vulkan, - .tios => .tios, - .ashetos => .ashetos, + inline else => |tag| @field(@This(), @tagName(tag)), }; } pub fn unwrap(this: @This()) ?std.Target.Os.Tag { return switch (this) { - .freestanding => .freestanding, - .other => .other, - .contiki => .contiki, - .fuchsia => .fuchsia, - .hermit => .hermit, - .managarm => .managarm, - .haiku => .haiku, - .hurd => .hurd, - .illumos => .illumos, - .linux => .linux, - .plan9 => .plan9, - .rtems => .rtems, - .serenity => .serenity, - .dragonfly => .dragonfly, - .freebsd => .freebsd, - .netbsd => .netbsd, - .openbsd => .openbsd, - .driverkit => .driverkit, - .ios => .ios, - .maccatalyst => .maccatalyst, - .macos => .macos, - .tvos => .tvos, - .visionos => .visionos, - .watchos => .watchos, - .windows => .windows, - .uefi => .uefi, - .@"3ds" => .@"3ds", - .wiiu => .wiiu, - .@"switch" => .@"switch", - .psx => .psx, - .ps3 => .ps3, - .ps4 => .ps4, - .ps5 => .ps5, - .psp => .psp, - .vita => .vita, - .emscripten => .emscripten, - .wasi => .wasi, - .amdhsa => .amdhsa, - .amdpal => .amdpal, - .cuda => .cuda, - .mesa3d => .mesa3d, - .nvcl => .nvcl, - .opencl => .opencl, - .opengl => .opengl, - .vulkan => .vulkan, - .tios => .tios, - .ashetos => .ashetos, - + inline else => |tag| @field(std.Target.Os.Tag, @tagName(tag)), .default => null, }; } @@ -2769,30 +2487,13 @@ pub const TargetQuery = struct { pub fn init(x: ?std.Target.ObjectFormat) @This() { return switch (x orelse return .default) { - .c => .c, - .coff => .coff, - .elf => .elf, - .hex => .hex, - .macho => .macho, - .plan9 => .plan9, - .raw => .raw, - .spirv => .spirv, - .wasm => .wasm, + inline else => |tag| @field(@This(), @tagName(tag)), }; } pub fn unwrap(this: @This()) ?std.Target.ObjectFormat { return switch (this) { - .c => .c, - .coff => .coff, - .elf => .elf, - .hex => .hex, - .macho => .macho, - .plan9 => .plan9, - .raw => .raw, - .spirv => .spirv, - .wasm => .wasm, - + inline else => |tag| @field(std.Target.ObjectFormat, @tagName(tag)), .default => null, }; } -- 2.54.0 From 0f332fd536aee4fcff4d0875d1d7136ba5b6f01b Mon Sep 17 00:00:00 2001 From: hemisputnik Date: Wed, 5 Aug 2026 06:50:26 +0300 Subject: [PATCH 2/2] std.Build.Configuration: serialize packages and their dependencies The serializer now traverses the builder's available_deps and their dependencies recursively, and serializes them into Configuration.packages. --- lib/compiler/Maker.zig | 8 ++- lib/compiler/Maker/ScannedConfig.zig | 21 +++++++ lib/std/Build.zig | 5 +- lib/std/Build/Configuration.zig | 49 ++++++++++++---- lib/std/Build/Serialize.zig | 86 ++++++++++++++++++++++------ 5 files changed, 136 insertions(+), 33 deletions(-) diff --git a/lib/compiler/Maker.zig b/lib/compiler/Maker.zig index 1a3a37b6dc008e7c536ab91e505d7559addbc7bb..48acfbf33b415311606da006a27590114e3319c9 100644 --- a/lib/compiler/Maker.zig +++ b/lib/compiler/Maker.zig @@ -3312,17 +3312,19 @@ pub fn packagePath( ) Allocator.Error!Path { const c = &maker.scanned_config.configuration; const graph = maker.graph; - const package = package_index.get(c) orelse return .{ + + if (package_index == .root) return .{ .root_dir = graph.build_root_directory, .sub_path = sub_path, }; + // Currently, neither configurer nor Maker is aware of the standard zig // package path, and the root path is stored as a bare string rather than // relative to a known base directory. Without changing that, we must // construct a cwd relative path here. return .{ .root_dir = .cwd(), - .sub_path = try Dir.path.join(arena, &.{ package.root_path.slice(c), sub_path }), + .sub_path = try Dir.path.join(arena, &.{ package_index.ptr(c).root_path.slice(c), sub_path }), }; } @@ -3952,7 +3954,7 @@ fn confPathDepToCachePath( .root_dir = graph.build_root_directory, .sub_path = switch (path_dep.pkg.unwrap().?) { .root => sub_path, - else => |index| try Dir.path.join(arena, &.{ index.get(c).?.root_path.slice(c), sub_path }), + else => |index| try Dir.path.join(arena, &.{ index.ptr(c).root_path.slice(c), sub_path }), }, }, .zig_lib => .{ diff --git a/lib/compiler/Maker/ScannedConfig.zig b/lib/compiler/Maker/ScannedConfig.zig index ed5661851351afb4c9a57b8723e2f4d13cd895ba..168ae8b7f61ec27abf36a4d46c2e675e982b0061 100644 --- a/lib/compiler/Maker/ScannedConfig.zig +++ b/lib/compiler/Maker/ScannedConfig.zig @@ -83,6 +83,27 @@ pub fn print(sc: *const ScannedConfig, w: *Writer) Writer.Error!void { try tf.end(); } + { + var tf = try s.beginTupleField("packages", .{}); + for (c.packages) |package| { + var sf = try tf.beginStructField(.{}); + try sf.field("dep_prefix", package.dep_prefix.slice(c), .{}); + try sf.field("hash", package.hash.slice(c), .{}); + try sf.field("root_path", package.root_path.slice(c), .{}); + + var dtf = try sf.beginTupleField("deps", .{}); + for (package.deps.slice(c)) |dep| { + var dsf = try dtf.beginStructField(.{}); + try sc.printStruct(&dsf, Configuration.Package.Dep, dep); + try dsf.end(); + } + try dtf.end(); + + try sf.end(); + } + try tf.end(); + } + try s.end(); } diff --git a/lib/std/Build.zig b/lib/std/Build.zig index eed57a0b15b47b23b54b412c4305f12020b9773c..da2dfb4e5a7fbfc9a357347c98d5f13ab4bd8114 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -2160,7 +2160,7 @@ pub fn dependencyLazy(b: *Build, name: []const u8, args: anytype) error{LazyDepe return dependencyResolved(b, name, entry, userInputOptionsFromArgs(b.graph.arena, args)); } -const PackageEntry = struct { +pub const PackageEntry = struct { hash: []const u8, available: bool, build_root: []const u8, @@ -2168,7 +2168,8 @@ const PackageEntry = struct { run_build: ?*const fn (*Build) void, }; -const package_map: std.StaticStringMap(PackageEntry) = blk: { +/// Build system implementation detail. +pub const package_map: std.StaticStringMap(PackageEntry) = blk: { const deps = @import("root").dependencies; const decl_names = @typeInfo(deps.packages).@"struct".decl_names; var kvs: [decl_names.len]struct { []const u8, PackageEntry } = undefined; diff --git a/lib/std/Build/Configuration.zig b/lib/std/Build/Configuration.zig index 3b0e6c2e7f7ee9e95bae247bb8e952850f4d9e7a..1f1da636d6ce0d64d4a22bc378d1a9c94a4a9754 100644 --- a/lib/std/Build/Configuration.zig +++ b/lib/std/Build/Configuration.zig @@ -15,6 +15,8 @@ unlazy_deps: []String, system_integrations: []SystemIntegration, available_options: []AvailableOption, search_prefixes: []String, +/// Index 0 always exists and is the root package. +packages: []Package, extra: []u32, default_step: Step.Index, generated_files_len: u32, @@ -30,6 +32,7 @@ pub const Header = extern struct { system_integrations_len: u32, available_options_len: u32, search_prefixes_len: u32, + packages_len: u32, extra_len: u32, default_step: Step.Index, @@ -58,6 +61,7 @@ pub const Wip = struct { steps: std.ArrayList(Step) = .empty, path_deps: std.ArrayList(PathDep) = .empty, search_prefixes: std.ArrayList(String) = .empty, + packages: std.ArrayList(Package) = .empty, extra: std.ArrayList(u32) = .empty, next_generated_file_index: u32 = 0, cache_poison: bool = false, @@ -139,6 +143,7 @@ pub const Wip = struct { wip.steps.deinit(gpa); wip.path_deps.deinit(gpa); wip.search_prefixes.deinit(gpa); + wip.packages.deinit(gpa); wip.extra.deinit(gpa); wip.* = undefined; } @@ -158,6 +163,7 @@ pub const Wip = struct { .system_integrations_len = @intCast(wip.system_integrations.items.len), .available_options_len = @intCast(wip.available_options.items.len), .search_prefixes_len = @intCast(wip.search_prefixes.items.len), + .packages_len = @intCast(wip.packages.items.len), .extra_len = @intCast(wip.extra.items.len), .default_step = static.default_step, @@ -175,6 +181,7 @@ pub const Wip = struct { @ptrCast(wip.system_integrations.items), @ptrCast(wip.available_options.items), @ptrCast(wip.search_prefixes.items), + @ptrCast(wip.packages.items), @ptrCast(wip.extra.items), }; try w.writeVecAll(&buffers); @@ -1596,30 +1603,28 @@ pub const OptionalGeneratedFileIndex = enum(u32) { } }; -pub const Package = struct { +pub const Package = extern struct { dep_prefix: String, hash: String, root_path: String, + deps: Dep.List.Index, pub const Index = enum(u32) { - root = max_u32, + root, _, - /// Returns `null` for root package. - pub fn get(i: @This(), c: *const Configuration) ?Package { - if (i == .root) return null; - return extraData(c, Package, @backingInt(i)); + pub fn ptr(i: @This(), c: *const Configuration) *const Package { + return &c.packages[@backingInt(i)]; } pub fn depPrefixSlice(i: @This(), c: *const Configuration) [:0]const u8 { - const package = get(i, c) orelse return ""; - return package.dep_prefix.slice(c); + return ptr(i, c).dep_prefix.slice(c); } }; pub const OptionalIndex = enum(u32) { - none = max_u32 - 1, - root = max_u32, + root, + none = max_u32, _, pub fn init(i: Index) OptionalIndex { @@ -1636,6 +1641,28 @@ pub const Package = struct { }; } }; + + pub const Dep = extern struct { + name: String, + /// Must not be `.root`. + package: Package.Index, + + pub const List = struct { + deps: Storage.LengthPrefixedList(Dep), + + pub const Index = enum(u32) { + _, + + pub fn get(this: @This(), c: *const Configuration) List { + return extraData(c, List, @backingInt(this)); + } + + pub fn slice(this: @This(), c: *const Configuration) []const Dep { + return get(this, c).deps.slice; + } + }; + }; + }; }; pub const Module = struct { @@ -3170,6 +3197,7 @@ pub fn load(arena: Allocator, reader: *Io.Reader) LoadError!Configuration { .system_integrations = try arena.alloc(SystemIntegration, header.system_integrations_len), .available_options = try arena.alloc(AvailableOption, header.available_options_len), .search_prefixes = try arena.alloc(String, header.search_prefixes_len), + .packages = try arena.alloc(Package, header.packages_len), .extra = try arena.alloc(u32, header.extra_len), .default_step = header.default_step, .generated_files_len = header.generated_files_len, @@ -3183,6 +3211,7 @@ pub fn load(arena: Allocator, reader: *Io.Reader) LoadError!Configuration { @ptrCast(result.system_integrations), @ptrCast(result.available_options), @ptrCast(result.search_prefixes), + @ptrCast(result.packages), @ptrCast(result.extra), }; try reader.readVecAll(&vecs); diff --git a/lib/std/Build/Serialize.zig b/lib/std/Build/Serialize.zig index 72355264d978c15b712d92242df14f0c92eb4b6f..68451454c7c85b4f1fd480e65e3520251805325f 100644 --- a/lib/std/Build/Serialize.zig +++ b/lib/std/Build/Serialize.zig @@ -10,7 +10,8 @@ const log = std.log; arena: Allocator, wc: *Configuration.Wip, module_map: std.array_hash_map.Auto(*std.Build.Module, Configuration.Module.Index) = .empty, -package_map: std.array_hash_map.Auto(*std.Build, Configuration.Package.Index) = .empty, +/// Keyed by package hash. +package_map: std.array_hash_map.String(Configuration.Package.Index) = .empty, /// Index corresponds to `Configuration.steps` index. step_map: std.array_hash_map.Auto(*Step, void) = .empty, @@ -21,6 +22,10 @@ pub fn write(b: *std.Build, wc: *Configuration.Wip, writer: *std.Io.Writer) !voi var s: Serialize = .{ .wc = wc, .arena = arena }; + // Serialize all of the packages first to seed the package_map, which is + // later used in calls to packageFromHash. + try s.addRootPackage(b); + try wc.path_deps.ensureTotalCapacityPrecise(gpa, graph.configure_dependencies.items.len); for ( graph.configure_dependencies.items, @@ -44,10 +49,10 @@ pub fn write(b: *std.Build, wc: *Configuration.Wip, writer: *std.Io.Writer) !voi .relative => |r| try wc.addString(r.sub_path), }, .pkg = switch (src.lazy_path) { - .src_path => |sp| .init(try s.builderToPackage(sp.owner)), + .src_path => |sp| .init(s.packageFromHash(sp.owner.pkg_hash)), .generated => unreachable, .cwd_relative, .relative => .none, - .dependency => |d| .init(try s.builderToPackage(d.dependency.builder)), + .dependency => |d| .init(s.packageFromHash(d.dependency.builder.pkg_hash)), }, }; } @@ -84,7 +89,7 @@ pub fn write(b: *std.Build, wc: *Configuration.Wip, writer: *std.Io.Writer) !voi try wc.steps.ensureTotalCapacity(gpa, s.step_map.entries.capacity); wc.steps.appendAssumeCapacity(.{ .name = try wc.addString(step.name), - .owner = try s.builderToPackage(step.owner), + .owner = s.packageFromHash(step.owner.pkg_hash), .deps = deps, .max_rss = .fromBytes(step.max_rss), .extended = @fromBackingInt(@intCast(switch (step.tag) { @@ -724,19 +729,64 @@ pub fn packageOptions(b: *std.Build, wc: *Configuration.Wip) Allocator.Error!voi } } -fn builderToPackage(s: *Serialize, b: *std.Build) !Configuration.Package.Index { - if (b.pkg_hash.len == 0) return .root; +fn addRootPackage(s: *Serialize, b: *std.Build) Allocator.Error!void { const arena = s.arena; const wc = s.wc; - const gop = try s.package_map.getOrPut(arena, b); - if (!gop.found_existing) { - gop.value_ptr.* = try wc.addExtra(Configuration.Package, .{ - .hash = try wc.addString(b.pkg_hash), - .dep_prefix = try wc.addString(b.dep_prefix), - .root_path = try wc.addString(try b.root.toString(arena)), - }); - } - return gop.value_ptr.*; + + try wc.packages.append(wc.gpa, .{ + .dep_prefix = .empty, + .hash = .empty, + .root_path = try wc.addString(try b.root.toString(arena)), + .deps = undefined, + }); + + const deps = try arena.alloc(Configuration.Package.Dep, b.available_deps.len); + for (deps, b.available_deps) |*dest, src| dest.* = try s.makePackageDep("", src[0], src[1]); + + wc.packages.items[0].deps = try wc.addExtra(Configuration.Package.Dep.List, .{ + .deps = .{ .slice = deps }, + }); +} + +fn makePackageDep(s: *Serialize, parent_dep_prefix: []const u8, name: []const u8, hash: []const u8) Allocator.Error!Configuration.Package.Dep { + const arena = s.arena; + const wc = s.wc; + + if (s.package_map.get(hash)) |index| return .{ + .name = try wc.addString(name), + .package = index, + }; + + const entry = std.Build.package_map.get(hash) orelse unreachable; + + const dep_prefix = try arena.print("{s}{s}.", .{ parent_dep_prefix, name }); + + const index: Configuration.Package.Index = @fromBackingInt(@intCast(wc.packages.items.len)); + try s.package_map.put(arena, hash, index); + + try wc.packages.append(wc.gpa, .{ + .dep_prefix = try wc.addString(dep_prefix), + .hash = try wc.addString(hash), + .root_path = try wc.addString(entry.build_root), + .deps = undefined, + }); + + const deps = try arena.alloc(Configuration.Package.Dep, entry.deps.len); + for (deps, entry.deps) |*dest, src| dest.* = try s.makePackageDep(dep_prefix, src[0], src[1]); + + wc.packages.items[@backingInt(index)].deps = try wc.addExtra(Configuration.Package.Dep.List, .{ + .deps = .{ .slice = deps }, + }); + + return .{ + .name = try wc.addString(name), + .package = index, + }; +} + +fn packageFromHash(s: *Serialize, pkg_hash: []const u8) Configuration.Package.Index { + if (pkg_hash.len == 0) return .root; + return s.package_map.get(pkg_hash) orelse std.debug.panic("unrecognized package hash: {q}", .{pkg_hash}); } fn addOptionalLazyPathEnum(s: *Serialize, lp: ?std.Build.LazyPath) !Configuration.LazyPath.OptionalIndex { @@ -745,7 +795,7 @@ fn addOptionalLazyPathEnum(s: *Serialize, lp: ?std.Build.LazyPath) !Configuratio .src_path => |src_path| i: { const sub_path = try wc.addString(src_path.sub_path); break :i try wc.addExtraErased(Configuration.LazyPath.SourcePath, .{ - .owner = try s.builderToPackage(src_path.owner), + .owner = s.packageFromHash(src_path.owner.pkg_hash), .sub_path = sub_path, }); }, @@ -773,7 +823,7 @@ fn addOptionalLazyPathEnum(s: *Serialize, lp: ?std.Build.LazyPath) !Configuratio .dependency => |dependency| i: { const sub_path = try wc.addString(dependency.sub_path); break :i try wc.addExtraErased(Configuration.LazyPath.SourcePath, .{ - .owner = try s.builderToPackage(dependency.dependency.builder), + .owner = s.packageFromHash(dependency.dependency.builder.pkg_hash), .sub_path = sub_path, }); }, @@ -1138,7 +1188,7 @@ fn addModule(s: *Serialize, m: *std.Build.Module) !Configuration.Module.Index { .link_libcpp = .init(m.link_libcpp), .no_builtin = .init(m.no_builtin), }, - .owner = try s.builderToPackage(m.owner), + .owner = s.packageFromHash(m.owner.pkg_hash), .root_source_file = try s.addOptionalLazyPathEnum(m.root_source_file), .import_table = .invalid, .resolved_target = try addOptionalResolvedTarget(wc, m.resolved_target), -- 2.54.0