authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-08-13 00:34:22+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-08-13 00:34:22+02:00
log8e48a5c524f970c4630725e2efe69243d8d79fde
tree5a97e78e8fbde363a127c2de8ac70dbf9d58b1ac
parent2aae46494a82c2d99e509a30d7e686b771737895
parente98205bd17bb39ba501213f9b8ce2b0559b90035

Merge pull request 'std.Build.Configuration: serialize public modules of packages' (#36461) from hemisputnik/zig:work/36388-configuration-package-modules into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/36461 Reviewed-by: Andrew Kelley <andrew@ziglang.org>

5 files changed, 344 insertions(+), 83 deletions(-)

lib/compiler/Maker.zig+5-5
......@@ -2226,7 +2226,7 @@ fn prepare(maker: *Maker, step_indices: []const Configuration.Step.Index) !void
22262226 }
22272227 } else {
22282228 log.err("{s}{s}: this step declares an upper bound of {d} bytes of memory, exceeding the available {d} bytes of memory", .{
2229 conf_step.owner.depPrefixSlice(c),
2229 conf_step.owner.package(c).depPrefixSlice(c),
22302230 conf_step.name.slice(c),
22312231 max_rss,
22322232 maker.available_rss,
......@@ -3320,13 +3320,13 @@ pub fn generatedPath(maker: *const Maker, index: Configuration.GeneratedFileInde
33203320pub fn packagePath(
33213321 maker: *const Maker,
33223322 arena: Allocator,
3323 package_index: Configuration.Package.Index,
3323 inst_index: Configuration.PackageInstance.Index,
33243324 sub_path: []const u8,
33253325) Allocator.Error!Path {
33263326 const c = &maker.scanned_config.configuration;
33273327 const graph = maker.graph;
33283328
3329 if (package_index == .root) return .{
3329 if (inst_index == .root) return .{
33303330 .root_dir = graph.build_root_directory,
33313331 .sub_path = sub_path,
33323332 };
......@@ -3337,7 +3337,7 @@ pub fn packagePath(
33373337 // construct a cwd relative path here.
33383338 return .{
33393339 .root_dir = .cwd(),
3340 .sub_path = try Dir.path.join(arena, &.{ package_index.ptr(c).root_path.slice(c), sub_path }),
3340 .sub_path = try Dir.path.join(arena, &.{ inst_index.package(c).ptr(c).root_path.slice(c), sub_path }),
33413341 };
33423342}
33433343
......@@ -3967,7 +3967,7 @@ fn confPathDepToCachePath(
39673967 .root_dir = graph.build_root_directory,
39683968 .sub_path = switch (path_dep.pkg.unwrap().?) {
39693969 .root => sub_path,
3970 else => |index| try Dir.path.join(arena, &.{ index.ptr(c).root_path.slice(c), sub_path }),
3970 else => |index| try Dir.path.join(arena, &.{ index.package(c).ptr(c).root_path.slice(c), sub_path }),
39713971 },
39723972 },
39733973 .zig_lib => .{
lib/compiler/Maker/ScannedConfig.zig+32
......@@ -104,6 +104,38 @@ pub fn print(sc: *const ScannedConfig, w: *Writer) Writer.Error!void {
104104 try tf.end();
105105 }
106106
107 {
108 var tf = try s.beginTupleField("package_instances", .{});
109 for (c.package_instances) |inst| {
110 var sf = try tf.beginStructField(.{});
111
112 try sf.fieldPrefix("package");
113 if (std.enums.tagName(Configuration.Package.Index, inst.package)) |name| {
114 try sf.container.serializer.ident(name);
115 } else {
116 try sf.container.serializer.int(@backingInt(inst.package));
117 }
118
119 var otf = try sf.beginTupleField("user_input_options", .{});
120 for (inst.user_input_options.slice(c)) |option| {
121 var osf = try otf.beginStructField(.{});
122 try sc.printStruct(&osf, Configuration.PackageInstance.UserInputOption, option.get(c));
123 try osf.end();
124 }
125 try otf.end();
126
127 var msf = try sf.beginStructField("modules", .{});
128 for (inst.modules.keys.slice(c), inst.modules.values.slice(c)) |key, value| {
129 var msf2 = try msf.beginStructField(key.slice(c), .{});
130 try sc.printStruct(&msf2, Configuration.Module, value.get(c));
131 try msf2.end();
132 }
133 try msf.end();
134
135 try sf.end();
136 }
137 }
138
107139 try s.end();
108140}
109141
lib/std/Build.zig+3-3
......@@ -272,7 +272,7 @@ const InitializedDepContext = struct {
272272 }
273273};
274274
275const UserInputOptionsMap = StringHashMap(UserInputOption);
275pub const UserInputOptionsMap = StringHashMap(UserInputOption);
276276
277277const AvailableOption = struct {
278278 name: []const u8,
......@@ -282,13 +282,13 @@ const AvailableOption = struct {
282282 enum_options: ?[]const []const u8,
283283};
284284
285const UserInputOption = struct {
285pub const UserInputOption = struct {
286286 name: []const u8,
287287 value: UserValue,
288288 used: bool,
289289};
290290
291const UserValue = union(enum) {
291pub const UserValue = union(enum) {
292292 flag: void,
293293 scalar: []const u8,
294294 list: std.array_list.Managed([]const u8),
lib/std/Build/Configuration.zig+158-54
......@@ -17,6 +17,12 @@ available_options: []AvailableOption,
1717search_prefixes: []String,
1818/// Index 0 always exists and is the root package.
1919packages: []Package,
20/// Index 0 always exists and is the root package instance.
21///
22/// Unlike `packages`, each item corresponds to a `std.Build`, which is a
23/// package that was instantiated by running its build script with specific
24/// input options.
25package_instances: []PackageInstance,
2026extra: []u32,
2127default_step: Step.Index,
2228generated_files_len: u32,
......@@ -33,6 +39,7 @@ pub const Header = extern struct {
3339 available_options_len: u32,
3440 search_prefixes_len: u32,
3541 packages_len: u32,
42 package_instances_len: u32,
3643 extra_len: u32,
3744
3845 default_step: Step.Index,
......@@ -62,6 +69,7 @@ pub const Wip = struct {
6269 path_deps: std.ArrayList(PathDep) = .empty,
6370 search_prefixes: std.ArrayList(String) = .empty,
6471 packages: std.ArrayList(Package) = .empty,
72 package_instances: std.ArrayList(PackageInstance) = .empty,
6573 extra: std.ArrayList(u32) = .empty,
6674 next_generated_file_index: u32 = 0,
6775 cache_poison: bool = false,
......@@ -144,6 +152,7 @@ pub const Wip = struct {
144152 wip.path_deps.deinit(gpa);
145153 wip.search_prefixes.deinit(gpa);
146154 wip.packages.deinit(gpa);
155 wip.package_instances.deinit(gpa);
147156 wip.extra.deinit(gpa);
148157 wip.* = undefined;
149158 }
......@@ -164,6 +173,7 @@ pub const Wip = struct {
164173 .available_options_len = @intCast(wip.available_options.items.len),
165174 .search_prefixes_len = @intCast(wip.search_prefixes.items.len),
166175 .packages_len = @intCast(wip.packages.items.len),
176 .package_instances_len = @intCast(wip.package_instances.items.len),
167177 .extra_len = @intCast(wip.extra.items.len),
168178
169179 .default_step = static.default_step,
......@@ -182,6 +192,7 @@ pub const Wip = struct {
182192 @ptrCast(wip.available_options.items),
183193 @ptrCast(wip.search_prefixes.items),
184194 @ptrCast(wip.packages.items),
195 @ptrCast(wip.package_instances.items),
185196 @ptrCast(wip.extra.items),
186197 };
187198 try w.writeVecAll(&buffers);
......@@ -483,7 +494,7 @@ pub const AvailableOption = extern struct {
483494
484495pub const Step = extern struct {
485496 name: String,
486 owner: Package.Index,
497 owner: PackageInstance.Index,
487498 deps: Deps.Index,
488499 max_rss: MaxRss,
489500 extended: Storage.Extended(Flags, union(Tag) {
......@@ -1515,13 +1526,7 @@ pub const LazyPath = union(@This().Tag) {
15151526 };
15161527
15171528 /// An index into `extra`.
1518 pub const Index = enum(u32) {
1519 _,
1520
1521 pub fn get(this: @This(), c: *const Configuration) LazyPath {
1522 return extraData(c, LazyPath, @backingInt(this));
1523 }
1524 };
1529 pub const Index = IndexType(@This());
15251530
15261531 /// An index into `extra`, or `null`.
15271532 pub const OptionalIndex = enum(u32) {
......@@ -1538,7 +1543,7 @@ pub const LazyPath = union(@This().Tag) {
15381543
15391544 pub const SourcePath = struct {
15401545 flags: @This().Flags = .{},
1541 owner: Package.Index,
1546 owner: PackageInstance.Index,
15421547 sub_path: String,
15431548
15441549 pub const Flags = packed struct(u32) {
......@@ -1671,11 +1676,128 @@ pub const Package = extern struct {
16711676 };
16721677};
16731678
1679pub const PackageInstance = extern struct {
1680 package: Package.Index,
1681 user_input_options: UserInputOption.List.Index,
1682 modules: PublicModules,
1683
1684 pub const UserInputOption = struct {
1685 flags: Flags,
1686 name: String,
1687 value: Storage.FlagUnion(.flags, .tag, UserValue),
1688
1689 pub const Flags = packed struct(u32) {
1690 tag: UserValue.Tag,
1691 used: bool,
1692 _: u28 = 0,
1693 };
1694
1695 pub const List = struct {
1696 options: Storage.LengthPrefixedList(UserInputOption.Index),
1697
1698 pub const Index = enum(u32) {
1699 _,
1700
1701 pub fn get(this: @This(), c: *const Configuration) List {
1702 return extraData(c, List, @backingInt(this));
1703 }
1704
1705 pub fn slice(this: @This(), c: *const Configuration) []const UserInputOption.Index {
1706 return this.get(c).options.slice;
1707 }
1708 };
1709 };
1710
1711 pub const Index = IndexType(@This());
1712 };
1713
1714 pub const UserValue = union(Tag) {
1715 flag,
1716 scalar: String,
1717 list: StringList,
1718 map: Map.Index,
1719 lazy_path: LazyPath.Index,
1720 lazy_path_list: Storage.LengthPrefixedList(LazyPath.Index),
1721
1722 pub const Standalone = struct {
1723 flags: Flags,
1724 value: Storage.FlagUnion(.flags, .tag, UserValue),
1725
1726 pub const Flags = packed struct(u32) {
1727 tag: UserValue.Tag,
1728 _: u29 = 0,
1729 };
1730
1731 pub const Index = IndexType(@This());
1732 };
1733
1734 pub const Tag = enum(u3) {
1735 flag,
1736 scalar,
1737 list,
1738 map,
1739 lazy_path,
1740 lazy_path_list,
1741
1742 pub fn init(uv: @typeInfo(std.Build.UserValue).@"union".tag_type.?) @This() {
1743 return switch (uv) {
1744 inline else => |tag| @field(@This(), @tagName(tag)),
1745 };
1746 }
1747 };
1748
1749 pub const Map = struct {
1750 keys: StringList,
1751 values: Storage.LengthPrefixedList(UserValue.Standalone.Index),
1752
1753 pub const Index = IndexType(@This());
1754 };
1755 };
1756
1757 pub const PublicModules = extern struct {
1758 keys: StringList,
1759 values: Module.List.Index,
1760 };
1761
1762 pub const Index = enum(u32) {
1763 root,
1764 _,
1765
1766 pub fn ptr(this: @This(), c: *const Configuration) *const PackageInstance {
1767 return &c.package_instances[@backingInt(this)];
1768 }
1769
1770 pub fn package(this: @This(), c: *const Configuration) Package.Index {
1771 return this.ptr(c).package;
1772 }
1773 };
1774
1775 pub const OptionalIndex = enum(u32) {
1776 root,
1777 none = max_u32,
1778 _,
1779
1780 pub fn init(i: Index) OptionalIndex {
1781 const result: OptionalIndex = @fromBackingInt(@intCast(@backingInt(i)));
1782 assert(result != .none);
1783 return result;
1784 }
1785
1786 pub fn unwrap(this: @This()) ?Index {
1787 return switch (this) {
1788 .none => null,
1789 .root => .root,
1790 _ => @fromBackingInt(@intCast(@backingInt(this))),
1791 };
1792 }
1793 };
1794};
1795
16741796pub const Module = struct {
16751797 flags: Flags,
16761798 flags2: Flags2,
16771799 import_table: ImportTable.Index,
1678 owner: Package.Index,
1800 owner: PackageInstance.Index,
16791801 root_source_file: LazyPath.OptionalIndex,
16801802 resolved_target: ResolvedTarget.OptionalIndex,
16811803 c_macros: Storage.FlagLengthPrefixedList(.flags, .c_macros, String),
......@@ -1746,14 +1868,6 @@ pub const Module = struct {
17461868 }
17471869 };
17481870
1749 pub const Index = enum(u32) {
1750 _,
1751
1752 pub fn get(this: @This(), c: *const Configuration) Module {
1753 return extraData(c, Module, @backingInt(this));
1754 }
1755 };
1756
17571871 pub const Flags = packed struct(u32) {
17581872 optimize: Optimize,
17591873 strip: DefaultingBool,
......@@ -1824,6 +1938,24 @@ pub const Module = struct {
18241938 _: u30 = 0,
18251939 };
18261940 };
1941
1942 pub const Index = IndexType(@This());
1943
1944 pub const List = struct {
1945 modules: Storage.LengthPrefixedList(Module.Index),
1946
1947 pub const Index = enum(u32) {
1948 _,
1949
1950 pub fn get(this: @This(), c: *const Configuration) List {
1951 return extraData(c, List, @backingInt(this));
1952 }
1953
1954 pub fn slice(this: @This(), c: *const Configuration) []const Module.Index {
1955 return this.get(c).modules.slice;
1956 }
1957 };
1958 };
18271959};
18281960
18291961pub const ImportTable = struct {
......@@ -1908,7 +2040,7 @@ pub const OptionalStringList = enum(u32) {
19082040pub const PathDep = extern struct {
19092041 flags: Flags,
19102042 sub: String,
1911 pkg: Package.OptionalIndex,
2043 pkg: PackageInstance.OptionalIndex,
19122044
19132045 pub const Flags = packed struct(u32) {
19142046 mode: Mode,
......@@ -2051,13 +2183,7 @@ pub const SystemLib = struct {
20512183 name: String,
20522184 flags: Flags,
20532185
2054 pub const Index = enum(u32) {
2055 _,
2056
2057 pub fn get(this: @This(), c: *const Configuration) SystemLib {
2058 return extraData(c, SystemLib, @backingInt(this));
2059 }
2060 };
2186 pub const Index = IndexType(@This());
20612187
20622188 pub const UsePkgConfig = enum(u2) {
20632189 /// Don't use pkg-config, just pass -lfoo where foo is name.
......@@ -2090,13 +2216,7 @@ pub const CSourceFiles = struct {
20902216 args: Storage.FlagList(.flags, .args_len, String),
20912217 sub_paths: Storage.LengthPrefixedList(String),
20922218
2093 pub const Index = enum(u32) {
2094 _,
2095
2096 pub fn get(this: @This(), c: *const Configuration) CSourceFiles {
2097 return extraData(c, CSourceFiles, @backingInt(this));
2098 }
2099 };
2219 pub const Index = IndexType(@This());
21002220
21012221 pub const Flags = packed struct(u32) {
21022222 /// C compiler CLI flags.
......@@ -2110,13 +2230,7 @@ pub const CSourceFile = struct {
21102230 file: LazyPath.Index,
21112231 args: Storage.FlagList(.flags, .args_len, String),
21122232
2113 pub const Index = enum(u32) {
2114 _,
2115
2116 pub fn get(this: @This(), c: *const Configuration) CSourceFile {
2117 return extraData(c, CSourceFile, @backingInt(this));
2118 }
2119 };
2233 pub const Index = IndexType(@This());
21202234
21212235 pub const Flags = packed struct(u32) {
21222236 /// C compiler CLI flags.
......@@ -2131,13 +2245,7 @@ pub const RcSourceFile = struct {
21312245 args: Storage.FlagList(.flags, .args_len, String),
21322246 include_paths: Storage.FlagLengthPrefixedList(.flags, .include_paths, LazyPath.Index),
21332247
2134 pub const Index = enum(u32) {
2135 _,
2136
2137 pub fn get(this: @This(), c: *const Configuration) RcSourceFile {
2138 return extraData(c, RcSourceFile, @backingInt(this));
2139 }
2140 };
2248 pub const Index = IndexType(@This());
21412249
21422250 pub const Flags = packed struct(u32) {
21432251 /// C compiler CLI flags.
......@@ -2176,13 +2284,7 @@ pub const ResolvedTarget = struct {
21762284 /// defaults will be resolved.
21772285 result: TargetQuery.Index,
21782286
2179 pub const Index = enum(u32) {
2180 _,
2181
2182 pub fn get(this: @This(), c: *const Configuration) ResolvedTarget {
2183 return extraData(c, ResolvedTarget, @backingInt(this));
2184 }
2185 };
2287 pub const Index = IndexType(@This());
21862288
21872289 pub const OptionalIndex = enum(u32) {
21882290 none = max_u32,
......@@ -3204,6 +3306,7 @@ pub fn load(arena: Allocator, reader: *Io.Reader) LoadError!Configuration {
32043306 .available_options = try arena.alloc(AvailableOption, header.available_options_len),
32053307 .search_prefixes = try arena.alloc(String, header.search_prefixes_len),
32063308 .packages = try arena.alloc(Package, header.packages_len),
3309 .package_instances = try arena.alloc(PackageInstance, header.package_instances_len),
32073310 .extra = try arena.alloc(u32, header.extra_len),
32083311 .default_step = header.default_step,
32093312 .generated_files_len = header.generated_files_len,
......@@ -3218,6 +3321,7 @@ pub fn load(arena: Allocator, reader: *Io.Reader) LoadError!Configuration {
32183321 @ptrCast(result.available_options),
32193322 @ptrCast(result.search_prefixes),
32203323 @ptrCast(result.packages),
3324 @ptrCast(result.package_instances),
32213325 @ptrCast(result.extra),
32223326 };
32233327 try reader.readVecAll(&vecs);
lib/std/Build/Serialize.zig+146-21
......@@ -10,8 +10,10 @@ const log = std.log;
1010arena: Allocator,
1111wc: *Configuration.Wip,
1212module_map: std.array_hash_map.Auto(*std.Build.Module, Configuration.Module.Index) = .empty,
13/// Keyed by package hash.
14package_map: std.array_hash_map.String(Configuration.Package.Index) = .empty,
13/// Keyed by package hash. Index + 1 corresponds to `Configuration.packages` index.
14package_map: std.array_hash_map.String(void) = .empty,
15/// Index corresponds to `Configuration.package_instances` index.
16package_instance_map: std.array_hash_map.Auto(*std.Build, void) = .empty,
1517/// Index corresponds to `Configuration.steps` index.
1618step_map: std.array_hash_map.Auto(*Step, void) = .empty,
1719
......@@ -22,9 +24,28 @@ pub fn write(b: *std.Build, wc: *Configuration.Wip, writer: *std.Io.Writer) !voi
2224
2325 var s: Serialize = .{ .wc = wc, .arena = arena };
2426
25 // Serialize all of the packages first to seed the package_map, which is
26 // later used in calls to packageFromHash.
27 try s.addRootPackage(b);
27 // Seed the package_map, which is later used when serializing package
28 // instances.
29 try s.traversePackages(b);
30
31 // Next, seed the package_instance_map, which is later used in calls to
32 // packageInstanceFromBuilder.
33
34 _ = try wc.package_instances.addManyAsSlice(gpa, 1 + b.graph.dependency_cache.count());
35 try s.package_instance_map.ensureTotalCapacity(arena, 1 + b.graph.dependency_cache.count());
36
37 // As serializing package instances also requires serializing the public
38 // modules of each one, we must first allocate an index for each package
39 // instance. Otherwise, addModule may access a package instance that hasn't
40 // been created yet with packageInstanceFromBuilder.
41
42 s.package_instance_map.putAssumeCapacityNoClobber(b, {});
43 var iter = b.graph.dependency_cache.valueIterator();
44 while (iter.next()) |dep| s.package_instance_map.putAssumeCapacityNoClobber(dep.*.builder, {});
45
46 try s.addPackageInstance(b);
47 var iter2 = b.graph.dependency_cache.valueIterator();
48 while (iter2.next()) |dep| try s.addPackageInstance(dep.*.builder);
2849
2950 try wc.path_deps.ensureTotalCapacityPrecise(gpa, graph.configure_dependencies.items.len);
3051 for (
......@@ -49,10 +70,10 @@ pub fn write(b: *std.Build, wc: *Configuration.Wip, writer: *std.Io.Writer) !voi
4970 .relative => |r| try wc.addString(r.sub_path),
5071 },
5172 .pkg = switch (src.lazy_path) {
52 .src_path => |sp| .init(s.packageFromHash(sp.owner.pkg_hash)),
73 .src_path => |sp| .init(s.packageInstanceFromBuilder(sp.owner)),
5374 .generated => unreachable,
5475 .cwd_relative, .relative => .none,
55 .dependency => |d| .init(s.packageFromHash(d.dependency.builder.pkg_hash)),
76 .dependency => |d| .init(s.packageInstanceFromBuilder(d.dependency.builder)),
5677 },
5778 };
5879 }
......@@ -89,7 +110,7 @@ pub fn write(b: *std.Build, wc: *Configuration.Wip, writer: *std.Io.Writer) !voi
89110 try wc.steps.ensureTotalCapacity(gpa, s.step_map.entries.capacity);
90111 wc.steps.appendAssumeCapacity(.{
91112 .name = try wc.addString(step.name),
92 .owner = s.packageFromHash(step.owner.pkg_hash),
113 .owner = s.packageInstanceFromBuilder(step.owner),
93114 .deps = deps,
94115 .max_rss = .fromBytes(step.max_rss),
95116 .extended = @fromBackingInt(@intCast(switch (step.tag) {
......@@ -727,7 +748,7 @@ pub fn packageOptions(b: *std.Build, wc: *Configuration.Wip) Allocator.Error!voi
727748 }
728749}
729750
730fn addRootPackage(s: *Serialize, b: *std.Build) Allocator.Error!void {
751fn traversePackages(s: *Serialize, b: *std.Build) Allocator.Error!void {
731752 const arena = s.arena;
732753 const wc = s.wc;
733754
......@@ -741,7 +762,7 @@ fn addRootPackage(s: *Serialize, b: *std.Build) Allocator.Error!void {
741762 const deps = try arena.alloc(Configuration.Package.Dep, b.available_deps.len);
742763 for (deps, b.available_deps) |*dest, src| dest.* = try s.makePackageDep("", src[0], src[1]);
743764
744 wc.packages.items[0].deps = try wc.addExtra(Configuration.Package.Dep.List, .{
765 wc.packages.items[0].deps = try wc.addDeduped(Configuration.Package.Dep.List, .{
745766 .deps = .{ .slice = deps },
746767 });
747768}
......@@ -750,18 +771,18 @@ fn makePackageDep(s: *Serialize, parent_dep_prefix: []const u8, name: []const u8
750771 const arena = s.arena;
751772 const wc = s.wc;
752773
753 if (s.package_map.get(hash)) |index| return .{
774 if (s.package_map.getIndex(hash)) |index| return .{
754775 .name = try wc.addString(name),
755 .package = index,
776 .package = @fromBackingInt(@intCast(index + 1)),
756777 };
757778
779 const index: Configuration.Package.Index = @fromBackingInt(@intCast(wc.packages.items.len));
780 try s.package_map.put(arena, hash, {});
781
758782 const entry = std.Build.package_map.get(hash) orelse unreachable;
759783
760784 const dep_prefix = try arena.print("{s}{s}.", .{ parent_dep_prefix, name });
761785
762 const index: Configuration.Package.Index = @fromBackingInt(@intCast(wc.packages.items.len));
763 try s.package_map.put(arena, hash, index);
764
765786 try wc.packages.append(wc.gpa, .{
766787 .dep_prefix = try wc.addString(dep_prefix),
767788 .hash = try wc.addString(hash),
......@@ -772,7 +793,7 @@ fn makePackageDep(s: *Serialize, parent_dep_prefix: []const u8, name: []const u8
772793 const deps = try arena.alloc(Configuration.Package.Dep, entry.deps.len);
773794 for (deps, entry.deps) |*dest, src| dest.* = try s.makePackageDep(dep_prefix, src[0], src[1]);
774795
775 wc.packages.items[@backingInt(index)].deps = try wc.addExtra(Configuration.Package.Dep.List, .{
796 wc.packages.items[@backingInt(index)].deps = try wc.addDeduped(Configuration.Package.Dep.List, .{
776797 .deps = .{ .slice = deps },
777798 });
778799
......@@ -784,7 +805,111 @@ fn makePackageDep(s: *Serialize, parent_dep_prefix: []const u8, name: []const u8
784805
785806fn packageFromHash(s: *Serialize, pkg_hash: []const u8) Configuration.Package.Index {
786807 if (pkg_hash.len == 0) return .root;
787 return s.package_map.get(pkg_hash) orelse std.debug.panic("unrecognized package hash: {q}", .{pkg_hash});
808 return @fromBackingInt(@intCast(s.package_map.getIndex(pkg_hash).? + 1));
809}
810
811fn addPackageInstance(s: *Serialize, b: *std.Build) Allocator.Error!void {
812 const arena = s.arena;
813 const wc = s.wc;
814
815 const index = s.package_instance_map.getIndex(b).?;
816
817 const options = try arena.alloc(
818 Configuration.PackageInstance.UserInputOption.Index,
819 b.user_input_options.count(),
820 );
821
822 {
823 var i: usize = 0;
824 var iter = b.user_input_options.valueIterator();
825 while (iter.next()) |option| : (i += 1) {
826 options[i] = try wc.addExtra(Configuration.PackageInstance.UserInputOption, .{
827 .flags = .{
828 .tag = .init(option.value),
829 .used = option.used,
830 },
831 .name = try wc.addString(option.name),
832 .value = .{ .u = try s.makeUserValue(&option.value) },
833 });
834 }
835 }
836
837 const modules_keys = try arena.alloc(
838 []const u8,
839 b.modules.count(),
840 );
841 const modules_values = try arena.alloc(
842 Configuration.Module.Index,
843 b.modules.count(),
844 );
845
846 {
847 var i: usize = 0;
848 var iter = b.modules.iterator();
849 while (iter.next()) |entry| : (i += 1) {
850 modules_keys[i] = entry.key_ptr.*;
851 modules_values[i] = try s.addModule(entry.value_ptr.*);
852 }
853 }
854
855 wc.package_instances.items[index] = .{
856 .package = s.packageFromHash(b.pkg_hash),
857 .user_input_options = try wc.addDeduped(Configuration.PackageInstance.UserInputOption.List, .{
858 .options = .{ .slice = options },
859 }),
860 .modules = .{
861 .keys = try wc.addStringList(modules_keys),
862 .values = try wc.addDeduped(Configuration.Module.List, .{
863 .modules = .{ .slice = modules_values },
864 }),
865 },
866 };
867}
868
869fn makeUserValue(s: *Serialize, user_value: *const std.Build.UserValue) Allocator.Error!Configuration.PackageInstance.UserValue {
870 const arena = s.arena;
871 const wc = s.wc;
872
873 return switch (user_value.*) {
874 .flag => .flag,
875 .scalar => |str| .{ .scalar = try wc.addString(str) },
876 .list => |list| .{ .list = try wc.addStringList(list.items) },
877 .map => |map| add: {
878 const keys = try arena.alloc([]const u8, map.count());
879 const values = try arena.alloc(Configuration.PackageInstance.UserValue.Standalone.Index, map.count());
880
881 var i: usize = 0;
882 var iter = map.iterator();
883 while (iter.next()) |entry| : (i += 1) {
884 const value = try s.makeUserValue(entry.value_ptr.*);
885
886 keys[i] = entry.key_ptr.*;
887 values[i] = try wc.addDeduped(
888 Configuration.PackageInstance.UserValue.Standalone,
889 .{ .flags = .{ .tag = value }, .value = .{ .u = value } },
890 );
891 }
892
893 break :add .{ .map = try wc.addDeduped(
894 Configuration.PackageInstance.UserValue.Map,
895 .{
896 .keys = try wc.addStringList(keys),
897 .values = .{ .slice = values },
898 },
899 ) };
900 },
901 .lazy_path => |lp| .{ .lazy_path = try s.addLazyPath(lp) },
902 .lazy_path_list => |lp_list| add: {
903 const paths = try arena.alloc(Configuration.LazyPath.Index, lp_list.items.len);
904 for (paths, lp_list.items) |*dest, src| dest.* = try s.addLazyPath(src);
905 break :add .{ .lazy_path_list = .{ .slice = paths } };
906 },
907 };
908}
909
910fn packageInstanceFromBuilder(s: *Serialize, b: *std.Build) Configuration.PackageInstance.Index {
911 if (b.pkg_hash.len == 0) return .root;
912 return @fromBackingInt(@intCast(s.package_instance_map.getIndex(b).?));
788913}
789914
790915fn addOptionalLazyPathEnum(s: *Serialize, lp: ?std.Build.LazyPath) !Configuration.LazyPath.OptionalIndex {
......@@ -793,7 +918,7 @@ fn addOptionalLazyPathEnum(s: *Serialize, lp: ?std.Build.LazyPath) !Configuratio
793918 .src_path => |src_path| i: {
794919 const sub_path = try wc.addString(src_path.sub_path);
795920 break :i try wc.addExtraErased(Configuration.LazyPath.SourcePath, .{
796 .owner = s.packageFromHash(src_path.owner.pkg_hash),
921 .owner = s.packageInstanceFromBuilder(src_path.owner),
797922 .sub_path = sub_path,
798923 });
799924 },
......@@ -821,7 +946,7 @@ fn addOptionalLazyPathEnum(s: *Serialize, lp: ?std.Build.LazyPath) !Configuratio
821946 .dependency => |dependency| i: {
822947 const sub_path = try wc.addString(dependency.sub_path);
823948 break :i try wc.addExtraErased(Configuration.LazyPath.SourcePath, .{
824 .owner = s.packageFromHash(dependency.dependency.builder.pkg_hash),
949 .owner = s.packageInstanceFromBuilder(dependency.dependency.builder),
825950 .sub_path = sub_path,
826951 });
827952 },
......@@ -1250,7 +1375,7 @@ fn addModule(s: *Serialize, m: *std.Build.Module) !Configuration.Module.Index {
12501375 const c_macros = try initStringList(s, m.c_macros.items);
12511376 const export_symbol_names = try initStringList(s, m.export_symbol_names);
12521377
1253 const module_index: Configuration.Module.Index = try wc.addExtra(Configuration.Module, .{
1378 const module_index: Configuration.Module.Index = try wc.addDeduped(Configuration.Module, .{
12541379 .flags = .{
12551380 .optimize = .init(m.optimize),
12561381 .strip = .init(m.strip),
......@@ -1281,7 +1406,7 @@ fn addModule(s: *Serialize, m: *std.Build.Module) !Configuration.Module.Index {
12811406 .link_libcpp = .init(m.link_libcpp),
12821407 .no_builtin = .init(m.no_builtin),
12831408 },
1284 .owner = s.packageFromHash(m.owner.pkg_hash),
1409 .owner = s.packageInstanceFromBuilder(m.owner),
12851410 .root_source_file = try s.addOptionalLazyPathEnum(m.root_source_file),
12861411 .import_table = .invalid,
12871412 .resolved_target = try addOptionalResolvedTarget(wc, m.resolved_target),