diff --git a/lib/compiler/Maker.zig b/lib/compiler/Maker.zig index ea2a05c1bb8e19b598e899ef3107348bd0e70da9..51195aaf23bea8bb551d175b61cc57804b3a50e1 100644 --- a/lib/compiler/Maker.zig +++ b/lib/compiler/Maker.zig @@ -2226,7 +2226,7 @@ fn prepare(maker: *Maker, step_indices: []const Configuration.Step.Index) !void } } else { log.err("{s}{s}: this step declares an upper bound of {d} bytes of memory, exceeding the available {d} bytes of memory", .{ - conf_step.owner.depPrefixSlice(c), + conf_step.owner.package(c).depPrefixSlice(c), conf_step.name.slice(c), max_rss, maker.available_rss, @@ -3320,13 +3320,13 @@ pub fn generatedPath(maker: *const Maker, index: Configuration.GeneratedFileInde pub fn packagePath( maker: *const Maker, arena: Allocator, - package_index: Configuration.Package.Index, + inst_index: Configuration.PackageInstance.Index, sub_path: []const u8, ) Allocator.Error!Path { const c = &maker.scanned_config.configuration; const graph = maker.graph; - if (package_index == .root) return .{ + if (inst_index == .root) return .{ .root_dir = graph.build_root_directory, .sub_path = sub_path, }; @@ -3337,7 +3337,7 @@ pub fn packagePath( // construct a cwd relative path here. return .{ .root_dir = .cwd(), - .sub_path = try Dir.path.join(arena, &.{ package_index.ptr(c).root_path.slice(c), sub_path }), + .sub_path = try Dir.path.join(arena, &.{ inst_index.package(c).ptr(c).root_path.slice(c), sub_path }), }; } @@ -3967,7 +3967,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.ptr(c).root_path.slice(c), sub_path }), + else => |index| try Dir.path.join(arena, &.{ index.package(c).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 168ae8b7f61ec27abf36a4d46c2e675e982b0061..e22a85f05485de0c63804b3e756e54ae627affe5 100644 --- a/lib/compiler/Maker/ScannedConfig.zig +++ b/lib/compiler/Maker/ScannedConfig.zig @@ -104,6 +104,30 @@ pub fn print(sc: *const ScannedConfig, w: *Writer) Writer.Error!void { try tf.end(); } + { + var tf = try s.beginTupleField("package_instances", .{}); + for (c.package_instances) |inst| { + var sf = try tf.beginStructField(.{}); + + try sf.fieldPrefix("package"); + if (std.enums.tagName(Configuration.Package.Index, inst.package)) |name| { + try sf.container.serializer.ident(name); + } else { + try sf.container.serializer.int(@backingInt(inst.package)); + } + + var otf = try sf.beginTupleField("user_input_options", .{}); + for (inst.user_input_options.slice(c)) |option| { + var osf = try otf.beginStructField(.{}); + try sc.printStruct(&osf, Configuration.PackageInstance.UserInputOption, option.get(c)); + try osf.end(); + } + try otf.end(); + + try sf.end(); + } + } + try s.end(); } diff --git a/lib/std/Build.zig b/lib/std/Build.zig index 97b80ff490a06211b4fe40c1e2852a087e59fea8..5a76ce30e3cb619e99d86f59b809aae29aa18c3b 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -272,7 +272,7 @@ const InitializedDepContext = struct { } }; -const UserInputOptionsMap = StringHashMap(UserInputOption); +pub const UserInputOptionsMap = StringHashMap(UserInputOption); const AvailableOption = struct { name: []const u8, @@ -282,13 +282,13 @@ const AvailableOption = struct { enum_options: ?[]const []const u8, }; -const UserInputOption = struct { +pub const UserInputOption = struct { name: []const u8, value: UserValue, used: bool, }; -const UserValue = union(enum) { +pub const UserValue = union(enum) { flag: void, scalar: []const u8, list: std.array_list.Managed([]const u8), diff --git a/lib/std/Build/Configuration.zig b/lib/std/Build/Configuration.zig index a4e8fbe2dc9743fdecef4f0b1eaf8c11e79cfe21..cf2b381eb50cee02e6f420c76de4d8d9e66cdead 100644 --- a/lib/std/Build/Configuration.zig +++ b/lib/std/Build/Configuration.zig @@ -17,6 +17,12 @@ available_options: []AvailableOption, search_prefixes: []String, /// Index 0 always exists and is the root package. packages: []Package, +/// Index 0 always exists and is the root package instance. +/// +/// Unlike `packages`, each item corresponds to a `std.Build`, which is a +/// package that was instantiated by running its build script with specific +/// input options. +package_instances: []PackageInstance, extra: []u32, default_step: Step.Index, generated_files_len: u32, @@ -33,6 +39,7 @@ pub const Header = extern struct { available_options_len: u32, search_prefixes_len: u32, packages_len: u32, + package_instances_len: u32, extra_len: u32, default_step: Step.Index, @@ -62,6 +69,7 @@ pub const Wip = struct { path_deps: std.ArrayList(PathDep) = .empty, search_prefixes: std.ArrayList(String) = .empty, packages: std.ArrayList(Package) = .empty, + package_instances: std.ArrayList(PackageInstance) = .empty, extra: std.ArrayList(u32) = .empty, next_generated_file_index: u32 = 0, cache_poison: bool = false, @@ -144,6 +152,7 @@ pub const Wip = struct { wip.path_deps.deinit(gpa); wip.search_prefixes.deinit(gpa); wip.packages.deinit(gpa); + wip.package_instances.deinit(gpa); wip.extra.deinit(gpa); wip.* = undefined; } @@ -164,6 +173,7 @@ pub const Wip = struct { .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), + .package_instances_len = @intCast(wip.package_instances.items.len), .extra_len = @intCast(wip.extra.items.len), .default_step = static.default_step, @@ -182,6 +192,7 @@ pub const Wip = struct { @ptrCast(wip.available_options.items), @ptrCast(wip.search_prefixes.items), @ptrCast(wip.packages.items), + @ptrCast(wip.package_instances.items), @ptrCast(wip.extra.items), }; try w.writeVecAll(&buffers); @@ -483,7 +494,7 @@ pub const AvailableOption = extern struct { pub const Step = extern struct { name: String, - owner: Package.Index, + owner: PackageInstance.Index, deps: Deps.Index, max_rss: MaxRss, extended: Storage.Extended(Flags, union(Tag) { @@ -1532,7 +1543,7 @@ pub const LazyPath = union(@This().Tag) { pub const SourcePath = struct { flags: @This().Flags = .{}, - owner: Package.Index, + owner: PackageInstance.Index, sub_path: String, pub const Flags = packed struct(u32) { @@ -1665,11 +1676,122 @@ pub const Package = extern struct { }; }; +pub const PackageInstance = extern struct { + package: Package.Index, + user_input_options: UserInputOption.List.Index, + + pub const UserInputOption = struct { + flags: Flags, + name: String, + value: Storage.FlagUnion(.flags, .tag, UserValue), + + pub const Flags = packed struct(u32) { + tag: UserValue.Tag, + used: bool, + _: u28 = 0, + }; + + pub const List = struct { + options: Storage.LengthPrefixedList(UserInputOption.Index), + + 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 UserInputOption.Index { + return this.get(c).options.slice; + } + }; + }; + + pub const Index = IndexType(@This()); + }; + + pub const UserValue = union(Tag) { + flag, + scalar: String, + list: StringList, + map: Map.Index, + lazy_path: LazyPath.Index, + lazy_path_list: Storage.LengthPrefixedList(LazyPath.Index), + + pub const Standalone = struct { + flags: Flags, + value: Storage.FlagUnion(.flags, .tag, UserValue), + + pub const Flags = packed struct(u32) { + tag: UserValue.Tag, + _: u29 = 0, + }; + + pub const Index = IndexType(@This()); + }; + + pub const Tag = enum(u3) { + flag, + scalar, + list, + map, + lazy_path, + lazy_path_list, + + pub fn init(uv: @typeInfo(std.Build.UserValue).@"union".tag_type.?) @This() { + return switch (uv) { + inline else => |tag| @field(@This(), @tagName(tag)), + }; + } + }; + + pub const Map = struct { + keys: StringList, + values: Storage.LengthPrefixedList(UserValue.Standalone.Index), + + pub const Index = IndexType(@This()); + }; + }; + + pub const Index = enum(u32) { + root, + _, + + pub fn ptr(this: @This(), c: *const Configuration) *const PackageInstance { + return &c.package_instances[@backingInt(this)]; + } + + pub fn package(this: @This(), c: *const Configuration) Package.Index { + return this.ptr(c).package; + } + }; + + pub const OptionalIndex = enum(u32) { + root, + none = max_u32, + _, + + pub fn init(i: Index) OptionalIndex { + const result: OptionalIndex = @fromBackingInt(@intCast(@backingInt(i))); + assert(result != .none); + return result; + } + + pub fn unwrap(this: @This()) ?Index { + return switch (this) { + .none => null, + .root => .root, + _ => @fromBackingInt(@intCast(@backingInt(this))), + }; + } + }; +}; + pub const Module = struct { flags: Flags, flags2: Flags2, import_table: ImportTable.Index, - owner: Package.Index, + owner: PackageInstance.Index, root_source_file: LazyPath.OptionalIndex, resolved_target: ResolvedTarget.OptionalIndex, c_macros: Storage.FlagLengthPrefixedList(.flags, .c_macros, String), @@ -1896,7 +2018,7 @@ pub const OptionalStringList = enum(u32) { pub const PathDep = extern struct { flags: Flags, sub: String, - pkg: Package.OptionalIndex, + pkg: PackageInstance.OptionalIndex, pub const Flags = packed struct(u32) { mode: Mode, @@ -3162,6 +3284,7 @@ pub fn load(arena: Allocator, reader: *Io.Reader) LoadError!Configuration { .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), + .package_instances = try arena.alloc(PackageInstance, header.package_instances_len), .extra = try arena.alloc(u32, header.extra_len), .default_step = header.default_step, .generated_files_len = header.generated_files_len, @@ -3176,6 +3299,7 @@ pub fn load(arena: Allocator, reader: *Io.Reader) LoadError!Configuration { @ptrCast(result.available_options), @ptrCast(result.search_prefixes), @ptrCast(result.packages), + @ptrCast(result.package_instances), @ptrCast(result.extra), }; try reader.readVecAll(&vecs); diff --git a/lib/std/Build/Serialize.zig b/lib/std/Build/Serialize.zig index 7ee9520662c9a7d63007dfe20ca9e9fc9445663d..07db1a98868fabda194cd5b25fc9d1be74239478 100644 --- a/lib/std/Build/Serialize.zig +++ b/lib/std/Build/Serialize.zig @@ -12,6 +12,8 @@ wc: *Configuration.Wip, module_map: std.array_hash_map.Auto(*std.Build.Module, Configuration.Module.Index) = .empty, /// Keyed by package hash. Index + 1 corresponds to `Configuration.packages` index. package_map: std.array_hash_map.String(void) = .empty, +/// Index corresponds to `Configuration.package_instances` index. +package_instance_map: std.array_hash_map.Auto(*std.Build, void) = .empty, /// Index corresponds to `Configuration.steps` index. step_map: std.array_hash_map.Auto(*Step, void) = .empty, @@ -22,9 +24,15 @@ 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); + // Seed the package_map, which is later used when serializing package + // instances. + try s.traversePackages(b); + + // Seed the package_instance_map, which is later used in calls to + // packageInstanceFromBuilder. + try s.addPackageInstance(b); + var iter = b.graph.dependency_cache.valueIterator(); + while (iter.next()) |dep| try s.addPackageInstance(dep.*.builder); try wc.path_deps.ensureTotalCapacityPrecise(gpa, graph.configure_dependencies.items.len); for ( @@ -49,10 +57,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(s.packageFromHash(sp.owner.pkg_hash)), + .src_path => |sp| .init(s.packageInstanceFromBuilder(sp.owner)), .generated => unreachable, .cwd_relative, .relative => .none, - .dependency => |d| .init(s.packageFromHash(d.dependency.builder.pkg_hash)), + .dependency => |d| .init(s.packageInstanceFromBuilder(d.dependency.builder)), }, }; } @@ -89,7 +97,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 = s.packageFromHash(step.owner.pkg_hash), + .owner = s.packageInstanceFromBuilder(step.owner), .deps = deps, .max_rss = .fromBytes(step.max_rss), .extended = @fromBackingInt(@intCast(switch (step.tag) { @@ -727,7 +735,7 @@ pub fn packageOptions(b: *std.Build, wc: *Configuration.Wip) Allocator.Error!voi } } -fn addRootPackage(s: *Serialize, b: *std.Build) Allocator.Error!void { +fn traversePackages(s: *Serialize, b: *std.Build) Allocator.Error!void { const arena = s.arena; const wc = s.wc; @@ -787,13 +795,91 @@ fn packageFromHash(s: *Serialize, pkg_hash: []const u8) Configuration.Package.In return @fromBackingInt(@intCast(s.package_map.getIndex(pkg_hash).? + 1)); } +fn addPackageInstance(s: *Serialize, b: *std.Build) Allocator.Error!void { + const arena = s.arena; + const wc = s.wc; + + const options = try arena.alloc( + Configuration.PackageInstance.UserInputOption.Index, + b.user_input_options.count(), + ); + + var i: usize = 0; + var iter = b.user_input_options.valueIterator(); + while (iter.next()) |option| : (i += 1) { + options[i] = try wc.addExtra(Configuration.PackageInstance.UserInputOption, .{ + .flags = .{ + .tag = .init(option.value), + .used = option.used, + }, + .name = try wc.addString(option.name), + .value = .{ .u = try s.makeUserValue(&option.value) }, + }); + } + + try wc.package_instances.append(wc.gpa, .{ + .package = s.packageFromHash(b.pkg_hash), + .user_input_options = try wc.addDeduped(Configuration.PackageInstance.UserInputOption.List, .{ + .options = .{ .slice = options }, + }), + }); + + try s.package_instance_map.put(arena, b, {}); +} + +fn makeUserValue(s: *Serialize, user_value: *const std.Build.UserValue) Allocator.Error!Configuration.PackageInstance.UserValue { + const arena = s.arena; + const wc = s.wc; + + return switch (user_value.*) { + .flag => .flag, + .scalar => |str| .{ .scalar = try wc.addString(str) }, + .list => |list| .{ .list = try wc.addStringList(list.items) }, + .map => |map| add: { + const keys = try arena.alloc([]const u8, map.count()); + const values = try arena.alloc(Configuration.PackageInstance.UserValue.Standalone.Index, map.count()); + + var i: usize = 0; + var iter = map.iterator(); + while (iter.next()) |entry| : (i += 1) { + const value = try s.makeUserValue(entry.value_ptr.*); + + keys[i] = entry.key_ptr.*; + values[i] = try wc.addDeduped( + Configuration.PackageInstance.UserValue.Standalone, + .{ .flags = .{ .tag = value }, .value = .{ .u = value } }, + ); + } + + break :add .{ .map = try wc.addDeduped( + Configuration.PackageInstance.UserValue.Map, + .{ + .keys = try wc.addStringList(keys), + .values = .{ .slice = values }, + }, + ) }; + }, + .lazy_path => |lp| .{ .lazy_path = try s.addLazyPath(lp) }, + .lazy_path_list => |lp_list| add: { + const paths = try arena.alloc(Configuration.LazyPath.Index, lp_list.items.len); + for (paths, lp_list.items) |*dest, src| dest.* = try s.addLazyPath(src); + break :add .{ .lazy_path_list = .{ .slice = paths } }; + }, + }; +} + +fn packageInstanceFromBuilder(s: *Serialize, b: *std.Build) Configuration.PackageInstance.Index { + if (b.pkg_hash.len == 0) return .root; + return @fromBackingInt(@intCast(s.package_instance_map.getIndex(b).?)); +} + fn addOptionalLazyPathEnum(s: *Serialize, lp: ?std.Build.LazyPath) !Configuration.LazyPath.OptionalIndex { const wc = s.wc; return @fromBackingInt(@intCast(switch (lp orelse return .none) { .src_path => |src_path| i: { const sub_path = try wc.addString(src_path.sub_path); break :i try wc.addExtraErased(Configuration.LazyPath.SourcePath, .{ - .owner = s.packageFromHash(src_path.owner.pkg_hash), + .owner = s.packageInstanceFromBuilder(src_path.owner), .sub_path = sub_path, }); }, @@ -821,7 +907,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 = s.packageFromHash(dependency.dependency.builder.pkg_hash), + .owner = s.packageInstanceFromBuilder(dependency.dependency.builder), .sub_path = sub_path, }); }, @@ -1281,7 +1367,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 = s.packageFromHash(m.owner.pkg_hash), + .owner = s.packageInstanceFromBuilder(m.owner), .root_source_file = try s.addOptionalLazyPathEnum(m.root_source_file), .import_table = .invalid, .resolved_target = try addOptionalResolvedTarget(wc, m.resolved_target),