commit 3e6bebbbca2acdcde7578c12e618cbcea233dc49 (tree)
parent 648e0e0cc0d6d1940d3bb2ebc265067f7eb62432
Author: Andrew Kelley <andrew@ziglang.org>
Date: Mon, 16 Feb 2026 16:02:31 -0800
configure runner: serialization of Module
Diffstat:
4 files changed, 824 insertions(+), 36 deletions(-)
diff --git a/lib/compiler/configure_runner.zig b/lib/compiler/configure_runner.zig
@@ -227,6 +227,9 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void {
const arena = graph.arena;
const gpa = wc.gpa;
+ var module_map: std.AutoArrayHashMapUnmanaged(*std.Build.Module, Configuration.Module.Index) = .empty;
+ defer module_map.deinit(gpa);
+
// Starting from all top-level steps in `b`, traverse the entire step graph
// and add all step dependencies implied by module graphs.
const top_level_steps = b.top_level_steps.values();
@@ -360,7 +363,7 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void {
.install_name = c.install_name != null,
.entitlements = c.entitlements != null,
},
- .root_module = try addModule(wc, c.root_module),
+ .root_module = try addModule(wc, &module_map, c.root_module),
.root_name = try wc.addString(c.name),
}));
@@ -462,20 +465,97 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void {
});
}
-fn addModule(wc: *Configuration.Wip, module: *std.Build.Module) !Configuration.Module {
- _ = wc;
- _ = module;
- @panic("TODO");
+fn addModule(
+ wc: *Configuration.Wip,
+ module_map: *std.AutoArrayHashMapUnmanaged(*std.Build.Module, Configuration.Module.Index),
+ m: *std.Build.Module,
+) !Configuration.Module.Index {
+ if (module_map.get(m)) |index| return index;
+
+ const gpa = wc.gpa;
+ const import_table: Configuration.ImportTable = @enumFromInt(wc.extra.items.len);
+ const import_table_extra_len = 1 + 2 * m.import_table.entries.len;
+ try wc.extra.ensureUnusedCapacity(gpa, import_table_extra_len);
+ wc.extra.items.len += import_table_extra_len;
+ wc.extra.appendAssumeCapacity(@intCast(m.import_table.entries.len));
+ wc.extra.items[@intFromEnum(import_table)] = @intCast(m.import_table.entries.len);
+ for (
+ m.import_table.keys(),
+ @intFromEnum(import_table) + 1..,
+ ) |mod_name, extra_index| {
+ wc.extra.items[extra_index] = @intFromEnum(try wc.addString(mod_name));
+ }
+ for (
+ m.import_table.values(),
+ @intFromEnum(import_table) + 1 + m.import_table.entries.len..,
+ ) |dep, extra_index| {
+ // TODO module dependencies can be cyclic
+ wc.extra.items[extra_index] = @intFromEnum(try addModule(wc, module_map, dep));
+ }
+
+ const module_index: Configuration.Module.Index = @enumFromInt(try wc.addExtra(@as(Configuration.Module, .{
+ .flags = .{
+ .optimize = .init(m.optimize),
+ .strip = .init(m.strip),
+ .unwind_tables = .init(m.unwind_tables),
+ .dwarf_format = .init(m.dwarf_format),
+ .single_threaded = .init(m.strip),
+ .stack_protector = .init(m.strip),
+ .stack_check = .init(m.strip),
+ .sanitize_c = .init(m.sanitize_c),
+ .sanitize_thread = .init(m.strip),
+ .fuzz = .init(m.strip),
+ .code_model = m.code_model,
+ .c_macros = m.c_macros.items.len != 0,
+ .include_dirs = m.include_dirs.items.len != 0,
+ .lib_paths = m.lib_paths.items.len != 0,
+ .rpaths = m.rpaths.items.len != 0,
+ .frameworks = m.frameworks.entries.len != 0,
+ .link_objects = m.link_objects.items.len != 0,
+ .export_symbol_names = m.export_symbol_names.len != 0,
+ },
+ .flags2 = .{
+ .valgrind = .init(m.strip),
+ .pic = .init(m.strip),
+ .red_zone = .init(m.strip),
+ .omit_frame_pointer = .init(m.strip),
+ .error_tracing = .init(m.strip),
+ .link_libc = .init(m.strip),
+ .link_libcpp = .init(m.strip),
+ .no_builtin = .init(m.strip),
+ },
+ .owner = builderToPackage(m.owner),
+ .root_source_file = try addOptionalLazyPath(wc, m.root_source_file),
+ .import_table = import_table,
+ .resolved_target = try addOptionalResolvedTarget(wc, m.resolved_target),
+ })));
+
+ std.log.err("TODO serialize the trailing Module data", .{});
+
+ try module_map.putNoClobber(gpa, m, module_index);
+
+ return module_index;
+}
+
+fn addOptionalResolvedTarget(
+ wc: *Configuration.Wip,
+ optional_resolved_target: ?std.Build.ResolvedTarget,
+) !Configuration.ResolvedTarget.OptionalIndex {
+ const resolved_target = optional_resolved_target orelse return .none;
+ // TODO dedupe
+ return @enumFromInt(try wc.addExtra(@as(Configuration.ResolvedTarget, .{
+ .query = try wc.addTargetQuery(resolved_target.query),
+ .result = try wc.addTarget(resolved_target.result),
+ })));
}
fn addOptionalLazyPath(wc: *Configuration.Wip, lp: ?std.Build.LazyPath) !Configuration.OptionalLazyPath {
return @enumFromInt(switch (lp orelse return .none) {
.src_path => |src_path| i: {
- const owner = builderToPackage(src_path.owner);
const sub_path = try wc.addString(src_path.sub_path);
break :i try wc.addExtra(@as(Configuration.LazyPath.SourcePath, .{
.flags = .{},
- .owner = owner,
+ .owner = builderToPackage(src_path.owner),
.sub_path = sub_path,
}));
},
@@ -494,18 +574,17 @@ fn addOptionalLazyPath(wc: *Configuration.Wip, lp: ?std.Build.LazyPath) !Configu
}));
},
.dependency => |dependency| i: {
- const owner = builderToPackage(dependency.dependency.builder);
const sub_path = try wc.addString(dependency.sub_path);
break :i try wc.addExtra(@as(Configuration.LazyPath.SourcePath, .{
.flags = .{},
- .owner = owner,
+ .owner = builderToPackage(dependency.dependency.builder),
.sub_path = sub_path,
}));
},
});
}
-fn builderToPackage(b: *std.Build) Configuration.Package {
+fn builderToPackage(b: *std.Build) Configuration.Package.Index {
_ = b;
@panic("TODO");
}
diff --git a/lib/std/Build/Module.zig b/lib/std/Build/Module.zig
@@ -1,3 +1,11 @@
+const Module = @This();
+
+const std = @import("std");
+const assert = std.debug.assert;
+const LazyPath = std.Build.LazyPath;
+const Step = std.Build.Step;
+const ArrayList = std.ArrayList;
+
/// The one responsible for creating this module.
owner: *std.Build,
root_source_file: ?LazyPath,
@@ -703,10 +711,3 @@ pub fn getGraph(root: *Module) Graph {
root.cached_graph = result;
return result;
}
-
-const Module = @This();
-const std = @import("std");
-const assert = std.debug.assert;
-const LazyPath = std.Build.LazyPath;
-const Step = std.Build.Step;
-const ArrayList = std.ArrayList;
diff --git a/lib/std/lang.zig b/lib/std/lang.zig
@@ -93,7 +93,7 @@ pub const AtomicRmwOp = enum {
///
/// This data structure is used by the Zig language code generation and
/// therefore must be kept in sync with the compiler implementation.
-pub const CodeModel = enum {
+pub const CodeModel = enum(u4) {
default,
extreme,
kernel,
diff --git a/lib/std/zig/Configuration.zig b/lib/std/zig/Configuration.zig
@@ -29,6 +29,7 @@ pub const Wip = struct {
gpa: Allocator,
string_table: StringTable = .empty,
deps_table: DepsTable = .empty,
+ targets_table: TargetsTable = .empty,
string_bytes: std.ArrayList(u8) = .empty,
unlazy_deps: std.ArrayList(String) = .empty,
@@ -37,6 +38,7 @@ pub const Wip = struct {
extra: std.ArrayList(u32) = .empty,
const DepsTable = std.HashMapUnmanaged(Deps, void, DepsTableContext, std.hash_map.default_max_load_percentage);
+ const TargetsTable = std.HashMapUnmanaged(TargetQuery.Index, void, TargetsTableContext, std.hash_map.default_max_load_percentage);
const DepsTableContext = struct {
extra: []const u32,
@@ -56,6 +58,21 @@ pub const Wip = struct {
}
};
+ const TargetsTableContext = struct {
+ extra: []const u32,
+
+ pub fn eql(ctx: @This(), a: TargetQuery.Index, b: TargetQuery.Index) bool {
+ const slice_a = a.extraSlice(ctx.extra);
+ const slice_b = b.extraSlice(ctx.extra);
+ return std.mem.eql(u32, slice_a, slice_b);
+ }
+
+ pub fn hash(ctx: @This(), key: TargetQuery.Index) u64 {
+ const slice = key.extraSlice(ctx.extra);
+ return std.hash_map.hashString(@ptrCast(slice));
+ }
+ };
+
const StringTable = std.HashMapUnmanaged(String, void, StringTableContext, std.hash_map.default_max_load_percentage);
const StringTableContext = struct {
bytes: []const u8,
@@ -144,6 +161,157 @@ pub const Wip = struct {
return new_off;
}
+ pub fn addSemVer(wip: *Wip, sv: std.SemanticVersion) Allocator.Error!String {
+ var buffer: [256]u8 = undefined;
+ var writer: std.Io.Writer = .fixed(&buffer);
+ sv.format(&writer) catch return error.OutOfMemory;
+ return addString(wip, writer.buffered());
+ }
+
+ pub fn addTargetQuery(wip: *Wip, q: std.Target.Query) !TargetQuery.OptionalIndex {
+ if (q.isNative()) return .none;
+ const gpa = wip.gpa;
+ const cpu_name: ?String = switch (q.cpu_model) {
+ .native, .baseline, .determined_by_arch_os => null,
+ .explicit => |model| try wip.addString(model.name),
+ };
+ const os_version_min: ?u32 = if (q.os_version_min) |ver| switch (ver) {
+ .none => null,
+ .semver => |sem_ver| @intFromEnum(try wip.addSemVer(sem_ver)),
+ .windows => |win_ver| @intFromEnum(win_ver),
+ } else null;
+ const os_version_max: ?u32 = if (q.os_version_max) |ver| switch (ver) {
+ .none => null,
+ .semver => |sem_ver| @intFromEnum(try wip.addSemVer(sem_ver)),
+ .windows => |win_ver| @intFromEnum(win_ver),
+ } else null;
+ const glibc_version: ?String = if (q.glibc_version) |sem_ver| try wip.addSemVer(sem_ver) else null;
+ const dynamic_linker: ?String = if (q.dynamic_linker) |*dl|
+ if (dl.get()) |s| try wip.addString(s) else .empty
+ else
+ null;
+ const cpu_features_add_empty = q.cpu_features_add.isEmpty();
+ const cpu_features_sub_empty = q.cpu_features_sub.isEmpty();
+ try wip.extra.ensureUnusedCapacity(gpa, @typeInfo(TargetQuery).@"struct".fields.len + 6 +
+ 2 * ((@sizeOf(std.Target.Cpu.Feature.Set) + 3) / 4));
+ const result_index: TargetQuery.Index = @enumFromInt(wip.addExtraAssumeCapacity(@as(TargetQuery, .{
+ .flags = .{
+ .cpu_arch = .init(q.cpu_arch),
+ .cpu_model = .init(q.cpu_model),
+ .cpu_features_add = !cpu_features_add_empty,
+ .cpu_features_sub = !cpu_features_sub_empty,
+ .os_tag = .init(q.os_tag),
+ .abi = .init(q.abi),
+ .object_format = .init(q.ofmt),
+ .os_version_min = .init(q.os_version_min),
+ .os_version_max = .init(q.os_version_max),
+ .glibc_version = q.glibc_version != null,
+ .android_api_level = q.android_api_level != null,
+ .dynamic_linker = q.dynamic_linker != null,
+ },
+ })));
+ if (!cpu_features_add_empty) wip.extra.appendSliceAssumeCapacity(@ptrCast(&q.cpu_features_add.ints));
+ if (!cpu_features_sub_empty) wip.extra.appendSliceAssumeCapacity(@ptrCast(&q.cpu_features_sub.ints));
+ wip.addExtraOptionalStringAssumeCapacity(cpu_name);
+ if (os_version_min) |v| wip.extra.appendAssumeCapacity(v);
+ if (os_version_max) |v| wip.extra.appendAssumeCapacity(v);
+ wip.addExtraOptionalStringAssumeCapacity(glibc_version);
+ if (q.android_api_level) |x| wip.extra.appendAssumeCapacity(x);
+ wip.addExtraOptionalStringAssumeCapacity(dynamic_linker);
+
+ // Deduplicate.
+ const gop = try wip.targets_table.getOrPutContext(gpa, result_index, @as(TargetsTableContext, .{
+ .extra = wip.extra.items,
+ }));
+ if (gop.found_existing) {
+ wip.extra.items.len = @intFromEnum(result_index);
+ return .init(gop.key_ptr.*);
+ } else {
+ return .init(result_index);
+ }
+ }
+
+ pub fn addTarget(wip: *Wip, t: std.Target) !TargetQuery.Index {
+ const gpa = wip.gpa;
+ const cpu_name: String = try wip.addString(t.cpu.model.name);
+
+ const os_version_min: ?u32, const os_version_max: ?u32, const glibc_version: ?String, const android_api_level: ?u32 = switch (t.os.versionRange()) {
+ .none => .{
+ null,
+ null,
+ null,
+ null,
+ },
+ .semver => |range| .{
+ @intFromEnum(try wip.addSemVer(range.min)),
+ @intFromEnum(try wip.addSemVer(range.max)),
+ null,
+ null,
+ },
+ .hurd => |hurd| .{
+ @intFromEnum(try wip.addSemVer(hurd.range.min)),
+ @intFromEnum(try wip.addSemVer(hurd.range.max)),
+ try wip.addSemVer(hurd.glibc),
+ null,
+ },
+ .linux => |linux| .{
+ @intFromEnum(try wip.addSemVer(linux.range.min)),
+ @intFromEnum(try wip.addSemVer(linux.range.max)),
+ try wip.addSemVer(linux.glibc),
+ linux.android,
+ },
+ .windows => |range| .{
+ @intFromEnum(range.min),
+ @intFromEnum(range.max),
+ null,
+ null,
+ },
+ };
+ const dynamic_linker: ?String = if (t.dynamic_linker.get()) |dl| try wip.addString(dl) else null;
+ const cpu_features_add_empty = t.cpu.features.isEmpty();
+ const os_version: TargetQuery.OsVersion = switch (t.os.versionRange()) {
+ .none => .none,
+ .semver, .linux, .hurd => .semver,
+ .windows => .windows,
+ };
+ try wip.extra.ensureUnusedCapacity(gpa, @typeInfo(TargetQuery).@"struct".fields.len + 6 +
+ 2 * ((@sizeOf(std.Target.Cpu.Feature.Set) + 3) / 4));
+ const result_index: TargetQuery.Index = @enumFromInt(wip.addExtraAssumeCapacity(@as(TargetQuery, .{
+ .flags = .{
+ .cpu_arch = .init(t.cpu.arch),
+ .cpu_model = .explicit,
+ .cpu_features_add = !cpu_features_add_empty,
+ .cpu_features_sub = false,
+ .os_tag = .init(t.os.tag),
+ .abi = .init(t.abi),
+ .object_format = .init(t.ofmt),
+ .os_version_min = os_version,
+ .os_version_max = os_version,
+ .glibc_version = glibc_version != null,
+ .android_api_level = android_api_level != null,
+ .dynamic_linker = dynamic_linker != null,
+ },
+ })));
+ if (!cpu_features_add_empty) wip.extra.appendSliceAssumeCapacity(@ptrCast(&t.cpu.features.ints));
+ wip.addExtraOptionalStringAssumeCapacity(cpu_name);
+ if (os_version_min) |v| wip.extra.appendAssumeCapacity(v);
+ if (os_version_max) |v| wip.extra.appendAssumeCapacity(v);
+ wip.addExtraOptionalStringAssumeCapacity(glibc_version);
+ if (android_api_level) |x| wip.extra.appendAssumeCapacity(x);
+ wip.addExtraOptionalStringAssumeCapacity(dynamic_linker);
+
+ // Deduplicate.
+ const gop = try wip.targets_table.getOrPutContext(gpa, result_index, @as(TargetsTableContext, .{
+ .extra = wip.extra.items,
+ }));
+ if (gop.found_existing) {
+ wip.extra.items.len = @intFromEnum(result_index);
+ return gop.key_ptr.*;
+ } else {
+ return result_index;
+ }
+ }
+
pub fn prepareDeps(wip: *Wip, n: usize) Allocator.Error![]u32 {
const slice = try wip.extra.addManyAsSlice(wip.gpa, n + 1);
slice[0] = @intCast(n);
@@ -178,6 +346,11 @@ pub const Wip = struct {
return result;
}
+ fn addExtraOptionalStringAssumeCapacity(wip: *Wip, optional_string: ?String) void {
+ const string = optional_string orelse return;
+ wip.extra.appendAssumeCapacity(@intFromEnum(string));
+ }
+
fn setExtra(wip: *Wip, index: usize, extra: anytype) void {
const fields = @typeInfo(@TypeOf(extra)).@"struct".fields;
var i = index;
@@ -386,7 +559,7 @@ pub const Step = extern struct {
flags3: Flags3,
flags4: Flags4,
- root_module: Module,
+ root_module: Module.Index,
root_name: String,
pub const ExpectedCompileErrors = enum(u3) { contains, exact, starts_with, stderr_contains, none };
@@ -466,19 +639,6 @@ pub const Step = extern struct {
};
}
};
- pub const DefaultingBool = enum(u2) {
- false,
- true,
- default,
-
- pub fn init(b: ?bool) DefaultingBool {
- return switch (b orelse return .default) {
- false => .false,
- true => .true,
- };
- }
- };
-
pub const Subsystem = enum(u4) {
console,
windows,
@@ -626,7 +786,7 @@ pub const LazyPath = enum(u32) {
pub const SourcePath = struct {
flags: Flags,
- owner: Package,
+ owner: Package.Index,
sub_path: String,
pub const Flags = packed struct(u32) {
@@ -662,11 +822,168 @@ pub const LazyPath = enum(u32) {
};
};
-pub const Package = enum(u32) {
- _,
+pub const Package = extern struct {
+ hash: String,
+ build_root: OptionalString,
+
+ pub const Index = enum(u32) {
+ root = maxInt(u32),
+ _,
+ };
+};
+
+/// Trailing:
+/// * c_macros: LengthPrefixedList(String), // if flag is set
+/// * lib_paths: LengthPrefixedList(LazyPath), // if flag is set
+/// * export_symbol_names: LengthPrefixedList(String), // if flag is set
+/// * frameworks: FlagsPrefixedList(FrameworkFlags), // if flag is set
+/// * include_dirs: UnionList(IncludeDir), // if flag is set
+/// * rpaths: UnionList(RPath), // if flag is set
+/// * link_objects: UnionList(LinkObject), // if flag is set
+pub const Module = struct {
+ flags: Flags,
+ flags2: Flags2,
+ owner: Package.Index,
+ root_source_file: OptionalLazyPath,
+ import_table: ImportTable,
+ resolved_target: ResolvedTarget.OptionalIndex,
+
+ pub const Optimize = enum(u3) {
+ debug,
+ safe,
+ fast,
+ small,
+ default,
+
+ pub fn init(o: ?std.builtin.OptimizeMode) Optimize {
+ return switch (o orelse return .default) {
+ .Debug => .debug,
+ .ReleaseSafe => .safe,
+ .ReleaseFast => .fast,
+ .ReleaseSmall => .small,
+ };
+ }
+ };
+
+ pub const UnwindTables = enum(u2) {
+ none,
+ sync,
+ async,
+ default,
+
+ pub fn init(ut: ?std.builtin.UnwindTables) UnwindTables {
+ return switch (ut orelse return .default) {
+ .none => .none,
+ .sync => .sync,
+ .async => .async,
+ };
+ }
+ };
+
+ pub const SanitizeC = enum(u2) {
+ off,
+ trap,
+ full,
+ default,
+
+ pub fn init(sc: ?std.zig.SanitizeC) SanitizeC {
+ return switch (sc orelse return .default) {
+ .off => .off,
+ .trap => .trap,
+ .full => .full,
+ };
+ }
+ };
+
+ pub const DwarfFormat = enum(u2) {
+ @"32",
+ @"64",
+ default,
+
+ pub fn init(df: ?std.dwarf.Format) DwarfFormat {
+ return switch (df orelse return .default) {
+ .@"32" => .@"32",
+ .@"64" => .@"64",
+ };
+ }
+ };
+
+ pub const Index = enum(u32) {
+ _,
+ };
+
+ pub const Flags = packed struct(u32) {
+ optimize: Optimize,
+ strip: DefaultingBool,
+ unwind_tables: UnwindTables,
+ dwarf_format: DwarfFormat,
+ single_threaded: DefaultingBool,
+ stack_protector: DefaultingBool,
+ stack_check: DefaultingBool,
+ sanitize_c: SanitizeC,
+ sanitize_thread: DefaultingBool,
+ fuzz: DefaultingBool,
+ code_model: std.builtin.CodeModel,
+ c_macros: bool,
+ include_dirs: bool,
+ lib_paths: bool,
+ rpaths: bool,
+ frameworks: bool,
+ link_objects: bool,
+ export_symbol_names: bool,
+ };
+
+ pub const Flags2 = packed struct(u32) {
+ valgrind: DefaultingBool,
+ pic: DefaultingBool,
+ red_zone: DefaultingBool,
+ omit_frame_pointer: DefaultingBool,
+ error_tracing: DefaultingBool,
+ link_libc: DefaultingBool,
+ link_libcpp: DefaultingBool,
+ no_builtin: DefaultingBool,
+ _: u16 = 0,
+ };
+
+ pub const IncludeDir = union(enum(u3)) {
+ path: LazyPath,
+ path_system: LazyPath,
+ path_after: LazyPath,
+ framework_path: LazyPath,
+ framework_path_system: LazyPath,
+ /// Always `Step.Tag.compile`.
+ other_step: Step.Index,
+ /// Always `Step.Tag.config_header`.
+ config_header_step: Step.Index,
+ embed_path: LazyPath,
+ };
+
+ pub const RPath = union(enum(u1)) {
+ lazy_path: LazyPath,
+ special: String,
+ };
+
+ pub const LinkObject = union(enum(u3)) {
+ static_path: LazyPath,
+ /// Always `Step.Tag.compile`.
+ other_step: Step.Index,
+ system_lib: SystemLib,
+ assembly_file: LazyPath,
+ c_source_file: CSourceFile.Index,
+ c_source_files: CSourceFiles.Index,
+ win32_resource_file: RcSourceFile.Index,
+ };
+
+ pub const FrameworkFlags = packed struct(u2) {
+ needed: bool,
+ weak: bool,
+ };
};
-pub const Module = enum(u32) {
+/// Points into `extra`, first element is len, then:
+/// * import_name: String, // for each len
+/// * Module.Index, // for each len
+pub const ImportTable = enum(u32) {
_,
};
@@ -734,6 +1051,397 @@ pub const String = enum(u32) {
}
};
+pub const DefaultingBool = enum(u2) {
+ false,
+ true,
+ default,
+
+ pub fn init(b: ?bool) DefaultingBool {
+ return switch (b orelse return .default) {
+ false => .false,
+ true => .true,
+ };
+ }
+};
+
+pub const SystemLib = struct {
+ name: String,
+ flags: Flags,
+
+ pub const Index = enum(u32) {
+ _,
+ };
+
+ pub const UsePkgConfig = enum(u2) { no, yes, force };
+ pub const LinkMode = enum { static, dynamic };
+
+ pub const Flags = packed struct(u32) {
+ needed: bool,
+ weak: bool,
+ use_pkg_config: UsePkgConfig,
+ preferred_link_mode: LinkMode,
+ search_strategy: SearchStrategy,
+ };
+
+ pub const SearchStrategy = enum(u2) { paths_first, mode_first, no_fallback };
+};
+
+/// Trailing:
+/// * flag: String, // for each flags_len
+/// * sub_path: String, // for each files_len
+pub const CSourceFiles = struct {
+ root: LazyPath,
+ files_len: u32,
+ flags: Flags,
+
+ pub const Index = enum(u32) {
+ _,
+ };
+
+ pub const Flags = packed struct(u32) {
+ /// C compiler CLI flags.
+ flags_len: u29,
+ lang: OptionalCSourceLanguage,
+ };
+};
+
+/// Trailing:
+/// * flag: String, // for each flags_len
+pub const CSourceFile = struct {
+ file: LazyPath,
+ flags: Flags,
+
+ pub const Index = enum(u32) {
+ _,
+ };
+
+ pub const Flags = packed struct(u32) {
+ /// C compiler CLI flags.
+ flags_len: u29,
+ lang: OptionalCSourceLanguage,
+ };
+};
+
+pub const OptionalCSourceLanguage = enum(u3) {
+ c,
+ cpp,
+ objective_c,
+ objective_cpp,
+ assembly,
+ assembly_with_preprocessor,
+ default,
+};
+
+pub const RcSourceFile = struct {
+ file: LazyPath,
+ /// Any option that rc.exe accepts will work here, with the exception of:
+ /// - `/fo`: The output filename is set by the build system
+ /// - `/p`: Only running the preprocessor is not supported in this context
+ /// - `/:no-preprocess` (non-standard option): Not supported in this context
+ /// - Any MUI-related option
+ /// https://learn.microsoft.com/en-us/windows/win32/menurc/using-rc-the-rc-command-line-
+ ///
+ /// Implicitly defined options:
+ /// /x (ignore the INCLUDE environment variable)
+ /// /D_DEBUG or /DNDEBUG depending on the optimization mode
+ flags: []const []const u8 = &.{},
+ /// Include paths that may or may not exist yet and therefore need to be
+ /// specified as a LazyPath. Each path will be appended to the flags
+ /// as `/I <resolved path>`.
+ include_paths: []const LazyPath = &.{},
+
+ pub const Index = enum(u32) {
+ _,
+ };
+};
+
+pub const ResolvedTarget = struct {
+ /// none indicates host.
+ query: TargetQuery.OptionalIndex,
+ /// defaults will be resolved.
+ result: TargetQuery.Index,
+
+ pub const Index = enum(u32) {
+ _,
+ };
+
+ pub const OptionalIndex = enum(u32) {
+ none = maxInt(u32),
+ _,
+ };
+};
+
+/// Trailing:
+/// * cpu_features_add: std.Target.Feature.Set, // if flag set
+/// * cpu_features_sub: std.Target.Feature.Set, // if flag set
+/// * cpu_name: String, // if cpu_model is explicit
+/// * os_version_min: WindowsVersion // if os_version_min is windows
+/// * os_version_min: String // if os_version_min is semver
+/// * os_version_max: WindowsVersion // if os_version_max is windows
+/// * os_version_max: String // if os_version_max is semver
+/// * glibc_version: String, // if flag is set
+/// * android_api_level: u32, // if flag is set
+/// * dynamic_linker: String, // if flag is set
+pub const TargetQuery = struct {
+ flags: Flags,
+
+ pub const Index = enum(u32) {
+ _,
+
+ pub fn extraSlice(i: Index, extra: []const u32) []const u32 {
+ return extra[@intFromEnum(i)..][0..length(i, extra)];
+ }
+
+ pub fn length(i: Index, extra: []const u32) usize {
+ //const flags = getExtra(extra, @intFromEnum(i), TargetQuery).flags;
+ const flags: Flags = @bitCast(extra[@intFromEnum(i)]);
+ const feature_set_size: usize = (@sizeOf(std.Target.Cpu.Feature.Set) + 3) / 4;
+ return @typeInfo(TargetQuery).@"struct".fields.len +
+ (if (flags.cpu_features_add) feature_set_size else 0) +
+ (if (flags.cpu_features_sub) feature_set_size else 0) +
+ @intFromBool(flags.cpu_model == .explicit) +
+ @as(usize, switch (flags.os_version_min) {
+ .semver, .windows => 1,
+ else => 0,
+ }) +
+ @as(usize, switch (flags.os_version_max) {
+ .semver, .windows => 1,
+ else => 0,
+ }) +
+ @intFromBool(flags.glibc_version) +
+ @intFromBool(flags.android_api_level) +
+ @intFromBool(flags.dynamic_linker);
+ }
+ };
+
+ pub const OptionalIndex = enum(u32) {
+ none = maxInt(u32),
+ _,
+
+ pub fn init(i: Index) OptionalIndex {
+ const result: OptionalIndex = @enumFromInt(@intFromEnum(i));
+ assert(result != .none);
+ return result;
+ }
+ };
+
+ pub const CpuModel = enum(u2) {
+ native,
+ baseline,
+ determined_by_arch_os,
+ explicit,
+
+ pub fn init(x: std.Target.Query.CpuModel) @This() {
+ return switch (x) {
+ .native => .native,
+ .baseline => .baseline,
+ .determined_by_arch_os => .determined_by_arch_os,
+ .explicit => .explicit,
+ };
+ }
+ };
+ pub const OsVersion = enum(u2) {
+ none,
+ semver,
+ windows,
+ default,
+
+ pub fn init(x: ?std.Target.Query.OsVersion) @This() {
+ return switch (x orelse return .default) {
+ .none => .none,
+ .semver => .semver,
+ .windows => .windows,
+ };
+ }
+ };
+ pub const Abi = enum(u5) {
+ none,
+ gnu,
+ gnuabin32,
+ gnuabi64,
+ gnueabi,
+ gnueabihf,
+ gnuf32,
+ gnusf,
+ gnux32,
+ eabi,
+ eabihf,
+ ilp32,
+ android,
+ androideabi,
+ musl,
+ muslabin32,
+ muslabi64,
+ musleabi,
+ musleabihf,
+ muslf32,
+ muslsf,
+ muslx32,
+ msvc,
+ itanium,
+ simulator,
+ ohos,
+ ohoseabi,
+
+ default,
+
+ pub fn init(x: ?std.Target.Abi) @This() {
+ // TODO comptime assert the enums match
+ return @enumFromInt(@intFromEnum(x orelse return .default));
+ }
+ };
+ pub const CpuArch = enum(u6) {
+ aarch64,
+ aarch64_be,
+ alpha,
+ amdgcn,
+ arc,
+ arceb,
+ arm,
+ armeb,
+ avr,
+ bpfeb,
+ bpfel,
+ csky,
+ hexagon,
+ hppa,
+ hppa64,
+ kalimba,
+ kvx,
+ lanai,
+ loongarch32,
+ loongarch64,
+ m68k,
+ microblaze,
+ microblazeel,
+ mips,
+ mipsel,
+ mips64,
+ mips64el,
+ msp430,
+ nvptx,
+ nvptx64,
+ or1k,
+ powerpc,
+ powerpcle,
+ powerpc64,
+ powerpc64le,
+ propeller,
+ riscv32,
+ riscv32be,
+ riscv64,
+ riscv64be,
+ s390x,
+ sh,
+ sheb,
+ sparc,
+ sparc64,
+ spirv32,
+ spirv64,
+ thumb,
+ thumbeb,
+ ve,
+ wasm32,
+ wasm64,
+ x86_16,
+ x86,
+ x86_64,
+ xcore,
+ xtensa,
+ xtensaeb,
+
+ default,
+
+ pub fn init(x: ?std.Target.Cpu.Arch) @This() {
+ // TODO comptime assert the enums match
+ return @enumFromInt(@intFromEnum(x orelse return .default));
+ }
+ };
+ pub const OsTag = enum(u6) {
+ freestanding,
+ other,
+ contiki,
+ fuchsia,
+ hermit,
+ managarm,
+ haiku,
+ hurd,
+ illumos,
+ linux,
+ plan9,
+ rtems,
+ serenity,
+ dragonfly,
+ freebsd,
+ netbsd,
+ openbsd,
+ driverkit,
+ ios,
+ maccatalyst,
+ macos,
+ tvos,
+ visionos,
+ watchos,
+ windows,
+ uefi,
+ @"3ds",
+ ps3,
+ ps4,
+ ps5,
+ vita,
+ emscripten,
+ wasi,
+ amdhsa,
+ amdpal,
+ cuda,
+ mesa3d,
+ nvcl,
+ opencl,
+ opengl,
+ vulkan,
+
+ default,
+
+ pub fn init(x: ?std.Target.Os.Tag) @This() {
+ // TODO comptime assert the enums match
+ return @enumFromInt(@intFromEnum(x orelse return .default));
+ }
+ };
+ pub const ObjectFormat = enum(u4) {
+ c,
+ coff,
+ elf,
+ hex,
+ macho,
+ plan9,
+ raw,
+ spirv,
+ wasm,
+
+ default,
+
+ pub fn init(x: ?std.Target.ObjectFormat) @This() {
+ // TODO comptime assert the enums match
+ return @enumFromInt(@intFromEnum(x orelse return .default));
+ }
+ };
+
+ pub const Flags = packed struct(u32) {
+ cpu_arch: CpuArch,
+ cpu_model: CpuModel,
+ cpu_features_add: bool,
+ cpu_features_sub: bool,
+ os_tag: OsTag,
+ abi: Abi,
+ object_format: ObjectFormat,
+ os_version_min: OsVersion,
+ os_version_max: OsVersion,
+ glibc_version: bool,
+ android_api_level: bool,
+ dynamic_linker: bool,
+ };
+};
+
pub const LoadFileError = Io.File.Reader.Error || Allocator.Error || error{EndOfStream};
pub fn loadFile(arena: Allocator, io: Io, file: Io.File) LoadFileError!Configuration {