authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-02-26 18:44:23-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-05-25 18:54:34-07:00
log6925a57d2fd4e4b1330d980cbfb84f7007f117ef
tree6c88e9d892c081e4ee53cf5ca4463fe006dc7538
parentb04818644c958e05de9b0d5fb4a8a2a3da6d2164

Configuration: implement UnionList storage


5 files changed, 301 insertions(+), 66 deletions(-)

lib/compiler/Maker/ScannedConfig.zig+3
...@@ -15,6 +15,7 @@ pub fn print(sc: *const ScannedConfig, w: *Writer) Writer.Error!void {...@@ -15,6 +15,7 @@ pub fn print(sc: *const ScannedConfig, w: *Writer) Writer.Error!void {
15 std.log.err("TODO also print unlazy deps", .{});15 std.log.err("TODO also print unlazy deps", .{});
16 std.log.err("TODO also print system integrations", .{});16 std.log.err("TODO also print system integrations", .{});
17 std.log.err("TODO also print available options", .{});17 std.log.err("TODO also print available options", .{});
18 std.log.err("TODO also print modules", .{});
18 const c = &sc.configuration;19 const c = &sc.configuration;
19 var serializer: Serializer = .{ .writer = w };20 var serializer: Serializer = .{ .writer = w };
20 var s = try serializer.beginStruct(.{});21 var s = try serializer.beginStruct(.{});
...@@ -83,6 +84,7 @@ fn printValue(sc: *const ScannedConfig, s: *Serializer, comptime Field: type, fi...@@ -83,6 +84,7 @@ fn printValue(sc: *const ScannedConfig, s: *Serializer, comptime Field: type, fi
83 .flag_optional => comptime unreachable,84 .flag_optional => comptime unreachable,
84 .flag_length_prefixed_list => comptime unreachable,85 .flag_length_prefixed_list => comptime unreachable,
85 .enum_optional => comptime unreachable,86 .enum_optional => comptime unreachable,
87 .union_list => comptime unreachable,
86 } else if (std.enums.tagName(Field, field_value)) |name| {88 } else if (std.enums.tagName(Field, field_value)) |name| {
87 try s.ident(name);89 try s.ident(name);
88 } else {90 } else {
...@@ -105,6 +107,7 @@ fn printValue(sc: *const ScannedConfig, s: *Serializer, comptime Field: type, fi...@@ -105,6 +107,7 @@ fn printValue(sc: *const ScannedConfig, s: *Serializer, comptime Field: type, fi
105 try printValue(sc, s, @TypeOf(field_value.slice), field_value.slice);107 try printValue(sc, s, @TypeOf(field_value.slice), field_value.slice);
106 },108 },
107 .extended => @compileError("TODO"),109 .extended => @compileError("TODO"),
110 .union_list => @compileError("TODO"),
108 },111 },
109 else => @compileError("not implemented: " ++ @typeName(Field)),112 else => @compileError("not implemented: " ++ @typeName(Field)),
110 },113 },
lib/compiler/configurer.zig+101-19
...@@ -224,6 +224,8 @@ const Serialize = struct {...@@ -224,6 +224,8 @@ const Serialize = struct {
224 wc: *Configuration.Wip,224 wc: *Configuration.Wip,
225 module_map: std.AutoArrayHashMapUnmanaged(*std.Build.Module, Configuration.Module.Index) = .empty,225 module_map: std.AutoArrayHashMapUnmanaged(*std.Build.Module, Configuration.Module.Index) = .empty,
226 package_map: std.AutoArrayHashMapUnmanaged(*std.Build, Configuration.Package.Index) = .empty,226 package_map: std.AutoArrayHashMapUnmanaged(*std.Build, Configuration.Package.Index) = .empty,
227 /// Index corresponds to `Configuration.steps` index.
228 step_map: std.AutoArrayHashMapUnmanaged(*Step, void) = .empty,
227229
228 fn builderToPackage(s: *Serialize, b: *std.Build) !Configuration.Package.Index {230 fn builderToPackage(s: *Serialize, b: *std.Build) !Configuration.Package.Index {
229 if (b.pkg_hash.len == 0) return .root;231 if (b.pkg_hash.len == 0) return .root;
...@@ -291,6 +293,56 @@ const Serialize = struct {...@@ -291,6 +293,56 @@ const Serialize = struct {
291 return if (opt_slice) |slice| try s.wc.addString(slice) else null;293 return if (opt_slice) |slice| try s.wc.addString(slice) else null;
292 }294 }
293295
296 fn addSystemLib(s: *Serialize, sl: *const std.Build.Module.SystemLib) !Configuration.SystemLib.Index {
297 log.err("TODO deduplicate addSystemLib", .{});
298 const wc = s.wc;
299 return @enumFromInt(try wc.addExtra(@as(Configuration.SystemLib, .{
300 .flags = .{
301 .needed = sl.needed,
302 .weak = sl.weak,
303 .use_pkg_config = sl.use_pkg_config,
304 .preferred_link_mode = sl.preferred_link_mode,
305 .search_strategy = sl.search_strategy,
306 },
307 .name = try wc.addString(sl.name),
308 })));
309 }
310
311 fn addCSourceFile(s: *Serialize, csf: *const std.Build.Module.CSourceFile) !Configuration.CSourceFile.Index {
312 log.err("TODO addCSourceFile trailing data", .{});
313 const wc = s.wc;
314 return @enumFromInt(try wc.addExtra(@as(Configuration.CSourceFile, .{
315 .flags = .{
316 .args_len = @intCast(csf.flags.len),
317 .lang = .init(csf.language),
318 },
319 .file = try addLazyPath(s, csf.file),
320 })));
321 }
322
323 fn addCSourceFiles(s: *Serialize, csf: *const std.Build.Module.CSourceFiles) !Configuration.CSourceFiles.Index {
324 log.err("TODO addCSourceFiles trailing data", .{});
325 const wc = s.wc;
326 return @enumFromInt(try wc.addExtra(@as(Configuration.CSourceFiles, .{
327 .flags = .{
328 .args_len = @intCast(csf.flags.len),
329 .lang = .init(csf.language),
330 },
331 .root = try addLazyPath(s, csf.root),
332 .files_len = @intCast(csf.files.len),
333 })));
334 }
335
336 fn addRcSourceFile(s: *Serialize, rsf: *const std.Build.Module.RcSourceFile) !Configuration.RcSourceFile.Index {
337 log.err("TODO addRcSourceFile trailing data", .{});
338 const wc = s.wc;
339 return @enumFromInt(try wc.addExtra(@as(Configuration.RcSourceFile, .{
340 .file = try addLazyPath(s, rsf.file),
341 .args_len = @intCast(rsf.flags.len),
342 .include_paths_len = @intCast(rsf.include_paths.len),
343 })));
344 }
345
294 fn initStringList(s: *Serialize, list: []const []const u8) ![]const Configuration.String {346 fn initStringList(s: *Serialize, list: []const []const u8) ![]const Configuration.String {
295 const wc = s.wc;347 const wc = s.wc;
296 const result = try s.arena.alloc(Configuration.String, list.len);348 const result = try s.arena.alloc(Configuration.String, list.len);
...@@ -312,6 +364,35 @@ const Serialize = struct {...@@ -312,6 +364,35 @@ const Serialize = struct {
312 const arena = s.arena;364 const arena = s.arena;
313 const gpa = wc.gpa;365 const gpa = wc.gpa;
314366
367 const include_dirs = try arena.alloc(Configuration.Module.IncludeDir, m.include_dirs.items.len);
368 for (include_dirs, m.include_dirs.items) |*dest, src| dest.* = switch (src) {
369 .path => |lp| .{ .path = try addLazyPath(s, lp) },
370 .path_system => |lp| .{ .path_system = try addLazyPath(s, lp) },
371 .path_after => |lp| .{ .path_after = try addLazyPath(s, lp) },
372 .framework_path => |lp| .{ .framework_path = try addLazyPath(s, lp) },
373 .framework_path_system => |lp| .{ .framework_path_system = try addLazyPath(s, lp) },
374 .embed_path => |lp| .{ .embed_path = try addLazyPath(s, lp) },
375 .other_step => |cs| .{ .other_step = stepIndex(s, &cs.step) },
376 .config_header_step => |chs| .{ .config_header_step = stepIndex(s, &chs.step) },
377 };
378
379 const rpaths = try arena.alloc(Configuration.Module.RPath, m.rpaths.items.len);
380 for (rpaths, m.rpaths.items) |*dest, src| dest.* = switch (src) {
381 .lazy_path => |lp| .{ .lazy_path = try addLazyPath(s, lp) },
382 .special => |slice| .{ .special = try wc.addString(slice) },
383 };
384
385 const link_objects = try arena.alloc(Configuration.Module.LinkObject, m.link_objects.items.len);
386 for (link_objects, m.link_objects.items) |*dest, *src| dest.* = switch (src.*) {
387 .static_path => |lp| .{ .static_path = try addLazyPath(s, lp) },
388 .other_step => |cs| .{ .other_step = stepIndex(s, &cs.step) },
389 .system_lib => |*sl| .{ .system_lib = try addSystemLib(s, sl) },
390 .assembly_file => |lp| .{ .assembly_file = try addLazyPath(s, lp) },
391 .c_source_file => |csf| .{ .c_source_file = try addCSourceFile(s, csf) },
392 .c_source_files => |csf| .{ .c_source_files = try addCSourceFiles(s, csf) },
393 .win32_resource_file => |wrf| .{ .win32_resource_file = try addRcSourceFile(s, wrf) },
394 };
395
315 const lib_paths = try arena.alloc(Configuration.LazyPath, m.lib_paths.items.len);396 const lib_paths = try arena.alloc(Configuration.LazyPath, m.lib_paths.items.len);
316 for (lib_paths, m.lib_paths.items) |*dest, src| dest.* = try addLazyPath(s, src);397 for (lib_paths, m.lib_paths.items) |*dest, src| dest.* = try addLazyPath(s, src);
317398
...@@ -352,11 +433,11 @@ const Serialize = struct {...@@ -352,11 +433,11 @@ const Serialize = struct {
352 .fuzz = .init(m.strip),433 .fuzz = .init(m.strip),
353 .code_model = m.code_model,434 .code_model = m.code_model,
354 .c_macros = c_macros.len != 0,435 .c_macros = c_macros.len != 0,
355 .include_dirs = m.include_dirs.items.len != 0,436 .include_dirs = include_dirs.len != 0,
356 .lib_paths = lib_paths.len != 0,437 .lib_paths = lib_paths.len != 0,
357 .rpaths = m.rpaths.items.len != 0,438 .rpaths = rpaths.len != 0,
358 .frameworks = m.frameworks.entries.len != 0,439 .frameworks = m.frameworks.entries.len != 0,
359 .link_objects = m.link_objects.items.len != 0,440 .link_objects = link_objects.len != 0,
360 .export_symbol_names = export_symbol_names.len != 0,441 .export_symbol_names = export_symbol_names.len != 0,
361 },442 },
362 .flags2 = .{443 .flags2 = .{
...@@ -376,6 +457,9 @@ const Serialize = struct {...@@ -376,6 +457,9 @@ const Serialize = struct {
376 .c_macros = .{ .slice = c_macros },457 .c_macros = .{ .slice = c_macros },
377 .lib_paths = .{ .slice = lib_paths },458 .lib_paths = .{ .slice = lib_paths },
378 .export_symbol_names = .{ .slice = export_symbol_names },459 .export_symbol_names = .{ .slice = export_symbol_names },
460 .include_dirs = .init(include_dirs),
461 .rpaths = .init(rpaths),
462 .link_objects = .init(link_objects),
379 })));463 })));
380464
381 log.err("TODO serialize the trailing Module data", .{});465 log.err("TODO serialize the trailing Module data", .{});
...@@ -384,6 +468,10 @@ const Serialize = struct {...@@ -384,6 +468,10 @@ const Serialize = struct {
384468
385 return module_index;469 return module_index;
386 }470 }
471
472 fn stepIndex(s: *const Serialize, step: *Step) Configuration.Step.Index {
473 return @enumFromInt(s.step_map.getIndex(step).?);
474 }
387};475};
388476
389fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void {477fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void {
...@@ -396,34 +484,32 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void {...@@ -396,34 +484,32 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void {
396 // Starting from all top-level steps in `b`, traverse the entire step graph484 // Starting from all top-level steps in `b`, traverse the entire step graph
397 // and add all step dependencies implied by module graphs.485 // and add all step dependencies implied by module graphs.
398 const top_level_steps = b.top_level_steps.values();486 const top_level_steps = b.top_level_steps.values();
399 // Index corresponds to `Configuration.steps` index.487 try s.step_map.ensureUnusedCapacity(arena, top_level_steps.len);
400 var step_map: std.AutoArrayHashMapUnmanaged(*Step, void) = .empty;
401 try step_map.ensureUnusedCapacity(arena, top_level_steps.len);
402 for (top_level_steps) |tls| {488 for (top_level_steps) |tls| {
403 step_map.putAssumeCapacityNoClobber(&tls.step, {});489 s.step_map.putAssumeCapacityNoClobber(&tls.step, {});
404 }490 }
405 {491 {
406 while (wc.steps.items.len < step_map.count()) {492 while (wc.steps.items.len < s.step_map.count()) {
407 const step = step_map.keys()[wc.steps.items.len];493 const step = s.step_map.keys()[wc.steps.items.len];
408494
409 // Set up any implied dependencies for this step. It's important that we do this first, so495 // Set up any implied dependencies for this step. It's important that we do this first, so
410 // that the loop below discovers steps implied by the module graph.496 // that the loop below discovers steps implied by the module graph.
411 try createModuleDependenciesForStep(step);497 try createModuleDependenciesForStep(step);
412498
413 try step_map.ensureUnusedCapacity(arena, step.dependencies.items.len);499 try s.step_map.ensureUnusedCapacity(arena, step.dependencies.items.len);
414 for (step.dependencies.items) |other_step| {500 for (step.dependencies.items) |other_step| {
415 step_map.putAssumeCapacity(other_step, {});501 s.step_map.putAssumeCapacity(other_step, {});
416 }502 }
417503
418 // Add and then de-duplicate dependencies.504 // Add and then de-duplicate dependencies.
419 const deps = d: {505 const deps = d: {
420 const deps: Configuration.Deps = @enumFromInt(wc.extra.items.len);506 const deps: Configuration.Deps = @enumFromInt(wc.extra.items.len);
421 for (try wc.reserveLengthPrefixed(step.dependencies.items.len), step.dependencies.items) |*dep, dep_step|507 for (try wc.reserveLengthPrefixed(step.dependencies.items.len), step.dependencies.items) |*dep, dep_step|
422 dep.* = @intCast(step_map.getIndex(dep_step).?);508 dep.* = @intCast(s.step_map.getIndex(dep_step).?);
423 break :d try wc.dedupeDeps(deps);509 break :d try wc.dedupeDeps(deps);
424 };510 };
425511
426 try wc.steps.ensureTotalCapacity(gpa, step_map.entries.capacity);512 try wc.steps.ensureTotalCapacity(gpa, s.step_map.entries.capacity);
427 wc.steps.appendAssumeCapacity(.{513 wc.steps.appendAssumeCapacity(.{
428 .name = try wc.addString(step.name),514 .name = try wc.addString(step.name),
429 .owner = try s.builderToPackage(step.owner),515 .owner = try s.builderToPackage(step.owner),
...@@ -613,7 +699,7 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void {...@@ -613,7 +699,7 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void {
613 .emitted_pdb = try s.addOptionalLazyPathEnum(ia.emitted_pdb),699 .emitted_pdb = try s.addOptionalLazyPathEnum(ia.emitted_pdb),
614 .h_dir = try addInstallDir(wc, ia.h_dir),700 .h_dir = try addInstallDir(wc, ia.h_dir),
615 .emitted_h = try s.addOptionalLazyPathEnum(ia.emitted_h),701 .emitted_h = try s.addOptionalLazyPathEnum(ia.emitted_h),
616 .artifact = stepIndex(&step_map, &ia.artifact.step),702 .artifact = s.stepIndex(&ia.artifact.step),
617 })));703 })));
618 },704 },
619 .install_file => @panic("TODO"),705 .install_file => @panic("TODO"),
...@@ -688,7 +774,7 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void {...@@ -688,7 +774,7 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void {
688 }774 }
689775
690 try wc.write(writer, .{776 try wc.write(writer, .{
691 .default_step = stepIndex(&step_map, b.default_step),777 .default_step = s.stepIndex(b.default_step),
692 });778 });
693}779}
694780
...@@ -714,10 +800,6 @@ fn addInstallDir(wc: *Configuration.Wip, install_dir: ?std.Build.InstallDir) !Co...@@ -714,10 +800,6 @@ fn addInstallDir(wc: *Configuration.Wip, install_dir: ?std.Build.InstallDir) !Co
714 }800 }
715}801}
716802
717fn stepIndex(step_map: *const std.AutoArrayHashMapUnmanaged(*Step, void), step: *Step) Configuration.Step.Index {
718 return @enumFromInt(step_map.getIndex(step).?);
719}
720
721/// If the given `Step` is a `Step.Compile`, adds any dependencies for that step which803/// If the given `Step` is a `Step.Compile`, adds any dependencies for that step which
722/// are implied by the module graph rooted at `step.cast(Step.Compile).?.root_module`.804/// are implied by the module graph rooted at `step.cast(Step.Compile).?.root_module`.
723fn createModuleDependenciesForStep(step: *Step) Allocator.Error!void {805fn createModuleDependenciesForStep(step: *Step) Allocator.Error!void {
lib/std/Build/Module.zig+2-12
...@@ -73,18 +73,8 @@ pub const SystemLib = struct {...@@ -73,18 +73,8 @@ pub const SystemLib = struct {
73 preferred_link_mode: std.builtin.LinkMode,73 preferred_link_mode: std.builtin.LinkMode,
74 search_strategy: SystemLib.SearchStrategy,74 search_strategy: SystemLib.SearchStrategy,
7575
76 pub const UsePkgConfig = enum {76 pub const UsePkgConfig = std.Build.Configuration.SystemLib.UsePkgConfig;
77 /// Don't use pkg-config, just pass -lfoo where foo is name.77 pub const SearchStrategy = std.Build.Configuration.SystemLib.SearchStrategy;
78 no,
79 /// Try to get information on how to link the library from pkg-config.
80 /// If that fails, fall back to passing -lfoo where foo is name.
81 yes,
82 /// Try to get information on how to link the library from pkg-config.
83 /// If that fails, error out.
84 force,
85 };
86
87 pub const SearchStrategy = enum { paths_first, mode_first, no_fallback };
88};78};
8979
90pub const CSourceLanguage = enum {80pub const CSourceLanguage = enum {
lib/std/lang.zig+1-1
...@@ -873,7 +873,7 @@ pub const OutputMode = enum {...@@ -873,7 +873,7 @@ pub const OutputMode = enum {
873873
874/// This data structure is used by the Zig language code generation and874/// This data structure is used by the Zig language code generation and
875/// therefore must be kept in sync with the compiler implementation.875/// therefore must be kept in sync with the compiler implementation.
876pub const LinkMode = enum {876pub const LinkMode = enum(u1) {
877 static,877 static,
878 dynamic,878 dynamic,
879};879};
lib/std/zig/Configuration.zig+194-34
...@@ -1071,9 +1071,6 @@ pub const Package = struct {...@@ -1071,9 +1071,6 @@ pub const Package = struct {
10711071
1072/// Trailing:1072/// Trailing:
1073/// * frameworks: FlagsPrefixedList(FrameworkFlags), // if flag is set1073/// * frameworks: FlagsPrefixedList(FrameworkFlags), // if flag is set
1074/// * include_dirs: UnionList(IncludeDir), // if flag is set
1075/// * rpaths: UnionList(RPath), // if flag is set
1076/// * link_objects: UnionList(LinkObject), // if flag is set
1077pub const Module = struct {1074pub const Module = struct {
1078 flags: Flags,1075 flags: Flags,
1079 flags2: Flags2,1076 flags2: Flags2,
...@@ -1084,6 +1081,9 @@ pub const Module = struct {...@@ -1084,6 +1081,9 @@ pub const Module = struct {
1084 c_macros: Storage.FlagLengthPrefixedList(.flags, .c_macros, String),1081 c_macros: Storage.FlagLengthPrefixedList(.flags, .c_macros, String),
1085 lib_paths: Storage.FlagLengthPrefixedList(.flags, .lib_paths, LazyPath),1082 lib_paths: Storage.FlagLengthPrefixedList(.flags, .lib_paths, LazyPath),
1086 export_symbol_names: Storage.FlagLengthPrefixedList(.flags, .export_symbol_names, String),1083 export_symbol_names: Storage.FlagLengthPrefixedList(.flags, .export_symbol_names, String),
1084 include_dirs: Storage.UnionList(.flags, .include_dirs, IncludeDir),
1085 rpaths: Storage.UnionList(.flags, .rpaths, RPath),
1086 link_objects: Storage.UnionList(.flags, .link_objects, LinkObject),
10871087
1088 pub const Optimize = enum(u3) {1088 pub const Optimize = enum(u3) {
1089 debug,1089 debug,
...@@ -1204,7 +1204,7 @@ pub const Module = struct {...@@ -1204,7 +1204,7 @@ pub const Module = struct {
1204 static_path: LazyPath,1204 static_path: LazyPath,
1205 /// Always `Step.Tag.compile`.1205 /// Always `Step.Tag.compile`.
1206 other_step: Step.Index,1206 other_step: Step.Index,
1207 system_lib: SystemLib,1207 system_lib: SystemLib.Index,
1208 assembly_file: LazyPath,1208 assembly_file: LazyPath,
1209 c_source_file: CSourceFile.Index,1209 c_source_file: CSourceFile.Index,
1210 c_source_files: CSourceFiles.Index,1210 c_source_files: CSourceFiles.Index,
...@@ -1328,8 +1328,18 @@ pub const SystemLib = struct {...@@ -1328,8 +1328,18 @@ pub const SystemLib = struct {
1328 _,1328 _,
1329 };1329 };
13301330
1331 pub const UsePkgConfig = enum(u2) { no, yes, force };1331 pub const UsePkgConfig = enum(u2) {
1332 pub const LinkMode = enum { static, dynamic };1332 /// Don't use pkg-config, just pass -lfoo where foo is name.
1333 no,
1334 /// Try to get information on how to link the library from pkg-config.
1335 /// If that fails, fall back to passing -lfoo where foo is name.
1336 yes,
1337 /// Try to get information on how to link the library from pkg-config.
1338 /// If that fails, error out.
1339 force,
1340 };
1341
1342 pub const LinkMode = std.builtin.LinkMode;
13331343
1334 pub const Flags = packed struct(u32) {1344 pub const Flags = packed struct(u32) {
1335 needed: bool,1345 needed: bool,
...@@ -1337,18 +1347,19 @@ pub const SystemLib = struct {...@@ -1337,18 +1347,19 @@ pub const SystemLib = struct {
1337 use_pkg_config: UsePkgConfig,1347 use_pkg_config: UsePkgConfig,
1338 preferred_link_mode: LinkMode,1348 preferred_link_mode: LinkMode,
1339 search_strategy: SearchStrategy,1349 search_strategy: SearchStrategy,
1350 _: u25 = 0,
1340 };1351 };
13411352
1342 pub const SearchStrategy = enum(u2) { paths_first, mode_first, no_fallback };1353 pub const SearchStrategy = enum(u2) { paths_first, mode_first, no_fallback };
1343};1354};
13441355
1345/// Trailing:1356/// Trailing:
1346/// * flag: String, // for each flags_len1357/// * arg: String, // for each args_len
1347/// * sub_path: String, // for each files_len1358/// * sub_path: String, // for each files_len
1348pub const CSourceFiles = struct {1359pub const CSourceFiles = struct {
1360 flags: Flags,
1349 root: LazyPath,1361 root: LazyPath,
1350 files_len: u32,1362 files_len: u32,
1351 flags: Flags,
13521363
1353 pub const Index = enum(u32) {1364 pub const Index = enum(u32) {
1354 _,1365 _,
...@@ -1356,16 +1367,16 @@ pub const CSourceFiles = struct {...@@ -1356,16 +1367,16 @@ pub const CSourceFiles = struct {
13561367
1357 pub const Flags = packed struct(u32) {1368 pub const Flags = packed struct(u32) {
1358 /// C compiler CLI flags.1369 /// C compiler CLI flags.
1359 flags_len: u29,1370 args_len: u29,
1360 lang: OptionalCSourceLanguage,1371 lang: OptionalCSourceLanguage,
1361 };1372 };
1362};1373};
13631374
1364/// Trailing:1375/// Trailing:
1365/// * flag: String, // for each flags_len1376/// * arg: String, // for each args_len
1366pub const CSourceFile = struct {1377pub const CSourceFile = struct {
1367 file: LazyPath,
1368 flags: Flags,1378 flags: Flags,
1379 file: LazyPath,
13691380
1370 pub const Index = enum(u32) {1381 pub const Index = enum(u32) {
1371 _,1382 _,
...@@ -1373,11 +1384,24 @@ pub const CSourceFile = struct {...@@ -1373,11 +1384,24 @@ pub const CSourceFile = struct {
13731384
1374 pub const Flags = packed struct(u32) {1385 pub const Flags = packed struct(u32) {
1375 /// C compiler CLI flags.1386 /// C compiler CLI flags.
1376 flags_len: u29,1387 args_len: u29,
1377 lang: OptionalCSourceLanguage,1388 lang: OptionalCSourceLanguage,
1378 };1389 };
1379};1390};
13801391
1392/// Trailing:
1393/// * arg: String, // for each args_len
1394/// * include_path: String, // for each include_paths_len
1395pub const RcSourceFile = struct {
1396 file: LazyPath,
1397 args_len: u32,
1398 include_paths_len: u32,
1399
1400 pub const Index = enum(u32) {
1401 _,
1402 };
1403};
1404
1381pub const OptionalCSourceLanguage = enum(u3) {1405pub const OptionalCSourceLanguage = enum(u3) {
1382 c,1406 c,
1383 cpp,1407 cpp,
...@@ -1386,29 +1410,17 @@ pub const OptionalCSourceLanguage = enum(u3) {...@@ -1386,29 +1410,17 @@ pub const OptionalCSourceLanguage = enum(u3) {
1386 assembly,1410 assembly,
1387 assembly_with_preprocessor,1411 assembly_with_preprocessor,
1388 default,1412 default,
1389};
13901413
1391pub const RcSourceFile = struct {1414 pub fn init(x: ?std.Build.Module.CSourceLanguage) @This() {
1392 file: LazyPath,1415 return switch (x orelse return .default) {
1393 /// Any option that rc.exe accepts will work here, with the exception of:1416 .c => .c,
1394 /// - `/fo`: The output filename is set by the build system1417 .cpp => .cpp,
1395 /// - `/p`: Only running the preprocessor is not supported in this context1418 .objective_c => .objective_c,
1396 /// - `/:no-preprocess` (non-standard option): Not supported in this context1419 .objective_cpp => .objective_cpp,
1397 /// - Any MUI-related option1420 .assembly => .assembly,
1398 /// https://learn.microsoft.com/en-us/windows/win32/menurc/using-rc-the-rc-command-line-1421 .assembly_with_preprocessor => .assembly_with_preprocessor,
1399 ///1422 };
1400 /// Implicitly defined options:1423 }
1401 /// /x (ignore the INCLUDE environment variable)
1402 /// /D_DEBUG or /DNDEBUG depending on the optimization mode
1403 flags: []const []const u8 = &.{},
1404 /// Include paths that may or may not exist yet and therefore need to be
1405 /// specified as a LazyPath. Each path will be appended to the flags
1406 /// as `/I <resolved path>`.
1407 include_paths: []const LazyPath = &.{},
1408
1409 pub const Index = enum(u32) {
1410 _,
1411 };
1412};1424};
14131425
1414pub const ResolvedTarget = struct {1426pub const ResolvedTarget = struct {
...@@ -1691,6 +1703,7 @@ pub const Storage = enum {...@@ -1691,6 +1703,7 @@ pub const Storage = enum {
1691 enum_optional,1703 enum_optional,
1692 extended,1704 extended,
1693 flag_length_prefixed_list,1705 flag_length_prefixed_list,
1706 union_list,
16941707
1695 /// The presence of the field is determined by a boolean within a packed1708 /// The presence of the field is determined by a boolean within a packed
1696 /// struct.1709 /// struct.
...@@ -1769,6 +1782,63 @@ pub const Storage = enum {...@@ -1769,6 +1782,63 @@ pub const Storage = enum {
1769 };1782 };
1770 }1783 }
17711784
1785 /// `UnionArg` is a tagged union with a small integer for the enum tag.
1786 ///
1787 /// A field in flags determines whether the metadata is present.
1788 ///
1789 /// The metadata is bit-packed consecutive packed struct which is the
1790 /// `UnionArg` enum tag combined with a "last" marker boolean field.
1791 /// When "last" is true, the element is the last one, providing
1792 /// the length of the list.
1793 ///
1794 /// Following is each element of the list; each bitcastable to u32.
1795 pub fn UnionList(
1796 comptime flags_arg: @EnumLiteral(),
1797 comptime flag_arg: @EnumLiteral(),
1798 comptime UnionArg: type,
1799 ) type {
1800 return struct {
1801 /// When serializing it is UnionArg slice pointer.
1802 /// When deserializing it is extra index of first UnionArg element.
1803 data: ?*const anyopaque,
1804 len: usize,
1805
1806 pub const storage: Storage = .union_list;
1807 pub const flags = flags_arg;
1808 pub const flag = flag_arg;
1809 pub const Union = UnionArg;
1810
1811 pub const Tag = @typeInfo(Union).@"union".tag_type.?;
1812 pub const MetaInt = @Int(.unsigned, @bitSizeOf(Tag) + 1);
1813 pub const Meta = packed struct(MetaInt) {
1814 tag: Tag,
1815 last: bool,
1816 };
1817
1818 /// Valid to call only when serializing.
1819 pub fn init(slice: []const Union) @This() {
1820 return .{ .data = slice.ptr, .len = slice.len };
1821 }
1822
1823 /// Valid to call only when deserializing.
1824 pub fn get(this: *const @This(), extra: []const u32) []const u32 {
1825 return extra[@intFromPtr(this.data)..][0..this.len];
1826 }
1827
1828 /// Valid to call only when deserializing.
1829 pub fn tag(this: *const @This(), extra: []const u32, i: usize) Tag {
1830 _ = this;
1831 _ = extra;
1832 _ = i;
1833 @panic("TODO implement UnionList.tag");
1834 }
1835
1836 fn extraLen(len: usize) usize {
1837 return len + (len * @bitSizeOf(Meta) + 31) / 32;
1838 }
1839 };
1840 }
1841
1772 pub fn dataLength(buffer: []const u32, i: usize, comptime S: type) usize {1842 pub fn dataLength(buffer: []const u32, i: usize, comptime S: type) usize {
1773 var end = i;1843 var end = i;
1774 _ = data(buffer, &end, S);1844 _ = data(buffer, &end, S);
...@@ -1848,6 +1918,23 @@ pub const Storage = enum {...@@ -1848,6 +1918,23 @@ pub const Storage = enum {
1848 defer i.* = data_start + len;1918 defer i.* = data_start + len;
1849 return .{ .slice = @ptrCast(buffer[data_start..][0..len]) };1919 return .{ .slice = @ptrCast(buffer[data_start..][0..len]) };
1850 },1920 },
1921 .union_list => {
1922 const flags = @field(container, @tagName(Field.flags));
1923 const flag = @field(flags, @tagName(Field.flag));
1924 if (!flag) return .{ .data = null, .len = 0 };
1925 const meta_start = i.*;
1926 const meta_buffer = buffer[meta_start..];
1927 var len: u32 = 0;
1928 var bit_offset: usize = 0;
1929 while (true) : (bit_offset += @bitSizeOf(Field.Meta)) {
1930 const meta = loadBits(u32, meta_buffer, bit_offset, Field.Meta);
1931 len += 1;
1932 if (meta.last) break;
1933 }
1934 const end = meta_start + Field.extraLen(len);
1935 i.* = end;
1936 return .{ .data = end - len, .len = len };
1937 },
1851 },1938 },
1852 },1939 },
1853 .@"extern" => comptime unreachable,1940 .@"extern" => comptime unreachable,
...@@ -1884,6 +1971,7 @@ pub const Storage = enum {...@@ -1884,6 +1971,7 @@ pub const Storage = enum {
1884 .auto => switch (Field.storage) {1971 .auto => switch (Field.storage) {
1885 .flag_optional, .enum_optional, .extended => 1,1972 .flag_optional, .enum_optional, .extended => 1,
1886 .flag_length_prefixed_list => field.slice.len + 1,1973 .flag_length_prefixed_list => field.slice.len + 1,
1974 .union_list => Field.extraLen(field.len),
1887 },1975 },
1888 .@"extern" => comptime unreachable,1976 .@"extern" => comptime unreachable,
1889 },1977 },
...@@ -1947,6 +2035,33 @@ pub const Storage = enum {...@@ -1947,6 +2035,33 @@ pub const Storage = enum {
1947 @memcpy(buffer[i + 1 ..][0..len], @as([]const u32, @ptrCast(value.slice)));2035 @memcpy(buffer[i + 1 ..][0..len], @as([]const u32, @ptrCast(value.slice)));
1948 return len + 1;2036 return len + 1;
1949 },2037 },
2038 .union_list => {
2039 if (value.len == 0) return 0;
2040 const Tag = @typeInfo(Field.Union).@"union".tag_type.?;
2041 const slice_ptr: [*]const Field.Union = @ptrCast(@alignCast(value.data));
2042 const slice = slice_ptr[0..value.len];
2043 const meta_buffer = buffer[i..][0 .. (slice.len * @bitSizeOf(Field.Meta) + 31) / 32];
2044 for (slice[0 .. slice.len - 1], 0..) |elem, elem_index| {
2045 const union_tag: Tag = elem;
2046 storeBits(u32, meta_buffer, elem_index * @bitSizeOf(Field.Meta), @as(Field.Meta, .{
2047 .tag = union_tag,
2048 .last = false,
2049 }));
2050 } else {
2051 const elem_index = slice.len - 1;
2052 const elem = slice[elem_index];
2053 const union_tag: Tag = elem;
2054 storeBits(u32, meta_buffer, elem_index * @bitSizeOf(Field.Meta), @as(Field.Meta, .{
2055 .tag = union_tag,
2056 .last = true,
2057 }));
2058 }
2059 var total: usize = meta_buffer.len;
2060 for (i + meta_buffer.len.., slice) |elem_index, src| switch (src) {
2061 inline else => |x| total += setExtraField(buffer, elem_index, @TypeOf(x), x),
2062 };
2063 return total;
2064 },
1950 },2065 },
1951 },2066 },
1952 .@"extern" => comptime unreachable,2067 .@"extern" => comptime unreachable,
...@@ -2000,3 +2115,48 @@ pub fn load(arena: Allocator, reader: *Io.Reader) LoadError!Configuration {...@@ -2000,3 +2115,48 @@ pub fn load(arena: Allocator, reader: *Io.Reader) LoadError!Configuration {
2000 try reader.readVecAll(&vecs);2115 try reader.readVecAll(&vecs);
2001 return result;2116 return result;
2002}2117}
2118
2119pub fn loadBits(comptime Int: type, buffer: []const Int, bit_offset: usize, comptime Result: type) Result {
2120 const index = bit_offset / @bitSizeOf(Int);
2121 const small_bit_offset = bit_offset % @bitSizeOf(Int);
2122 const ResultInt = @Int(.unsigned, @bitSizeOf(Result));
2123 const result: ResultInt = @truncate(buffer[index] >> @intCast(small_bit_offset));
2124 const available_bits = @bitSizeOf(Int) - small_bit_offset;
2125 if (available_bits >= @bitSizeOf(ResultInt)) return @bitCast(result);
2126 const missing_bits = @bitSizeOf(ResultInt) - available_bits;
2127 const upper: ResultInt = @truncate(buffer[index + 1] & ((@as(usize, 1) << @intCast(missing_bits)) - 1));
2128 return @bitCast(result | (upper << @intCast(available_bits)));
2129}
2130
2131pub fn storeBits(comptime Int: type, buffer: []Int, bit_offset: usize, value: anytype) void {
2132 const Value = @TypeOf(value);
2133 const ValueInt = @Int(.unsigned, @bitSizeOf(Value));
2134 const value_int: ValueInt = @bitCast(value);
2135 const index = bit_offset / @bitSizeOf(Int);
2136 const small_bit_offset = bit_offset % @bitSizeOf(Int);
2137 const available_bits = @bitSizeOf(Int) - small_bit_offset;
2138 if (available_bits >= @bitSizeOf(ValueInt)) {
2139 buffer[index] &= ~(((@as(Int, 1) << @intCast(@bitSizeOf(Value))) - 1) << @intCast(small_bit_offset));
2140 buffer[index] |= @as(Int, value_int) << @intCast(small_bit_offset);
2141 } else {
2142 const DoubleInt = @Int(.unsigned, @bitSizeOf(Int) * 2);
2143 const ptr: *align(@alignOf(Int)) DoubleInt = @ptrCast(buffer[index..][0..2]);
2144 ptr.* &= ~(((@as(DoubleInt, 1) << @intCast(@bitSizeOf(Value))) - 1) << @intCast(small_bit_offset));
2145 ptr.* |= @as(DoubleInt, value_int) << @intCast(small_bit_offset);
2146 }
2147}
2148
2149test "loadBits and storeBits" {
2150 var buffer: [2]u32 = .{
2151 0b01111111000000001111111100000000,
2152 0b11111111000000001111111100000100,
2153 };
2154 try std.testing.expectEqual(0b100, loadBits(u32, &buffer, 6, u3));
2155 try std.testing.expectEqual(0b100011, loadBits(u32, &buffer, 29, u6));
2156
2157 storeBits(u32, &buffer, 6, @as(u3, 0b010));
2158 storeBits(u32, &buffer, 29, @as(u6, 0b010010));
2159
2160 try std.testing.expectEqual(0b010, loadBits(u32, &buffer, 6, u3));
2161 try std.testing.expectEqual(0b010010, loadBits(u32, &buffer, 29, u6));
2162}