authorgravatar for hemisputnik@proton.mehemisputnik <hemisputnik@proton.me> 2026-08-09 11:12:22+03:00
committergravatar for hemisputnik@proton.mehemisputnik <hemisputnik@proton.me> 2026-08-10 11:20:19+03:00
log3d50222f9b20fb2cb4ab5ae6e8bcb35f74adbda9
tree5ffb999dc6de6632c509f84c4e9668ff478a1708
parent27bf90f12b70c427411779c4fed99a6288c43710
signaturebadge-check Signed by SSH key SHA256:iUK/EffQPyeXTXChJNV0UrxsscinNLxnk+0pu4OGU7Q

std.Build.Configuration: reintroduce serialization of std.Build instances


5 files changed, 256 insertions(+), 22 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+24
......@@ -104,6 +104,30 @@ 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 try sf.end();
128 }
129 }
130
107131 try s.end();
108132}
109133
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+128-4
......@@ -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) {
......@@ -1532,7 +1543,7 @@ pub const LazyPath = union(@This().Tag) {
15321543
15331544 pub const SourcePath = struct {
15341545 flags: @This().Flags = .{},
1535 owner: Package.Index,
1546 owner: PackageInstance.Index,
15361547 sub_path: String,
15371548
15381549 pub const Flags = packed struct(u32) {
......@@ -1665,11 +1676,122 @@ pub const Package = extern struct {
16651676 };
16661677};
16671678
1679pub const PackageInstance = extern struct {
1680 package: Package.Index,
1681 user_input_options: UserInputOption.List.Index,
1682
1683 pub const UserInputOption = struct {
1684 flags: Flags,
1685 name: String,
1686 value: Storage.FlagUnion(.flags, .tag, UserValue),
1687
1688 pub const Flags = packed struct(u32) {
1689 tag: UserValue.Tag,
1690 used: bool,
1691 _: u28 = 0,
1692 };
1693
1694 pub const List = struct {
1695 options: Storage.LengthPrefixedList(UserInputOption.Index),
1696
1697 pub const Index = enum(u32) {
1698 _,
1699
1700 pub fn get(this: @This(), c: *const Configuration) List {
1701 return extraData(c, List, @backingInt(this));
1702 }
1703
1704 pub fn slice(this: @This(), c: *const Configuration) []const UserInputOption.Index {
1705 return this.get(c).options.slice;
1706 }
1707 };
1708 };
1709
1710 pub const Index = IndexType(@This());
1711 };
1712
1713 pub const UserValue = union(Tag) {
1714 flag,
1715 scalar: String,
1716 list: StringList,
1717 map: Map.Index,
1718 lazy_path: LazyPath.Index,
1719 lazy_path_list: Storage.LengthPrefixedList(LazyPath.Index),
1720
1721 pub const Standalone = struct {
1722 flags: Flags,
1723 value: Storage.FlagUnion(.flags, .tag, UserValue),
1724
1725 pub const Flags = packed struct(u32) {
1726 tag: UserValue.Tag,
1727 _: u29 = 0,
1728 };
1729
1730 pub const Index = IndexType(@This());
1731 };
1732
1733 pub const Tag = enum(u3) {
1734 flag,
1735 scalar,
1736 list,
1737 map,
1738 lazy_path,
1739 lazy_path_list,
1740
1741 pub fn init(uv: @typeInfo(std.Build.UserValue).@"union".tag_type.?) @This() {
1742 return switch (uv) {
1743 inline else => |tag| @field(@This(), @tagName(tag)),
1744 };
1745 }
1746 };
1747
1748 pub const Map = struct {
1749 keys: StringList,
1750 values: Storage.LengthPrefixedList(UserValue.Standalone.Index),
1751
1752 pub const Index = IndexType(@This());
1753 };
1754 };
1755
1756 pub const Index = enum(u32) {
1757 root,
1758 _,
1759
1760 pub fn ptr(this: @This(), c: *const Configuration) *const PackageInstance {
1761 return &c.package_instances[@backingInt(this)];
1762 }
1763
1764 pub fn package(this: @This(), c: *const Configuration) Package.Index {
1765 return this.ptr(c).package;
1766 }
1767 };
1768
1769 pub const OptionalIndex = enum(u32) {
1770 root,
1771 none = max_u32,
1772 _,
1773
1774 pub fn init(i: Index) OptionalIndex {
1775 const result: OptionalIndex = @fromBackingInt(@intCast(@backingInt(i)));
1776 assert(result != .none);
1777 return result;
1778 }
1779
1780 pub fn unwrap(this: @This()) ?Index {
1781 return switch (this) {
1782 .none => null,
1783 .root => .root,
1784 _ => @fromBackingInt(@intCast(@backingInt(this))),
1785 };
1786 }
1787 };
1788};
1789
16681790pub const Module = struct {
16691791 flags: Flags,
16701792 flags2: Flags2,
16711793 import_table: ImportTable.Index,
1672 owner: Package.Index,
1794 owner: PackageInstance.Index,
16731795 root_source_file: LazyPath.OptionalIndex,
16741796 resolved_target: ResolvedTarget.OptionalIndex,
16751797 c_macros: Storage.FlagLengthPrefixedList(.flags, .c_macros, String),
......@@ -1896,7 +2018,7 @@ pub const OptionalStringList = enum(u32) {
18962018pub const PathDep = extern struct {
18972019 flags: Flags,
18982020 sub: String,
1899 pkg: Package.OptionalIndex,
2021 pkg: PackageInstance.OptionalIndex,
19002022
19012023 pub const Flags = packed struct(u32) {
19022024 mode: Mode,
......@@ -3162,6 +3284,7 @@ pub fn load(arena: Allocator, reader: *Io.Reader) LoadError!Configuration {
31623284 .available_options = try arena.alloc(AvailableOption, header.available_options_len),
31633285 .search_prefixes = try arena.alloc(String, header.search_prefixes_len),
31643286 .packages = try arena.alloc(Package, header.packages_len),
3287 .package_instances = try arena.alloc(PackageInstance, header.package_instances_len),
31653288 .extra = try arena.alloc(u32, header.extra_len),
31663289 .default_step = header.default_step,
31673290 .generated_files_len = header.generated_files_len,
......@@ -3176,6 +3299,7 @@ pub fn load(arena: Allocator, reader: *Io.Reader) LoadError!Configuration {
31763299 @ptrCast(result.available_options),
31773300 @ptrCast(result.search_prefixes),
31783301 @ptrCast(result.packages),
3302 @ptrCast(result.package_instances),
31793303 @ptrCast(result.extra),
31803304 };
31813305 try reader.readVecAll(&vecs);
lib/std/Build/Serialize.zig+96-10
......@@ -12,6 +12,8 @@ wc: *Configuration.Wip,
1212module_map: std.array_hash_map.Auto(*std.Build.Module, Configuration.Module.Index) = .empty,
1313/// Keyed by package hash. Index + 1 corresponds to `Configuration.packages` index.
1414package_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,15 @@ 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 // Seed the package_instance_map, which is later used in calls to
32 // packageInstanceFromBuilder.
33 try s.addPackageInstance(b);
34 var iter = b.graph.dependency_cache.valueIterator();
35 while (iter.next()) |dep| try s.addPackageInstance(dep.*.builder);
2836
2937 try wc.path_deps.ensureTotalCapacityPrecise(gpa, graph.configure_dependencies.items.len);
3038 for (
......@@ -49,10 +57,10 @@ pub fn write(b: *std.Build, wc: *Configuration.Wip, writer: *std.Io.Writer) !voi
4957 .relative => |r| try wc.addString(r.sub_path),
5058 },
5159 .pkg = switch (src.lazy_path) {
52 .src_path => |sp| .init(s.packageFromHash(sp.owner.pkg_hash)),
60 .src_path => |sp| .init(s.packageInstanceFromBuilder(sp.owner)),
5361 .generated => unreachable,
5462 .cwd_relative, .relative => .none,
55 .dependency => |d| .init(s.packageFromHash(d.dependency.builder.pkg_hash)),
63 .dependency => |d| .init(s.packageInstanceFromBuilder(d.dependency.builder)),
5664 },
5765 };
5866 }
......@@ -89,7 +97,7 @@ pub fn write(b: *std.Build, wc: *Configuration.Wip, writer: *std.Io.Writer) !voi
8997 try wc.steps.ensureTotalCapacity(gpa, s.step_map.entries.capacity);
9098 wc.steps.appendAssumeCapacity(.{
9199 .name = try wc.addString(step.name),
92 .owner = s.packageFromHash(step.owner.pkg_hash),
100 .owner = s.packageInstanceFromBuilder(step.owner),
93101 .deps = deps,
94102 .max_rss = .fromBytes(step.max_rss),
95103 .extended = @fromBackingInt(@intCast(switch (step.tag) {
......@@ -727,7 +735,7 @@ pub fn packageOptions(b: *std.Build, wc: *Configuration.Wip) Allocator.Error!voi
727735 }
728736}
729737
730fn addRootPackage(s: *Serialize, b: *std.Build) Allocator.Error!void {
738fn traversePackages(s: *Serialize, b: *std.Build) Allocator.Error!void {
731739 const arena = s.arena;
732740 const wc = s.wc;
733741
......@@ -787,13 +795,91 @@ fn packageFromHash(s: *Serialize, pkg_hash: []const u8) Configuration.Package.In
787795 return @fromBackingInt(@intCast(s.package_map.getIndex(pkg_hash).? + 1));
788796}
789797
798fn addPackageInstance(s: *Serialize, b: *std.Build) Allocator.Error!void {
799 const arena = s.arena;
800 const wc = s.wc;
801
802 const options = try arena.alloc(
803 Configuration.PackageInstance.UserInputOption.Index,
804 b.user_input_options.count(),
805 );
806
807 var i: usize = 0;
808 var iter = b.user_input_options.valueIterator();
809 while (iter.next()) |option| : (i += 1) {
810 options[i] = try wc.addExtra(Configuration.PackageInstance.UserInputOption, .{
811 .flags = .{
812 .tag = .init(option.value),
813 .used = option.used,
814 },
815 .name = try wc.addString(option.name),
816 .value = .{ .u = try s.makeUserValue(&option.value) },
817 });
818 }
819
820 try wc.package_instances.append(wc.gpa, .{
821 .package = s.packageFromHash(b.pkg_hash),
822 .user_input_options = try wc.addDeduped(Configuration.PackageInstance.UserInputOption.List, .{
823 .options = .{ .slice = options },
824 }),
825 });
826
827 try s.package_instance_map.put(arena, b, {});
828}
829
830fn makeUserValue(s: *Serialize, user_value: *const std.Build.UserValue) Allocator.Error!Configuration.PackageInstance.UserValue {
831 const arena = s.arena;
832 const wc = s.wc;
833
834 return switch (user_value.*) {
835 .flag => .flag,
836 .scalar => |str| .{ .scalar = try wc.addString(str) },
837 .list => |list| .{ .list = try wc.addStringList(list.items) },
838 .map => |map| add: {
839 const keys = try arena.alloc([]const u8, map.count());
840 const values = try arena.alloc(Configuration.PackageInstance.UserValue.Standalone.Index, map.count());
841
842 var i: usize = 0;
843 var iter = map.iterator();
844 while (iter.next()) |entry| : (i += 1) {
845 const value = try s.makeUserValue(entry.value_ptr.*);
846
847 keys[i] = entry.key_ptr.*;
848 values[i] = try wc.addDeduped(
849 Configuration.PackageInstance.UserValue.Standalone,
850 .{ .flags = .{ .tag = value }, .value = .{ .u = value } },
851 );
852 }
853
854 break :add .{ .map = try wc.addDeduped(
855 Configuration.PackageInstance.UserValue.Map,
856 .{
857 .keys = try wc.addStringList(keys),
858 .values = .{ .slice = values },
859 },
860 ) };
861 },
862 .lazy_path => |lp| .{ .lazy_path = try s.addLazyPath(lp) },
863 .lazy_path_list => |lp_list| add: {
864 const paths = try arena.alloc(Configuration.LazyPath.Index, lp_list.items.len);
865 for (paths, lp_list.items) |*dest, src| dest.* = try s.addLazyPath(src);
866 break :add .{ .lazy_path_list = .{ .slice = paths } };
867 },
868 };
869}
870
871fn packageInstanceFromBuilder(s: *Serialize, b: *std.Build) Configuration.PackageInstance.Index {
872 if (b.pkg_hash.len == 0) return .root;
873 return @fromBackingInt(@intCast(s.package_instance_map.getIndex(b).?));
874}
875
790876fn addOptionalLazyPathEnum(s: *Serialize, lp: ?std.Build.LazyPath) !Configuration.LazyPath.OptionalIndex {
791877 const wc = s.wc;
792878 return @fromBackingInt(@intCast(switch (lp orelse return .none) {
793879 .src_path => |src_path| i: {
794880 const sub_path = try wc.addString(src_path.sub_path);
795881 break :i try wc.addExtraErased(Configuration.LazyPath.SourcePath, .{
796 .owner = s.packageFromHash(src_path.owner.pkg_hash),
882 .owner = s.packageInstanceFromBuilder(src_path.owner),
797883 .sub_path = sub_path,
798884 });
799885 },
......@@ -821,7 +907,7 @@ fn addOptionalLazyPathEnum(s: *Serialize, lp: ?std.Build.LazyPath) !Configuratio
821907 .dependency => |dependency| i: {
822908 const sub_path = try wc.addString(dependency.sub_path);
823909 break :i try wc.addExtraErased(Configuration.LazyPath.SourcePath, .{
824 .owner = s.packageFromHash(dependency.dependency.builder.pkg_hash),
910 .owner = s.packageInstanceFromBuilder(dependency.dependency.builder),
825911 .sub_path = sub_path,
826912 });
827913 },
......@@ -1281,7 +1367,7 @@ fn addModule(s: *Serialize, m: *std.Build.Module) !Configuration.Module.Index {
12811367 .link_libcpp = .init(m.link_libcpp),
12821368 .no_builtin = .init(m.no_builtin),
12831369 },
1284 .owner = s.packageFromHash(m.owner.pkg_hash),
1370 .owner = s.packageInstanceFromBuilder(m.owner),
12851371 .root_source_file = try s.addOptionalLazyPathEnum(m.root_source_file),
12861372 .import_table = .invalid,
12871373 .resolved_target = try addOptionalResolvedTarget(wc, m.resolved_target),