authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-03-11 17:11:01-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-05-25 18:54:34-07:00
logec2b156720dec2873ca0a7958b282bfda12d5250
tree2058b99e46d92141f86e2b180e4a7d4238231ef7
parent71ac3f15b3740974e1bac091f32fc56933134ca2

std: rename zig.Configuration to Build.Configuration


4 files changed, 2529 insertions(+), 2529 deletions(-)

BRANCH_TODO+1-1
...@@ -1,4 +1,3 @@...@@ -1,4 +1,3 @@
1* rename std.zig.Configuration to std.Build.Configuration
2* replace union(@This().Tag)1* replace union(@This().Tag)
3* replace b.dupe() with string internment2* replace b.dupe() with string internment
4* don't forget to add -listen arg back3* don't forget to add -listen arg back
...@@ -10,3 +9,4 @@...@@ -10,3 +9,4 @@
10* get zig tests passing9* get zig tests passing
11* test a bunch of third party projects / help people migrate10* test a bunch of third party projects / help people migrate
12* refactor with DefaultingEnum11* refactor with DefaultingEnum
12* add flag for compiling maker in debug mode
lib/std/Build.zig+1-1
...@@ -22,7 +22,7 @@ pub const Step = @import("Build/Step.zig");...@@ -22,7 +22,7 @@ pub const Step = @import("Build/Step.zig");
22pub const Module = @import("Build/Module.zig");22pub const Module = @import("Build/Module.zig");
23pub const abi = @import("Build/abi.zig");23pub const abi = @import("Build/abi.zig");
24/// The serialized output of configure phase ingested by make phase.24/// The serialized output of configure phase ingested by make phase.
25pub const Configuration = @import("zig/Configuration.zig");25pub const Configuration = @import("Build/Configuration.zig");
2626
27/// Shared state among all Build instances.27/// Shared state among all Build instances.
28graph: *Graph,28graph: *Graph,
lib/std/Build/Configuration.zig created+2527
...@@ -0,0 +1,2527 @@
1const Configuration = @This();
2
3const std = @import("../std.zig");
4const Io = std.Io;
5const Allocator = std.mem.Allocator;
6const assert = std.debug.assert;
7const maxInt = std.math.maxInt;
8
9string_bytes: []u8,
10steps: []Step,
11path_deps_base: []Path.Base,
12path_deps_sub: []String,
13unlazy_deps: []String,
14system_integrations: []SystemIntegration,
15available_options: []AvailableOption,
16extra: []u32,
17default_step: Step.Index,
18generated_files_len: u32,
19
20/// The field order here matches `Configuration` which documents the order in
21/// the serialized format.
22pub const Header = extern struct {
23 string_bytes_len: u32,
24 steps_len: u32,
25 path_deps_len: u32,
26 unlazy_deps_len: u32,
27 system_integrations_len: u32,
28 available_options_len: u32,
29 extra_len: u32,
30
31 default_step: Step.Index,
32 /// There is not actually any data stored for this - it just provides a way
33 /// for maker process to preallocate an array for these.
34 generated_files_len: u32,
35};
36
37pub const Wip = struct {
38 gpa: Allocator,
39 string_table: StringTable = .empty,
40 /// De-duplicates an array inside `extra`.
41 dedupe_table: DedupeTable = .empty,
42 targets_table: TargetsTable = .empty,
43
44 string_bytes: std.ArrayList(u8) = .empty,
45 unlazy_deps: std.ArrayList(String) = .empty,
46 system_integrations: std.ArrayList(SystemIntegration) = .empty,
47 available_options: std.ArrayList(AvailableOption) = .empty,
48 steps: std.ArrayList(Step) = .empty,
49 path_deps: std.MultiArrayList(Path) = .empty,
50 extra: std.ArrayList(u32) = .empty,
51 next_generated_file_index: u32 = 0,
52
53 const DedupeTable = std.HashMapUnmanaged(ExtraSlice, void, ExtraSlice.Context, std.hash_map.default_max_load_percentage);
54 const TargetsTable = std.HashMapUnmanaged(TargetQuery.Index, void, TargetsTableContext, std.hash_map.default_max_load_percentage);
55
56 const ExtraSlice = struct {
57 index: u32,
58 len: u32,
59
60 const Context = struct {
61 extra: []const u32,
62
63 pub fn eql(ctx: @This(), a: ExtraSlice, b: ExtraSlice) bool {
64 const slice_a = ctx.extra[a.index..][0..a.len];
65 const slice_b = ctx.extra[b.index..][0..b.len];
66 return std.mem.eql(u32, slice_a, slice_b);
67 }
68
69 pub fn hash(ctx: @This(), key: ExtraSlice) u64 {
70 const slice = ctx.extra[key.index..][0..key.len];
71 return std.hash_map.hashString(@ptrCast(slice));
72 }
73 };
74 };
75
76 const TargetsTableContext = struct {
77 extra: []const u32,
78
79 pub fn eql(ctx: @This(), a: TargetQuery.Index, b: TargetQuery.Index) bool {
80 const slice_a = a.extraSlice(ctx.extra);
81 const slice_b = b.extraSlice(ctx.extra);
82 return std.mem.eql(u32, slice_a, slice_b);
83 }
84
85 pub fn hash(ctx: @This(), key: TargetQuery.Index) u64 {
86 const slice = key.extraSlice(ctx.extra);
87 return std.hash_map.hashString(@ptrCast(slice));
88 }
89 };
90
91 const StringTable = std.HashMapUnmanaged(String, void, StringTableContext, std.hash_map.default_max_load_percentage);
92 const StringTableContext = struct {
93 bytes: []const u8,
94
95 pub fn eql(_: @This(), a: String, b: String) bool {
96 return a == b;
97 }
98
99 pub fn hash(ctx: @This(), key: String) u64 {
100 return std.hash_map.hashString(std.mem.sliceTo(ctx.bytes[@intFromEnum(key)..], 0));
101 }
102 };
103
104 const StringTableIndexAdapter = struct {
105 bytes: []const u8,
106
107 pub fn eql(ctx: @This(), a: []const u8, b: String) bool {
108 return std.mem.eql(u8, a, std.mem.sliceTo(ctx.bytes[@intFromEnum(b)..], 0));
109 }
110
111 pub fn hash(_: @This(), adapted_key: []const u8) u64 {
112 assert(std.mem.indexOfScalar(u8, adapted_key, 0) == null);
113 return std.hash_map.hashString(adapted_key);
114 }
115 };
116
117 pub fn init(gpa: Allocator) Wip {
118 return .{ .gpa = gpa };
119 }
120
121 pub fn deinit(wip: *Wip) void {
122 const gpa = wip.gpa;
123 wip.string_bytes.deinit(gpa);
124 wip.unlazy_deps.deinit(gpa);
125 wip.system_integrations.deinit(gpa);
126 wip.available_options.deinit(gpa);
127 wip.steps.deinit(gpa);
128 wip.path_deps.deinit(gpa);
129 wip.extra.deinit(gpa);
130 wip.* = undefined;
131 }
132
133 pub const Static = struct {
134 default_step: Step.Index,
135 generated_files_len: u32,
136 };
137
138 pub fn write(wip: *Wip, w: *Io.Writer, static: Static) Io.Writer.Error!void {
139 const header: Header = .{
140 .string_bytes_len = @intCast(wip.string_bytes.items.len),
141 .steps_len = @intCast(wip.steps.items.len),
142 .path_deps_len = @intCast(wip.path_deps.len),
143 .unlazy_deps_len = @intCast(wip.unlazy_deps.items.len),
144 .system_integrations_len = @intCast(wip.system_integrations.items.len),
145 .available_options_len = @intCast(wip.available_options.items.len),
146 .extra_len = @intCast(wip.extra.items.len),
147
148 .default_step = static.default_step,
149 .generated_files_len = static.generated_files_len,
150 };
151 var buffers = [_][]const u8{
152 @ptrCast(&header),
153 wip.string_bytes.items,
154 @ptrCast(wip.steps.items),
155 @ptrCast(wip.path_deps.items(.base)),
156 @ptrCast(wip.path_deps.items(.sub)),
157 @ptrCast(wip.unlazy_deps.items),
158 @ptrCast(wip.system_integrations.items),
159 @ptrCast(wip.available_options.items),
160 @ptrCast(wip.extra.items),
161 };
162 try w.writeVecAll(&buffers);
163 }
164
165 pub fn addString(wip: *Wip, bytes: []const u8) Allocator.Error!String {
166 const gpa = wip.gpa;
167 assert(std.mem.indexOfScalar(u8, bytes, 0) == null);
168 const gop = try wip.string_table.getOrPutContextAdapted(
169 gpa,
170 @as([]const u8, bytes),
171 @as(StringTableIndexAdapter, .{ .bytes = wip.string_bytes.items }),
172 @as(StringTableContext, .{ .bytes = wip.string_bytes.items }),
173 );
174 if (gop.found_existing) return gop.key_ptr.*;
175
176 try wip.string_bytes.ensureUnusedCapacity(gpa, bytes.len + 1);
177 const new_off: String = @enumFromInt(wip.string_bytes.items.len);
178
179 wip.string_bytes.appendSliceAssumeCapacity(bytes);
180 wip.string_bytes.appendAssumeCapacity(0);
181
182 gop.key_ptr.* = new_off;
183
184 return new_off;
185 }
186
187 pub fn addOptionalString(wip: *Wip, bytes: ?[]const u8) Allocator.Error!OptionalString {
188 return .init(try addString(wip, bytes orelse return .none));
189 }
190
191 pub fn addSemVer(wip: *Wip, sv: std.SemanticVersion) Allocator.Error!String {
192 var buffer: [256]u8 = undefined;
193 var writer: std.Io.Writer = .fixed(&buffer);
194 sv.format(&writer) catch return error.OutOfMemory;
195 return addString(wip, writer.buffered());
196 }
197
198 pub fn addTargetQuery(wip: *Wip, q: std.Target.Query) !TargetQuery.OptionalIndex {
199 if (q.isNative()) return .none;
200 const gpa = wip.gpa;
201 const cpu_name: ?String = switch (q.cpu_model) {
202 .native, .baseline, .determined_by_arch_os => null,
203 .explicit => |model| try wip.addString(model.name),
204 };
205 const os_version_min: TargetQuery.OsVersion = if (q.os_version_min) |ver| switch (ver) {
206 .none => .none,
207 .semver => |sem_ver| .{ .semver = try wip.addSemVer(sem_ver) },
208 .windows => |win_ver| .{ .windows = win_ver },
209 } else .default;
210 const os_version_max: TargetQuery.OsVersion = if (q.os_version_max) |ver| switch (ver) {
211 .none => .none,
212 .semver => |sem_ver| .{ .semver = try wip.addSemVer(sem_ver) },
213 .windows => |win_ver| .{ .windows = win_ver },
214 } else .default;
215 const glibc_version: ?String = if (q.glibc_version) |sem_ver| try wip.addSemVer(sem_ver) else null;
216 const dynamic_linker: ?String = if (q.dynamic_linker) |*dl|
217 if (dl.get()) |s| try wip.addString(s) else .empty
218 else
219 null;
220 const cpu_features_add_empty = q.cpu_features_add.isEmpty();
221 const cpu_features_sub_empty = q.cpu_features_sub.isEmpty();
222 const result_index: TargetQuery.Index = @enumFromInt(try wip.addExtra(@as(TargetQuery, .{
223 .flags = .{
224 .cpu_arch = .init(q.cpu_arch),
225 .cpu_model = .init(q.cpu_model),
226 .cpu_features_add = !cpu_features_add_empty,
227 .cpu_features_sub = !cpu_features_sub_empty,
228 .os_tag = .init(q.os_tag),
229 .abi = .init(q.abi),
230 .object_format = .init(q.ofmt),
231 .os_version_min = os_version_min,
232 .os_version_max = os_version_max,
233 .glibc_version = glibc_version != null,
234 .android_api_level = q.android_api_level != null,
235 .dynamic_linker = dynamic_linker != null,
236 },
237 .cpu_features_add = .{ .value = if (cpu_features_add_empty) null else q.cpu_features_add },
238 .cpu_features_sub = .{ .value = if (cpu_features_sub_empty) null else q.cpu_features_sub },
239 .glibc_version = .{ .value = glibc_version },
240 .android_api_level = .{ .value = q.android_api_level },
241 .dynamic_linker = .{ .value = dynamic_linker },
242 .cpu_name = .{ .value = cpu_name },
243 .os_version_min = .{ .u = os_version_min },
244 .os_version_max = .{ .u = os_version_max },
245 })));
246
247 // Deduplicate.
248 const gop = try wip.targets_table.getOrPutContext(gpa, result_index, @as(TargetsTableContext, .{
249 .extra = wip.extra.items,
250 }));
251 if (gop.found_existing) {
252 wip.extra.items.len = @intFromEnum(result_index);
253 return .init(gop.key_ptr.*);
254 } else {
255 return .init(result_index);
256 }
257 }
258
259 pub fn addTarget(wip: *Wip, t: std.Target) !TargetQuery.Index {
260 const gpa = wip.gpa;
261 const cpu_name: String = try wip.addString(t.cpu.model.name);
262
263 const os_version_min: TargetQuery.OsVersion, const os_version_max: TargetQuery.OsVersion, const glibc_version: ?String, const android_api_level: ?u32 = switch (t.os.versionRange()) {
264 .none => .{
265 .none,
266 .none,
267 null,
268 null,
269 },
270 .semver => |range| .{
271 .{ .semver = try wip.addSemVer(range.min) },
272 .{ .semver = try wip.addSemVer(range.max) },
273 null,
274 null,
275 },
276 .hurd => |hurd| .{
277 .{ .semver = try wip.addSemVer(hurd.range.min) },
278 .{ .semver = try wip.addSemVer(hurd.range.max) },
279 try wip.addSemVer(hurd.glibc),
280 null,
281 },
282 .linux => |linux| .{
283 .{ .semver = try wip.addSemVer(linux.range.min) },
284 .{ .semver = try wip.addSemVer(linux.range.max) },
285 try wip.addSemVer(linux.glibc),
286 linux.android,
287 },
288 .windows => |range| .{
289 .{ .windows = range.min },
290 .{ .windows = range.max },
291 null,
292 null,
293 },
294 };
295 const dynamic_linker: ?String = if (t.dynamic_linker.get()) |dl| try wip.addString(dl) else null;
296 const cpu_features_add_empty = t.cpu.features.isEmpty();
297 const result_index: TargetQuery.Index = @enumFromInt(try wip.addExtra(@as(TargetQuery, .{
298 .flags = .{
299 .cpu_arch = .init(t.cpu.arch),
300 .cpu_model = .explicit,
301 .cpu_features_add = !cpu_features_add_empty,
302 .cpu_features_sub = false,
303 .os_tag = .init(t.os.tag),
304 .abi = .init(t.abi),
305 .object_format = .init(t.ofmt),
306 .os_version_min = os_version_min,
307 .os_version_max = os_version_max,
308 .glibc_version = glibc_version != null,
309 .android_api_level = android_api_level != null,
310 .dynamic_linker = dynamic_linker != null,
311 },
312 .cpu_features_add = .{ .value = if (cpu_features_add_empty) null else t.cpu.features },
313 .cpu_features_sub = .{ .value = null },
314 .glibc_version = .{ .value = glibc_version },
315 .android_api_level = .{ .value = android_api_level },
316 .dynamic_linker = .{ .value = dynamic_linker },
317 .cpu_name = .{ .value = cpu_name },
318 .os_version_min = .{ .u = os_version_min },
319 .os_version_max = .{ .u = os_version_max },
320 })));
321
322 // Deduplicate.
323 const gop = try wip.targets_table.getOrPutContext(gpa, result_index, @as(TargetsTableContext, .{
324 .extra = wip.extra.items,
325 }));
326 if (gop.found_existing) {
327 wip.extra.items.len = @intFromEnum(result_index);
328 return gop.key_ptr.*;
329 } else {
330 return result_index;
331 }
332 }
333
334 pub fn addExtra(wip: *Wip, extra: anytype) Allocator.Error!u32 {
335 const extra_len = Storage.extraLen(extra);
336 try wip.extra.ensureUnusedCapacity(wip.gpa, extra_len);
337 return addExtraAssumeCapacity(wip, extra);
338 }
339
340 /// Same as `addExtra` but uses a hash map to possibly return an already
341 /// existing index instead of appending to `extra`.
342 pub fn addDeduped(wip: *Wip, extra: anytype) Allocator.Error!u32 {
343 const gpa = wip.gpa;
344 const revert_index = wip.extra.items.len;
345 const extra_len = Storage.extraLen(extra);
346 try wip.extra.ensureUnusedCapacity(gpa, extra_len);
347 const new_index = addExtraAssumeCapacity(wip, extra);
348 const len: u32 = @intCast(wip.extra.items.len - new_index);
349
350 const gop = try wip.dedupe_table.getOrPutContext(gpa, .{
351 .index = new_index,
352 .len = len,
353 }, @as(ExtraSlice.Context, .{ .extra = wip.extra.items }));
354
355 if (gop.found_existing) {
356 wip.extra.items.len = revert_index;
357 return gop.key_ptr.index;
358 }
359
360 return new_index;
361 }
362
363 pub fn addExtraAssumeCapacity(wip: *Wip, extra: anytype) u32 {
364 const result: u32 = @intCast(wip.extra.items.len);
365 wip.extra.items.len = Storage.setExtra(wip.extra.allocatedSlice(), result, extra);
366 return result;
367 }
368
369 fn addExtraOptionalStringAssumeCapacity(wip: *Wip, optional_string: ?String) void {
370 const string = optional_string orelse return;
371 wip.extra.appendAssumeCapacity(@intFromEnum(string));
372 }
373
374 pub fn addGeneratedFile(wip: *Wip) GeneratedFileIndex {
375 defer wip.next_generated_file_index += 1;
376 return @enumFromInt(wip.next_generated_file_index);
377 }
378};
379
380pub const SystemIntegration = extern struct {
381 name: String,
382 status: Status,
383
384 pub const Status = enum(u32) {
385 disabled = 0,
386 enabled = 1,
387 };
388};
389
390pub const AvailableOption = extern struct {
391 name: String,
392 description: String,
393 type: Type,
394 /// If the `type_id` is `enum` or `enum_list` this provides the list of enum options
395 enum_options: OptionalStringList,
396
397 pub const Type = enum(u8) {
398 bool,
399 int,
400 float,
401 @"enum",
402 enum_list,
403 string,
404 list,
405 build_id,
406 lazy_path,
407 lazy_path_list,
408 };
409};
410
411pub const Step = extern struct {
412 name: String,
413 owner: Package.Index,
414 deps: Deps.Index,
415 max_rss: MaxRss,
416 extended: Storage.Extended(Flags, union(Tag) {
417 check_file: CheckFile,
418 check_object: CheckObject,
419 compile: Compile,
420 config_header: ConfigHeader,
421 fail: Fail,
422 fmt: Fmt,
423 install_artifact: InstallArtifact,
424 install_dir: InstallDir,
425 install_file: InstallFile,
426 objcopy: Objcopy,
427 options: Options,
428 remove_dir: RemoveDir,
429 run: Run,
430 top_level: TopLevel,
431 translate_c: TranslateC,
432 update_source_files: UpdateSourceFiles,
433 write_file: WriteFile,
434 }),
435
436 /// Points into `steps`.
437 pub const Index = enum(u32) {
438 _,
439
440 pub fn ptr(i: Index, c: *const Configuration) *const Step {
441 return &c.steps[@intFromEnum(i)];
442 }
443 };
444
445 /// Shared by all steps.
446 pub const Flags = packed struct(u32) {
447 tag: Tag,
448 _: u27 = 0,
449 };
450
451 pub const Tag = enum(u5) {
452 check_file,
453 check_object,
454 compile,
455 config_header,
456 fail,
457 fmt,
458 install_artifact,
459 install_dir,
460 install_file,
461 objcopy,
462 options,
463 remove_dir,
464 run,
465 top_level,
466 translate_c,
467 update_source_files,
468 write_file,
469 };
470
471 pub const TopLevel = struct {
472 flags: @This().Flags = .{},
473 description: String,
474
475 pub const Flags = packed struct(u32) {
476 tag: Tag = .top_level,
477 _: u27 = 0,
478 };
479 };
480
481 pub const InstallArtifact = struct {
482 flags: @This().Flags,
483
484 dest_dir: InstallDestDir,
485 dest_sub_path: String,
486 emitted_bin: LazyPath.OptionalIndex,
487
488 implib_dir: InstallDestDir,
489 emitted_implib: LazyPath.OptionalIndex,
490
491 pdb_dir: InstallDestDir,
492 emitted_pdb: LazyPath.OptionalIndex,
493
494 h_dir: InstallDestDir,
495 emitted_h: LazyPath.OptionalIndex,
496
497 /// Always a compile step.
498 artifact: Step.Index,
499
500 pub const Flags = packed struct(u32) {
501 tag: Tag = .install_artifact,
502 dylib_symlinks: bool,
503 _: u26 = 0,
504 };
505 };
506
507 /// Trailing:
508 /// * LazyPath.Index for each file_inputs_len
509 /// * Arg for each args_len
510 /// * environ_map if corresponding flag is set
511 /// * stdin: Bytes, // if StdIn.bytes is chosen
512 /// * stdin: LazyPath.Index, // if StdIn.lazy_path is chosen
513 /// * checks: Checks, // if StdIo.check is chosen
514 /// * stdio_limit: u64, // if stdio_limit is set
515 /// * producer: Step.Index, // if producer is set. always compile step
516 pub const Run = struct {
517 flags: @This().Flags,
518 file_inputs_len: u32,
519 args_len: u32,
520 cwd: LazyPath.OptionalIndex,
521 captured_stdout: OptionalString, // basename
522 captured_stderr: OptionalString, // basename
523
524 /// Trailing:
525 /// * String if prefix set
526 /// * String if suffix set
527 /// * String if basename set
528 /// * Step.Index which is always a compile step if tag is artifact
529 /// * LazyPath.Index if tag is path_file, path_directory, or file_content
530 pub const Arg = struct {
531 flags: Arg.Flags,
532
533 pub const Flags = packed struct(u32) {
534 tag: Arg.Tag,
535 prefix: bool,
536 suffix: bool,
537 basename: bool,
538 /// Implies Tag is output_file
539 dep_file: bool,
540 _: u20 = 0,
541 };
542
543 pub const Tag = enum(u8) {
544 artifact,
545 path_file,
546 path_directory,
547 file_content,
548 bytes,
549 output_file,
550 output_directory,
551 cli_rest_positionals,
552 };
553 };
554
555 pub const Color = enum(u4) {
556 /// `CLICOLOR_FORCE` is set, and `NO_COLOR` is unset.
557 enable,
558 /// `NO_COLOR` is set, and `CLICOLOR_FORCE` is unset.
559 disable,
560 /// If the build runner is using color, equivalent to `.enable`. Otherwise, equivalent to `.disable`.
561 inherit,
562 /// If stderr is captured or checked, equivalent to `.disable`. Otherwise, equivalent to `.inherit`.
563 auto,
564 /// The build runner does not modify the `CLICOLOR_FORCE` or `NO_COLOR` environment variables.
565 /// They are treated like normal variables, so can be controlled through `setEnvironmentVariable`.
566 manual,
567 };
568
569 pub const StdIn = enum(u2) { none, bytes, lazy_path };
570 pub const TrimWhitespace = enum(u2) { none, all, leading, trailing };
571 pub const StdIo = enum(u2) { infer_from_args, inherit, check, zig_test };
572
573 pub const Flags = packed struct(u32) {
574 tag: Tag = .run,
575
576 disable_zig_progress: bool,
577 skip_foreign_checks: bool,
578 failing_to_execute_foreign_is_an_error: bool,
579 has_side_effects: bool,
580 test_runner_mode: bool,
581 color: Color,
582 stdin: StdIn,
583 stdio: StdIo,
584 stdout_trim_whitespace: TrimWhitespace,
585 stderr_trim_whitespace: TrimWhitespace,
586 stdio_limit: bool,
587 producer: bool,
588 _: u8 = 0,
589 };
590 };
591
592 pub const Compile = struct {
593 flags: @This().Flags,
594 flags2: Flags2,
595 flags3: Flags3,
596 flags4: Flags4,
597
598 root_module: Module.Index,
599 root_name: String,
600
601 filters: Storage.FlagLengthPrefixedList(.flags, .filters_len, String),
602 exec_cmd_args: Storage.FlagLengthPrefixedList(.flags, .exec_cmd_args_len, OptionalString),
603 installed_headers: Storage.FlagLengthPrefixedList(.flags, .installed_headers_len, Storage.Extended(InstalledHeader.Flags, InstalledHeader)),
604 force_undefined_symbols: Storage.FlagLengthPrefixedList(.flags, .force_undefined_symbols_len, String),
605 expect_errors: Storage.FlagUnion(.flags4, .expect_errors, ExpectErrors),
606 linker_script: Storage.FlagOptional(.flags4, .linker_script, LazyPath.Index),
607 version_script: Storage.FlagOptional(.flags4, .version_script, LazyPath.Index),
608 zig_lib_dir: Storage.FlagOptional(.flags3, .zig_lib_dir, LazyPath.Index),
609 libc_file: Storage.FlagOptional(.flags4, .libc_file, LazyPath.Index),
610 win32_manifest: Storage.FlagOptional(.flags3, .win32_manifest, LazyPath.Index),
611 win32_module_definition: Storage.FlagOptional(.flags3, .win32_module_definition, LazyPath.Index),
612 entitlements: Storage.FlagOptional(.flags4, .entitlements, LazyPath.Index),
613 version: Storage.FlagOptional(.flags3, .version, String), // semantic version string
614 entry: Storage.EnumOptional(.flags3, .entry, .symbol_name, String),
615 install_name: Storage.FlagOptional(.flags4, .install_name, String),
616 initial_memory: Storage.FlagOptional(.flags3, .initial_memory, u64),
617 max_memory: Storage.FlagOptional(.flags3, .max_memory, u64),
618 global_base: Storage.FlagOptional(.flags3, .global_base, u64),
619 image_base: Storage.FlagOptional(.flags3, .image_base, u64),
620 link_z_common_page_size: Storage.FlagOptional(.flags4, .link_z_common_page_size, u64),
621 link_z_max_page_size: Storage.FlagOptional(.flags4, .link_z_max_page_size, u64),
622 pagezero_size: Storage.FlagOptional(.flags4, .pagezero_size, u64),
623 stack_size: Storage.FlagOptional(.flags4, .stack_size, u64),
624 headerpad_size: Storage.FlagOptional(.flags4, .headerpad_size, u32),
625 error_limit: Storage.FlagOptional(.flags4, .error_limit, u32),
626 build_id: Storage.EnumOptional(.flags3, .build_id, .hexstring, String),
627 test_runner: Storage.FlagUnion(.flags3, .test_runner, TestRunner),
628
629 emit_directory: Storage.FlagOptional(.flags4, .emit_directory, GeneratedFileIndex),
630 generated_docs: Storage.FlagOptional(.flags4, .generated_docs, GeneratedFileIndex),
631 generated_asm: Storage.FlagOptional(.flags4, .generated_asm, GeneratedFileIndex),
632 generated_bin: Storage.FlagOptional(.flags4, .generated_bin, GeneratedFileIndex),
633 generated_pdb: Storage.FlagOptional(.flags4, .generated_pdb, GeneratedFileIndex),
634 generated_implib: Storage.FlagOptional(.flags4, .generated_implib, GeneratedFileIndex),
635 generated_llvm_bc: Storage.FlagOptional(.flags4, .generated_llvm_bc, GeneratedFileIndex),
636 generated_llvm_ir: Storage.FlagOptional(.flags4, .generated_llvm_ir, GeneratedFileIndex),
637 generated_h: Storage.FlagOptional(.flags4, .generated_h, GeneratedFileIndex),
638
639 pub const InstalledHeader = union(@This().Tag) {
640 file: File,
641 directory: Directory,
642
643 pub const Flags = packed struct(u32) {
644 tag: InstalledHeader.Tag,
645 _: u24 = 0,
646 };
647
648 pub const Tag = enum(u8) {
649 file,
650 directory,
651 };
652
653 pub const File = struct {
654 flags: @This().Flags = .{},
655 source: LazyPath.Index,
656 dest_sub_path: String,
657
658 pub const Flags = packed struct(u32) {
659 tag: InstalledHeader.Tag = .file,
660 _: u24 = 0,
661 };
662 };
663
664 pub const Directory = struct {
665 flags: @This().Flags,
666 source: LazyPath.Index,
667 dest_sub_path: String,
668 exclude_extensions: Storage.FlagLengthPrefixedList(.flags, .exclude_extensions, String),
669 include_extensions: Storage.FlagLengthPrefixedList(.flags, .include_extensions, String),
670
671 pub const Flags = packed struct(u32) {
672 tag: InstalledHeader.Tag = .directory,
673 exclude_extensions: bool,
674 include_extensions: bool,
675 _: u22 = 0,
676 };
677 };
678 };
679 pub const ExpectErrors = union(@This().Tag) {
680 pub const Tag = enum(u3) { contains, exact, starts_with, stderr_contains, none };
681
682 contains: String,
683 exact: Storage.LengthPrefixedList(String),
684 starts_with: String,
685 stderr_contains: String,
686 none: void,
687 };
688 pub const TestRunner = union(@This().Tag) {
689 pub const Tag = enum(u2) { default, simple, server };
690
691 default: void,
692 simple: LazyPath.Index,
693 server: LazyPath.Index,
694 };
695 pub const Entry = enum(u2) { default, disabled, enabled, symbol_name };
696
697 pub const Lto = enum(u2) {
698 none,
699 full,
700 thin,
701 default,
702
703 pub fn init(lto: ?std.zig.LtoMode) Lto {
704 return switch (lto orelse return .default) {
705 .none => .none,
706 .full => .full,
707 .thin => .thin,
708 };
709 }
710 };
711
712 pub const BuildId = enum(u3) {
713 none,
714 fast,
715 uuid,
716 sha1,
717 md5,
718 hexstring,
719 default,
720
721 pub fn init(build_id: ?std.zig.BuildId) BuildId {
722 return switch (build_id orelse return .default) {
723 .none => .none,
724 .fast => .fast,
725 .uuid => .uuid,
726 .sha1 => .sha1,
727 .md5 => .md5,
728 .hexstring => .hexstring,
729 };
730 }
731 };
732 pub const WasiExecModel = enum(u2) {
733 default,
734 command,
735 reactor,
736
737 pub fn init(wasi_exec_model: ?std.builtin.WasiExecModel) WasiExecModel {
738 return switch (wasi_exec_model orelse return .default) {
739 .command => .command,
740 .reactor => .reactor,
741 };
742 }
743 };
744 pub const Linkage = enum(u2) {
745 static,
746 dynamic,
747 default,
748
749 pub fn init(link_mode: ?std.builtin.LinkMode) Linkage {
750 return switch (link_mode orelse return .default) {
751 .static => .static,
752 .dynamic => .dynamic,
753 };
754 }
755 };
756 pub const Kind = enum(u3) {
757 exe,
758 lib,
759 obj,
760 @"test",
761 test_obj,
762
763 pub fn isTest(kind: Kind) bool {
764 return switch (kind) {
765 .exe, .lib, .obj => false,
766 .@"test", .test_obj => true,
767 };
768 }
769 };
770 pub const Subsystem = enum(u4) {
771 console,
772 windows,
773 posix,
774 native,
775 efi_application,
776 efi_boot_service_driver,
777 efi_rom,
778 efi_runtime_driver,
779 default,
780
781 pub fn init(subsystem: ?std.zig.Subsystem) Subsystem {
782 return switch (subsystem orelse return .default) {
783 .console => .console,
784 .windows => .windows,
785 .posix => .posix,
786 .native => .native,
787 .efi_application => .efi_application,
788 .efi_boot_service_driver => .efi_boot_service_driver,
789 .efi_rom => .efi_rom,
790 .efi_runtime_driver => .efi_runtime_driver,
791 };
792 }
793 };
794
795 pub const Flags = packed struct(u32) {
796 tag: Tag = .compile,
797
798 filters_len: bool,
799 exec_cmd_args_len: bool,
800 installed_headers_len: bool,
801 force_undefined_symbols_len: bool,
802
803 verbose_link: bool,
804 verbose_cc: bool,
805 rdynamic: bool,
806 import_memory: bool,
807 export_memory: bool,
808 import_symbols: bool,
809 import_table: bool,
810 export_table: bool,
811 shared_memory: bool,
812 link_eh_frame_hdr: bool,
813 link_emit_relocs: bool,
814 link_function_sections: bool,
815 link_data_sections: bool,
816 linker_dynamicbase: bool,
817 link_z_notext: bool,
818 link_z_relro: bool,
819 link_z_lazy: bool,
820 link_z_defs: bool,
821 headerpad_max_install_names: bool,
822 dead_strip_dylibs: bool,
823 force_load_objc: bool,
824 discard_local_symbols: bool,
825 mingw_unicode_entry_point: bool,
826 };
827
828 pub const Flags2 = packed struct(u32) {
829 pie: DefaultingBool,
830 formatted_panics: DefaultingBool,
831 bundle_compiler_rt: DefaultingBool,
832 bundle_ubsan_rt: DefaultingBool,
833 each_lib_rpath: DefaultingBool,
834 link_gc_sections: DefaultingBool,
835 linker_allow_shlib_undefined: DefaultingBool,
836 linker_allow_undefined_version: DefaultingBool,
837 linker_enable_new_dtags: DefaultingBool,
838 dll_export_fns: DefaultingBool,
839 use_llvm: DefaultingBool,
840 use_lld: DefaultingBool,
841 use_new_linker: DefaultingBool,
842 allow_so_scripts: DefaultingBool,
843 sanitize_coverage_trace_pc_guard: DefaultingBool,
844 linkage: Linkage,
845 };
846
847 pub const Flags3 = packed struct(u32) {
848 is_linking_libc: bool,
849 is_linking_libcpp: bool,
850 version: bool,
851 initial_memory: bool,
852 max_memory: bool,
853 kind: Kind,
854 compress_debug_sections: std.zig.CompressDebugSections,
855 global_base: bool,
856 test_runner: TestRunner.Tag,
857 wasi_exec_model: WasiExecModel,
858 win32_manifest: bool,
859 win32_module_definition: bool,
860 zig_lib_dir: bool,
861 rc_includes: std.zig.RcIncludes,
862 image_base: bool,
863 build_id: BuildId,
864 entry: Entry,
865 lto: Lto,
866 subsystem: Subsystem,
867 };
868
869 pub const Flags4 = packed struct(u32) {
870 libc_file: bool,
871 link_z_common_page_size: bool,
872 link_z_max_page_size: bool,
873 pagezero_size: bool,
874 stack_size: bool,
875 headerpad_size: bool,
876 error_limit: bool,
877 install_name: bool,
878 entitlements: bool,
879 expect_errors: ExpectErrors.Tag,
880 linker_script: bool,
881 version_script: bool,
882 emit_directory: bool,
883 generated_docs: bool,
884 generated_asm: bool,
885 generated_bin: bool,
886 generated_pdb: bool,
887 generated_implib: bool,
888 generated_llvm_bc: bool,
889 generated_llvm_ir: bool,
890 generated_h: bool,
891 _: u9 = 0,
892 };
893
894 pub fn isDynamicLibrary(compile: *const Compile) bool {
895 return compile.flags3.kind == .lib and compile.flags2.linkage == .dynamic;
896 }
897
898 pub fn isStaticLibrary(compile: *const Compile) bool {
899 return compile.flags3.kind == .lib and compile.flags2.linkage != .dynamic;
900 }
901
902 pub fn producesImplib(compile: *const Compile, c: *const Configuration) bool {
903 return isDll(compile, c);
904 }
905
906 pub fn isDll(compile: *const Compile, c: *const Configuration) bool {
907 return isDynamicLibrary(compile) and rootModuleTarget(compile, c).flags.os_tag == .windows;
908 }
909
910 pub fn rootModuleTarget(compile: *const Compile, c: *const Configuration) TargetQuery {
911 return compile.root_module.get(c).resolved_target.get(c).?.result.get(c);
912 }
913 };
914
915 pub const CheckFile = struct {
916 flags: @This().Flags,
917
918 pub const Flags = packed struct(u32) {
919 tag: Tag = .check_file,
920 _: u27 = 0,
921 };
922 };
923
924 pub const CheckObject = struct {
925 flags: @This().Flags,
926
927 pub const Flags = packed struct(u32) {
928 tag: Tag = .check_object,
929 _: u27 = 0,
930 };
931 };
932
933 pub const ConfigHeader = struct {
934 flags: @This().Flags,
935
936 pub const Flags = packed struct(u32) {
937 tag: Tag = .config_header,
938 _: u27 = 0,
939 };
940 };
941
942 pub const Fail = struct {
943 flags: @This().Flags,
944
945 pub const Flags = packed struct(u32) {
946 tag: Tag = .fail,
947 _: u27 = 0,
948 };
949 };
950
951 pub const Fmt = struct {
952 flags: @This().Flags,
953
954 pub const Flags = packed struct(u32) {
955 tag: Tag = .fmt,
956 _: u27 = 0,
957 };
958 };
959
960 pub const InstallDir = struct {
961 flags: @This().Flags,
962
963 pub const Flags = packed struct(u32) {
964 tag: Tag = .install_dir,
965 _: u27 = 0,
966 };
967 };
968
969 pub const InstallFile = struct {
970 flags: @This().Flags,
971
972 pub const Flags = packed struct(u32) {
973 tag: Tag = .install_file,
974 _: u27 = 0,
975 };
976 };
977
978 pub const Objcopy = struct {
979 flags: @This().Flags,
980
981 pub const Flags = packed struct(u32) {
982 tag: Tag = .objcopy,
983 _: u27 = 0,
984 };
985 };
986
987 pub const Options = struct {
988 flags: @This().Flags,
989
990 pub const Flags = packed struct(u32) {
991 tag: Tag = .options,
992 _: u27 = 0,
993 };
994 };
995
996 pub const RemoveDir = struct {
997 flags: @This().Flags,
998
999 pub const Flags = packed struct(u32) {
1000 tag: Tag = .remove_dir,
1001 _: u27 = 0,
1002 };
1003 };
1004
1005 pub const TranslateC = struct {
1006 flags: @This().Flags,
1007
1008 pub const Flags = packed struct(u32) {
1009 tag: Tag = .translate_c,
1010 _: u27 = 0,
1011 };
1012 };
1013
1014 pub const UpdateSourceFiles = struct {
1015 flags: @This().Flags,
1016
1017 pub const Flags = packed struct(u32) {
1018 tag: Tag = .update_source_files,
1019 _: u27 = 0,
1020 };
1021 };
1022
1023 pub const WriteFile = struct {
1024 flags: @This().Flags,
1025
1026 pub const Flags = packed struct(u32) {
1027 tag: Tag = .write_file,
1028 _: u27 = 0,
1029 };
1030 };
1031
1032 pub fn flags(s: *const Step, c: *const Configuration) Flags {
1033 return @bitCast(c.extra[@intFromEnum(s.extended)]);
1034 }
1035};
1036
1037pub const MaxRss = enum(u32) {
1038 none = 0,
1039 _,
1040
1041 pub fn toBytes(mr: MaxRss) usize {
1042 const x: usize = @intFromEnum(mr);
1043 return x << 8;
1044 }
1045
1046 pub fn fromBytes(bytes: usize) MaxRss {
1047 return @enumFromInt(bytes >> 8);
1048 }
1049};
1050
1051pub const LazyPath = union(@This().Tag) {
1052 source_path: SourcePath,
1053 relative: Relative,
1054 generated: Generated,
1055
1056 pub const Tag = enum(u8) {
1057 /// A source file path relative to build root.
1058 source_path,
1059 /// Relative to the directory indicated in flags.
1060 relative,
1061 /// Path is available only after it is populated by its owning step.
1062 generated,
1063 };
1064
1065 pub const Flags = packed struct(u32) {
1066 tag: Tag,
1067 _: u24 = 0,
1068 };
1069
1070 /// An index into `extra`.
1071 pub const Index = enum(u32) {
1072 _,
1073
1074 pub fn get(this: @This(), c: *const Configuration) LazyPath {
1075 return extraData(c, LazyPath, @intFromEnum(this));
1076 }
1077 };
1078
1079 /// An index into `extra`, or `null`.
1080 pub const OptionalIndex = enum(u32) {
1081 none = maxInt(u32),
1082 _,
1083
1084 pub fn unwrap(this: @This()) ?Index {
1085 return switch (this) {
1086 .none => null,
1087 else => @enumFromInt(@intFromEnum(this)),
1088 };
1089 }
1090 };
1091
1092 pub const SourcePath = struct {
1093 flags: @This().Flags,
1094 owner: Package.Index,
1095 sub_path: String,
1096
1097 pub const Flags = packed struct(u32) {
1098 tag: Tag = .source_path,
1099 _: u24 = 0,
1100 };
1101 };
1102
1103 pub const Generated = struct {
1104 flags: @This().Flags = .{},
1105 index: GeneratedFileIndex,
1106 /// Applied after `up`.
1107 sub_path: String = .empty,
1108
1109 pub const Flags = packed struct(u32) {
1110 tag: Tag = .generated,
1111 /// The number of parent directories to go up.
1112 /// 0 means the generated file itself.
1113 /// 1 means the directory of the generated file.
1114 /// 2 means the parent of that directory, and so on.
1115 up: u24 = 0,
1116 };
1117 };
1118
1119 pub const Relative = struct {
1120 flags: @This().Flags,
1121 sub_path: String,
1122
1123 pub const Flags = packed struct(u32) {
1124 tag: Tag = .relative,
1125 base: Path.Base,
1126 _: u16 = 0,
1127 };
1128 };
1129};
1130
1131pub const GeneratedFileIndex = enum(u32) {
1132 _,
1133};
1134
1135pub const OptionalGeneratedFileIndex = enum(u32) {
1136 none = maxInt(u32),
1137 _,
1138
1139 pub fn init(i: ?GeneratedFileIndex) OptionalGeneratedFileIndex {
1140 return @enumFromInt(@intFromEnum(i orelse return .none));
1141 }
1142
1143 pub fn unwrap(this: @This()) ?GeneratedFileIndex {
1144 return switch (this) {
1145 .none => null,
1146 else => @enumFromInt(@intFromEnum(this)),
1147 };
1148 }
1149};
1150
1151pub const Package = struct {
1152 dep_prefix: String,
1153 hash: String,
1154
1155 pub const Index = enum(u32) {
1156 root = maxInt(u32),
1157 _,
1158
1159 /// Returns `null` for root package.
1160 pub fn get(i: @This(), c: *const Configuration) ?Package {
1161 if (i == .root) return null;
1162 return extraData(c, Package, @intFromEnum(i));
1163 }
1164
1165 pub fn depPrefixSlice(i: @This(), c: *const Configuration) [:0]const u8 {
1166 const package = get(i, c) orelse return "";
1167 return package.dep_prefix.slice(c);
1168 }
1169 };
1170};
1171
1172pub const Module = struct {
1173 flags: Flags,
1174 flags2: Flags2,
1175 import_table: ImportTable.Index,
1176 owner: Package.Index,
1177 root_source_file: LazyPath.OptionalIndex,
1178 resolved_target: ResolvedTarget.OptionalIndex,
1179 c_macros: Storage.FlagLengthPrefixedList(.flags, .c_macros, String),
1180 lib_paths: Storage.FlagLengthPrefixedList(.flags, .lib_paths, LazyPath.Index),
1181 export_symbol_names: Storage.FlagLengthPrefixedList(.flags, .export_symbol_names, String),
1182 include_dirs: Storage.UnionList(.flags, .include_dirs, IncludeDir),
1183 rpaths: Storage.UnionList(.flags, .rpaths, RPath),
1184 link_objects: Storage.UnionList(.flags, .link_objects, LinkObject),
1185 frameworks: Storage.FlagLengthPrefixedList(.flags, .frameworks, Framework),
1186
1187 pub const Optimize = enum(u3) {
1188 debug,
1189 safe,
1190 fast,
1191 small,
1192 default,
1193
1194 pub fn init(o: ?std.builtin.OptimizeMode) Optimize {
1195 return switch (o orelse return .default) {
1196 .Debug => .debug,
1197 .ReleaseSafe => .safe,
1198 .ReleaseFast => .fast,
1199 .ReleaseSmall => .small,
1200 };
1201 }
1202 };
1203
1204 pub const UnwindTables = enum(u2) {
1205 none,
1206 sync,
1207 async,
1208 default,
1209
1210 pub fn init(ut: ?std.builtin.UnwindTables) UnwindTables {
1211 return switch (ut orelse return .default) {
1212 .none => .none,
1213 .sync => .sync,
1214 .async => .async,
1215 };
1216 }
1217 };
1218
1219 pub const SanitizeC = enum(u2) {
1220 off,
1221 trap,
1222 full,
1223 default,
1224
1225 pub fn init(sc: ?std.zig.SanitizeC) SanitizeC {
1226 return switch (sc orelse return .default) {
1227 .off => .off,
1228 .trap => .trap,
1229 .full => .full,
1230 };
1231 }
1232 };
1233
1234 pub const DwarfFormat = enum(u2) {
1235 @"32",
1236 @"64",
1237 default,
1238
1239 pub fn init(df: ?std.dwarf.Format) DwarfFormat {
1240 return switch (df orelse return .default) {
1241 .@"32" => .@"32",
1242 .@"64" => .@"64",
1243 };
1244 }
1245 };
1246
1247 pub const Index = enum(u32) {
1248 _,
1249
1250 pub fn get(this: @This(), c: *const Configuration) Module {
1251 return extraData(c, Module, @intFromEnum(this));
1252 }
1253 };
1254
1255 pub const Flags = packed struct(u32) {
1256 optimize: Optimize,
1257 strip: DefaultingBool,
1258 unwind_tables: UnwindTables,
1259 dwarf_format: DwarfFormat,
1260 single_threaded: DefaultingBool,
1261 stack_protector: DefaultingBool,
1262 stack_check: DefaultingBool,
1263 sanitize_c: SanitizeC,
1264 sanitize_thread: DefaultingBool,
1265 fuzz: DefaultingBool,
1266 code_model: std.builtin.CodeModel,
1267 c_macros: bool,
1268 include_dirs: bool,
1269 lib_paths: bool,
1270 rpaths: bool,
1271 frameworks: bool,
1272 link_objects: bool,
1273 export_symbol_names: bool,
1274 };
1275
1276 pub const Flags2 = packed struct(u32) {
1277 valgrind: DefaultingBool,
1278 pic: DefaultingBool,
1279 red_zone: DefaultingBool,
1280 omit_frame_pointer: DefaultingBool,
1281 error_tracing: DefaultingBool,
1282 link_libc: DefaultingBool,
1283 link_libcpp: DefaultingBool,
1284 no_builtin: DefaultingBool,
1285 _: u16 = 0,
1286 };
1287
1288 pub const IncludeDir = union(enum(u3)) {
1289 path: LazyPath.Index,
1290 path_system: LazyPath.Index,
1291 path_after: LazyPath.Index,
1292 framework_path: LazyPath.Index,
1293 framework_path_system: LazyPath.Index,
1294 /// Always `Step.Tag.compile`.
1295 other_step: Step.Index,
1296 /// Always `Step.Tag.config_header`.
1297 config_header_step: Step.Index,
1298 embed_path: LazyPath.Index,
1299 };
1300
1301 pub const RPath = union(enum(u1)) {
1302 lazy_path: LazyPath.Index,
1303 special: String,
1304 };
1305
1306 pub const LinkObject = union(enum(u3)) {
1307 static_path: LazyPath.Index,
1308 /// Always `Step.Tag.compile`.
1309 other_step: Step.Index,
1310 system_lib: SystemLib.Index,
1311 assembly_file: LazyPath.Index,
1312 c_source_file: CSourceFile.Index,
1313 c_source_files: CSourceFiles.Index,
1314 win32_resource_file: RcSourceFile.Index,
1315 };
1316
1317 pub const Framework = extern struct {
1318 flags: @This().Flags,
1319 name: String,
1320
1321 pub const Flags = packed struct(u32) {
1322 needed: bool,
1323 weak: bool,
1324 _: u30 = 0,
1325 };
1326 };
1327};
1328
1329pub const ImportTable = struct {
1330 imports: Storage.MultiList(Import),
1331
1332 pub const Import = struct {
1333 name: String,
1334 module: Module.Index,
1335 };
1336
1337 /// Points into `extra`.
1338 pub const Index = enum(u32) {
1339 invalid = maxInt(u32),
1340 _,
1341
1342 pub fn get(this: @This(), c: *const Configuration) ImportTable {
1343 return switch (this) {
1344 .invalid => unreachable,
1345 _ => extraData(c, ImportTable, @intFromEnum(this)),
1346 };
1347 }
1348 };
1349};
1350
1351pub const Deps = struct {
1352 steps: Storage.LengthPrefixedList(Step.Index),
1353
1354 pub const Index = enum(u32) {
1355 _,
1356
1357 pub fn get(this: @This(), c: *const Configuration) Deps {
1358 return extraData(c, Deps, @intFromEnum(this));
1359 }
1360
1361 pub fn slice(this: @This(), c: *const Configuration) []const Step.Index {
1362 return get(this, c).steps.slice;
1363 }
1364 };
1365};
1366
1367/// Points into `extra`, where the first element is count of strings, following
1368/// elements is `String` per count.
1369///
1370/// Stored identically to `Deps`.
1371pub const OptionalStringList = enum(u32) {
1372 none = maxInt(u32),
1373 _,
1374
1375 pub fn slice(osl: OptionalStringList, c: *const Configuration) ?[]const String {
1376 const len = c.extra[@intFromEnum(osl)];
1377 return @ptrCast(c.extra[@intFromEnum(osl) + 1 ..][0..len]);
1378 }
1379};
1380
1381pub const Path = extern struct {
1382 base: Base,
1383 sub: String,
1384
1385 pub const Base = enum(u8) {
1386 cwd,
1387 local_cache,
1388 global_cache,
1389 build_root,
1390 };
1391
1392 pub fn toCachePath(path: Path, c: *const Configuration, arena: Allocator) std.Build.Cache.Path {
1393 _ = c;
1394 _ = arena;
1395 _ = path;
1396 @panic("TODO");
1397 }
1398};
1399
1400pub const InstallDestDir = enum(u32) {
1401 none = maxInt(u32) - 4,
1402 prefix = maxInt(u32) - 3,
1403 lib = maxInt(u32) - 2,
1404 bin = maxInt(u32) - 1,
1405 header = maxInt(u32),
1406 /// A `String` path relative to the prefix.
1407 _,
1408
1409 pub fn initCustom(sub_path: String) InstallDestDir {
1410 assert(@intFromEnum(sub_path) < @intFromEnum(InstallDestDir.none));
1411 return @enumFromInt(@intFromEnum(sub_path));
1412 }
1413};
1414
1415/// Points into `string_bytes`, null-terminated.
1416pub const OptionalString = enum(u32) {
1417 empty = 0,
1418 /// The string "root".
1419 root = 1,
1420 none = maxInt(u32),
1421 _,
1422
1423 pub fn init(s: String) OptionalString {
1424 const result: OptionalString = @enumFromInt(@intFromEnum(s));
1425 assert(result != .none);
1426 return result;
1427 }
1428};
1429
1430/// Points into `string_bytes`, null-terminated.
1431pub const String = enum(u32) {
1432 empty = 0,
1433 /// The string "root".
1434 root = 1,
1435 _,
1436
1437 pub fn slice(index: String, c: *const Configuration) [:0]const u8 {
1438 const start_slice = c.string_bytes[@intFromEnum(index)..];
1439 return start_slice[0..std.mem.indexOfScalar(u8, start_slice, 0).? :0];
1440 }
1441};
1442
1443pub const DefaultingBool = enum(u2) {
1444 false,
1445 true,
1446 default,
1447
1448 pub fn init(b: ?bool) DefaultingBool {
1449 return switch (b orelse return .default) {
1450 false => .false,
1451 true => .true,
1452 };
1453 }
1454
1455 pub fn toBool(db: DefaultingBool) ?bool {
1456 return switch (db) {
1457 .false => false,
1458 .true => true,
1459 .default => null,
1460 };
1461 }
1462};
1463
1464pub const SystemLib = struct {
1465 name: String,
1466 flags: Flags,
1467
1468 pub const Index = enum(u32) {
1469 _,
1470
1471 pub fn get(this: @This(), c: *const Configuration) SystemLib {
1472 return extraData(c, SystemLib, @intFromEnum(this));
1473 }
1474 };
1475
1476 pub const UsePkgConfig = enum(u2) {
1477 /// Don't use pkg-config, just pass -lfoo where foo is name.
1478 no,
1479 /// Try to get information on how to link the library from pkg-config.
1480 /// If that fails, fall back to passing -lfoo where foo is name.
1481 yes,
1482 /// Try to get information on how to link the library from pkg-config.
1483 /// If that fails, error out.
1484 force,
1485 };
1486
1487 pub const LinkMode = std.builtin.LinkMode;
1488
1489 pub const Flags = packed struct(u32) {
1490 needed: bool,
1491 weak: bool,
1492 use_pkg_config: UsePkgConfig,
1493 preferred_link_mode: LinkMode,
1494 search_strategy: SearchStrategy,
1495 _: u25 = 0,
1496 };
1497
1498 pub const SearchStrategy = enum(u2) { paths_first, mode_first, no_fallback };
1499};
1500
1501pub const CSourceFiles = struct {
1502 flags: Flags,
1503 root: LazyPath.Index,
1504 args: Storage.FlagList(.flags, .args_len, String),
1505 sub_paths: Storage.LengthPrefixedList(String),
1506
1507 pub const Index = enum(u32) {
1508 _,
1509
1510 pub fn get(this: @This(), c: *const Configuration) CSourceFiles {
1511 return extraData(c, CSourceFiles, @intFromEnum(this));
1512 }
1513 };
1514
1515 pub const Flags = packed struct(u32) {
1516 /// C compiler CLI flags.
1517 args_len: u29,
1518 lang: OptionalCSourceLanguage,
1519 };
1520};
1521
1522pub const CSourceFile = struct {
1523 flags: Flags,
1524 file: LazyPath.Index,
1525 args: Storage.FlagList(.flags, .args_len, String),
1526
1527 pub const Index = enum(u32) {
1528 _,
1529
1530 pub fn get(this: @This(), c: *const Configuration) CSourceFile {
1531 return extraData(c, CSourceFile, @intFromEnum(this));
1532 }
1533 };
1534
1535 pub const Flags = packed struct(u32) {
1536 /// C compiler CLI flags.
1537 args_len: u29,
1538 lang: OptionalCSourceLanguage,
1539 };
1540};
1541
1542pub const RcSourceFile = struct {
1543 flags: Flags,
1544 file: LazyPath.Index,
1545 args: Storage.FlagList(.flags, .args_len, String),
1546 include_paths: Storage.FlagLengthPrefixedList(.flags, .include_paths, LazyPath.Index),
1547
1548 pub const Index = enum(u32) {
1549 _,
1550
1551 pub fn get(this: @This(), c: *const Configuration) RcSourceFile {
1552 return extraData(c, RcSourceFile, @intFromEnum(this));
1553 }
1554 };
1555
1556 pub const Flags = packed struct(u32) {
1557 /// C compiler CLI flags.
1558 args_len: u31,
1559 include_paths: bool,
1560 };
1561};
1562
1563pub const OptionalCSourceLanguage = enum(u3) {
1564 c,
1565 cpp,
1566 objective_c,
1567 objective_cpp,
1568 assembly,
1569 assembly_with_preprocessor,
1570 default,
1571
1572 pub fn init(x: ?std.Build.Module.CSourceLanguage) @This() {
1573 return switch (x orelse return .default) {
1574 .c => .c,
1575 .cpp => .cpp,
1576 .objective_c => .objective_c,
1577 .objective_cpp => .objective_cpp,
1578 .assembly => .assembly,
1579 .assembly_with_preprocessor => .assembly_with_preprocessor,
1580 };
1581 }
1582
1583 pub fn get(this: @This()) ?std.Build.Module.CSourceLanguage {
1584 return switch (this) {
1585 .c => .c,
1586 .cpp => .cpp,
1587 .objective_c => .objective_c,
1588 .objective_cpp => .objective_cpp,
1589 .assembly => .assembly,
1590 .assembly_with_preprocessor => .assembly_with_preprocessor,
1591 .default => null,
1592 };
1593 }
1594};
1595
1596pub const ResolvedTarget = struct {
1597 /// none indicates host.
1598 query: TargetQuery.OptionalIndex,
1599 /// defaults will be resolved.
1600 result: TargetQuery.Index,
1601
1602 pub const Index = enum(u32) {
1603 _,
1604
1605 pub fn get(this: @This(), c: *const Configuration) ResolvedTarget {
1606 return extraData(c, ResolvedTarget, @intFromEnum(this));
1607 }
1608 };
1609
1610 pub const OptionalIndex = enum(u32) {
1611 none = maxInt(u32),
1612 _,
1613
1614 pub fn unwrap(this: @This()) ?Index {
1615 return switch (this) {
1616 .none => null,
1617 _ => @enumFromInt(@intFromEnum(this)),
1618 };
1619 }
1620
1621 pub fn get(this: @This(), c: *const Configuration) ?ResolvedTarget {
1622 return (unwrap(this) orelse return null).get(c);
1623 }
1624 };
1625};
1626
1627pub const TargetQuery = struct {
1628 flags: Flags,
1629
1630 cpu_features_add: Storage.FlagOptional(.flags, .cpu_features_add, std.Target.Cpu.Feature.Set),
1631 cpu_features_sub: Storage.FlagOptional(.flags, .cpu_features_sub, std.Target.Cpu.Feature.Set),
1632 cpu_name: Storage.EnumOptional(.flags, .cpu_model, .explicit, String),
1633 os_version_min: Storage.FlagUnion(.flags, .os_version_min, OsVersion),
1634 os_version_max: Storage.FlagUnion(.flags, .os_version_max, OsVersion),
1635 glibc_version: Storage.FlagOptional(.flags, .glibc_version, String),
1636 android_api_level: Storage.FlagOptional(.flags, .android_api_level, u32),
1637 dynamic_linker: Storage.FlagOptional(.flags, .dynamic_linker, String),
1638
1639 pub const Index = enum(u32) {
1640 _,
1641
1642 pub fn extraSlice(i: Index, extra: []const u32) []const u32 {
1643 return extra[@intFromEnum(i)..][0..length(i, extra)];
1644 }
1645
1646 pub fn length(i: Index, extra: []const u32) usize {
1647 return Storage.dataLength(extra, @intFromEnum(i), TargetQuery);
1648 }
1649
1650 pub fn get(this: @This(), c: *const Configuration) TargetQuery {
1651 return extraData(c, TargetQuery, @intFromEnum(this));
1652 }
1653 };
1654
1655 pub const OptionalIndex = enum(u32) {
1656 none = maxInt(u32),
1657 _,
1658
1659 pub fn init(i: Index) OptionalIndex {
1660 const result: OptionalIndex = @enumFromInt(@intFromEnum(i));
1661 assert(result != .none);
1662 return result;
1663 }
1664
1665 pub fn unwrap(this: @This()) ?Index {
1666 return switch (this) {
1667 .none => null,
1668 _ => @enumFromInt(@intFromEnum(this)),
1669 };
1670 }
1671 };
1672
1673 pub const CpuModel = enum(u2) {
1674 native,
1675 baseline,
1676 determined_by_arch_os,
1677 explicit,
1678
1679 pub fn init(x: std.Target.Query.CpuModel) @This() {
1680 return switch (x) {
1681 .native => .native,
1682 .baseline => .baseline,
1683 .determined_by_arch_os => .determined_by_arch_os,
1684 .explicit => .explicit,
1685 };
1686 }
1687 };
1688 pub const OsVersion = union(@This().Tag) {
1689 pub const Tag = enum(u2) { none, semver, windows, default };
1690
1691 none: void,
1692 semver: String,
1693 windows: std.Target.Os.WindowsVersion,
1694 default: void,
1695
1696 pub fn init(x: ?std.Target.Query.OsVersion) @This() {
1697 return switch (x orelse return .default) {
1698 .none => .none,
1699 .semver => .semver,
1700 .windows => .windows,
1701 };
1702 }
1703 };
1704 pub const Abi = enum(u5) {
1705 none,
1706 gnu,
1707 gnuabin32,
1708 gnuabi64,
1709 gnueabi,
1710 gnueabihf,
1711 gnuf32,
1712 gnusf,
1713 gnux32,
1714 eabi,
1715 eabihf,
1716 ilp32,
1717 android,
1718 androideabi,
1719 musl,
1720 muslabin32,
1721 muslabi64,
1722 musleabi,
1723 musleabihf,
1724 muslf32,
1725 muslsf,
1726 muslx32,
1727 msvc,
1728 itanium,
1729 simulator,
1730 ohos,
1731 ohoseabi,
1732
1733 default,
1734
1735 pub fn init(x: ?std.Target.Abi) @This() {
1736 // TODO comptime assert the enums match
1737 return @enumFromInt(@intFromEnum(x orelse return .default));
1738 }
1739 };
1740 pub const CpuArch = enum(u6) {
1741 aarch64,
1742 aarch64_be,
1743 alpha,
1744 amdgcn,
1745 arc,
1746 arceb,
1747 arm,
1748 armeb,
1749 avr,
1750 bpfeb,
1751 bpfel,
1752 csky,
1753 hexagon,
1754 hppa,
1755 hppa64,
1756 kalimba,
1757 kvx,
1758 lanai,
1759 loongarch32,
1760 loongarch64,
1761 m68k,
1762 microblaze,
1763 microblazeel,
1764 mips,
1765 mipsel,
1766 mips64,
1767 mips64el,
1768 msp430,
1769 nvptx,
1770 nvptx64,
1771 or1k,
1772 powerpc,
1773 powerpcle,
1774 powerpc64,
1775 powerpc64le,
1776 propeller,
1777 riscv32,
1778 riscv32be,
1779 riscv64,
1780 riscv64be,
1781 s390x,
1782 sh,
1783 sheb,
1784 sparc,
1785 sparc64,
1786 spirv32,
1787 spirv64,
1788 thumb,
1789 thumbeb,
1790 ve,
1791 wasm32,
1792 wasm64,
1793 x86_16,
1794 x86,
1795 x86_64,
1796 xcore,
1797 xtensa,
1798 xtensaeb,
1799
1800 default,
1801
1802 pub fn init(x: ?std.Target.Cpu.Arch) @This() {
1803 // TODO comptime assert the enums match
1804 return @enumFromInt(@intFromEnum(x orelse return .default));
1805 }
1806 };
1807 pub const OsTag = enum(u6) {
1808 freestanding,
1809 other,
1810 contiki,
1811 fuchsia,
1812 hermit,
1813 managarm,
1814 haiku,
1815 hurd,
1816 illumos,
1817 linux,
1818 plan9,
1819 rtems,
1820 serenity,
1821 dragonfly,
1822 freebsd,
1823 netbsd,
1824 openbsd,
1825 driverkit,
1826 ios,
1827 maccatalyst,
1828 macos,
1829 tvos,
1830 visionos,
1831 watchos,
1832 windows,
1833 uefi,
1834 @"3ds",
1835 ps3,
1836 ps4,
1837 ps5,
1838 vita,
1839 emscripten,
1840 wasi,
1841 amdhsa,
1842 amdpal,
1843 cuda,
1844 mesa3d,
1845 nvcl,
1846 opencl,
1847 opengl,
1848 vulkan,
1849
1850 default,
1851
1852 pub fn init(x: ?std.Target.Os.Tag) @This() {
1853 // TODO comptime assert the enums match
1854 return @enumFromInt(@intFromEnum(x orelse return .default));
1855 }
1856 };
1857 pub const ObjectFormat = enum(u4) {
1858 c,
1859 coff,
1860 elf,
1861 hex,
1862 macho,
1863 plan9,
1864 raw,
1865 spirv,
1866 wasm,
1867
1868 default,
1869
1870 pub fn init(x: ?std.Target.ObjectFormat) @This() {
1871 // TODO comptime assert the enums match
1872 return @enumFromInt(@intFromEnum(x orelse return .default));
1873 }
1874
1875 pub fn get(this: @This()) ?std.Target.ObjectFormat {
1876 return switch (this) {
1877 .c => .c,
1878 .coff => .coff,
1879 .elf => .elf,
1880 .hex => .hex,
1881 .macho => .macho,
1882 .plan9 => .plan9,
1883 .raw => .raw,
1884 .spirv => .spirv,
1885 .wasm => .wasm,
1886
1887 .default => null,
1888 };
1889 }
1890 };
1891
1892 pub const Flags = packed struct(u32) {
1893 cpu_arch: CpuArch,
1894 cpu_model: CpuModel,
1895 cpu_features_add: bool,
1896 cpu_features_sub: bool,
1897 os_tag: OsTag,
1898 abi: Abi,
1899 object_format: ObjectFormat,
1900 os_version_min: OsVersion.Tag,
1901 os_version_max: OsVersion.Tag,
1902 glibc_version: bool,
1903 android_api_level: bool,
1904 dynamic_linker: bool,
1905 };
1906};
1907
1908pub const Storage = enum {
1909 flag_optional,
1910 enum_optional,
1911 extended,
1912 length_prefixed_list,
1913 flag_length_prefixed_list,
1914 union_list,
1915 flag_union,
1916 multi_list,
1917 flag_list,
1918
1919 /// The presence of the field is determined by a boolean within a packed
1920 /// struct.
1921 pub fn FlagOptional(
1922 comptime flags_arg: @EnumLiteral(),
1923 comptime flag_arg: @EnumLiteral(),
1924 comptime ValueArg: type,
1925 ) type {
1926 return struct {
1927 value: ?Value,
1928
1929 pub const storage: Storage = .flag_optional;
1930 pub const flags = flags_arg;
1931 pub const flag = flag_arg;
1932 pub const Value = ValueArg;
1933 };
1934 }
1935
1936 /// The type of the field is determined by an enum within a packed struct.
1937 pub fn FlagUnion(
1938 comptime flags_arg: @EnumLiteral(),
1939 comptime flag_arg: @EnumLiteral(),
1940 comptime UnionArg: type,
1941 ) type {
1942 return struct {
1943 u: Union,
1944
1945 pub const storage: Storage = .flag_union;
1946 pub const flags = flags_arg;
1947 pub const flag = flag_arg;
1948 pub const Union = UnionArg;
1949
1950 pub const Tag = @typeInfo(Union).@"union".tag_type.?;
1951 };
1952 }
1953
1954 /// The field is present if an enum tag from flags matches a specific value.
1955 pub fn EnumOptional(
1956 comptime flags_arg: @EnumLiteral(),
1957 comptime flag_arg: @EnumLiteral(),
1958 comptime tag_arg: @EnumLiteral(),
1959 comptime ValueArg: type,
1960 ) type {
1961 return struct {
1962 value: ?Value,
1963
1964 pub const storage: Storage = .enum_optional;
1965 pub const flags = flags_arg;
1966 pub const flag = flag_arg;
1967 pub const tag = tag_arg;
1968 pub const Value = ValueArg;
1969 };
1970 }
1971
1972 /// The field indexes into an auxilary buffer, with the first element being
1973 /// a packed struct that contains the tag.
1974 pub fn Extended(comptime BaseFlags: type, comptime U: type) type {
1975 return enum(u32) {
1976 _,
1977
1978 pub const storage: Storage = .extended;
1979
1980 pub fn get(this: @This(), buffer: []const u32) U {
1981 var i: usize = @intFromEnum(this);
1982 const base_flags: BaseFlags = @bitCast(buffer[i]);
1983 return switch (base_flags.tag) {
1984 inline else => |tag| @unionInit(U, @tagName(tag), data(buffer, &i, @FieldType(U, @tagName(tag)))),
1985 };
1986 }
1987 };
1988 }
1989
1990 /// A field in flags determines whether the length is zero or nonzero. If the length is
1991 /// nonzero, then there is a length field followed by the list.
1992 pub fn FlagLengthPrefixedList(
1993 comptime flags_arg: @EnumLiteral(),
1994 comptime flag_arg: @EnumLiteral(),
1995 comptime ElemArg: type,
1996 ) type {
1997 return struct {
1998 slice: []const Elem,
1999
2000 pub const storage: Storage = .flag_length_prefixed_list;
2001 pub const flags = flags_arg;
2002 pub const flag = flag_arg;
2003 pub const Elem = ElemArg;
2004
2005 pub fn initErased(s: []const u32) @This() {
2006 return .{ .slice = @ptrCast(s) };
2007 }
2008 };
2009 }
2010
2011 /// The field contains a u32 length followed by that many items, each
2012 /// element bitcastable to u32.
2013 pub fn LengthPrefixedList(comptime ElemArg: type) type {
2014 return struct {
2015 slice: []const Elem,
2016
2017 pub const storage: Storage = .length_prefixed_list;
2018 pub const Elem = ElemArg;
2019
2020 pub fn initErased(s: []const u32) @This() {
2021 return .{ .slice = @ptrCast(s) };
2022 }
2023 };
2024 }
2025
2026 /// The field is a list whose length is an integer inside flags.
2027 pub fn FlagList(
2028 comptime flags_arg: @EnumLiteral(),
2029 comptime flag_arg: @EnumLiteral(),
2030 comptime ElemArg: type,
2031 ) type {
2032 return struct {
2033 slice: []const Elem,
2034
2035 pub const storage: Storage = .flag_list;
2036 pub const flags = flags_arg;
2037 pub const flag = flag_arg;
2038 pub const Elem = ElemArg;
2039
2040 pub fn initErased(s: []const u32) @This() {
2041 return .{ .slice = @ptrCast(s) };
2042 }
2043 };
2044 }
2045
2046 /// The field contains a u32 length followed by that many items for the
2047 /// first field, that many items for the second field, etc.
2048 pub fn MultiList(comptime ElemArg: type) type {
2049 return struct {
2050 mal: std.MultiArrayList(Elem),
2051
2052 pub const storage: Storage = .multi_list;
2053 pub const Elem = ElemArg;
2054 };
2055 }
2056
2057 /// `UnionArg` is a tagged union with a small integer for the enum tag.
2058 ///
2059 /// A field in flags determines whether the metadata is present.
2060 ///
2061 /// The metadata is bit-packed consecutive packed struct which is the
2062 /// `UnionArg` enum tag combined with a "last" marker boolean field.
2063 /// When "last" is true, the element is the last one, providing
2064 /// the length of the list.
2065 ///
2066 /// Following is each element of the list; each bitcastable to u32.
2067 pub fn UnionList(
2068 comptime flags_arg: @EnumLiteral(),
2069 comptime flag_arg: @EnumLiteral(),
2070 comptime UnionArg: type,
2071 ) type {
2072 return struct {
2073 /// When serializing it is UnionArg slice pointer.
2074 /// When deserializing it is extra index of first UnionArg element.
2075 data: ?*const anyopaque,
2076 len: usize,
2077
2078 pub const storage: Storage = .union_list;
2079 pub const flags = flags_arg;
2080 pub const flag = flag_arg;
2081 pub const Union = UnionArg;
2082
2083 pub const Tag = @typeInfo(Union).@"union".tag_type.?;
2084 pub const MetaInt = @Int(.unsigned, @bitSizeOf(Tag) + 1);
2085 pub const Meta = packed struct(MetaInt) {
2086 tag: Tag,
2087 last: bool,
2088 };
2089
2090 /// Valid to call only when serializing.
2091 pub fn init(s: []const Union) @This() {
2092 return .{ .data = s.ptr, .len = s.len };
2093 }
2094
2095 /// Valid to call only when deserializing.
2096 pub fn slice(this: *const @This(), extra: []const u32) []const u32 {
2097 return extra[@intFromPtr(this.data)..][0..this.len];
2098 }
2099
2100 /// Valid to call only when deserializing.
2101 pub fn get(this: *const @This(), extra: []const u32, i: usize) Union {
2102 const elem = slice(this, extra)[i];
2103 return switch (this.tag(extra, i)) {
2104 inline else => |comptime_tag| @unionInit(Union, @tagName(comptime_tag), @enumFromInt(elem)),
2105 };
2106 }
2107
2108 /// Valid to call only when deserializing.
2109 pub fn tag(this: *const @This(), extra: []const u32, i: usize) Tag {
2110 _ = this;
2111 _ = extra;
2112 _ = i;
2113 @panic("TODO implement UnionList.tag");
2114 }
2115
2116 fn extraLen(len: usize) usize {
2117 return len + (len * @bitSizeOf(Meta) + 31) / 32;
2118 }
2119 };
2120 }
2121
2122 pub fn dataLength(buffer: []const u32, i: usize, comptime S: type) usize {
2123 var end = i;
2124 _ = data(buffer, &end, S);
2125 return end - i;
2126 }
2127
2128 pub fn data(buffer: []const u32, i: *usize, comptime T: type) T {
2129 switch (@typeInfo(T)) {
2130 .@"struct" => |info| {
2131 var result: T = undefined;
2132 inline for (info.fields) |field| {
2133 @field(result, field.name) = dataField(buffer, i, &result, field.type);
2134 }
2135 return result;
2136 },
2137 .@"union" => |info| {
2138 const flags: T.Flags = @bitCast(buffer[i.*]);
2139 return switch (flags.tag) {
2140 inline else => |comptime_tag| @unionInit(
2141 T,
2142 @tagName(comptime_tag),
2143 data(buffer, i, info.fields[@intFromEnum(comptime_tag)].type),
2144 ),
2145 };
2146 },
2147 else => comptime unreachable,
2148 }
2149 }
2150
2151 fn dataField(buffer: []const u32, i: *usize, container: anytype, comptime Field: type) Field {
2152 switch (@typeInfo(Field)) {
2153 .void => return {},
2154 .int => |info| switch (info.bits) {
2155 32 => {
2156 defer i.* += 1;
2157 return buffer[i.*];
2158 },
2159 64 => {
2160 defer i.* += 2;
2161 return @bitCast(buffer[i.*..][0..2].*);
2162 },
2163 else => comptime unreachable,
2164 },
2165 .@"enum" => {
2166 defer i.* += 1;
2167 return @enumFromInt(buffer[i.*]);
2168 },
2169 .@"struct" => |info| switch (info.layout) {
2170 .@"packed" => switch (info.backing_integer.?) {
2171 u32 => {
2172 defer i.* += 1;
2173 return @bitCast(buffer[i.*]);
2174 },
2175 u64 => {
2176 defer i.* += 2;
2177 return @bitCast(buffer[i.*..][0..2].*);
2178 },
2179 else => comptime unreachable,
2180 },
2181 .auto => switch (Field) {
2182 std.Target.Cpu.Feature.Set => {
2183 const u32_count = (Field.usize_count * @sizeOf(usize)) / @sizeOf(u32);
2184 defer i.* += u32_count;
2185 return .{ .ints = @as(
2186 *align(@alignOf(u32)) const [Field.usize_count]usize,
2187 @ptrCast(buffer[i.*..][0..u32_count]),
2188 ).* };
2189 },
2190 else => switch (Field.storage) {
2191 .flag_optional => {
2192 const flags = @field(container, @tagName(Field.flags));
2193 const flag = @field(flags, @tagName(Field.flag));
2194 return .{
2195 .value = if (flag) dataField(buffer, i, container, Field.Value) else null,
2196 };
2197 },
2198 .flag_union => {
2199 const flags = @field(container, @tagName(Field.flags));
2200 const tag: Field.Tag = @field(flags, @tagName(Field.flag));
2201 return .{
2202 .u = switch (tag) {
2203 inline else => |comptime_tag| @unionInit(
2204 Field.Union,
2205 @tagName(comptime_tag),
2206 dataField(
2207 buffer,
2208 i,
2209 container,
2210 @typeInfo(Field.Union).@"union".fields[@intFromEnum(comptime_tag)].type,
2211 ),
2212 ),
2213 },
2214 };
2215 },
2216 .enum_optional => {
2217 const flags = @field(container, @tagName(Field.flags));
2218 const tag = @field(flags, @tagName(Field.flag));
2219 const match = tag == Field.tag;
2220 return .{
2221 .value = if (match) dataField(buffer, i, container, Field.Value) else null,
2222 };
2223 },
2224 .extended => @compileError("TODO"),
2225 .length_prefixed_list => {
2226 const data_start = i.* + 1;
2227 const len = buffer[data_start - 1];
2228 defer i.* = data_start + len;
2229 return .{ .slice = @ptrCast(buffer[data_start..][0..len]) };
2230 },
2231 .flag_length_prefixed_list => {
2232 const flags = @field(container, @tagName(Field.flags));
2233 const flag = @field(flags, @tagName(Field.flag));
2234 if (!flag) return .{ .slice = &.{} };
2235 const data_start = i.* + 1;
2236 const len = buffer[data_start - 1];
2237 defer i.* = data_start + len;
2238 return .{ .slice = @ptrCast(buffer[data_start..][0..len]) };
2239 },
2240 .flag_list => {
2241 const flags = @field(container, @tagName(Field.flags));
2242 const len: u32 = @field(flags, @tagName(Field.flag));
2243 const data_start = i.*;
2244 defer i.* = data_start + len;
2245 return .{ .slice = @ptrCast(buffer[data_start..][0..len]) };
2246 },
2247 .multi_list => {
2248 const data_start = i.* + 1;
2249 const len = buffer[data_start - 1];
2250 defer i.* = data_start + len * @typeInfo(Field.Elem).@"struct".fields.len;
2251 return .{ .mal = .{
2252 .bytes = @ptrCast(@constCast(buffer[data_start..][0..len])),
2253 .len = len,
2254 .capacity = len,
2255 } };
2256 },
2257 .union_list => {
2258 const flags = @field(container, @tagName(Field.flags));
2259 const flag = @field(flags, @tagName(Field.flag));
2260 if (!flag) return .{ .data = null, .len = 0 };
2261 const meta_start = i.*;
2262 const meta_buffer = buffer[meta_start..];
2263 var len: u32 = 0;
2264 var bit_offset: usize = 0;
2265 while (true) : (bit_offset += @bitSizeOf(Field.Meta)) {
2266 const meta = loadBits(u32, meta_buffer, bit_offset, Field.Meta);
2267 len += 1;
2268 if (meta.last) break;
2269 }
2270 const end = meta_start + Field.extraLen(len);
2271 i.* = end;
2272 return .{ .data = @ptrFromInt(end - len), .len = len };
2273 },
2274 },
2275 },
2276 .@"extern" => comptime unreachable,
2277 },
2278 else => comptime unreachable,
2279 }
2280 }
2281
2282 /// Returns new end index.
2283 fn setExtra(buffer: []u32, index: usize, extra: anytype) usize {
2284 const fields = @typeInfo(@TypeOf(extra)).@"struct".fields;
2285 var i = index;
2286 inline for (fields) |field| {
2287 i += setExtraField(buffer, i, field.type, @field(extra, field.name));
2288 }
2289 return i;
2290 }
2291
2292 fn extraFieldLen(field: anytype) usize {
2293 const Field = @TypeOf(field);
2294 return switch (@typeInfo(Field)) {
2295 .void => 0,
2296 .int => |info| switch (info.bits) {
2297 32 => 1,
2298 64 => 2,
2299 else => comptime unreachable,
2300 },
2301 .@"enum" => 1,
2302 .@"struct" => |info| switch (info.layout) {
2303 .@"packed" => switch (info.backing_integer.?) {
2304 u32 => 1,
2305 u64 => 2,
2306 else => comptime unreachable,
2307 },
2308 .auto => switch (Field.storage) {
2309 .flag_optional, .enum_optional, .extended => 1,
2310 .length_prefixed_list,
2311 .flag_length_prefixed_list,
2312 .flag_list,
2313 => 1 + @divExact(@sizeOf(Field.Elem), @sizeOf(u32)) * field.slice.len,
2314 .multi_list => 1 + field.mal.len * @typeInfo(Field.Elem).@"struct".fields.len,
2315 .union_list => Field.extraLen(field.len),
2316 .flag_union => switch (field.u) {
2317 inline else => |v| extraFieldLen(v),
2318 },
2319 },
2320 .@"extern" => comptime unreachable,
2321 },
2322 else => @compileError("bad type: " ++ @typeName(Field)),
2323 };
2324 }
2325
2326 fn extraLen(extra: anytype) usize {
2327 const fields = @typeInfo(@TypeOf(extra)).@"struct".fields;
2328 var i: usize = 0;
2329 inline for (fields) |field| {
2330 i += Storage.extraFieldLen(@field(extra, field.name));
2331 }
2332 return i;
2333 }
2334
2335 inline fn setExtraField(buffer: []u32, i: usize, comptime Field: type, value: anytype) usize {
2336 switch (@typeInfo(Field)) {
2337 .void => return 0,
2338 .int => |info| switch (info.bits) {
2339 32 => {
2340 buffer[i] = value;
2341 return 1;
2342 },
2343 64 => {
2344 buffer[i..][0..2].* = @bitCast(value);
2345 return 2;
2346 },
2347 else => comptime unreachable,
2348 },
2349 .@"enum" => {
2350 buffer[i] = @intFromEnum(value);
2351 return 1;
2352 },
2353 .@"struct" => |info| switch (info.layout) {
2354 .@"packed" => switch (info.backing_integer.?) {
2355 u32 => {
2356 buffer[i] = @bitCast(value);
2357 return 1;
2358 },
2359 u64 => {
2360 buffer[i..][0..2].* = @bitCast(value);
2361 return 2;
2362 },
2363 else => comptime unreachable,
2364 },
2365 .auto => switch (Field) {
2366 std.Target.Cpu.Feature.Set => {
2367 const casted: []const u32 = @ptrCast(&value.ints);
2368 @memcpy(buffer[i..][0..casted.len], casted);
2369 return casted.len;
2370 },
2371 else => switch (Field.storage) {
2372 .flag_optional, .enum_optional => {
2373 return if (value.value) |v| setExtraField(buffer, i, Field.Value, v) else 0;
2374 },
2375 .flag_union => return switch (value.u) {
2376 inline else => |x| setExtraField(buffer, i, @TypeOf(x), x),
2377 },
2378 .extended => @compileError("TODO"),
2379 .flag_length_prefixed_list, .length_prefixed_list => {
2380 const len: u32 = @intCast(value.slice.len);
2381 if (len == 0) return 0;
2382 buffer[i] = len;
2383 @memcpy(buffer[i + 1 ..][0..len], @as([]const u32, @ptrCast(value.slice)));
2384 return len + 1;
2385 },
2386 .flag_list => {
2387 const len: u32 = @intCast(value.slice.len);
2388 @memcpy(buffer[i..][0..len], @as([]const u32, @ptrCast(value.slice)));
2389 return len;
2390 },
2391 .multi_list => {
2392 const len: u32 = @intCast(value.mal.len);
2393 if (len == 0) return 0;
2394 buffer[i] = len;
2395 const fields = @typeInfo(Field.Elem).@"struct".fields;
2396 inline for (0..fields.len) |field_i| @memcpy(
2397 buffer[i + 1 + field_i * len ..][0..len],
2398 @as([]const u32, @ptrCast(value.mal.items(@enumFromInt(field_i)))),
2399 );
2400 return 1 + fields.len * len;
2401 },
2402 .union_list => {
2403 if (value.len == 0) return 0;
2404 const Tag = @typeInfo(Field.Union).@"union".tag_type.?;
2405 const slice_ptr: [*]const Field.Union = @ptrCast(@alignCast(value.data));
2406 const slice = slice_ptr[0..value.len];
2407 const meta_buffer = buffer[i..][0 .. (slice.len * @bitSizeOf(Field.Meta) + 31) / 32];
2408 for (slice[0 .. slice.len - 1], 0..) |elem, elem_index| {
2409 const union_tag: Tag = elem;
2410 storeBits(u32, meta_buffer, elem_index * @bitSizeOf(Field.Meta), @as(Field.Meta, .{
2411 .tag = union_tag,
2412 .last = false,
2413 }));
2414 } else {
2415 const elem_index = slice.len - 1;
2416 const elem = slice[elem_index];
2417 const union_tag: Tag = elem;
2418 storeBits(u32, meta_buffer, elem_index * @bitSizeOf(Field.Meta), @as(Field.Meta, .{
2419 .tag = union_tag,
2420 .last = true,
2421 }));
2422 }
2423 var total: usize = meta_buffer.len;
2424 for (i + meta_buffer.len.., slice) |elem_index, src| switch (src) {
2425 inline else => |x| total += setExtraField(buffer, elem_index, @TypeOf(x), x),
2426 };
2427 return total;
2428 },
2429 },
2430 },
2431 .@"extern" => comptime unreachable,
2432 },
2433 else => @compileError("bad field type: " ++ @typeName(Field)),
2434 }
2435 }
2436};
2437
2438pub fn extraData(c: *const Configuration, comptime T: type, index: usize) T {
2439 var i: usize = index;
2440 return Storage.data(c.extra, &i, T);
2441}
2442
2443pub const LoadFileError = Io.File.Reader.Error || Allocator.Error || error{EndOfStream};
2444
2445pub fn loadFile(arena: Allocator, io: Io, file: Io.File) LoadFileError!Configuration {
2446 var buffer: [2000]u8 = undefined;
2447 var fr = file.reader(io, &buffer);
2448 return load(arena, &fr.interface) catch |err| switch (err) {
2449 error.ReadFailed => return fr.err.?,
2450 else => |e| return e,
2451 };
2452}
2453
2454pub const LoadError = Io.Reader.Error || Allocator.Error;
2455
2456pub fn load(arena: Allocator, reader: *Io.Reader) LoadError!Configuration {
2457 const header = try reader.takeStruct(Header, .little);
2458 var result: Configuration = .{
2459 .string_bytes = try arena.alloc(u8, header.string_bytes_len),
2460 .steps = try arena.alloc(Step, header.steps_len),
2461 .path_deps_sub = try arena.alloc(String, header.path_deps_len),
2462 .path_deps_base = try arena.alloc(Path.Base, header.path_deps_len),
2463 .unlazy_deps = try arena.alloc(String, header.unlazy_deps_len),
2464 .system_integrations = try arena.alloc(SystemIntegration, header.system_integrations_len),
2465 .available_options = try arena.alloc(AvailableOption, header.available_options_len),
2466 .extra = try arena.alloc(u32, header.extra_len),
2467 .default_step = header.default_step,
2468 .generated_files_len = header.generated_files_len,
2469 };
2470 var vecs = [_][]u8{
2471 result.string_bytes,
2472 @ptrCast(result.steps),
2473 @ptrCast(result.path_deps_base),
2474 @ptrCast(result.path_deps_sub),
2475 @ptrCast(result.unlazy_deps),
2476 @ptrCast(result.system_integrations),
2477 @ptrCast(result.available_options),
2478 @ptrCast(result.extra),
2479 };
2480 try reader.readVecAll(&vecs);
2481 return result;
2482}
2483
2484pub fn loadBits(comptime Int: type, buffer: []const Int, bit_offset: usize, comptime Result: type) Result {
2485 const index = bit_offset / @bitSizeOf(Int);
2486 const small_bit_offset = bit_offset % @bitSizeOf(Int);
2487 const ResultInt = @Int(.unsigned, @bitSizeOf(Result));
2488 const result: ResultInt = @truncate(buffer[index] >> @intCast(small_bit_offset));
2489 const available_bits = @bitSizeOf(Int) - small_bit_offset;
2490 if (available_bits >= @bitSizeOf(ResultInt)) return @bitCast(result);
2491 const missing_bits = @bitSizeOf(ResultInt) - available_bits;
2492 const upper: ResultInt = @truncate(buffer[index + 1] & ((@as(usize, 1) << @intCast(missing_bits)) - 1));
2493 return @bitCast(result | (upper << @intCast(available_bits)));
2494}
2495
2496pub fn storeBits(comptime Int: type, buffer: []Int, bit_offset: usize, value: anytype) void {
2497 const Value = @TypeOf(value);
2498 const ValueInt = @Int(.unsigned, @bitSizeOf(Value));
2499 const value_int: ValueInt = @bitCast(value);
2500 const index = bit_offset / @bitSizeOf(Int);
2501 const small_bit_offset = bit_offset % @bitSizeOf(Int);
2502 const available_bits = @bitSizeOf(Int) - small_bit_offset;
2503 if (available_bits >= @bitSizeOf(ValueInt)) {
2504 buffer[index] &= ~(((@as(Int, 1) << @intCast(@bitSizeOf(Value))) - 1) << @intCast(small_bit_offset));
2505 buffer[index] |= @as(Int, value_int) << @intCast(small_bit_offset);
2506 } else {
2507 const DoubleInt = @Int(.unsigned, @bitSizeOf(Int) * 2);
2508 const ptr: *align(@alignOf(Int)) DoubleInt = @ptrCast(buffer[index..][0..2]);
2509 ptr.* &= ~(((@as(DoubleInt, 1) << @intCast(@bitSizeOf(Value))) - 1) << @intCast(small_bit_offset));
2510 ptr.* |= @as(DoubleInt, value_int) << @intCast(small_bit_offset);
2511 }
2512}
2513
2514test "loadBits and storeBits" {
2515 var buffer: [2]u32 = .{
2516 0b01111111000000001111111100000000,
2517 0b11111111000000001111111100000100,
2518 };
2519 try std.testing.expectEqual(0b100, loadBits(u32, &buffer, 6, u3));
2520 try std.testing.expectEqual(0b100011, loadBits(u32, &buffer, 29, u6));
2521
2522 storeBits(u32, &buffer, 6, @as(u3, 0b010));
2523 storeBits(u32, &buffer, 29, @as(u6, 0b010010));
2524
2525 try std.testing.expectEqual(0b010, loadBits(u32, &buffer, 6, u3));
2526 try std.testing.expectEqual(0b010010, loadBits(u32, &buffer, 29, u6));
2527}
lib/std/zig/Configuration.zig deleted-2527
...@@ -1,2527 +0,0 @@
1const Configuration = @This();
2
3const std = @import("../std.zig");
4const Io = std.Io;
5const Allocator = std.mem.Allocator;
6const assert = std.debug.assert;
7const maxInt = std.math.maxInt;
8
9string_bytes: []u8,
10steps: []Step,
11path_deps_base: []Path.Base,
12path_deps_sub: []String,
13unlazy_deps: []String,
14system_integrations: []SystemIntegration,
15available_options: []AvailableOption,
16extra: []u32,
17default_step: Step.Index,
18generated_files_len: u32,
19
20/// The field order here matches `Configuration` which documents the order in
21/// the serialized format.
22pub const Header = extern struct {
23 string_bytes_len: u32,
24 steps_len: u32,
25 path_deps_len: u32,
26 unlazy_deps_len: u32,
27 system_integrations_len: u32,
28 available_options_len: u32,
29 extra_len: u32,
30
31 default_step: Step.Index,
32 /// There is not actually any data stored for this - it just provides a way
33 /// for maker process to preallocate an array for these.
34 generated_files_len: u32,
35};
36
37pub const Wip = struct {
38 gpa: Allocator,
39 string_table: StringTable = .empty,
40 /// De-duplicates an array inside `extra`.
41 dedupe_table: DedupeTable = .empty,
42 targets_table: TargetsTable = .empty,
43
44 string_bytes: std.ArrayList(u8) = .empty,
45 unlazy_deps: std.ArrayList(String) = .empty,
46 system_integrations: std.ArrayList(SystemIntegration) = .empty,
47 available_options: std.ArrayList(AvailableOption) = .empty,
48 steps: std.ArrayList(Step) = .empty,
49 path_deps: std.MultiArrayList(Path) = .empty,
50 extra: std.ArrayList(u32) = .empty,
51 next_generated_file_index: u32 = 0,
52
53 const DedupeTable = std.HashMapUnmanaged(ExtraSlice, void, ExtraSlice.Context, std.hash_map.default_max_load_percentage);
54 const TargetsTable = std.HashMapUnmanaged(TargetQuery.Index, void, TargetsTableContext, std.hash_map.default_max_load_percentage);
55
56 const ExtraSlice = struct {
57 index: u32,
58 len: u32,
59
60 const Context = struct {
61 extra: []const u32,
62
63 pub fn eql(ctx: @This(), a: ExtraSlice, b: ExtraSlice) bool {
64 const slice_a = ctx.extra[a.index..][0..a.len];
65 const slice_b = ctx.extra[b.index..][0..b.len];
66 return std.mem.eql(u32, slice_a, slice_b);
67 }
68
69 pub fn hash(ctx: @This(), key: ExtraSlice) u64 {
70 const slice = ctx.extra[key.index..][0..key.len];
71 return std.hash_map.hashString(@ptrCast(slice));
72 }
73 };
74 };
75
76 const TargetsTableContext = struct {
77 extra: []const u32,
78
79 pub fn eql(ctx: @This(), a: TargetQuery.Index, b: TargetQuery.Index) bool {
80 const slice_a = a.extraSlice(ctx.extra);
81 const slice_b = b.extraSlice(ctx.extra);
82 return std.mem.eql(u32, slice_a, slice_b);
83 }
84
85 pub fn hash(ctx: @This(), key: TargetQuery.Index) u64 {
86 const slice = key.extraSlice(ctx.extra);
87 return std.hash_map.hashString(@ptrCast(slice));
88 }
89 };
90
91 const StringTable = std.HashMapUnmanaged(String, void, StringTableContext, std.hash_map.default_max_load_percentage);
92 const StringTableContext = struct {
93 bytes: []const u8,
94
95 pub fn eql(_: @This(), a: String, b: String) bool {
96 return a == b;
97 }
98
99 pub fn hash(ctx: @This(), key: String) u64 {
100 return std.hash_map.hashString(std.mem.sliceTo(ctx.bytes[@intFromEnum(key)..], 0));
101 }
102 };
103
104 const StringTableIndexAdapter = struct {
105 bytes: []const u8,
106
107 pub fn eql(ctx: @This(), a: []const u8, b: String) bool {
108 return std.mem.eql(u8, a, std.mem.sliceTo(ctx.bytes[@intFromEnum(b)..], 0));
109 }
110
111 pub fn hash(_: @This(), adapted_key: []const u8) u64 {
112 assert(std.mem.indexOfScalar(u8, adapted_key, 0) == null);
113 return std.hash_map.hashString(adapted_key);
114 }
115 };
116
117 pub fn init(gpa: Allocator) Wip {
118 return .{ .gpa = gpa };
119 }
120
121 pub fn deinit(wip: *Wip) void {
122 const gpa = wip.gpa;
123 wip.string_bytes.deinit(gpa);
124 wip.unlazy_deps.deinit(gpa);
125 wip.system_integrations.deinit(gpa);
126 wip.available_options.deinit(gpa);
127 wip.steps.deinit(gpa);
128 wip.path_deps.deinit(gpa);
129 wip.extra.deinit(gpa);
130 wip.* = undefined;
131 }
132
133 pub const Static = struct {
134 default_step: Step.Index,
135 generated_files_len: u32,
136 };
137
138 pub fn write(wip: *Wip, w: *Io.Writer, static: Static) Io.Writer.Error!void {
139 const header: Header = .{
140 .string_bytes_len = @intCast(wip.string_bytes.items.len),
141 .steps_len = @intCast(wip.steps.items.len),
142 .path_deps_len = @intCast(wip.path_deps.len),
143 .unlazy_deps_len = @intCast(wip.unlazy_deps.items.len),
144 .system_integrations_len = @intCast(wip.system_integrations.items.len),
145 .available_options_len = @intCast(wip.available_options.items.len),
146 .extra_len = @intCast(wip.extra.items.len),
147
148 .default_step = static.default_step,
149 .generated_files_len = static.generated_files_len,
150 };
151 var buffers = [_][]const u8{
152 @ptrCast(&header),
153 wip.string_bytes.items,
154 @ptrCast(wip.steps.items),
155 @ptrCast(wip.path_deps.items(.base)),
156 @ptrCast(wip.path_deps.items(.sub)),
157 @ptrCast(wip.unlazy_deps.items),
158 @ptrCast(wip.system_integrations.items),
159 @ptrCast(wip.available_options.items),
160 @ptrCast(wip.extra.items),
161 };
162 try w.writeVecAll(&buffers);
163 }
164
165 pub fn addString(wip: *Wip, bytes: []const u8) Allocator.Error!String {
166 const gpa = wip.gpa;
167 assert(std.mem.indexOfScalar(u8, bytes, 0) == null);
168 const gop = try wip.string_table.getOrPutContextAdapted(
169 gpa,
170 @as([]const u8, bytes),
171 @as(StringTableIndexAdapter, .{ .bytes = wip.string_bytes.items }),
172 @as(StringTableContext, .{ .bytes = wip.string_bytes.items }),
173 );
174 if (gop.found_existing) return gop.key_ptr.*;
175
176 try wip.string_bytes.ensureUnusedCapacity(gpa, bytes.len + 1);
177 const new_off: String = @enumFromInt(wip.string_bytes.items.len);
178
179 wip.string_bytes.appendSliceAssumeCapacity(bytes);
180 wip.string_bytes.appendAssumeCapacity(0);
181
182 gop.key_ptr.* = new_off;
183
184 return new_off;
185 }
186
187 pub fn addOptionalString(wip: *Wip, bytes: ?[]const u8) Allocator.Error!OptionalString {
188 return .init(try addString(wip, bytes orelse return .none));
189 }
190
191 pub fn addSemVer(wip: *Wip, sv: std.SemanticVersion) Allocator.Error!String {
192 var buffer: [256]u8 = undefined;
193 var writer: std.Io.Writer = .fixed(&buffer);
194 sv.format(&writer) catch return error.OutOfMemory;
195 return addString(wip, writer.buffered());
196 }
197
198 pub fn addTargetQuery(wip: *Wip, q: std.Target.Query) !TargetQuery.OptionalIndex {
199 if (q.isNative()) return .none;
200 const gpa = wip.gpa;
201 const cpu_name: ?String = switch (q.cpu_model) {
202 .native, .baseline, .determined_by_arch_os => null,
203 .explicit => |model| try wip.addString(model.name),
204 };
205 const os_version_min: TargetQuery.OsVersion = if (q.os_version_min) |ver| switch (ver) {
206 .none => .none,
207 .semver => |sem_ver| .{ .semver = try wip.addSemVer(sem_ver) },
208 .windows => |win_ver| .{ .windows = win_ver },
209 } else .default;
210 const os_version_max: TargetQuery.OsVersion = if (q.os_version_max) |ver| switch (ver) {
211 .none => .none,
212 .semver => |sem_ver| .{ .semver = try wip.addSemVer(sem_ver) },
213 .windows => |win_ver| .{ .windows = win_ver },
214 } else .default;
215 const glibc_version: ?String = if (q.glibc_version) |sem_ver| try wip.addSemVer(sem_ver) else null;
216 const dynamic_linker: ?String = if (q.dynamic_linker) |*dl|
217 if (dl.get()) |s| try wip.addString(s) else .empty
218 else
219 null;
220 const cpu_features_add_empty = q.cpu_features_add.isEmpty();
221 const cpu_features_sub_empty = q.cpu_features_sub.isEmpty();
222 const result_index: TargetQuery.Index = @enumFromInt(try wip.addExtra(@as(TargetQuery, .{
223 .flags = .{
224 .cpu_arch = .init(q.cpu_arch),
225 .cpu_model = .init(q.cpu_model),
226 .cpu_features_add = !cpu_features_add_empty,
227 .cpu_features_sub = !cpu_features_sub_empty,
228 .os_tag = .init(q.os_tag),
229 .abi = .init(q.abi),
230 .object_format = .init(q.ofmt),
231 .os_version_min = os_version_min,
232 .os_version_max = os_version_max,
233 .glibc_version = glibc_version != null,
234 .android_api_level = q.android_api_level != null,
235 .dynamic_linker = dynamic_linker != null,
236 },
237 .cpu_features_add = .{ .value = if (cpu_features_add_empty) null else q.cpu_features_add },
238 .cpu_features_sub = .{ .value = if (cpu_features_sub_empty) null else q.cpu_features_sub },
239 .glibc_version = .{ .value = glibc_version },
240 .android_api_level = .{ .value = q.android_api_level },
241 .dynamic_linker = .{ .value = dynamic_linker },
242 .cpu_name = .{ .value = cpu_name },
243 .os_version_min = .{ .u = os_version_min },
244 .os_version_max = .{ .u = os_version_max },
245 })));
246
247 // Deduplicate.
248 const gop = try wip.targets_table.getOrPutContext(gpa, result_index, @as(TargetsTableContext, .{
249 .extra = wip.extra.items,
250 }));
251 if (gop.found_existing) {
252 wip.extra.items.len = @intFromEnum(result_index);
253 return .init(gop.key_ptr.*);
254 } else {
255 return .init(result_index);
256 }
257 }
258
259 pub fn addTarget(wip: *Wip, t: std.Target) !TargetQuery.Index {
260 const gpa = wip.gpa;
261 const cpu_name: String = try wip.addString(t.cpu.model.name);
262
263 const os_version_min: TargetQuery.OsVersion, const os_version_max: TargetQuery.OsVersion, const glibc_version: ?String, const android_api_level: ?u32 = switch (t.os.versionRange()) {
264 .none => .{
265 .none,
266 .none,
267 null,
268 null,
269 },
270 .semver => |range| .{
271 .{ .semver = try wip.addSemVer(range.min) },
272 .{ .semver = try wip.addSemVer(range.max) },
273 null,
274 null,
275 },
276 .hurd => |hurd| .{
277 .{ .semver = try wip.addSemVer(hurd.range.min) },
278 .{ .semver = try wip.addSemVer(hurd.range.max) },
279 try wip.addSemVer(hurd.glibc),
280 null,
281 },
282 .linux => |linux| .{
283 .{ .semver = try wip.addSemVer(linux.range.min) },
284 .{ .semver = try wip.addSemVer(linux.range.max) },
285 try wip.addSemVer(linux.glibc),
286 linux.android,
287 },
288 .windows => |range| .{
289 .{ .windows = range.min },
290 .{ .windows = range.max },
291 null,
292 null,
293 },
294 };
295 const dynamic_linker: ?String = if (t.dynamic_linker.get()) |dl| try wip.addString(dl) else null;
296 const cpu_features_add_empty = t.cpu.features.isEmpty();
297 const result_index: TargetQuery.Index = @enumFromInt(try wip.addExtra(@as(TargetQuery, .{
298 .flags = .{
299 .cpu_arch = .init(t.cpu.arch),
300 .cpu_model = .explicit,
301 .cpu_features_add = !cpu_features_add_empty,
302 .cpu_features_sub = false,
303 .os_tag = .init(t.os.tag),
304 .abi = .init(t.abi),
305 .object_format = .init(t.ofmt),
306 .os_version_min = os_version_min,
307 .os_version_max = os_version_max,
308 .glibc_version = glibc_version != null,
309 .android_api_level = android_api_level != null,
310 .dynamic_linker = dynamic_linker != null,
311 },
312 .cpu_features_add = .{ .value = if (cpu_features_add_empty) null else t.cpu.features },
313 .cpu_features_sub = .{ .value = null },
314 .glibc_version = .{ .value = glibc_version },
315 .android_api_level = .{ .value = android_api_level },
316 .dynamic_linker = .{ .value = dynamic_linker },
317 .cpu_name = .{ .value = cpu_name },
318 .os_version_min = .{ .u = os_version_min },
319 .os_version_max = .{ .u = os_version_max },
320 })));
321
322 // Deduplicate.
323 const gop = try wip.targets_table.getOrPutContext(gpa, result_index, @as(TargetsTableContext, .{
324 .extra = wip.extra.items,
325 }));
326 if (gop.found_existing) {
327 wip.extra.items.len = @intFromEnum(result_index);
328 return gop.key_ptr.*;
329 } else {
330 return result_index;
331 }
332 }
333
334 pub fn addExtra(wip: *Wip, extra: anytype) Allocator.Error!u32 {
335 const extra_len = Storage.extraLen(extra);
336 try wip.extra.ensureUnusedCapacity(wip.gpa, extra_len);
337 return addExtraAssumeCapacity(wip, extra);
338 }
339
340 /// Same as `addExtra` but uses a hash map to possibly return an already
341 /// existing index instead of appending to `extra`.
342 pub fn addDeduped(wip: *Wip, extra: anytype) Allocator.Error!u32 {
343 const gpa = wip.gpa;
344 const revert_index = wip.extra.items.len;
345 const extra_len = Storage.extraLen(extra);
346 try wip.extra.ensureUnusedCapacity(gpa, extra_len);
347 const new_index = addExtraAssumeCapacity(wip, extra);
348 const len: u32 = @intCast(wip.extra.items.len - new_index);
349
350 const gop = try wip.dedupe_table.getOrPutContext(gpa, .{
351 .index = new_index,
352 .len = len,
353 }, @as(ExtraSlice.Context, .{ .extra = wip.extra.items }));
354
355 if (gop.found_existing) {
356 wip.extra.items.len = revert_index;
357 return gop.key_ptr.index;
358 }
359
360 return new_index;
361 }
362
363 pub fn addExtraAssumeCapacity(wip: *Wip, extra: anytype) u32 {
364 const result: u32 = @intCast(wip.extra.items.len);
365 wip.extra.items.len = Storage.setExtra(wip.extra.allocatedSlice(), result, extra);
366 return result;
367 }
368
369 fn addExtraOptionalStringAssumeCapacity(wip: *Wip, optional_string: ?String) void {
370 const string = optional_string orelse return;
371 wip.extra.appendAssumeCapacity(@intFromEnum(string));
372 }
373
374 pub fn addGeneratedFile(wip: *Wip) GeneratedFileIndex {
375 defer wip.next_generated_file_index += 1;
376 return @enumFromInt(wip.next_generated_file_index);
377 }
378};
379
380pub const SystemIntegration = extern struct {
381 name: String,
382 status: Status,
383
384 pub const Status = enum(u32) {
385 disabled = 0,
386 enabled = 1,
387 };
388};
389
390pub const AvailableOption = extern struct {
391 name: String,
392 description: String,
393 type: Type,
394 /// If the `type_id` is `enum` or `enum_list` this provides the list of enum options
395 enum_options: OptionalStringList,
396
397 pub const Type = enum(u8) {
398 bool,
399 int,
400 float,
401 @"enum",
402 enum_list,
403 string,
404 list,
405 build_id,
406 lazy_path,
407 lazy_path_list,
408 };
409};
410
411pub const Step = extern struct {
412 name: String,
413 owner: Package.Index,
414 deps: Deps.Index,
415 max_rss: MaxRss,
416 extended: Storage.Extended(Flags, union(Tag) {
417 check_file: CheckFile,
418 check_object: CheckObject,
419 compile: Compile,
420 config_header: ConfigHeader,
421 fail: Fail,
422 fmt: Fmt,
423 install_artifact: InstallArtifact,
424 install_dir: InstallDir,
425 install_file: InstallFile,
426 objcopy: Objcopy,
427 options: Options,
428 remove_dir: RemoveDir,
429 run: Run,
430 top_level: TopLevel,
431 translate_c: TranslateC,
432 update_source_files: UpdateSourceFiles,
433 write_file: WriteFile,
434 }),
435
436 /// Points into `steps`.
437 pub const Index = enum(u32) {
438 _,
439
440 pub fn ptr(i: Index, c: *const Configuration) *const Step {
441 return &c.steps[@intFromEnum(i)];
442 }
443 };
444
445 /// Shared by all steps.
446 pub const Flags = packed struct(u32) {
447 tag: Tag,
448 _: u27 = 0,
449 };
450
451 pub const Tag = enum(u5) {
452 check_file,
453 check_object,
454 compile,
455 config_header,
456 fail,
457 fmt,
458 install_artifact,
459 install_dir,
460 install_file,
461 objcopy,
462 options,
463 remove_dir,
464 run,
465 top_level,
466 translate_c,
467 update_source_files,
468 write_file,
469 };
470
471 pub const TopLevel = struct {
472 flags: @This().Flags = .{},
473 description: String,
474
475 pub const Flags = packed struct(u32) {
476 tag: Tag = .top_level,
477 _: u27 = 0,
478 };
479 };
480
481 pub const InstallArtifact = struct {
482 flags: @This().Flags,
483
484 dest_dir: InstallDestDir,
485 dest_sub_path: String,
486 emitted_bin: LazyPath.OptionalIndex,
487
488 implib_dir: InstallDestDir,
489 emitted_implib: LazyPath.OptionalIndex,
490
491 pdb_dir: InstallDestDir,
492 emitted_pdb: LazyPath.OptionalIndex,
493
494 h_dir: InstallDestDir,
495 emitted_h: LazyPath.OptionalIndex,
496
497 /// Always a compile step.
498 artifact: Step.Index,
499
500 pub const Flags = packed struct(u32) {
501 tag: Tag = .install_artifact,
502 dylib_symlinks: bool,
503 _: u26 = 0,
504 };
505 };
506
507 /// Trailing:
508 /// * LazyPath.Index for each file_inputs_len
509 /// * Arg for each args_len
510 /// * environ_map if corresponding flag is set
511 /// * stdin: Bytes, // if StdIn.bytes is chosen
512 /// * stdin: LazyPath.Index, // if StdIn.lazy_path is chosen
513 /// * checks: Checks, // if StdIo.check is chosen
514 /// * stdio_limit: u64, // if stdio_limit is set
515 /// * producer: Step.Index, // if producer is set. always compile step
516 pub const Run = struct {
517 flags: @This().Flags,
518 file_inputs_len: u32,
519 args_len: u32,
520 cwd: LazyPath.OptionalIndex,
521 captured_stdout: OptionalString, // basename
522 captured_stderr: OptionalString, // basename
523
524 /// Trailing:
525 /// * String if prefix set
526 /// * String if suffix set
527 /// * String if basename set
528 /// * Step.Index which is always a compile step if tag is artifact
529 /// * LazyPath.Index if tag is path_file, path_directory, or file_content
530 pub const Arg = struct {
531 flags: Arg.Flags,
532
533 pub const Flags = packed struct(u32) {
534 tag: Arg.Tag,
535 prefix: bool,
536 suffix: bool,
537 basename: bool,
538 /// Implies Tag is output_file
539 dep_file: bool,
540 _: u20 = 0,
541 };
542
543 pub const Tag = enum(u8) {
544 artifact,
545 path_file,
546 path_directory,
547 file_content,
548 bytes,
549 output_file,
550 output_directory,
551 cli_rest_positionals,
552 };
553 };
554
555 pub const Color = enum(u4) {
556 /// `CLICOLOR_FORCE` is set, and `NO_COLOR` is unset.
557 enable,
558 /// `NO_COLOR` is set, and `CLICOLOR_FORCE` is unset.
559 disable,
560 /// If the build runner is using color, equivalent to `.enable`. Otherwise, equivalent to `.disable`.
561 inherit,
562 /// If stderr is captured or checked, equivalent to `.disable`. Otherwise, equivalent to `.inherit`.
563 auto,
564 /// The build runner does not modify the `CLICOLOR_FORCE` or `NO_COLOR` environment variables.
565 /// They are treated like normal variables, so can be controlled through `setEnvironmentVariable`.
566 manual,
567 };
568
569 pub const StdIn = enum(u2) { none, bytes, lazy_path };
570 pub const TrimWhitespace = enum(u2) { none, all, leading, trailing };
571 pub const StdIo = enum(u2) { infer_from_args, inherit, check, zig_test };
572
573 pub const Flags = packed struct(u32) {
574 tag: Tag = .run,
575
576 disable_zig_progress: bool,
577 skip_foreign_checks: bool,
578 failing_to_execute_foreign_is_an_error: bool,
579 has_side_effects: bool,
580 test_runner_mode: bool,
581 color: Color,
582 stdin: StdIn,
583 stdio: StdIo,
584 stdout_trim_whitespace: TrimWhitespace,
585 stderr_trim_whitespace: TrimWhitespace,
586 stdio_limit: bool,
587 producer: bool,
588 _: u8 = 0,
589 };
590 };
591
592 pub const Compile = struct {
593 flags: @This().Flags,
594 flags2: Flags2,
595 flags3: Flags3,
596 flags4: Flags4,
597
598 root_module: Module.Index,
599 root_name: String,
600
601 filters: Storage.FlagLengthPrefixedList(.flags, .filters_len, String),
602 exec_cmd_args: Storage.FlagLengthPrefixedList(.flags, .exec_cmd_args_len, OptionalString),
603 installed_headers: Storage.FlagLengthPrefixedList(.flags, .installed_headers_len, Storage.Extended(InstalledHeader.Flags, InstalledHeader)),
604 force_undefined_symbols: Storage.FlagLengthPrefixedList(.flags, .force_undefined_symbols_len, String),
605 expect_errors: Storage.FlagUnion(.flags4, .expect_errors, ExpectErrors),
606 linker_script: Storage.FlagOptional(.flags4, .linker_script, LazyPath.Index),
607 version_script: Storage.FlagOptional(.flags4, .version_script, LazyPath.Index),
608 zig_lib_dir: Storage.FlagOptional(.flags3, .zig_lib_dir, LazyPath.Index),
609 libc_file: Storage.FlagOptional(.flags4, .libc_file, LazyPath.Index),
610 win32_manifest: Storage.FlagOptional(.flags3, .win32_manifest, LazyPath.Index),
611 win32_module_definition: Storage.FlagOptional(.flags3, .win32_module_definition, LazyPath.Index),
612 entitlements: Storage.FlagOptional(.flags4, .entitlements, LazyPath.Index),
613 version: Storage.FlagOptional(.flags3, .version, String), // semantic version string
614 entry: Storage.EnumOptional(.flags3, .entry, .symbol_name, String),
615 install_name: Storage.FlagOptional(.flags4, .install_name, String),
616 initial_memory: Storage.FlagOptional(.flags3, .initial_memory, u64),
617 max_memory: Storage.FlagOptional(.flags3, .max_memory, u64),
618 global_base: Storage.FlagOptional(.flags3, .global_base, u64),
619 image_base: Storage.FlagOptional(.flags3, .image_base, u64),
620 link_z_common_page_size: Storage.FlagOptional(.flags4, .link_z_common_page_size, u64),
621 link_z_max_page_size: Storage.FlagOptional(.flags4, .link_z_max_page_size, u64),
622 pagezero_size: Storage.FlagOptional(.flags4, .pagezero_size, u64),
623 stack_size: Storage.FlagOptional(.flags4, .stack_size, u64),
624 headerpad_size: Storage.FlagOptional(.flags4, .headerpad_size, u32),
625 error_limit: Storage.FlagOptional(.flags4, .error_limit, u32),
626 build_id: Storage.EnumOptional(.flags3, .build_id, .hexstring, String),
627 test_runner: Storage.FlagUnion(.flags3, .test_runner, TestRunner),
628
629 emit_directory: Storage.FlagOptional(.flags4, .emit_directory, GeneratedFileIndex),
630 generated_docs: Storage.FlagOptional(.flags4, .generated_docs, GeneratedFileIndex),
631 generated_asm: Storage.FlagOptional(.flags4, .generated_asm, GeneratedFileIndex),
632 generated_bin: Storage.FlagOptional(.flags4, .generated_bin, GeneratedFileIndex),
633 generated_pdb: Storage.FlagOptional(.flags4, .generated_pdb, GeneratedFileIndex),
634 generated_implib: Storage.FlagOptional(.flags4, .generated_implib, GeneratedFileIndex),
635 generated_llvm_bc: Storage.FlagOptional(.flags4, .generated_llvm_bc, GeneratedFileIndex),
636 generated_llvm_ir: Storage.FlagOptional(.flags4, .generated_llvm_ir, GeneratedFileIndex),
637 generated_h: Storage.FlagOptional(.flags4, .generated_h, GeneratedFileIndex),
638
639 pub const InstalledHeader = union(@This().Tag) {
640 file: File,
641 directory: Directory,
642
643 pub const Flags = packed struct(u32) {
644 tag: InstalledHeader.Tag,
645 _: u24 = 0,
646 };
647
648 pub const Tag = enum(u8) {
649 file,
650 directory,
651 };
652
653 pub const File = struct {
654 flags: @This().Flags = .{},
655 source: LazyPath.Index,
656 dest_sub_path: String,
657
658 pub const Flags = packed struct(u32) {
659 tag: InstalledHeader.Tag = .file,
660 _: u24 = 0,
661 };
662 };
663
664 pub const Directory = struct {
665 flags: @This().Flags,
666 source: LazyPath.Index,
667 dest_sub_path: String,
668 exclude_extensions: Storage.FlagLengthPrefixedList(.flags, .exclude_extensions, String),
669 include_extensions: Storage.FlagLengthPrefixedList(.flags, .include_extensions, String),
670
671 pub const Flags = packed struct(u32) {
672 tag: InstalledHeader.Tag = .directory,
673 exclude_extensions: bool,
674 include_extensions: bool,
675 _: u22 = 0,
676 };
677 };
678 };
679 pub const ExpectErrors = union(@This().Tag) {
680 pub const Tag = enum(u3) { contains, exact, starts_with, stderr_contains, none };
681
682 contains: String,
683 exact: Storage.LengthPrefixedList(String),
684 starts_with: String,
685 stderr_contains: String,
686 none: void,
687 };
688 pub const TestRunner = union(@This().Tag) {
689 pub const Tag = enum(u2) { default, simple, server };
690
691 default: void,
692 simple: LazyPath.Index,
693 server: LazyPath.Index,
694 };
695 pub const Entry = enum(u2) { default, disabled, enabled, symbol_name };
696
697 pub const Lto = enum(u2) {
698 none,
699 full,
700 thin,
701 default,
702
703 pub fn init(lto: ?std.zig.LtoMode) Lto {
704 return switch (lto orelse return .default) {
705 .none => .none,
706 .full => .full,
707 .thin => .thin,
708 };
709 }
710 };
711
712 pub const BuildId = enum(u3) {
713 none,
714 fast,
715 uuid,
716 sha1,
717 md5,
718 hexstring,
719 default,
720
721 pub fn init(build_id: ?std.zig.BuildId) BuildId {
722 return switch (build_id orelse return .default) {
723 .none => .none,
724 .fast => .fast,
725 .uuid => .uuid,
726 .sha1 => .sha1,
727 .md5 => .md5,
728 .hexstring => .hexstring,
729 };
730 }
731 };
732 pub const WasiExecModel = enum(u2) {
733 default,
734 command,
735 reactor,
736
737 pub fn init(wasi_exec_model: ?std.builtin.WasiExecModel) WasiExecModel {
738 return switch (wasi_exec_model orelse return .default) {
739 .command => .command,
740 .reactor => .reactor,
741 };
742 }
743 };
744 pub const Linkage = enum(u2) {
745 static,
746 dynamic,
747 default,
748
749 pub fn init(link_mode: ?std.builtin.LinkMode) Linkage {
750 return switch (link_mode orelse return .default) {
751 .static => .static,
752 .dynamic => .dynamic,
753 };
754 }
755 };
756 pub const Kind = enum(u3) {
757 exe,
758 lib,
759 obj,
760 @"test",
761 test_obj,
762
763 pub fn isTest(kind: Kind) bool {
764 return switch (kind) {
765 .exe, .lib, .obj => false,
766 .@"test", .test_obj => true,
767 };
768 }
769 };
770 pub const Subsystem = enum(u4) {
771 console,
772 windows,
773 posix,
774 native,
775 efi_application,
776 efi_boot_service_driver,
777 efi_rom,
778 efi_runtime_driver,
779 default,
780
781 pub fn init(subsystem: ?std.zig.Subsystem) Subsystem {
782 return switch (subsystem orelse return .default) {
783 .console => .console,
784 .windows => .windows,
785 .posix => .posix,
786 .native => .native,
787 .efi_application => .efi_application,
788 .efi_boot_service_driver => .efi_boot_service_driver,
789 .efi_rom => .efi_rom,
790 .efi_runtime_driver => .efi_runtime_driver,
791 };
792 }
793 };
794
795 pub const Flags = packed struct(u32) {
796 tag: Tag = .compile,
797
798 filters_len: bool,
799 exec_cmd_args_len: bool,
800 installed_headers_len: bool,
801 force_undefined_symbols_len: bool,
802
803 verbose_link: bool,
804 verbose_cc: bool,
805 rdynamic: bool,
806 import_memory: bool,
807 export_memory: bool,
808 import_symbols: bool,
809 import_table: bool,
810 export_table: bool,
811 shared_memory: bool,
812 link_eh_frame_hdr: bool,
813 link_emit_relocs: bool,
814 link_function_sections: bool,
815 link_data_sections: bool,
816 linker_dynamicbase: bool,
817 link_z_notext: bool,
818 link_z_relro: bool,
819 link_z_lazy: bool,
820 link_z_defs: bool,
821 headerpad_max_install_names: bool,
822 dead_strip_dylibs: bool,
823 force_load_objc: bool,
824 discard_local_symbols: bool,
825 mingw_unicode_entry_point: bool,
826 };
827
828 pub const Flags2 = packed struct(u32) {
829 pie: DefaultingBool,
830 formatted_panics: DefaultingBool,
831 bundle_compiler_rt: DefaultingBool,
832 bundle_ubsan_rt: DefaultingBool,
833 each_lib_rpath: DefaultingBool,
834 link_gc_sections: DefaultingBool,
835 linker_allow_shlib_undefined: DefaultingBool,
836 linker_allow_undefined_version: DefaultingBool,
837 linker_enable_new_dtags: DefaultingBool,
838 dll_export_fns: DefaultingBool,
839 use_llvm: DefaultingBool,
840 use_lld: DefaultingBool,
841 use_new_linker: DefaultingBool,
842 allow_so_scripts: DefaultingBool,
843 sanitize_coverage_trace_pc_guard: DefaultingBool,
844 linkage: Linkage,
845 };
846
847 pub const Flags3 = packed struct(u32) {
848 is_linking_libc: bool,
849 is_linking_libcpp: bool,
850 version: bool,
851 initial_memory: bool,
852 max_memory: bool,
853 kind: Kind,
854 compress_debug_sections: std.zig.CompressDebugSections,
855 global_base: bool,
856 test_runner: TestRunner.Tag,
857 wasi_exec_model: WasiExecModel,
858 win32_manifest: bool,
859 win32_module_definition: bool,
860 zig_lib_dir: bool,
861 rc_includes: std.zig.RcIncludes,
862 image_base: bool,
863 build_id: BuildId,
864 entry: Entry,
865 lto: Lto,
866 subsystem: Subsystem,
867 };
868
869 pub const Flags4 = packed struct(u32) {
870 libc_file: bool,
871 link_z_common_page_size: bool,
872 link_z_max_page_size: bool,
873 pagezero_size: bool,
874 stack_size: bool,
875 headerpad_size: bool,
876 error_limit: bool,
877 install_name: bool,
878 entitlements: bool,
879 expect_errors: ExpectErrors.Tag,
880 linker_script: bool,
881 version_script: bool,
882 emit_directory: bool,
883 generated_docs: bool,
884 generated_asm: bool,
885 generated_bin: bool,
886 generated_pdb: bool,
887 generated_implib: bool,
888 generated_llvm_bc: bool,
889 generated_llvm_ir: bool,
890 generated_h: bool,
891 _: u9 = 0,
892 };
893
894 pub fn isDynamicLibrary(compile: *const Compile) bool {
895 return compile.flags3.kind == .lib and compile.flags2.linkage == .dynamic;
896 }
897
898 pub fn isStaticLibrary(compile: *const Compile) bool {
899 return compile.flags3.kind == .lib and compile.flags2.linkage != .dynamic;
900 }
901
902 pub fn producesImplib(compile: *const Compile, c: *const Configuration) bool {
903 return isDll(compile, c);
904 }
905
906 pub fn isDll(compile: *const Compile, c: *const Configuration) bool {
907 return isDynamicLibrary(compile) and rootModuleTarget(compile, c).flags.os_tag == .windows;
908 }
909
910 pub fn rootModuleTarget(compile: *const Compile, c: *const Configuration) TargetQuery {
911 return compile.root_module.get(c).resolved_target.get(c).?.result.get(c);
912 }
913 };
914
915 pub const CheckFile = struct {
916 flags: @This().Flags,
917
918 pub const Flags = packed struct(u32) {
919 tag: Tag = .check_file,
920 _: u27 = 0,
921 };
922 };
923
924 pub const CheckObject = struct {
925 flags: @This().Flags,
926
927 pub const Flags = packed struct(u32) {
928 tag: Tag = .check_object,
929 _: u27 = 0,
930 };
931 };
932
933 pub const ConfigHeader = struct {
934 flags: @This().Flags,
935
936 pub const Flags = packed struct(u32) {
937 tag: Tag = .config_header,
938 _: u27 = 0,
939 };
940 };
941
942 pub const Fail = struct {
943 flags: @This().Flags,
944
945 pub const Flags = packed struct(u32) {
946 tag: Tag = .fail,
947 _: u27 = 0,
948 };
949 };
950
951 pub const Fmt = struct {
952 flags: @This().Flags,
953
954 pub const Flags = packed struct(u32) {
955 tag: Tag = .fmt,
956 _: u27 = 0,
957 };
958 };
959
960 pub const InstallDir = struct {
961 flags: @This().Flags,
962
963 pub const Flags = packed struct(u32) {
964 tag: Tag = .install_dir,
965 _: u27 = 0,
966 };
967 };
968
969 pub const InstallFile = struct {
970 flags: @This().Flags,
971
972 pub const Flags = packed struct(u32) {
973 tag: Tag = .install_file,
974 _: u27 = 0,
975 };
976 };
977
978 pub const Objcopy = struct {
979 flags: @This().Flags,
980
981 pub const Flags = packed struct(u32) {
982 tag: Tag = .objcopy,
983 _: u27 = 0,
984 };
985 };
986
987 pub const Options = struct {
988 flags: @This().Flags,
989
990 pub const Flags = packed struct(u32) {
991 tag: Tag = .options,
992 _: u27 = 0,
993 };
994 };
995
996 pub const RemoveDir = struct {
997 flags: @This().Flags,
998
999 pub const Flags = packed struct(u32) {
1000 tag: Tag = .remove_dir,
1001 _: u27 = 0,
1002 };
1003 };
1004
1005 pub const TranslateC = struct {
1006 flags: @This().Flags,
1007
1008 pub const Flags = packed struct(u32) {
1009 tag: Tag = .translate_c,
1010 _: u27 = 0,
1011 };
1012 };
1013
1014 pub const UpdateSourceFiles = struct {
1015 flags: @This().Flags,
1016
1017 pub const Flags = packed struct(u32) {
1018 tag: Tag = .update_source_files,
1019 _: u27 = 0,
1020 };
1021 };
1022
1023 pub const WriteFile = struct {
1024 flags: @This().Flags,
1025
1026 pub const Flags = packed struct(u32) {
1027 tag: Tag = .write_file,
1028 _: u27 = 0,
1029 };
1030 };
1031
1032 pub fn flags(s: *const Step, c: *const Configuration) Flags {
1033 return @bitCast(c.extra[@intFromEnum(s.extended)]);
1034 }
1035};
1036
1037pub const MaxRss = enum(u32) {
1038 none = 0,
1039 _,
1040
1041 pub fn toBytes(mr: MaxRss) usize {
1042 const x: usize = @intFromEnum(mr);
1043 return x << 8;
1044 }
1045
1046 pub fn fromBytes(bytes: usize) MaxRss {
1047 return @enumFromInt(bytes >> 8);
1048 }
1049};
1050
1051pub const LazyPath = union(@This().Tag) {
1052 source_path: SourcePath,
1053 relative: Relative,
1054 generated: Generated,
1055
1056 pub const Tag = enum(u8) {
1057 /// A source file path relative to build root.
1058 source_path,
1059 /// Relative to the directory indicated in flags.
1060 relative,
1061 /// Path is available only after it is populated by its owning step.
1062 generated,
1063 };
1064
1065 pub const Flags = packed struct(u32) {
1066 tag: Tag,
1067 _: u24 = 0,
1068 };
1069
1070 /// An index into `extra`.
1071 pub const Index = enum(u32) {
1072 _,
1073
1074 pub fn get(this: @This(), c: *const Configuration) LazyPath {
1075 return extraData(c, LazyPath, @intFromEnum(this));
1076 }
1077 };
1078
1079 /// An index into `extra`, or `null`.
1080 pub const OptionalIndex = enum(u32) {
1081 none = maxInt(u32),
1082 _,
1083
1084 pub fn unwrap(this: @This()) ?Index {
1085 return switch (this) {
1086 .none => null,
1087 else => @enumFromInt(@intFromEnum(this)),
1088 };
1089 }
1090 };
1091
1092 pub const SourcePath = struct {
1093 flags: @This().Flags,
1094 owner: Package.Index,
1095 sub_path: String,
1096
1097 pub const Flags = packed struct(u32) {
1098 tag: Tag = .source_path,
1099 _: u24 = 0,
1100 };
1101 };
1102
1103 pub const Generated = struct {
1104 flags: @This().Flags = .{},
1105 index: GeneratedFileIndex,
1106 /// Applied after `up`.
1107 sub_path: String = .empty,
1108
1109 pub const Flags = packed struct(u32) {
1110 tag: Tag = .generated,
1111 /// The number of parent directories to go up.
1112 /// 0 means the generated file itself.
1113 /// 1 means the directory of the generated file.
1114 /// 2 means the parent of that directory, and so on.
1115 up: u24 = 0,
1116 };
1117 };
1118
1119 pub const Relative = struct {
1120 flags: @This().Flags,
1121 sub_path: String,
1122
1123 pub const Flags = packed struct(u32) {
1124 tag: Tag = .relative,
1125 base: Path.Base,
1126 _: u16 = 0,
1127 };
1128 };
1129};
1130
1131pub const GeneratedFileIndex = enum(u32) {
1132 _,
1133};
1134
1135pub const OptionalGeneratedFileIndex = enum(u32) {
1136 none = maxInt(u32),
1137 _,
1138
1139 pub fn init(i: ?GeneratedFileIndex) OptionalGeneratedFileIndex {
1140 return @enumFromInt(@intFromEnum(i orelse return .none));
1141 }
1142
1143 pub fn unwrap(this: @This()) ?GeneratedFileIndex {
1144 return switch (this) {
1145 .none => null,
1146 else => @enumFromInt(@intFromEnum(this)),
1147 };
1148 }
1149};
1150
1151pub const Package = struct {
1152 dep_prefix: String,
1153 hash: String,
1154
1155 pub const Index = enum(u32) {
1156 root = maxInt(u32),
1157 _,
1158
1159 /// Returns `null` for root package.
1160 pub fn get(i: @This(), c: *const Configuration) ?Package {
1161 if (i == .root) return null;
1162 return extraData(c, Package, @intFromEnum(i));
1163 }
1164
1165 pub fn depPrefixSlice(i: @This(), c: *const Configuration) [:0]const u8 {
1166 const package = get(i, c) orelse return "";
1167 return package.dep_prefix.slice(c);
1168 }
1169 };
1170};
1171
1172pub const Module = struct {
1173 flags: Flags,
1174 flags2: Flags2,
1175 import_table: ImportTable.Index,
1176 owner: Package.Index,
1177 root_source_file: LazyPath.OptionalIndex,
1178 resolved_target: ResolvedTarget.OptionalIndex,
1179 c_macros: Storage.FlagLengthPrefixedList(.flags, .c_macros, String),
1180 lib_paths: Storage.FlagLengthPrefixedList(.flags, .lib_paths, LazyPath.Index),
1181 export_symbol_names: Storage.FlagLengthPrefixedList(.flags, .export_symbol_names, String),
1182 include_dirs: Storage.UnionList(.flags, .include_dirs, IncludeDir),
1183 rpaths: Storage.UnionList(.flags, .rpaths, RPath),
1184 link_objects: Storage.UnionList(.flags, .link_objects, LinkObject),
1185 frameworks: Storage.FlagLengthPrefixedList(.flags, .frameworks, Framework),
1186
1187 pub const Optimize = enum(u3) {
1188 debug,
1189 safe,
1190 fast,
1191 small,
1192 default,
1193
1194 pub fn init(o: ?std.builtin.OptimizeMode) Optimize {
1195 return switch (o orelse return .default) {
1196 .Debug => .debug,
1197 .ReleaseSafe => .safe,
1198 .ReleaseFast => .fast,
1199 .ReleaseSmall => .small,
1200 };
1201 }
1202 };
1203
1204 pub const UnwindTables = enum(u2) {
1205 none,
1206 sync,
1207 async,
1208 default,
1209
1210 pub fn init(ut: ?std.builtin.UnwindTables) UnwindTables {
1211 return switch (ut orelse return .default) {
1212 .none => .none,
1213 .sync => .sync,
1214 .async => .async,
1215 };
1216 }
1217 };
1218
1219 pub const SanitizeC = enum(u2) {
1220 off,
1221 trap,
1222 full,
1223 default,
1224
1225 pub fn init(sc: ?std.zig.SanitizeC) SanitizeC {
1226 return switch (sc orelse return .default) {
1227 .off => .off,
1228 .trap => .trap,
1229 .full => .full,
1230 };
1231 }
1232 };
1233
1234 pub const DwarfFormat = enum(u2) {
1235 @"32",
1236 @"64",
1237 default,
1238
1239 pub fn init(df: ?std.dwarf.Format) DwarfFormat {
1240 return switch (df orelse return .default) {
1241 .@"32" => .@"32",
1242 .@"64" => .@"64",
1243 };
1244 }
1245 };
1246
1247 pub const Index = enum(u32) {
1248 _,
1249
1250 pub fn get(this: @This(), c: *const Configuration) Module {
1251 return extraData(c, Module, @intFromEnum(this));
1252 }
1253 };
1254
1255 pub const Flags = packed struct(u32) {
1256 optimize: Optimize,
1257 strip: DefaultingBool,
1258 unwind_tables: UnwindTables,
1259 dwarf_format: DwarfFormat,
1260 single_threaded: DefaultingBool,
1261 stack_protector: DefaultingBool,
1262 stack_check: DefaultingBool,
1263 sanitize_c: SanitizeC,
1264 sanitize_thread: DefaultingBool,
1265 fuzz: DefaultingBool,
1266 code_model: std.builtin.CodeModel,
1267 c_macros: bool,
1268 include_dirs: bool,
1269 lib_paths: bool,
1270 rpaths: bool,
1271 frameworks: bool,
1272 link_objects: bool,
1273 export_symbol_names: bool,
1274 };
1275
1276 pub const Flags2 = packed struct(u32) {
1277 valgrind: DefaultingBool,
1278 pic: DefaultingBool,
1279 red_zone: DefaultingBool,
1280 omit_frame_pointer: DefaultingBool,
1281 error_tracing: DefaultingBool,
1282 link_libc: DefaultingBool,
1283 link_libcpp: DefaultingBool,
1284 no_builtin: DefaultingBool,
1285 _: u16 = 0,
1286 };
1287
1288 pub const IncludeDir = union(enum(u3)) {
1289 path: LazyPath.Index,
1290 path_system: LazyPath.Index,
1291 path_after: LazyPath.Index,
1292 framework_path: LazyPath.Index,
1293 framework_path_system: LazyPath.Index,
1294 /// Always `Step.Tag.compile`.
1295 other_step: Step.Index,
1296 /// Always `Step.Tag.config_header`.
1297 config_header_step: Step.Index,
1298 embed_path: LazyPath.Index,
1299 };
1300
1301 pub const RPath = union(enum(u1)) {
1302 lazy_path: LazyPath.Index,
1303 special: String,
1304 };
1305
1306 pub const LinkObject = union(enum(u3)) {
1307 static_path: LazyPath.Index,
1308 /// Always `Step.Tag.compile`.
1309 other_step: Step.Index,
1310 system_lib: SystemLib.Index,
1311 assembly_file: LazyPath.Index,
1312 c_source_file: CSourceFile.Index,
1313 c_source_files: CSourceFiles.Index,
1314 win32_resource_file: RcSourceFile.Index,
1315 };
1316
1317 pub const Framework = extern struct {
1318 flags: @This().Flags,
1319 name: String,
1320
1321 pub const Flags = packed struct(u32) {
1322 needed: bool,
1323 weak: bool,
1324 _: u30 = 0,
1325 };
1326 };
1327};
1328
1329pub const ImportTable = struct {
1330 imports: Storage.MultiList(Import),
1331
1332 pub const Import = struct {
1333 name: String,
1334 module: Module.Index,
1335 };
1336
1337 /// Points into `extra`.
1338 pub const Index = enum(u32) {
1339 invalid = maxInt(u32),
1340 _,
1341
1342 pub fn get(this: @This(), c: *const Configuration) ImportTable {
1343 return switch (this) {
1344 .invalid => unreachable,
1345 _ => extraData(c, ImportTable, @intFromEnum(this)),
1346 };
1347 }
1348 };
1349};
1350
1351pub const Deps = struct {
1352 steps: Storage.LengthPrefixedList(Step.Index),
1353
1354 pub const Index = enum(u32) {
1355 _,
1356
1357 pub fn get(this: @This(), c: *const Configuration) Deps {
1358 return extraData(c, Deps, @intFromEnum(this));
1359 }
1360
1361 pub fn slice(this: @This(), c: *const Configuration) []const Step.Index {
1362 return get(this, c).steps.slice;
1363 }
1364 };
1365};
1366
1367/// Points into `extra`, where the first element is count of strings, following
1368/// elements is `String` per count.
1369///
1370/// Stored identically to `Deps`.
1371pub const OptionalStringList = enum(u32) {
1372 none = maxInt(u32),
1373 _,
1374
1375 pub fn slice(osl: OptionalStringList, c: *const Configuration) ?[]const String {
1376 const len = c.extra[@intFromEnum(osl)];
1377 return @ptrCast(c.extra[@intFromEnum(osl) + 1 ..][0..len]);
1378 }
1379};
1380
1381pub const Path = extern struct {
1382 base: Base,
1383 sub: String,
1384
1385 pub const Base = enum(u8) {
1386 cwd,
1387 local_cache,
1388 global_cache,
1389 build_root,
1390 };
1391
1392 pub fn toCachePath(path: Path, c: *const Configuration, arena: Allocator) std.Build.Cache.Path {
1393 _ = c;
1394 _ = arena;
1395 _ = path;
1396 @panic("TODO");
1397 }
1398};
1399
1400pub const InstallDestDir = enum(u32) {
1401 none = maxInt(u32) - 4,
1402 prefix = maxInt(u32) - 3,
1403 lib = maxInt(u32) - 2,
1404 bin = maxInt(u32) - 1,
1405 header = maxInt(u32),
1406 /// A `String` path relative to the prefix.
1407 _,
1408
1409 pub fn initCustom(sub_path: String) InstallDestDir {
1410 assert(@intFromEnum(sub_path) < @intFromEnum(InstallDestDir.none));
1411 return @enumFromInt(@intFromEnum(sub_path));
1412 }
1413};
1414
1415/// Points into `string_bytes`, null-terminated.
1416pub const OptionalString = enum(u32) {
1417 empty = 0,
1418 /// The string "root".
1419 root = 1,
1420 none = maxInt(u32),
1421 _,
1422
1423 pub fn init(s: String) OptionalString {
1424 const result: OptionalString = @enumFromInt(@intFromEnum(s));
1425 assert(result != .none);
1426 return result;
1427 }
1428};
1429
1430/// Points into `string_bytes`, null-terminated.
1431pub const String = enum(u32) {
1432 empty = 0,
1433 /// The string "root".
1434 root = 1,
1435 _,
1436
1437 pub fn slice(index: String, c: *const Configuration) [:0]const u8 {
1438 const start_slice = c.string_bytes[@intFromEnum(index)..];
1439 return start_slice[0..std.mem.indexOfScalar(u8, start_slice, 0).? :0];
1440 }
1441};
1442
1443pub const DefaultingBool = enum(u2) {
1444 false,
1445 true,
1446 default,
1447
1448 pub fn init(b: ?bool) DefaultingBool {
1449 return switch (b orelse return .default) {
1450 false => .false,
1451 true => .true,
1452 };
1453 }
1454
1455 pub fn toBool(db: DefaultingBool) ?bool {
1456 return switch (db) {
1457 .false => false,
1458 .true => true,
1459 .default => null,
1460 };
1461 }
1462};
1463
1464pub const SystemLib = struct {
1465 name: String,
1466 flags: Flags,
1467
1468 pub const Index = enum(u32) {
1469 _,
1470
1471 pub fn get(this: @This(), c: *const Configuration) SystemLib {
1472 return extraData(c, SystemLib, @intFromEnum(this));
1473 }
1474 };
1475
1476 pub const UsePkgConfig = enum(u2) {
1477 /// Don't use pkg-config, just pass -lfoo where foo is name.
1478 no,
1479 /// Try to get information on how to link the library from pkg-config.
1480 /// If that fails, fall back to passing -lfoo where foo is name.
1481 yes,
1482 /// Try to get information on how to link the library from pkg-config.
1483 /// If that fails, error out.
1484 force,
1485 };
1486
1487 pub const LinkMode = std.builtin.LinkMode;
1488
1489 pub const Flags = packed struct(u32) {
1490 needed: bool,
1491 weak: bool,
1492 use_pkg_config: UsePkgConfig,
1493 preferred_link_mode: LinkMode,
1494 search_strategy: SearchStrategy,
1495 _: u25 = 0,
1496 };
1497
1498 pub const SearchStrategy = enum(u2) { paths_first, mode_first, no_fallback };
1499};
1500
1501pub const CSourceFiles = struct {
1502 flags: Flags,
1503 root: LazyPath.Index,
1504 args: Storage.FlagList(.flags, .args_len, String),
1505 sub_paths: Storage.LengthPrefixedList(String),
1506
1507 pub const Index = enum(u32) {
1508 _,
1509
1510 pub fn get(this: @This(), c: *const Configuration) CSourceFiles {
1511 return extraData(c, CSourceFiles, @intFromEnum(this));
1512 }
1513 };
1514
1515 pub const Flags = packed struct(u32) {
1516 /// C compiler CLI flags.
1517 args_len: u29,
1518 lang: OptionalCSourceLanguage,
1519 };
1520};
1521
1522pub const CSourceFile = struct {
1523 flags: Flags,
1524 file: LazyPath.Index,
1525 args: Storage.FlagList(.flags, .args_len, String),
1526
1527 pub const Index = enum(u32) {
1528 _,
1529
1530 pub fn get(this: @This(), c: *const Configuration) CSourceFile {
1531 return extraData(c, CSourceFile, @intFromEnum(this));
1532 }
1533 };
1534
1535 pub const Flags = packed struct(u32) {
1536 /// C compiler CLI flags.
1537 args_len: u29,
1538 lang: OptionalCSourceLanguage,
1539 };
1540};
1541
1542pub const RcSourceFile = struct {
1543 flags: Flags,
1544 file: LazyPath.Index,
1545 args: Storage.FlagList(.flags, .args_len, String),
1546 include_paths: Storage.FlagLengthPrefixedList(.flags, .include_paths, LazyPath.Index),
1547
1548 pub const Index = enum(u32) {
1549 _,
1550
1551 pub fn get(this: @This(), c: *const Configuration) RcSourceFile {
1552 return extraData(c, RcSourceFile, @intFromEnum(this));
1553 }
1554 };
1555
1556 pub const Flags = packed struct(u32) {
1557 /// C compiler CLI flags.
1558 args_len: u31,
1559 include_paths: bool,
1560 };
1561};
1562
1563pub const OptionalCSourceLanguage = enum(u3) {
1564 c,
1565 cpp,
1566 objective_c,
1567 objective_cpp,
1568 assembly,
1569 assembly_with_preprocessor,
1570 default,
1571
1572 pub fn init(x: ?std.Build.Module.CSourceLanguage) @This() {
1573 return switch (x orelse return .default) {
1574 .c => .c,
1575 .cpp => .cpp,
1576 .objective_c => .objective_c,
1577 .objective_cpp => .objective_cpp,
1578 .assembly => .assembly,
1579 .assembly_with_preprocessor => .assembly_with_preprocessor,
1580 };
1581 }
1582
1583 pub fn get(this: @This()) ?std.Build.Module.CSourceLanguage {
1584 return switch (this) {
1585 .c => .c,
1586 .cpp => .cpp,
1587 .objective_c => .objective_c,
1588 .objective_cpp => .objective_cpp,
1589 .assembly => .assembly,
1590 .assembly_with_preprocessor => .assembly_with_preprocessor,
1591 .default => null,
1592 };
1593 }
1594};
1595
1596pub const ResolvedTarget = struct {
1597 /// none indicates host.
1598 query: TargetQuery.OptionalIndex,
1599 /// defaults will be resolved.
1600 result: TargetQuery.Index,
1601
1602 pub const Index = enum(u32) {
1603 _,
1604
1605 pub fn get(this: @This(), c: *const Configuration) ResolvedTarget {
1606 return extraData(c, ResolvedTarget, @intFromEnum(this));
1607 }
1608 };
1609
1610 pub const OptionalIndex = enum(u32) {
1611 none = maxInt(u32),
1612 _,
1613
1614 pub fn unwrap(this: @This()) ?Index {
1615 return switch (this) {
1616 .none => null,
1617 _ => @enumFromInt(@intFromEnum(this)),
1618 };
1619 }
1620
1621 pub fn get(this: @This(), c: *const Configuration) ?ResolvedTarget {
1622 return (unwrap(this) orelse return null).get(c);
1623 }
1624 };
1625};
1626
1627pub const TargetQuery = struct {
1628 flags: Flags,
1629
1630 cpu_features_add: Storage.FlagOptional(.flags, .cpu_features_add, std.Target.Cpu.Feature.Set),
1631 cpu_features_sub: Storage.FlagOptional(.flags, .cpu_features_sub, std.Target.Cpu.Feature.Set),
1632 cpu_name: Storage.EnumOptional(.flags, .cpu_model, .explicit, String),
1633 os_version_min: Storage.FlagUnion(.flags, .os_version_min, OsVersion),
1634 os_version_max: Storage.FlagUnion(.flags, .os_version_max, OsVersion),
1635 glibc_version: Storage.FlagOptional(.flags, .glibc_version, String),
1636 android_api_level: Storage.FlagOptional(.flags, .android_api_level, u32),
1637 dynamic_linker: Storage.FlagOptional(.flags, .dynamic_linker, String),
1638
1639 pub const Index = enum(u32) {
1640 _,
1641
1642 pub fn extraSlice(i: Index, extra: []const u32) []const u32 {
1643 return extra[@intFromEnum(i)..][0..length(i, extra)];
1644 }
1645
1646 pub fn length(i: Index, extra: []const u32) usize {
1647 return Storage.dataLength(extra, @intFromEnum(i), TargetQuery);
1648 }
1649
1650 pub fn get(this: @This(), c: *const Configuration) TargetQuery {
1651 return extraData(c, TargetQuery, @intFromEnum(this));
1652 }
1653 };
1654
1655 pub const OptionalIndex = enum(u32) {
1656 none = maxInt(u32),
1657 _,
1658
1659 pub fn init(i: Index) OptionalIndex {
1660 const result: OptionalIndex = @enumFromInt(@intFromEnum(i));
1661 assert(result != .none);
1662 return result;
1663 }
1664
1665 pub fn unwrap(this: @This()) ?Index {
1666 return switch (this) {
1667 .none => null,
1668 _ => @enumFromInt(@intFromEnum(this)),
1669 };
1670 }
1671 };
1672
1673 pub const CpuModel = enum(u2) {
1674 native,
1675 baseline,
1676 determined_by_arch_os,
1677 explicit,
1678
1679 pub fn init(x: std.Target.Query.CpuModel) @This() {
1680 return switch (x) {
1681 .native => .native,
1682 .baseline => .baseline,
1683 .determined_by_arch_os => .determined_by_arch_os,
1684 .explicit => .explicit,
1685 };
1686 }
1687 };
1688 pub const OsVersion = union(@This().Tag) {
1689 pub const Tag = enum(u2) { none, semver, windows, default };
1690
1691 none: void,
1692 semver: String,
1693 windows: std.Target.Os.WindowsVersion,
1694 default: void,
1695
1696 pub fn init(x: ?std.Target.Query.OsVersion) @This() {
1697 return switch (x orelse return .default) {
1698 .none => .none,
1699 .semver => .semver,
1700 .windows => .windows,
1701 };
1702 }
1703 };
1704 pub const Abi = enum(u5) {
1705 none,
1706 gnu,
1707 gnuabin32,
1708 gnuabi64,
1709 gnueabi,
1710 gnueabihf,
1711 gnuf32,
1712 gnusf,
1713 gnux32,
1714 eabi,
1715 eabihf,
1716 ilp32,
1717 android,
1718 androideabi,
1719 musl,
1720 muslabin32,
1721 muslabi64,
1722 musleabi,
1723 musleabihf,
1724 muslf32,
1725 muslsf,
1726 muslx32,
1727 msvc,
1728 itanium,
1729 simulator,
1730 ohos,
1731 ohoseabi,
1732
1733 default,
1734
1735 pub fn init(x: ?std.Target.Abi) @This() {
1736 // TODO comptime assert the enums match
1737 return @enumFromInt(@intFromEnum(x orelse return .default));
1738 }
1739 };
1740 pub const CpuArch = enum(u6) {
1741 aarch64,
1742 aarch64_be,
1743 alpha,
1744 amdgcn,
1745 arc,
1746 arceb,
1747 arm,
1748 armeb,
1749 avr,
1750 bpfeb,
1751 bpfel,
1752 csky,
1753 hexagon,
1754 hppa,
1755 hppa64,
1756 kalimba,
1757 kvx,
1758 lanai,
1759 loongarch32,
1760 loongarch64,
1761 m68k,
1762 microblaze,
1763 microblazeel,
1764 mips,
1765 mipsel,
1766 mips64,
1767 mips64el,
1768 msp430,
1769 nvptx,
1770 nvptx64,
1771 or1k,
1772 powerpc,
1773 powerpcle,
1774 powerpc64,
1775 powerpc64le,
1776 propeller,
1777 riscv32,
1778 riscv32be,
1779 riscv64,
1780 riscv64be,
1781 s390x,
1782 sh,
1783 sheb,
1784 sparc,
1785 sparc64,
1786 spirv32,
1787 spirv64,
1788 thumb,
1789 thumbeb,
1790 ve,
1791 wasm32,
1792 wasm64,
1793 x86_16,
1794 x86,
1795 x86_64,
1796 xcore,
1797 xtensa,
1798 xtensaeb,
1799
1800 default,
1801
1802 pub fn init(x: ?std.Target.Cpu.Arch) @This() {
1803 // TODO comptime assert the enums match
1804 return @enumFromInt(@intFromEnum(x orelse return .default));
1805 }
1806 };
1807 pub const OsTag = enum(u6) {
1808 freestanding,
1809 other,
1810 contiki,
1811 fuchsia,
1812 hermit,
1813 managarm,
1814 haiku,
1815 hurd,
1816 illumos,
1817 linux,
1818 plan9,
1819 rtems,
1820 serenity,
1821 dragonfly,
1822 freebsd,
1823 netbsd,
1824 openbsd,
1825 driverkit,
1826 ios,
1827 maccatalyst,
1828 macos,
1829 tvos,
1830 visionos,
1831 watchos,
1832 windows,
1833 uefi,
1834 @"3ds",
1835 ps3,
1836 ps4,
1837 ps5,
1838 vita,
1839 emscripten,
1840 wasi,
1841 amdhsa,
1842 amdpal,
1843 cuda,
1844 mesa3d,
1845 nvcl,
1846 opencl,
1847 opengl,
1848 vulkan,
1849
1850 default,
1851
1852 pub fn init(x: ?std.Target.Os.Tag) @This() {
1853 // TODO comptime assert the enums match
1854 return @enumFromInt(@intFromEnum(x orelse return .default));
1855 }
1856 };
1857 pub const ObjectFormat = enum(u4) {
1858 c,
1859 coff,
1860 elf,
1861 hex,
1862 macho,
1863 plan9,
1864 raw,
1865 spirv,
1866 wasm,
1867
1868 default,
1869
1870 pub fn init(x: ?std.Target.ObjectFormat) @This() {
1871 // TODO comptime assert the enums match
1872 return @enumFromInt(@intFromEnum(x orelse return .default));
1873 }
1874
1875 pub fn get(this: @This()) ?std.Target.ObjectFormat {
1876 return switch (this) {
1877 .c => .c,
1878 .coff => .coff,
1879 .elf => .elf,
1880 .hex => .hex,
1881 .macho => .macho,
1882 .plan9 => .plan9,
1883 .raw => .raw,
1884 .spirv => .spirv,
1885 .wasm => .wasm,
1886
1887 .default => null,
1888 };
1889 }
1890 };
1891
1892 pub const Flags = packed struct(u32) {
1893 cpu_arch: CpuArch,
1894 cpu_model: CpuModel,
1895 cpu_features_add: bool,
1896 cpu_features_sub: bool,
1897 os_tag: OsTag,
1898 abi: Abi,
1899 object_format: ObjectFormat,
1900 os_version_min: OsVersion.Tag,
1901 os_version_max: OsVersion.Tag,
1902 glibc_version: bool,
1903 android_api_level: bool,
1904 dynamic_linker: bool,
1905 };
1906};
1907
1908pub const Storage = enum {
1909 flag_optional,
1910 enum_optional,
1911 extended,
1912 length_prefixed_list,
1913 flag_length_prefixed_list,
1914 union_list,
1915 flag_union,
1916 multi_list,
1917 flag_list,
1918
1919 /// The presence of the field is determined by a boolean within a packed
1920 /// struct.
1921 pub fn FlagOptional(
1922 comptime flags_arg: @EnumLiteral(),
1923 comptime flag_arg: @EnumLiteral(),
1924 comptime ValueArg: type,
1925 ) type {
1926 return struct {
1927 value: ?Value,
1928
1929 pub const storage: Storage = .flag_optional;
1930 pub const flags = flags_arg;
1931 pub const flag = flag_arg;
1932 pub const Value = ValueArg;
1933 };
1934 }
1935
1936 /// The type of the field is determined by an enum within a packed struct.
1937 pub fn FlagUnion(
1938 comptime flags_arg: @EnumLiteral(),
1939 comptime flag_arg: @EnumLiteral(),
1940 comptime UnionArg: type,
1941 ) type {
1942 return struct {
1943 u: Union,
1944
1945 pub const storage: Storage = .flag_union;
1946 pub const flags = flags_arg;
1947 pub const flag = flag_arg;
1948 pub const Union = UnionArg;
1949
1950 pub const Tag = @typeInfo(Union).@"union".tag_type.?;
1951 };
1952 }
1953
1954 /// The field is present if an enum tag from flags matches a specific value.
1955 pub fn EnumOptional(
1956 comptime flags_arg: @EnumLiteral(),
1957 comptime flag_arg: @EnumLiteral(),
1958 comptime tag_arg: @EnumLiteral(),
1959 comptime ValueArg: type,
1960 ) type {
1961 return struct {
1962 value: ?Value,
1963
1964 pub const storage: Storage = .enum_optional;
1965 pub const flags = flags_arg;
1966 pub const flag = flag_arg;
1967 pub const tag = tag_arg;
1968 pub const Value = ValueArg;
1969 };
1970 }
1971
1972 /// The field indexes into an auxilary buffer, with the first element being
1973 /// a packed struct that contains the tag.
1974 pub fn Extended(comptime BaseFlags: type, comptime U: type) type {
1975 return enum(u32) {
1976 _,
1977
1978 pub const storage: Storage = .extended;
1979
1980 pub fn get(this: @This(), buffer: []const u32) U {
1981 var i: usize = @intFromEnum(this);
1982 const base_flags: BaseFlags = @bitCast(buffer[i]);
1983 return switch (base_flags.tag) {
1984 inline else => |tag| @unionInit(U, @tagName(tag), data(buffer, &i, @FieldType(U, @tagName(tag)))),
1985 };
1986 }
1987 };
1988 }
1989
1990 /// A field in flags determines whether the length is zero or nonzero. If the length is
1991 /// nonzero, then there is a length field followed by the list.
1992 pub fn FlagLengthPrefixedList(
1993 comptime flags_arg: @EnumLiteral(),
1994 comptime flag_arg: @EnumLiteral(),
1995 comptime ElemArg: type,
1996 ) type {
1997 return struct {
1998 slice: []const Elem,
1999
2000 pub const storage: Storage = .flag_length_prefixed_list;
2001 pub const flags = flags_arg;
2002 pub const flag = flag_arg;
2003 pub const Elem = ElemArg;
2004
2005 pub fn initErased(s: []const u32) @This() {
2006 return .{ .slice = @ptrCast(s) };
2007 }
2008 };
2009 }
2010
2011 /// The field contains a u32 length followed by that many items, each
2012 /// element bitcastable to u32.
2013 pub fn LengthPrefixedList(comptime ElemArg: type) type {
2014 return struct {
2015 slice: []const Elem,
2016
2017 pub const storage: Storage = .length_prefixed_list;
2018 pub const Elem = ElemArg;
2019
2020 pub fn initErased(s: []const u32) @This() {
2021 return .{ .slice = @ptrCast(s) };
2022 }
2023 };
2024 }
2025
2026 /// The field is a list whose length is an integer inside flags.
2027 pub fn FlagList(
2028 comptime flags_arg: @EnumLiteral(),
2029 comptime flag_arg: @EnumLiteral(),
2030 comptime ElemArg: type,
2031 ) type {
2032 return struct {
2033 slice: []const Elem,
2034
2035 pub const storage: Storage = .flag_list;
2036 pub const flags = flags_arg;
2037 pub const flag = flag_arg;
2038 pub const Elem = ElemArg;
2039
2040 pub fn initErased(s: []const u32) @This() {
2041 return .{ .slice = @ptrCast(s) };
2042 }
2043 };
2044 }
2045
2046 /// The field contains a u32 length followed by that many items for the
2047 /// first field, that many items for the second field, etc.
2048 pub fn MultiList(comptime ElemArg: type) type {
2049 return struct {
2050 mal: std.MultiArrayList(Elem),
2051
2052 pub const storage: Storage = .multi_list;
2053 pub const Elem = ElemArg;
2054 };
2055 }
2056
2057 /// `UnionArg` is a tagged union with a small integer for the enum tag.
2058 ///
2059 /// A field in flags determines whether the metadata is present.
2060 ///
2061 /// The metadata is bit-packed consecutive packed struct which is the
2062 /// `UnionArg` enum tag combined with a "last" marker boolean field.
2063 /// When "last" is true, the element is the last one, providing
2064 /// the length of the list.
2065 ///
2066 /// Following is each element of the list; each bitcastable to u32.
2067 pub fn UnionList(
2068 comptime flags_arg: @EnumLiteral(),
2069 comptime flag_arg: @EnumLiteral(),
2070 comptime UnionArg: type,
2071 ) type {
2072 return struct {
2073 /// When serializing it is UnionArg slice pointer.
2074 /// When deserializing it is extra index of first UnionArg element.
2075 data: ?*const anyopaque,
2076 len: usize,
2077
2078 pub const storage: Storage = .union_list;
2079 pub const flags = flags_arg;
2080 pub const flag = flag_arg;
2081 pub const Union = UnionArg;
2082
2083 pub const Tag = @typeInfo(Union).@"union".tag_type.?;
2084 pub const MetaInt = @Int(.unsigned, @bitSizeOf(Tag) + 1);
2085 pub const Meta = packed struct(MetaInt) {
2086 tag: Tag,
2087 last: bool,
2088 };
2089
2090 /// Valid to call only when serializing.
2091 pub fn init(s: []const Union) @This() {
2092 return .{ .data = s.ptr, .len = s.len };
2093 }
2094
2095 /// Valid to call only when deserializing.
2096 pub fn slice(this: *const @This(), extra: []const u32) []const u32 {
2097 return extra[@intFromPtr(this.data)..][0..this.len];
2098 }
2099
2100 /// Valid to call only when deserializing.
2101 pub fn get(this: *const @This(), extra: []const u32, i: usize) Union {
2102 const elem = slice(this, extra)[i];
2103 return switch (this.tag(extra, i)) {
2104 inline else => |comptime_tag| @unionInit(Union, @tagName(comptime_tag), @enumFromInt(elem)),
2105 };
2106 }
2107
2108 /// Valid to call only when deserializing.
2109 pub fn tag(this: *const @This(), extra: []const u32, i: usize) Tag {
2110 _ = this;
2111 _ = extra;
2112 _ = i;
2113 @panic("TODO implement UnionList.tag");
2114 }
2115
2116 fn extraLen(len: usize) usize {
2117 return len + (len * @bitSizeOf(Meta) + 31) / 32;
2118 }
2119 };
2120 }
2121
2122 pub fn dataLength(buffer: []const u32, i: usize, comptime S: type) usize {
2123 var end = i;
2124 _ = data(buffer, &end, S);
2125 return end - i;
2126 }
2127
2128 pub fn data(buffer: []const u32, i: *usize, comptime T: type) T {
2129 switch (@typeInfo(T)) {
2130 .@"struct" => |info| {
2131 var result: T = undefined;
2132 inline for (info.fields) |field| {
2133 @field(result, field.name) = dataField(buffer, i, &result, field.type);
2134 }
2135 return result;
2136 },
2137 .@"union" => |info| {
2138 const flags: T.Flags = @bitCast(buffer[i.*]);
2139 return switch (flags.tag) {
2140 inline else => |comptime_tag| @unionInit(
2141 T,
2142 @tagName(comptime_tag),
2143 data(buffer, i, info.fields[@intFromEnum(comptime_tag)].type),
2144 ),
2145 };
2146 },
2147 else => comptime unreachable,
2148 }
2149 }
2150
2151 fn dataField(buffer: []const u32, i: *usize, container: anytype, comptime Field: type) Field {
2152 switch (@typeInfo(Field)) {
2153 .void => return {},
2154 .int => |info| switch (info.bits) {
2155 32 => {
2156 defer i.* += 1;
2157 return buffer[i.*];
2158 },
2159 64 => {
2160 defer i.* += 2;
2161 return @bitCast(buffer[i.*..][0..2].*);
2162 },
2163 else => comptime unreachable,
2164 },
2165 .@"enum" => {
2166 defer i.* += 1;
2167 return @enumFromInt(buffer[i.*]);
2168 },
2169 .@"struct" => |info| switch (info.layout) {
2170 .@"packed" => switch (info.backing_integer.?) {
2171 u32 => {
2172 defer i.* += 1;
2173 return @bitCast(buffer[i.*]);
2174 },
2175 u64 => {
2176 defer i.* += 2;
2177 return @bitCast(buffer[i.*..][0..2].*);
2178 },
2179 else => comptime unreachable,
2180 },
2181 .auto => switch (Field) {
2182 std.Target.Cpu.Feature.Set => {
2183 const u32_count = (Field.usize_count * @sizeOf(usize)) / @sizeOf(u32);
2184 defer i.* += u32_count;
2185 return .{ .ints = @as(
2186 *align(@alignOf(u32)) const [Field.usize_count]usize,
2187 @ptrCast(buffer[i.*..][0..u32_count]),
2188 ).* };
2189 },
2190 else => switch (Field.storage) {
2191 .flag_optional => {
2192 const flags = @field(container, @tagName(Field.flags));
2193 const flag = @field(flags, @tagName(Field.flag));
2194 return .{
2195 .value = if (flag) dataField(buffer, i, container, Field.Value) else null,
2196 };
2197 },
2198 .flag_union => {
2199 const flags = @field(container, @tagName(Field.flags));
2200 const tag: Field.Tag = @field(flags, @tagName(Field.flag));
2201 return .{
2202 .u = switch (tag) {
2203 inline else => |comptime_tag| @unionInit(
2204 Field.Union,
2205 @tagName(comptime_tag),
2206 dataField(
2207 buffer,
2208 i,
2209 container,
2210 @typeInfo(Field.Union).@"union".fields[@intFromEnum(comptime_tag)].type,
2211 ),
2212 ),
2213 },
2214 };
2215 },
2216 .enum_optional => {
2217 const flags = @field(container, @tagName(Field.flags));
2218 const tag = @field(flags, @tagName(Field.flag));
2219 const match = tag == Field.tag;
2220 return .{
2221 .value = if (match) dataField(buffer, i, container, Field.Value) else null,
2222 };
2223 },
2224 .extended => @compileError("TODO"),
2225 .length_prefixed_list => {
2226 const data_start = i.* + 1;
2227 const len = buffer[data_start - 1];
2228 defer i.* = data_start + len;
2229 return .{ .slice = @ptrCast(buffer[data_start..][0..len]) };
2230 },
2231 .flag_length_prefixed_list => {
2232 const flags = @field(container, @tagName(Field.flags));
2233 const flag = @field(flags, @tagName(Field.flag));
2234 if (!flag) return .{ .slice = &.{} };
2235 const data_start = i.* + 1;
2236 const len = buffer[data_start - 1];
2237 defer i.* = data_start + len;
2238 return .{ .slice = @ptrCast(buffer[data_start..][0..len]) };
2239 },
2240 .flag_list => {
2241 const flags = @field(container, @tagName(Field.flags));
2242 const len: u32 = @field(flags, @tagName(Field.flag));
2243 const data_start = i.*;
2244 defer i.* = data_start + len;
2245 return .{ .slice = @ptrCast(buffer[data_start..][0..len]) };
2246 },
2247 .multi_list => {
2248 const data_start = i.* + 1;
2249 const len = buffer[data_start - 1];
2250 defer i.* = data_start + len * @typeInfo(Field.Elem).@"struct".fields.len;
2251 return .{ .mal = .{
2252 .bytes = @ptrCast(@constCast(buffer[data_start..][0..len])),
2253 .len = len,
2254 .capacity = len,
2255 } };
2256 },
2257 .union_list => {
2258 const flags = @field(container, @tagName(Field.flags));
2259 const flag = @field(flags, @tagName(Field.flag));
2260 if (!flag) return .{ .data = null, .len = 0 };
2261 const meta_start = i.*;
2262 const meta_buffer = buffer[meta_start..];
2263 var len: u32 = 0;
2264 var bit_offset: usize = 0;
2265 while (true) : (bit_offset += @bitSizeOf(Field.Meta)) {
2266 const meta = loadBits(u32, meta_buffer, bit_offset, Field.Meta);
2267 len += 1;
2268 if (meta.last) break;
2269 }
2270 const end = meta_start + Field.extraLen(len);
2271 i.* = end;
2272 return .{ .data = @ptrFromInt(end - len), .len = len };
2273 },
2274 },
2275 },
2276 .@"extern" => comptime unreachable,
2277 },
2278 else => comptime unreachable,
2279 }
2280 }
2281
2282 /// Returns new end index.
2283 fn setExtra(buffer: []u32, index: usize, extra: anytype) usize {
2284 const fields = @typeInfo(@TypeOf(extra)).@"struct".fields;
2285 var i = index;
2286 inline for (fields) |field| {
2287 i += setExtraField(buffer, i, field.type, @field(extra, field.name));
2288 }
2289 return i;
2290 }
2291
2292 fn extraFieldLen(field: anytype) usize {
2293 const Field = @TypeOf(field);
2294 return switch (@typeInfo(Field)) {
2295 .void => 0,
2296 .int => |info| switch (info.bits) {
2297 32 => 1,
2298 64 => 2,
2299 else => comptime unreachable,
2300 },
2301 .@"enum" => 1,
2302 .@"struct" => |info| switch (info.layout) {
2303 .@"packed" => switch (info.backing_integer.?) {
2304 u32 => 1,
2305 u64 => 2,
2306 else => comptime unreachable,
2307 },
2308 .auto => switch (Field.storage) {
2309 .flag_optional, .enum_optional, .extended => 1,
2310 .length_prefixed_list,
2311 .flag_length_prefixed_list,
2312 .flag_list,
2313 => 1 + @divExact(@sizeOf(Field.Elem), @sizeOf(u32)) * field.slice.len,
2314 .multi_list => 1 + field.mal.len * @typeInfo(Field.Elem).@"struct".fields.len,
2315 .union_list => Field.extraLen(field.len),
2316 .flag_union => switch (field.u) {
2317 inline else => |v| extraFieldLen(v),
2318 },
2319 },
2320 .@"extern" => comptime unreachable,
2321 },
2322 else => @compileError("bad type: " ++ @typeName(Field)),
2323 };
2324 }
2325
2326 fn extraLen(extra: anytype) usize {
2327 const fields = @typeInfo(@TypeOf(extra)).@"struct".fields;
2328 var i: usize = 0;
2329 inline for (fields) |field| {
2330 i += Storage.extraFieldLen(@field(extra, field.name));
2331 }
2332 return i;
2333 }
2334
2335 inline fn setExtraField(buffer: []u32, i: usize, comptime Field: type, value: anytype) usize {
2336 switch (@typeInfo(Field)) {
2337 .void => return 0,
2338 .int => |info| switch (info.bits) {
2339 32 => {
2340 buffer[i] = value;
2341 return 1;
2342 },
2343 64 => {
2344 buffer[i..][0..2].* = @bitCast(value);
2345 return 2;
2346 },
2347 else => comptime unreachable,
2348 },
2349 .@"enum" => {
2350 buffer[i] = @intFromEnum(value);
2351 return 1;
2352 },
2353 .@"struct" => |info| switch (info.layout) {
2354 .@"packed" => switch (info.backing_integer.?) {
2355 u32 => {
2356 buffer[i] = @bitCast(value);
2357 return 1;
2358 },
2359 u64 => {
2360 buffer[i..][0..2].* = @bitCast(value);
2361 return 2;
2362 },
2363 else => comptime unreachable,
2364 },
2365 .auto => switch (Field) {
2366 std.Target.Cpu.Feature.Set => {
2367 const casted: []const u32 = @ptrCast(&value.ints);
2368 @memcpy(buffer[i..][0..casted.len], casted);
2369 return casted.len;
2370 },
2371 else => switch (Field.storage) {
2372 .flag_optional, .enum_optional => {
2373 return if (value.value) |v| setExtraField(buffer, i, Field.Value, v) else 0;
2374 },
2375 .flag_union => return switch (value.u) {
2376 inline else => |x| setExtraField(buffer, i, @TypeOf(x), x),
2377 },
2378 .extended => @compileError("TODO"),
2379 .flag_length_prefixed_list, .length_prefixed_list => {
2380 const len: u32 = @intCast(value.slice.len);
2381 if (len == 0) return 0;
2382 buffer[i] = len;
2383 @memcpy(buffer[i + 1 ..][0..len], @as([]const u32, @ptrCast(value.slice)));
2384 return len + 1;
2385 },
2386 .flag_list => {
2387 const len: u32 = @intCast(value.slice.len);
2388 @memcpy(buffer[i..][0..len], @as([]const u32, @ptrCast(value.slice)));
2389 return len;
2390 },
2391 .multi_list => {
2392 const len: u32 = @intCast(value.mal.len);
2393 if (len == 0) return 0;
2394 buffer[i] = len;
2395 const fields = @typeInfo(Field.Elem).@"struct".fields;
2396 inline for (0..fields.len) |field_i| @memcpy(
2397 buffer[i + 1 + field_i * len ..][0..len],
2398 @as([]const u32, @ptrCast(value.mal.items(@enumFromInt(field_i)))),
2399 );
2400 return 1 + fields.len * len;
2401 },
2402 .union_list => {
2403 if (value.len == 0) return 0;
2404 const Tag = @typeInfo(Field.Union).@"union".tag_type.?;
2405 const slice_ptr: [*]const Field.Union = @ptrCast(@alignCast(value.data));
2406 const slice = slice_ptr[0..value.len];
2407 const meta_buffer = buffer[i..][0 .. (slice.len * @bitSizeOf(Field.Meta) + 31) / 32];
2408 for (slice[0 .. slice.len - 1], 0..) |elem, elem_index| {
2409 const union_tag: Tag = elem;
2410 storeBits(u32, meta_buffer, elem_index * @bitSizeOf(Field.Meta), @as(Field.Meta, .{
2411 .tag = union_tag,
2412 .last = false,
2413 }));
2414 } else {
2415 const elem_index = slice.len - 1;
2416 const elem = slice[elem_index];
2417 const union_tag: Tag = elem;
2418 storeBits(u32, meta_buffer, elem_index * @bitSizeOf(Field.Meta), @as(Field.Meta, .{
2419 .tag = union_tag,
2420 .last = true,
2421 }));
2422 }
2423 var total: usize = meta_buffer.len;
2424 for (i + meta_buffer.len.., slice) |elem_index, src| switch (src) {
2425 inline else => |x| total += setExtraField(buffer, elem_index, @TypeOf(x), x),
2426 };
2427 return total;
2428 },
2429 },
2430 },
2431 .@"extern" => comptime unreachable,
2432 },
2433 else => @compileError("bad field type: " ++ @typeName(Field)),
2434 }
2435 }
2436};
2437
2438pub fn extraData(c: *const Configuration, comptime T: type, index: usize) T {
2439 var i: usize = index;
2440 return Storage.data(c.extra, &i, T);
2441}
2442
2443pub const LoadFileError = Io.File.Reader.Error || Allocator.Error || error{EndOfStream};
2444
2445pub fn loadFile(arena: Allocator, io: Io, file: Io.File) LoadFileError!Configuration {
2446 var buffer: [2000]u8 = undefined;
2447 var fr = file.reader(io, &buffer);
2448 return load(arena, &fr.interface) catch |err| switch (err) {
2449 error.ReadFailed => return fr.err.?,
2450 else => |e| return e,
2451 };
2452}
2453
2454pub const LoadError = Io.Reader.Error || Allocator.Error;
2455
2456pub fn load(arena: Allocator, reader: *Io.Reader) LoadError!Configuration {
2457 const header = try reader.takeStruct(Header, .little);
2458 var result: Configuration = .{
2459 .string_bytes = try arena.alloc(u8, header.string_bytes_len),
2460 .steps = try arena.alloc(Step, header.steps_len),
2461 .path_deps_sub = try arena.alloc(String, header.path_deps_len),
2462 .path_deps_base = try arena.alloc(Path.Base, header.path_deps_len),
2463 .unlazy_deps = try arena.alloc(String, header.unlazy_deps_len),
2464 .system_integrations = try arena.alloc(SystemIntegration, header.system_integrations_len),
2465 .available_options = try arena.alloc(AvailableOption, header.available_options_len),
2466 .extra = try arena.alloc(u32, header.extra_len),
2467 .default_step = header.default_step,
2468 .generated_files_len = header.generated_files_len,
2469 };
2470 var vecs = [_][]u8{
2471 result.string_bytes,
2472 @ptrCast(result.steps),
2473 @ptrCast(result.path_deps_base),
2474 @ptrCast(result.path_deps_sub),
2475 @ptrCast(result.unlazy_deps),
2476 @ptrCast(result.system_integrations),
2477 @ptrCast(result.available_options),
2478 @ptrCast(result.extra),
2479 };
2480 try reader.readVecAll(&vecs);
2481 return result;
2482}
2483
2484pub fn loadBits(comptime Int: type, buffer: []const Int, bit_offset: usize, comptime Result: type) Result {
2485 const index = bit_offset / @bitSizeOf(Int);
2486 const small_bit_offset = bit_offset % @bitSizeOf(Int);
2487 const ResultInt = @Int(.unsigned, @bitSizeOf(Result));
2488 const result: ResultInt = @truncate(buffer[index] >> @intCast(small_bit_offset));
2489 const available_bits = @bitSizeOf(Int) - small_bit_offset;
2490 if (available_bits >= @bitSizeOf(ResultInt)) return @bitCast(result);
2491 const missing_bits = @bitSizeOf(ResultInt) - available_bits;
2492 const upper: ResultInt = @truncate(buffer[index + 1] & ((@as(usize, 1) << @intCast(missing_bits)) - 1));
2493 return @bitCast(result | (upper << @intCast(available_bits)));
2494}
2495
2496pub fn storeBits(comptime Int: type, buffer: []Int, bit_offset: usize, value: anytype) void {
2497 const Value = @TypeOf(value);
2498 const ValueInt = @Int(.unsigned, @bitSizeOf(Value));
2499 const value_int: ValueInt = @bitCast(value);
2500 const index = bit_offset / @bitSizeOf(Int);
2501 const small_bit_offset = bit_offset % @bitSizeOf(Int);
2502 const available_bits = @bitSizeOf(Int) - small_bit_offset;
2503 if (available_bits >= @bitSizeOf(ValueInt)) {
2504 buffer[index] &= ~(((@as(Int, 1) << @intCast(@bitSizeOf(Value))) - 1) << @intCast(small_bit_offset));
2505 buffer[index] |= @as(Int, value_int) << @intCast(small_bit_offset);
2506 } else {
2507 const DoubleInt = @Int(.unsigned, @bitSizeOf(Int) * 2);
2508 const ptr: *align(@alignOf(Int)) DoubleInt = @ptrCast(buffer[index..][0..2]);
2509 ptr.* &= ~(((@as(DoubleInt, 1) << @intCast(@bitSizeOf(Value))) - 1) << @intCast(small_bit_offset));
2510 ptr.* |= @as(DoubleInt, value_int) << @intCast(small_bit_offset);
2511 }
2512}
2513
2514test "loadBits and storeBits" {
2515 var buffer: [2]u32 = .{
2516 0b01111111000000001111111100000000,
2517 0b11111111000000001111111100000100,
2518 };
2519 try std.testing.expectEqual(0b100, loadBits(u32, &buffer, 6, u3));
2520 try std.testing.expectEqual(0b100011, loadBits(u32, &buffer, 29, u6));
2521
2522 storeBits(u32, &buffer, 6, @as(u3, 0b010));
2523 storeBits(u32, &buffer, 29, @as(u6, 0b010010));
2524
2525 try std.testing.expectEqual(0b010, loadBits(u32, &buffer, 6, u3));
2526 try std.testing.expectEqual(0b010010, loadBits(u32, &buffer, 29, u6));
2527}