commit 4381a387bfa73c523a49d6b5c4d8ea336c7d4275 (tree)
parent d3d3fb8473e25273ddca2e0da8d9c76cc43c794b
Author: Andrew Kelley <andrew@ziglang.org>
Date: Fri, 27 Feb 2026 18:48:27 -0800
Configuration: complete serialization of Compile steps
Diffstat:
4 files changed, 144 insertions(+), 44 deletions(-)
diff --git a/lib/compiler/Maker/ScannedConfig.zig b/lib/compiler/Maker/ScannedConfig.zig
@@ -85,6 +85,8 @@ fn printValue(sc: *const ScannedConfig, s: *Serializer, comptime Field: type, fi
.flag_length_prefixed_list => comptime unreachable,
.enum_optional => comptime unreachable,
.union_list => comptime unreachable,
+ .length_prefixed_list => comptime unreachable,
+ .flag_union => comptime unreachable,
} else if (std.enums.tagName(Field, field_value)) |name| {
try s.ident(name);
} else {
@@ -103,14 +105,29 @@ fn printValue(sc: *const ScannedConfig, s: *Serializer, comptime Field: type, fi
try s.value(null, .{});
}
},
- .flag_length_prefixed_list => {
+ .length_prefixed_list, .flag_length_prefixed_list => {
try printValue(sc, s, @TypeOf(field_value.slice), field_value.slice);
},
.extended => @compileError("TODO"),
.union_list => @compileError("TODO"),
+ .flag_union => try printValue(sc, s, Field.Union, field_value.u),
},
else => @compileError("not implemented: " ++ @typeName(Field)),
},
+ .@"union" => {
+ switch (field_value) {
+ inline else => |u, tag| {
+ if (@TypeOf(u) == void) {
+ try s.ident(@tagName(tag));
+ } else {
+ var sub_struct = try s.beginStruct(.{});
+ try sub_struct.fieldPrefix(@tagName(tag));
+ try printValue(sc, s, @TypeOf(u), u);
+ try sub_struct.end();
+ }
+ },
+ }
+ },
else => @compileError("not implemented: " ++ @typeName(Field)),
},
}
diff --git a/lib/compiler/Maker/Step/Compile.zig b/lib/compiler/Maker/Step/Compile.zig
@@ -134,21 +134,20 @@ fn lowerZigArgs(
},
}
- if (true) @panic("TODO");
-
- {
- for (compile.force_undefined_symbols.keys()) |symbol_name| {
- try zig_args.append(gpa, "--force_undefined");
- try zig_args.append(gpa, symbol_name.*);
- }
+ for (conf_comp.force_undefined_symbols.slice) |symbol_name| {
+ try zig_args.appendSlice(gpa, &.{ "--force_undefined", symbol_name.slice(conf) });
}
- if (compile.stack_size) |stack_size| {
- try zig_args.append(gpa, "--stack");
- try zig_args.append(gpa, try allocPrint(arena, "{}", .{stack_size}));
+ if (conf_comp.stack_size.value) |stack_size| {
+ try zig_args.appendSlice(gpa, &.{ "--stack", try allocPrint(arena, "{d}", .{stack_size}) });
}
- try addBool(gpa, zig_args, fuzz, "-ffuzz");
+ try addBool(gpa, zig_args, "-ffuzz", fuzz);
+
+ if (true) @panic("TODO");
+
+ var is_linking_libc = conf_comp.flags3.is_linking_libc;
+ var is_linking_libcpp = conf_comp.flags3.is_linking_libcpp;
{
// Stores system libraries that have already been seen for at least one
@@ -163,14 +162,14 @@ fn lowerZigArgs(
var prev_preferred_link_mode: std.builtin.LinkMode = .dynamic;
// Track the number of positional arguments so that a nice error can be
// emitted if there is nothing to link.
- var total_linker_objects: usize = @intFromBool(compile.root_module.root_source_file != null);
+ var total_linker_objects: usize = @intFromBool(root_module.root_source_file != .none);
// Fully recursive iteration including dynamic libraries to detect
// libc and libc++ linkage.
for (getCompileDependencies(true)) |some_compile| {
for (some_compile.root_module.getGraph().modules) |mod| {
- if (mod.link_libc == true) compile.is_linking_libc = true;
- if (mod.link_libcpp == true) compile.is_linking_libcpp = true;
+ if (mod.link_libc == true) is_linking_libc = true;
+ if (mod.link_libcpp == true) is_linking_libcpp = true;
}
}
@@ -465,11 +464,11 @@ fn lowerZigArgs(
try zig_args.append(gpa, name);
}
- if (compile.is_linking_libcpp) {
+ if (is_linking_libcpp) {
try zig_args.append(gpa, "-lc++");
}
- if (compile.is_linking_libc) {
+ if (is_linking_libc) {
try zig_args.append(gpa, "-lc");
}
}
@@ -500,14 +499,14 @@ fn lowerZigArgs(
try zig_args.appendSlice(gpa, &.{ "--debug-log", log_scope });
}
- try addBool(gpa, zig_args, graph.debug_compile_errors, "--debug-compile-errors");
- try addBool(gpa, zig_args, graph.debug_incremental, "--debug-incremental");
- try addBool(gpa, zig_args, graph.verbose_air, "--verbose-air");
- try addBool(gpa, zig_args, graph.verbose_llvm_ir, "--verbose-llvm-ir");
- try addBool(gpa, zig_args, graph.verbose_link or compile.verbose_link, "--verbose-link");
- try addBool(gpa, zig_args, graph.verbose_cc or compile.verbose_cc, "--verbose-cc");
- try addBool(gpa, zig_args, graph.verbose_llvm_cpu_features, "--verbose-llvm-cpu-features");
- try addBool(gpa, zig_args, graph.time_report, "--time-report");
+ try addBool(gpa, zig_args, "--debug-compile-errors", graph.debug_compile_errors);
+ try addBool(gpa, zig_args, "--debug-incremental", graph.debug_incremental);
+ try addBool(gpa, zig_args, "--verbose-air", graph.verbose_air);
+ try addBool(gpa, zig_args, "--verbose-llvm-ir", graph.verbose_llvm_ir);
+ try addBool(gpa, zig_args, "--verbose-link", graph.verbose_link or compile.verbose_link);
+ try addBool(gpa, zig_args, "--verbose-cc", graph.verbose_cc or compile.verbose_cc);
+ try addBool(gpa, zig_args, "--verbose-llvm-cpu-features", graph.verbose_llvm_cpu_features);
+ try addBool(gpa, zig_args, "--time-report", graph.time_report);
if (compile.generated_asm != null) try zig_args.append(gpa, "-femit-asm");
if (compile.generated_bin == null) try zig_args.append(gpa, "-fno-emit-bin");
diff --git a/lib/compiler/configurer.zig b/lib/compiler/configurer.zig
@@ -606,7 +606,7 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void {
.max_memory = c.max_memory != null,
.kind = c.kind,
.global_base = c.global_base != null,
- .test_runner_mode = if (c.test_runner) |tr| switch (tr.mode) {
+ .test_runner = if (c.test_runner) |tr| switch (tr.mode) {
.simple => .simple,
.server => .server,
} else .default,
@@ -678,10 +678,18 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void {
.exec_cmd_args = .{ .slice = try s.initOptionalStringList(exec_cmd_args) },
.installed_headers = .initErased(installed_headers),
.force_undefined_symbols = .{ .slice = try s.initStringList(c.force_undefined_symbols.keys()) },
+ .expect_errors = .{ .u = if (c.expect_errors) |x| switch (x) {
+ .contains => |slice| .{ .contains = try wc.addString(slice) },
+ .exact => |exact| .{ .exact = .{ .slice = try s.initStringList(exact) } },
+ .starts_with => |slice| .{ .starts_with = try wc.addString(slice) },
+ .stderr_contains => |slice| .{ .stderr_contains = try wc.addString(slice) },
+ } else .none },
+ .test_runner = .{ .u = if (c.test_runner) |tr| switch (tr.mode) {
+ .simple => .{ .simple = try s.addLazyPath(tr.path) },
+ .server => .{ .server = try s.addLazyPath(tr.path) },
+ } else .default },
}));
- log.err("TODO serialize the trailing Compile step data", .{});
-
break :e @enumFromInt(extra_index);
},
.install_artifact => e: {
diff --git a/lib/std/zig/Configuration.zig b/lib/std/zig/Configuration.zig
@@ -584,9 +584,6 @@ pub const Step = extern struct {
};
};
- /// Trailing:
- /// * exact_match: String, // if expect_errors is contains, starts_with, or stderr_contains
- /// * test_runner: LazyPath, // if test_runner_mode is not default
pub const Compile = struct {
flags: @This().Flags,
flags2: Flags2,
@@ -600,7 +597,7 @@ pub const Step = extern struct {
exec_cmd_args: Storage.FlagLengthPrefixedList(.flags, .exec_cmd_args_len, OptionalString),
installed_headers: Storage.FlagLengthPrefixedList(.flags, .installed_headers_len, Storage.Extended(InstalledHeader.Flags, InstalledHeader)),
force_undefined_symbols: Storage.FlagLengthPrefixedList(.flags, .force_undefined_symbols_len, String),
- //exacts: EnumConditionalPrefixedList(.flags4, .expect_errors, .exact, String),
+ expect_errors: Storage.FlagUnion(.flags4, .expect_errors, ExpectErrors),
linker_script: Storage.FlagOptional(.flags4, .linker_script, LazyPath),
version_script: Storage.FlagOptional(.flags4, .version_script, LazyPath),
zig_lib_dir: Storage.FlagOptional(.flags3, .zig_lib_dir, LazyPath),
@@ -622,6 +619,7 @@ pub const Step = extern struct {
headerpad_size: Storage.FlagOptional(.flags4, .headerpad_size, u32),
error_limit: Storage.FlagOptional(.flags4, .error_limit, u32),
build_id: Storage.EnumOptional(.flags3, .build_id, .hexstring, String),
+ test_runner: Storage.FlagUnion(.flags3, .test_runner, TestRunner),
pub const InstalledHeader = union(@This().Tag) {
file: File,
@@ -663,8 +661,22 @@ pub const Step = extern struct {
};
};
};
- pub const ExpectErrors = enum(u3) { contains, exact, starts_with, stderr_contains, none };
- pub const TestRunnerMode = enum(u2) { default, simple, server };
+ pub const ExpectErrors = union(@This().Tag) {
+ pub const Tag = enum(u3) { contains, exact, starts_with, stderr_contains, none };
+
+ contains: String,
+ exact: Storage.LengthPrefixedList(String),
+ starts_with: String,
+ stderr_contains: String,
+ none: void,
+ };
+ pub const TestRunner = union(@This().Tag) {
+ pub const Tag = enum(u2) { default, simple, server };
+
+ default: void,
+ simple: LazyPath,
+ server: LazyPath,
+ };
pub const Entry = enum(u2) { default, disabled, enabled, symbol_name };
pub const Lto = enum(u2) {
@@ -826,7 +838,7 @@ pub const Step = extern struct {
kind: Kind,
compress_debug_sections: std.zig.CompressDebugSections,
global_base: bool,
- test_runner_mode: TestRunnerMode,
+ test_runner: TestRunner.Tag,
wasi_exec_model: WasiExecModel,
win32_manifest: bool,
win32_module_definition: bool,
@@ -849,7 +861,7 @@ pub const Step = extern struct {
error_limit: bool,
install_name: bool,
entitlements: bool,
- expect_errors: ExpectErrors,
+ expect_errors: ExpectErrors.Tag,
linker_script: bool,
version_script: bool,
_: u18 = 0,
@@ -1756,8 +1768,10 @@ pub const Storage = enum {
flag_optional,
enum_optional,
extended,
+ length_prefixed_list,
flag_length_prefixed_list,
union_list,
+ flag_union,
/// The presence of the field is determined by a boolean within a packed
/// struct.
@@ -1776,6 +1790,24 @@ pub const Storage = enum {
};
}
+ /// The type of the field is determined by an enum within a packed struct.
+ pub fn FlagUnion(
+ comptime flags_arg: @EnumLiteral(),
+ comptime flag_arg: @EnumLiteral(),
+ comptime UnionArg: type,
+ ) type {
+ return struct {
+ u: Union,
+
+ pub const storage: Storage = .flag_union;
+ pub const flags = flags_arg;
+ pub const flag = flag_arg;
+ pub const Union = UnionArg;
+
+ pub const Tag = @typeInfo(Union).@"union".tag_type.?;
+ };
+ }
+
/// The field is present if an enum tag from flags matches a specific value.
pub fn EnumOptional(
comptime flags_arg: @EnumLiteral(),
@@ -1814,21 +1846,32 @@ pub const Storage = enum {
/// A field in flags determines whether the length is zero or nonzero. If the length is
/// nonzero, then there is a length field followed by the list.
- ///
- /// When deserializing, the slice field is set. When serializing, the index
- /// field must be set.
pub fn FlagLengthPrefixedList(
comptime flags_arg: @EnumLiteral(),
comptime flag_arg: @EnumLiteral(),
- comptime ValueArg: type,
+ comptime ElemArg: type,
) type {
return struct {
- slice: []const Value,
+ slice: []const Elem,
pub const storage: Storage = .flag_length_prefixed_list;
pub const flags = flags_arg;
pub const flag = flag_arg;
- pub const Value = ValueArg;
+ pub const Elem = ElemArg;
+
+ pub fn initErased(s: []const u32) @This() {
+ return .{ .slice = @ptrCast(s) };
+ }
+ };
+ }
+
+ /// The field contains a u32 length followed by that many items.
+ pub fn LengthPrefixedList(comptime ElemArg: type) type {
+ return struct {
+ slice: []const Elem,
+
+ pub const storage: Storage = .length_prefixed_list;
+ pub const Elem = ElemArg;
pub fn initErased(s: []const u32) @This() {
return .{ .slice = @ptrCast(s) };
@@ -1910,6 +1953,7 @@ pub const Storage = enum {
fn dataField(buffer: []const u32, i: *usize, container: anytype, comptime Field: type) Field {
switch (@typeInfo(Field)) {
+ .void => return {},
.int => |info| switch (info.bits) {
32 => {
defer i.* += 1;
@@ -1954,6 +1998,24 @@ pub const Storage = enum {
.value = if (flag) dataField(buffer, i, container, Field.Value) else null,
};
},
+ .flag_union => {
+ const flags = @field(container, @tagName(Field.flags));
+ const tag: Field.Tag = @field(flags, @tagName(Field.flag));
+ return .{
+ .u = switch (tag) {
+ inline else => |comptime_tag| @unionInit(
+ Field.Union,
+ @tagName(comptime_tag),
+ dataField(
+ buffer,
+ i,
+ container,
+ @typeInfo(Field.Union).@"union".fields[@intFromEnum(comptime_tag)].type,
+ ),
+ ),
+ },
+ };
+ },
.enum_optional => {
const flags = @field(container, @tagName(Field.flags));
const tag = @field(flags, @tagName(Field.flag));
@@ -1963,6 +2025,12 @@ pub const Storage = enum {
};
},
.extended => @compileError("TODO"),
+ .length_prefixed_list => {
+ const data_start = i.* + 1;
+ const len = buffer[data_start - 1];
+ defer i.* = data_start + len;
+ return .{ .slice = @ptrCast(buffer[data_start..][0..len]) };
+ },
.flag_length_prefixed_list => {
const flags = @field(container, @tagName(Field.flags));
const flag = @field(flags, @tagName(Field.flag));
@@ -2010,6 +2078,7 @@ pub const Storage = enum {
fn extraFieldLen(field: anytype) usize {
const Field = @TypeOf(field);
return switch (@typeInfo(Field)) {
+ .void => 0,
.int => |info| switch (info.bits) {
32 => 1,
64 => 2,
@@ -2024,8 +2093,11 @@ pub const Storage = enum {
},
.auto => switch (Field.storage) {
.flag_optional, .enum_optional, .extended => 1,
- .flag_length_prefixed_list => field.slice.len + 1,
+ .length_prefixed_list, .flag_length_prefixed_list => field.slice.len + 1,
.union_list => Field.extraLen(field.len),
+ .flag_union => switch (field.u) {
+ inline else => |v| extraFieldLen(v),
+ },
},
.@"extern" => comptime unreachable,
},
@@ -2044,6 +2116,7 @@ pub const Storage = enum {
inline fn setExtraField(buffer: []u32, i: usize, comptime Field: type, value: anytype) usize {
switch (@typeInfo(Field)) {
+ .void => return 0,
.int => |info| switch (info.bits) {
32 => {
buffer[i] = value;
@@ -2081,8 +2154,11 @@ pub const Storage = enum {
.flag_optional, .enum_optional => {
return if (value.value) |v| setExtraField(buffer, i, Field.Value, v) else 0;
},
+ .flag_union => return switch (value.u) {
+ inline else => |x| setExtraField(buffer, i, @TypeOf(x), x),
+ },
.extended => @compileError("TODO"),
- .flag_length_prefixed_list => {
+ .flag_length_prefixed_list, .length_prefixed_list => {
const len: u32 = @intCast(value.slice.len);
if (len == 0) return 0;
buffer[i] = len;