authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-07-01 14:15:31-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-07-01 14:15:31-07:00
log8923dd4ca257436f04408a2a9ad9a429275a98dc
treee6444900a4e26e988080820ba6bf06819fdf09dc
parentca948d62d0a5762c2438da0a0a59034dc0a16cdb

move main configurer logic to std.Build.Serialize


3 files changed, 1258 insertions(+), 1273 deletions(-)

lib/compiler/configurer.zig+4-1273
...@@ -4,16 +4,14 @@ const std = @import("std");...@@ -4,16 +4,14 @@ const std = @import("std");
4const Allocator = std.mem.Allocator;4const Allocator = std.mem.Allocator;
5const Color = std.zig.Color;5const Color = std.zig.Color;
6const Configuration = std.Build.Configuration;6const Configuration = std.Build.Configuration;
7const File = std.Io.File;
8const Io = std.Io;7const Io = std.Io;
9const Step = std.Build.Step;8const Step = std.Build.Step;
10const Writer = std.Io.Writer;
11const assert = std.debug.assert;9const assert = std.debug.assert;
12const fatal = std.process.fatal;10const fatal = std.process.fatal;
13const fmt = std.fmt;
14const log = std.log;11const log = std.log;
15const mem = std.mem;12const mem = std.mem;
16const process = std.process;13const process = std.process;
14const Serialize = std.Build.Serialize;
1715
18pub const root = @import("@build");16pub const root = @import("@build");
19pub const dependencies = @import("@dependencies");17pub const dependencies = @import("@dependencies");
...@@ -139,12 +137,12 @@ pub fn main(init: process.Init.Minimal) !void {...@@ -139,12 +137,12 @@ pub fn main(init: process.Init.Minimal) !void {
139 fatal(" access the help menu with 'zig build -h'", .{});137 fatal(" access the help menu with 'zig build -h'", .{});
140 }138 }
141139
142 try serializePackageOptions(builder, &graph.wip_configuration);140 try Serialize.packageOptions(builder, &graph.wip_configuration);
143 try serializeSystemIntegrationOptions(&graph, &graph.wip_configuration);141 try Serialize.systemIntegrationOptions(&graph, &graph.wip_configuration);
144142
145 var stdout_buffer: [1024]u8 = undefined;143 var stdout_buffer: [1024]u8 = undefined;
146 var file_writer = Io.File.stdout().writerStreaming(io, &stdout_buffer);144 var file_writer = Io.File.stdout().writerStreaming(io, &stdout_buffer);
147 serialize(builder, &graph.wip_configuration, &file_writer.interface) catch |err| switch (err) {145 Serialize.write(builder, &graph.wip_configuration, &file_writer.interface) catch |err| switch (err) {
148 error.WriteFailed => fatal("failed to write configuration output: {t}", .{file_writer.err.?}),146 error.WriteFailed => fatal("failed to write configuration output: {t}", .{file_writer.err.?}),
149 error.OutOfMemory => |e| return e,147 error.OutOfMemory => |e| return e,
150 };148 };
...@@ -157,1211 +155,6 @@ pub fn main(init: process.Init.Minimal) !void {...@@ -157,1211 +155,6 @@ pub fn main(init: process.Init.Minimal) !void {
157 process.exit(0);155 process.exit(0);
158}156}
159157
160const Serialize = struct {
161 arena: Allocator,
162 wc: *Configuration.Wip,
163 module_map: std.array_hash_map.Auto(*std.Build.Module, Configuration.Module.Index) = .empty,
164 package_map: std.array_hash_map.Auto(*std.Build, Configuration.Package.Index) = .empty,
165 /// Index corresponds to `Configuration.steps` index.
166 step_map: std.array_hash_map.Auto(*Step, void) = .empty,
167
168 fn builderToPackage(s: *Serialize, b: *std.Build) !Configuration.Package.Index {
169 if (b.pkg_hash.len == 0) return .root;
170 const arena = s.arena;
171 const wc = s.wc;
172 const gop = try s.package_map.getOrPut(arena, b);
173 if (!gop.found_existing) {
174 gop.value_ptr.* = try wc.addExtra(Configuration.Package, .{
175 .hash = try wc.addString(b.pkg_hash),
176 .dep_prefix = try wc.addString(b.dep_prefix),
177 .root_path = try wc.addString(try b.root.toString(arena)),
178 });
179 }
180 return gop.value_ptr.*;
181 }
182
183 fn addOptionalLazyPathEnum(s: *Serialize, lp: ?std.Build.LazyPath) !Configuration.LazyPath.OptionalIndex {
184 const wc = s.wc;
185 return @enumFromInt(switch (lp orelse return .none) {
186 .src_path => |src_path| i: {
187 const sub_path = try wc.addString(src_path.sub_path);
188 break :i try wc.addExtraErased(Configuration.LazyPath.SourcePath, .{
189 .owner = try s.builderToPackage(src_path.owner),
190 .sub_path = sub_path,
191 });
192 },
193 .generated => |generated| i: {
194 const sub_path = try wc.addString(generated.sub_path);
195 break :i try wc.addExtraErased(Configuration.LazyPath.Generated, .{
196 .flags = .{ .up = @intCast(generated.up) },
197 .index = generated.index,
198 .sub_path = sub_path,
199 });
200 },
201 .cwd_relative => |cwd_relative_sub_path| i: {
202 const sub_path = try wc.addString(cwd_relative_sub_path);
203 break :i try wc.addExtraErased(Configuration.LazyPath.Relative, .{
204 .flags = .{ .base = .cwd },
205 .sub_path = sub_path,
206 });
207 },
208 .relative => |relative| i: {
209 break :i try wc.addExtraErased(Configuration.LazyPath.Relative, .{
210 .flags = .{ .base = relative.base },
211 .sub_path = try wc.addString(relative.sub_path),
212 });
213 },
214 .dependency => |dependency| i: {
215 const sub_path = try wc.addString(dependency.sub_path);
216 break :i try wc.addExtraErased(Configuration.LazyPath.SourcePath, .{
217 .owner = try s.builderToPackage(dependency.dependency.builder),
218 .sub_path = sub_path,
219 });
220 },
221 });
222 }
223
224 fn addOptionalLazyPath(s: *Serialize, lp: ?std.Build.LazyPath) !?Configuration.LazyPath.Index {
225 return (try addOptionalLazyPathEnum(s, lp)).unwrap();
226 }
227
228 fn addLazyPath(s: *Serialize, lp: std.Build.LazyPath) !Configuration.LazyPath.Index {
229 return @enumFromInt(@intFromEnum(try addOptionalLazyPathEnum(s, lp)));
230 }
231
232 fn addOptionalSemVer(s: *Serialize, sem_ver: ?std.SemanticVersion) !?Configuration.String {
233 return if (sem_ver) |sv| try s.wc.addSemVer(sv) else null;
234 }
235
236 fn addOptionalString(s: *Serialize, opt_slice: ?[]const u8) !?Configuration.String {
237 return if (opt_slice) |slice| try s.wc.addString(slice) else null;
238 }
239
240 fn addSystemLib(s: *Serialize, sl: *const std.Build.Module.SystemLib) !Configuration.SystemLib.Index {
241 const wc = s.wc;
242 return try wc.addDeduped(Configuration.SystemLib, .{
243 .flags = .{
244 .needed = sl.needed,
245 .weak = sl.weak,
246 .use_pkg_config = sl.use_pkg_config,
247 .preferred_link_mode = sl.preferred_link_mode,
248 .search_strategy = sl.search_strategy,
249 },
250 .name = try wc.addString(sl.name),
251 });
252 }
253
254 fn addCSourceFile(s: *Serialize, csf: *const std.Build.Module.CSourceFile) !Configuration.CSourceFile.Index {
255 const wc = s.wc;
256 const args = try initStringList(s, csf.flags);
257 return try wc.addExtra(Configuration.CSourceFile, .{
258 .flags = .{
259 .args_len = @intCast(args.len),
260 .lang = .init(csf.language),
261 },
262 .file = try addLazyPath(s, csf.file),
263 .args = .{ .slice = args },
264 });
265 }
266
267 fn addCSourceFiles(s: *Serialize, csf: *const std.Build.Module.CSourceFiles) !Configuration.CSourceFiles.Index {
268 const wc = s.wc;
269 const sub_paths = try initStringList(s, csf.files);
270 const args = try initStringList(s, csf.flags);
271 return try wc.addExtra(Configuration.CSourceFiles, .{
272 .flags = .{
273 .args_len = @intCast(args.len),
274 .lang = .init(csf.language),
275 },
276 .root = try addLazyPath(s, csf.root),
277 .sub_paths = .{ .slice = sub_paths },
278 .args = .{ .slice = args },
279 });
280 }
281
282 fn addRcSourceFile(s: *Serialize, rsf: *const std.Build.Module.RcSourceFile) !Configuration.RcSourceFile.Index {
283 const wc = s.wc;
284 const include_paths = try initLazyPathList(s, rsf.include_paths);
285 const args = try initStringList(s, rsf.flags);
286 return try wc.addExtra(Configuration.RcSourceFile, .{
287 .flags = .{
288 .args_len = @intCast(args.len),
289 .include_paths = include_paths.len != 0,
290 },
291 .file = try addLazyPath(s, rsf.file),
292 .include_paths = .{ .slice = include_paths },
293 .args = .{ .slice = args },
294 });
295 }
296
297 fn addEnvironMap(s: *Serialize, opt_map: ?*std.process.Environ.Map) !?Configuration.EnvironMap.Index {
298 const wc = s.wc;
299 const map = opt_map orelse return null;
300 return try wc.addDeduped(Configuration.EnvironMap, .{
301 .keys = try wc.addStringList(map.array_hash_map.keys()),
302 .values = try wc.addStringList(map.array_hash_map.values()),
303 });
304 }
305
306 fn initArgsList(s: *Serialize, args: []const Step.Run.Arg) ![]const Configuration.Step.Run.Arg.Index {
307 const wc = s.wc;
308 const result = try s.arena.alloc(Configuration.Step.Run.Arg.Index, args.len);
309 for (result, args) |*dest, src| {
310 dest.* = try wc.addExtra(Configuration.Step.Run.Arg, switch (src) {
311 .artifact => |a| .{
312 .flags = .{
313 .tag = .artifact,
314 .prefix = a.prefix.len != 0,
315 .suffix = a.suffix.len != 0,
316 .basename = false,
317 .path = false,
318 .producer = true,
319 .generated = false,
320 .dep_file = false,
321 .make_absolute = a.make_absolute,
322 },
323 .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null },
324 .suffix = .{ .value = if (a.suffix.len != 0) try wc.addString(a.suffix) else null },
325 .basename = .{ .value = null },
326 .path = .{ .value = null },
327 .producer = .{ .value = stepIndex(s, &a.artifact.step) },
328 .generated = .{ .value = null },
329 },
330 .lazy_path => |a| .{
331 .flags = .{
332 .tag = .path_file,
333 .prefix = a.prefix.len != 0,
334 .suffix = a.suffix.len != 0,
335 .basename = false,
336 .path = true,
337 .producer = false,
338 .generated = false,
339 .dep_file = false,
340 .make_absolute = a.make_absolute,
341 },
342 .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null },
343 .suffix = .{ .value = if (a.suffix.len != 0) try wc.addString(a.suffix) else null },
344 .basename = .{ .value = null },
345 .path = .{ .value = try addLazyPath(s, a.lazy_path) },
346 .producer = .{ .value = null },
347 .generated = .{ .value = null },
348 },
349 .decorated_directory => |a| .{
350 .flags = .{
351 .tag = .path_directory,
352 .prefix = a.prefix.len != 0,
353 .suffix = a.suffix.len != 0,
354 .basename = false,
355 .path = true,
356 .producer = false,
357 .generated = false,
358 .dep_file = false,
359 .make_absolute = a.make_absolute,
360 },
361 .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null },
362 .suffix = .{ .value = if (a.suffix.len != 0) try wc.addString(a.suffix) else null },
363 .basename = .{ .value = null },
364 .path = .{ .value = try addLazyPath(s, a.lazy_path) },
365 .producer = .{ .value = null },
366 .generated = .{ .value = null },
367 },
368 .file_content => |a| .{
369 .flags = .{
370 .tag = .file_content,
371 .prefix = a.prefix.len != 0,
372 .suffix = a.suffix.len != 0,
373 .basename = false,
374 .path = true,
375 .producer = false,
376 .generated = false,
377 .dep_file = false,
378 .make_absolute = false,
379 },
380 .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null },
381 .suffix = .{ .value = if (a.suffix.len != 0) try wc.addString(a.suffix) else null },
382 .basename = .{ .value = null },
383 .path = .{ .value = try addLazyPath(s, a.lazy_path) },
384 .producer = .{ .value = null },
385 .generated = .{ .value = null },
386 },
387 .bytes => |a| .{
388 .flags = .{
389 .tag = .string,
390 .prefix = true,
391 .suffix = false,
392 .basename = false,
393 .path = false,
394 .producer = false,
395 .generated = false,
396 .dep_file = false,
397 .make_absolute = false,
398 },
399 .prefix = .{ .value = try wc.addString(a) },
400 .suffix = .{ .value = null },
401 .basename = .{ .value = null },
402 .path = .{ .value = null },
403 .producer = .{ .value = null },
404 .generated = .{ .value = null },
405 },
406 .output_file, .output_file_dep => |a, tag| .{
407 .flags = .{
408 .tag = .output_file,
409 .prefix = a.prefix.len != 0,
410 .suffix = a.suffix.len != 0,
411 .basename = a.basename.len != 0,
412 .path = false,
413 .producer = false,
414 .generated = true,
415 .dep_file = tag == .output_file_dep,
416 .make_absolute = a.make_absolute,
417 },
418 .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null },
419 .suffix = .{ .value = if (a.suffix.len != 0) try wc.addString(a.suffix) else null },
420 .basename = .{ .value = if (a.basename.len != 0) try wc.addString(a.basename) else null },
421 .path = .{ .value = null },
422 .producer = .{ .value = null },
423 .generated = .{ .value = a.generated_file },
424 },
425 .output_directory => |a| .{
426 .flags = .{
427 .tag = .output_directory,
428 .prefix = a.prefix.len != 0,
429 .suffix = a.suffix.len != 0,
430 .basename = a.basename.len != 0,
431 .path = false,
432 .producer = false,
433 .generated = true,
434 .dep_file = false,
435 .make_absolute = a.make_absolute,
436 },
437 .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null },
438 .suffix = .{ .value = if (a.suffix.len != 0) try wc.addString(a.suffix) else null },
439 .basename = .{ .value = if (a.basename.len != 0) try wc.addString(a.basename) else null },
440 .path = .{ .value = null },
441 .producer = .{ .value = null },
442 .generated = .{ .value = a.generated_file },
443 },
444 .passthru => .{
445 .flags = .{
446 .tag = .passthru,
447 .prefix = false,
448 .suffix = false,
449 .basename = false,
450 .path = false,
451 .producer = false,
452 .generated = false,
453 .dep_file = false,
454 .make_absolute = false,
455 },
456 .prefix = .{ .value = null },
457 .suffix = .{ .value = null },
458 .basename = .{ .value = null },
459 .path = .{ .value = null },
460 .producer = .{ .value = null },
461 .generated = .{ .value = null },
462 },
463 });
464 }
465 return result;
466 }
467
468 fn initIncludeDirList(
469 s: *Serialize,
470 list: []const std.Build.Module.IncludeDir,
471 ) ![]const Configuration.Module.IncludeDir {
472 const result = try s.arena.alloc(Configuration.Module.IncludeDir, list.len);
473 for (result, list) |*dest, src| dest.* = switch (src) {
474 .path => |lp| .{ .path = try addLazyPath(s, lp) },
475 .path_system => |lp| .{ .path_system = try addLazyPath(s, lp) },
476 .path_after => |lp| .{ .path_after = try addLazyPath(s, lp) },
477 .framework_path => |lp| .{ .framework_path = try addLazyPath(s, lp) },
478 .framework_path_system => |lp| .{ .framework_path_system = try addLazyPath(s, lp) },
479 .embed_path => |lp| .{ .embed_path = try addLazyPath(s, lp) },
480 .other_step => |cs| .{ .path = try addLazyPath(s, cs.installed_headers_include_tree.?.getDirectory()) },
481 .config_header_step => |chs| .{ .config_header_step = stepIndex(s, &chs.step) },
482 };
483 return result;
484 }
485
486 fn initLazyPathList(s: *Serialize, list: []const std.Build.LazyPath) ![]const Configuration.LazyPath.Index {
487 const result = try s.arena.alloc(Configuration.LazyPath.Index, list.len);
488 for (result, list) |*dest, src| dest.* = try addLazyPath(s, src);
489 return result;
490 }
491
492 fn initStringList(s: *Serialize, list: []const []const u8) ![]const Configuration.String {
493 const wc = s.wc;
494 const result = try s.arena.alloc(Configuration.String, list.len);
495 for (result, list) |*dest, src| dest.* = try wc.addString(src);
496 return result;
497 }
498
499 fn initCopyList(s: *Serialize, list: []const Step.WriteFile.Copy) ![]const Configuration.Step.WriteFile.Copy {
500 const result = try s.arena.alloc(Configuration.Step.WriteFile.Copy, list.len);
501 for (result, list) |*dest, src| dest.* = .{
502 .sub_path = src.sub_path,
503 .src_file = try s.addLazyPath(src.src_file),
504 };
505 return result;
506 }
507
508 fn initOptionalStringList(s: *Serialize, list: []const ?[]const u8) ![]const Configuration.OptionalString {
509 const wc = s.wc;
510 const result = try s.arena.alloc(Configuration.OptionalString, list.len);
511 for (result, list) |*dest, src| dest.* = try wc.addOptionalString(src);
512 return result;
513 }
514
515 fn addModule(s: *Serialize, m: *std.Build.Module) !Configuration.Module.Index {
516 if (s.module_map.get(m)) |index| return index;
517
518 const wc = s.wc;
519 const arena = s.arena;
520
521 const rpaths = try arena.alloc(Configuration.Module.RPath, m.rpaths.items.len);
522 for (rpaths, m.rpaths.items) |*dest, src| dest.* = switch (src) {
523 .lazy_path => |lp| .{ .lazy_path = try addLazyPath(s, lp) },
524 .special => |slice| .{ .special = try wc.addString(slice) },
525 };
526
527 const link_objects = try arena.alloc(Configuration.Module.LinkObject, m.link_objects.items.len);
528 for (link_objects, m.link_objects.items) |*dest, *src| dest.* = switch (src.*) {
529 .static_path => |lp| .{ .static_path = try addLazyPath(s, lp) },
530 .other_step => |cs| .{ .other_step = stepIndex(s, &cs.step) },
531 .system_lib => |*sl| .{ .system_lib = try addSystemLib(s, sl) },
532 .assembly_file => |lp| .{ .assembly_file = try addLazyPath(s, lp) },
533 .c_source_file => |csf| .{ .c_source_file = try addCSourceFile(s, csf) },
534 .c_source_files => |csf| .{ .c_source_files = try addCSourceFiles(s, csf) },
535 .win32_resource_file => |wrf| .{ .win32_resource_file = try addRcSourceFile(s, wrf) },
536 };
537
538 const frameworks = try arena.alloc(Configuration.Module.Framework, m.frameworks.entries.len);
539 for (frameworks, m.frameworks.keys(), m.frameworks.values()) |*dest, name, options| dest.* = .{
540 .flags = .{
541 .needed = options.needed,
542 .weak = options.weak,
543 },
544 .name = try wc.addString(name),
545 };
546
547 const lib_paths = try initLazyPathList(s, m.lib_paths.items);
548 const c_macros = try initStringList(s, m.c_macros.items);
549 const export_symbol_names = try initStringList(s, m.export_symbol_names);
550
551 const module_index: Configuration.Module.Index = try wc.addExtra(Configuration.Module, .{
552 .flags = .{
553 .optimize = .init(m.optimize),
554 .strip = .init(m.strip),
555 .unwind_tables = .init(m.unwind_tables),
556 .dwarf_format = .init(m.dwarf_format),
557 .single_threaded = .init(m.single_threaded),
558 .stack_protector = .init(m.stack_protector),
559 .stack_check = .init(m.stack_check),
560 .sanitize_c = .init(m.sanitize_c),
561 .sanitize_thread = .init(m.sanitize_thread),
562 .fuzz = .init(m.fuzz),
563 .code_model = m.code_model,
564 .c_macros = c_macros.len != 0,
565 .include_dirs = m.include_dirs.items.len != 0,
566 .lib_paths = lib_paths.len != 0,
567 .rpaths = rpaths.len != 0,
568 .frameworks = frameworks.len != 0,
569 .link_objects = link_objects.len != 0,
570 .export_symbol_names = export_symbol_names.len != 0,
571 },
572 .flags2 = .{
573 .valgrind = .init(m.valgrind),
574 .pic = .init(m.pic),
575 .red_zone = .init(m.red_zone),
576 .omit_frame_pointer = .init(m.omit_frame_pointer),
577 .error_tracing = .init(m.error_tracing),
578 .link_libc = .init(m.link_libc),
579 .link_libcpp = .init(m.link_libcpp),
580 .no_builtin = .init(m.no_builtin),
581 },
582 .owner = try s.builderToPackage(m.owner),
583 .root_source_file = try s.addOptionalLazyPathEnum(m.root_source_file),
584 .import_table = .invalid,
585 .resolved_target = try addOptionalResolvedTarget(wc, m.resolved_target),
586 .c_macros = .{ .slice = c_macros },
587 .lib_paths = .{ .slice = lib_paths },
588 .export_symbol_names = .{ .slice = export_symbol_names },
589 .include_dirs = .init(try s.initIncludeDirList(m.include_dirs.items)),
590 .rpaths = .init(rpaths),
591 .link_objects = .init(link_objects),
592 .frameworks = .{ .slice = frameworks },
593 });
594
595 // The import table is the only place that modules can form dependency
596 // loops. Therefore, we populate the module indexes only after adding
597 // the module to module_map.
598 try s.module_map.putNoClobber(arena, m, module_index);
599
600 var imports = try std.MultiArrayList(Configuration.ImportTable.Import).initCapacity(arena, m.import_table.entries.len);
601 imports.len = m.import_table.entries.len;
602 for (
603 imports.items(.name),
604 imports.items(.module),
605 m.import_table.keys(),
606 m.import_table.values(),
607 ) |*dest_name, *dest_module, src_name, src_module| {
608 dest_name.* = try wc.addString(src_name);
609 dest_module.* = try addModule(s, src_module);
610 }
611
612 comptime assert(std.mem.eql(u8, @typeInfo(Configuration.Module).@"struct".field_names[2], "import_table"));
613 comptime assert(@typeInfo(Configuration.Module).@"struct".field_types[2] == Configuration.ImportTable.Index);
614 assert(wc.extra.items[@intFromEnum(module_index) + 2] == @intFromEnum(Configuration.ImportTable.Index.invalid));
615 const import_table_index = try wc.addDeduped(Configuration.ImportTable, .{
616 .imports = .{ .mal = imports },
617 });
618 wc.extra.items[@intFromEnum(module_index) + 2] = @intFromEnum(import_table_index);
619
620 return module_index;
621 }
622
623 fn stepIndex(s: *const Serialize, step: *Step) Configuration.Step.Index {
624 return @enumFromInt(s.step_map.getIndex(step).?);
625 }
626};
627
628fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void {
629 const graph = b.graph;
630 const arena = graph.arena;
631 const gpa = wc.gpa;
632
633 var s: Serialize = .{ .wc = wc, .arena = arena };
634
635 try wc.path_deps.ensureTotalCapacityPrecise(gpa, graph.configure_dependencies.items.len);
636 for (
637 graph.configure_dependencies.items,
638 wc.path_deps.addManyAsSliceAssumeCapacity(graph.configure_dependencies.items.len),
639 ) |src, *dest| {
640 dest.* = .{
641 .flags = .{
642 .base = switch (src.lazy_path) {
643 .src_path, .dependency => .build_root,
644 .generated => unreachable,
645 .cwd_relative => .cwd,
646 .relative => |r| r.base,
647 },
648 .mode = src.mode,
649 },
650 .sub = switch (src.lazy_path) {
651 .src_path => |sp| try wc.addString(sp.sub_path),
652 .generated => unreachable,
653 .cwd_relative => |sub_path| try wc.addString(sub_path),
654 .dependency => |d| try wc.addString(d.sub_path),
655 .relative => |r| try wc.addString(r.sub_path),
656 },
657 .pkg = switch (src.lazy_path) {
658 .src_path => |sp| .init(try s.builderToPackage(sp.owner)),
659 .generated => unreachable,
660 .cwd_relative, .relative => .none,
661 .dependency => |d| .init(try s.builderToPackage(d.dependency.builder)),
662 },
663 };
664 }
665
666 // Starting from all top-level steps in `b`, traverse the entire step graph
667 // and add all step dependencies implied by module graphs.
668 const top_level_steps = b.top_level_steps.values();
669 try s.step_map.ensureUnusedCapacity(arena, top_level_steps.len);
670 for (top_level_steps) |tls| {
671 s.step_map.putAssumeCapacityNoClobber(&tls.step, {});
672 }
673 {
674 while (wc.steps.items.len < s.step_map.count()) {
675 const step = s.step_map.keys()[wc.steps.items.len];
676
677 // Set up any implied dependencies for this step. It's important that we do this first, so
678 // that the loop below discovers steps implied by the module graph.
679 try createModuleDependenciesForStep(step);
680
681 try s.step_map.ensureUnusedCapacity(arena, step.dependencies.items.len);
682 for (step.dependencies.items) |other_step| {
683 s.step_map.putAssumeCapacity(other_step, {});
684 }
685
686 // Add and then de-duplicate dependencies.
687 const dep_steps = try arena.alloc(Configuration.Step.Index, step.dependencies.items.len);
688 for (dep_steps, step.dependencies.items) |*dest, src|
689 dest.* = @enumFromInt(s.step_map.getIndex(src).?);
690
691 const deps: Configuration.Deps.Index = try wc.addDeduped(Configuration.Deps, .{
692 .steps = .{ .slice = dep_steps },
693 });
694
695 try wc.steps.ensureTotalCapacity(gpa, s.step_map.entries.capacity);
696 wc.steps.appendAssumeCapacity(.{
697 .name = try wc.addString(step.name),
698 .owner = try s.builderToPackage(step.owner),
699 .deps = deps,
700 .max_rss = .fromBytes(step.max_rss),
701 .extended = @enumFromInt(switch (step.tag) {
702 .top_level => e: {
703 const top_level: *Step.TopLevel = @fieldParentPtr("step", step);
704 break :e try wc.addExtraErased(Configuration.Step.TopLevel, .{
705 .description = try wc.addString(top_level.description),
706 });
707 },
708 .compile => e: {
709 const c: *Step.Compile = @fieldParentPtr("step", step);
710 const installed_headers: []u32 = try arena.alloc(u32, c.installed_headers.items.len);
711 for (installed_headers, c.installed_headers.items) |*dst, src| switch (src) {
712 .file => |file| {
713 dst.* = try wc.addExtraErased(Configuration.Step.Compile.InstalledHeader.File, .{
714 .source = try s.addLazyPath(file.source),
715 .dest_sub_path = try wc.addString(file.dest_rel_path),
716 });
717 },
718 .directory => |directory| {
719 const include_extensions = directory.options.include_extensions orelse &.{};
720 dst.* = try wc.addExtraErased(Configuration.Step.Compile.InstalledHeader.Directory, .{
721 .flags = .{
722 .include_extensions = include_extensions.len != 0,
723 .exclude_extensions = directory.options.exclude_extensions.len != 0,
724 },
725 .source = try s.addLazyPath(directory.source),
726 .dest_sub_path = try wc.addString(directory.dest_rel_path),
727 .exclude_extensions = .{ .slice = try s.initStringList(directory.options.exclude_extensions) },
728 .include_extensions = .{ .slice = try s.initStringList(include_extensions) },
729 });
730 },
731 };
732
733 break :e try wc.addExtraErased(Configuration.Step.Compile, .{
734 .flags = .{
735 .filters_len = c.filters.len != 0,
736 .installed_headers_len = installed_headers.len != 0,
737 .force_undefined_symbols_len = c.force_undefined_symbols.entries.len != 0,
738
739 .verbose_link = c.verbose_link,
740 .verbose_cc = c.verbose_cc,
741 .rdynamic = c.rdynamic,
742 .import_memory = c.import_memory,
743 .export_memory = c.export_memory,
744 .import_symbols = c.import_symbols,
745 .import_table = c.import_table,
746 .export_table = c.export_table,
747 .shared_memory = c.shared_memory,
748 .link_eh_frame_hdr = c.link_eh_frame_hdr,
749 .link_emit_relocs = c.link_emit_relocs,
750 .link_function_sections = c.link_function_sections,
751 .link_data_sections = c.link_data_sections,
752 .linker_dynamicbase = c.linker_dynamicbase,
753 .link_z_notext = c.link_z_notext,
754 .link_z_relro = c.link_z_relro,
755 .link_z_lazy = c.link_z_lazy,
756 .link_z_defs = c.link_z_defs,
757 .headerpad_max_install_names = c.headerpad_max_install_names,
758 .dead_strip_dylibs = c.dead_strip_dylibs,
759 .force_load_objc = c.force_load_objc,
760 .discard_local_symbols = c.discard_local_symbols,
761 .mingw_unicode_entry_point = c.mingw_unicode_entry_point,
762 },
763 .flags2 = .{
764 .pie = .init(c.pie),
765 .formatted_panics = .init(c.formatted_panics),
766 .bundle_compiler_rt = .init(c.bundle_compiler_rt),
767 .bundle_ubsan_rt = .init(c.bundle_ubsan_rt),
768 .each_lib_rpath = .init(c.each_lib_rpath),
769 .link_gc_sections = .init(c.link_gc_sections),
770 .linker_allow_shlib_undefined = .init(c.linker_allow_shlib_undefined),
771 .linker_allow_undefined_version = .init(c.linker_allow_undefined_version),
772 .linker_enable_new_dtags = .init(c.linker_enable_new_dtags),
773 .dll_export_fns = .init(c.dll_export_fns),
774 .use_llvm = .init(c.use_llvm),
775 .use_lld = .init(c.use_lld),
776 .use_new_linker = .init(c.use_new_linker),
777 .allow_so_scripts = .init(c.allow_so_scripts),
778 .sanitize_coverage_trace_pc_guard = .init(c.sanitize_coverage_trace_pc_guard),
779 .linkage = .init(c.linkage),
780 },
781 .flags3 = .{
782 .is_linking_libc = c.is_linking_libc,
783 .is_linking_libcpp = c.is_linking_libcpp,
784 .version = c.version != null,
785 .compress_debug_sections = c.compress_debug_sections,
786 .initial_memory = c.initial_memory != null,
787 .max_memory = c.max_memory != null,
788 .kind = c.kind,
789 .global_base = c.global_base != null,
790 .test_runner = if (c.test_runner) |tr| switch (tr.mode) {
791 .simple => .simple,
792 .server => .server,
793 } else .default,
794 .wasi_exec_model = .init(c.wasi_exec_model),
795 .win32_manifest = c.win32_manifest != null,
796 .win32_module_definition = c.win32_module_definition != null,
797 .zig_lib_dir = c.zig_lib_dir != null,
798 .rc_includes = c.rc_includes,
799 .image_base = c.image_base != null,
800 .build_id = .init(c.build_id),
801 .entry = switch (c.entry) {
802 .default => .default,
803 .disabled => .disabled,
804 .enabled => .enabled,
805 .symbol_name => .symbol_name,
806 },
807 .lto = .init(c.lto),
808 .subsystem = .init(c.subsystem),
809 },
810 .flags4 = .{
811 .libc_file = c.libc_file != null,
812 .link_z_common_page_size = c.link_z_common_page_size != null,
813 .link_z_max_page_size = c.link_z_max_page_size != null,
814 .pagezero_size = c.pagezero_size != null,
815 .stack_size = c.stack_size != null,
816 .headerpad_size = c.headerpad_size != null,
817 .error_limit = c.error_limit != null,
818 .install_name = c.install_name != null,
819 .entitlements = c.entitlements != null,
820 .expect_errors = if (c.expect_errors) |x| switch (x) {
821 .contains => .contains,
822 .exact => .exact,
823 .starts_with => .starts_with,
824 .stderr_contains => .stderr_contains,
825 } else .none,
826 .linker_script = c.linker_script != null,
827 .version_script = c.version_script != null,
828 .emit_directory = c.emit_directory != .none,
829 .generated_docs = c.generated_docs != .none,
830 .generated_asm = c.generated_asm != .none,
831 .generated_bin = c.generated_bin != .none,
832 .generated_pdb = c.generated_pdb != .none,
833 .generated_implib = c.generated_implib != .none,
834 .generated_llvm_bc = c.generated_llvm_bc != .none,
835 .generated_llvm_ir = c.generated_llvm_ir != .none,
836 .generated_h = c.generated_h != .none,
837 .incremental = .init(c.incremental),
838 },
839 .root_module = try s.addModule(c.root_module),
840 .root_name = try wc.addString(c.name),
841 .linker_script = .{ .value = try s.addOptionalLazyPath(c.linker_script) },
842 .version_script = .{ .value = try s.addOptionalLazyPath(c.version_script) },
843 .zig_lib_dir = .{ .value = try s.addOptionalLazyPath(c.zig_lib_dir) },
844 .libc_file = .{ .value = try s.addOptionalLazyPath(c.libc_file) },
845 .win32_manifest = .{ .value = try s.addOptionalLazyPath(c.win32_manifest) },
846 .win32_module_definition = .{ .value = try s.addOptionalLazyPath(c.win32_module_definition) },
847 .entitlements = .{ .value = try s.addOptionalLazyPath(c.entitlements) },
848 .version = .{ .value = try s.addOptionalSemVer(c.version) },
849 .install_name = .{ .value = try s.addOptionalString(c.install_name) },
850 .initial_memory = .{ .value = c.initial_memory },
851 .max_memory = .{ .value = c.max_memory },
852 .global_base = .{ .value = c.global_base },
853 .image_base = .{ .value = c.image_base },
854 .link_z_common_page_size = .{ .value = c.link_z_common_page_size },
855 .link_z_max_page_size = .{ .value = c.link_z_max_page_size },
856 .pagezero_size = .{ .value = c.pagezero_size },
857 .stack_size = .{ .value = c.stack_size },
858 .headerpad_size = .{ .value = c.headerpad_size },
859 .error_limit = .{ .value = c.error_limit },
860 .entry = .{ .value = switch (c.entry) {
861 .symbol_name => |name| try wc.addString(name),
862 .default, .disabled, .enabled => null,
863 } },
864 .build_id = .{ .value = if (c.build_id) |id| switch (id) {
865 .hexstring => |*hexstring| try wc.addString(hexstring.toSlice()),
866 .none, .fast, .uuid, .sha1, .md5 => null,
867 } else null },
868 .filters = .{ .slice = try s.initStringList(c.filters) },
869 .installed_headers = .initErased(installed_headers),
870 .force_undefined_symbols = .{ .slice = try s.initStringList(c.force_undefined_symbols.keys()) },
871 .expect_errors = .{ .u = if (c.expect_errors) |x| switch (x) {
872 .contains => |slice| .{ .contains = try wc.addString(slice) },
873 .exact => |exact| .{ .exact = .{ .slice = try s.initStringList(exact) } },
874 .starts_with => |slice| .{ .starts_with = try wc.addString(slice) },
875 .stderr_contains => |slice| .{ .stderr_contains = try wc.addString(slice) },
876 } else .none },
877 .test_runner = .{ .u = if (c.test_runner) |tr| switch (tr.mode) {
878 .simple => .{ .simple = try s.addLazyPath(tr.path) },
879 .server => .{ .server = try s.addLazyPath(tr.path) },
880 } else .default },
881
882 .emit_directory = .{ .value = c.emit_directory.unwrap() },
883 .generated_docs = .{ .value = c.generated_docs.unwrap() },
884 .generated_asm = .{ .value = c.generated_asm.unwrap() },
885 .generated_bin = .{ .value = c.generated_bin.unwrap() },
886 .generated_pdb = .{ .value = c.generated_pdb.unwrap() },
887 .generated_implib = .{ .value = c.generated_implib.unwrap() },
888 .generated_llvm_bc = .{ .value = c.generated_llvm_bc.unwrap() },
889 .generated_llvm_ir = .{ .value = c.generated_llvm_ir.unwrap() },
890 .generated_h = .{ .value = c.generated_h.unwrap() },
891 });
892 },
893 .install_artifact => e: {
894 const ia: *Step.InstallArtifact = @fieldParentPtr("step", step);
895 break :e try wc.addExtraErased(Configuration.Step.InstallArtifact, .{
896 .flags = .{
897 .dylib_symlinks = ia.dylib_symlinks,
898 .bin_dir = ia.dest_dir != null,
899 .implib_dir = ia.implib_dir != null,
900 .pdb_dir = ia.pdb_dir != null,
901 .h_dir = ia.h_dir != null,
902 .bin_sub_path = ia.dest_sub_path != null,
903 },
904 .bin_dir = .{ .value = try addInstallDirDefaultNull(wc, ia.dest_dir) },
905 .implib_dir = .{ .value = try addInstallDirDefaultNull(wc, ia.implib_dir) },
906 .pdb_dir = .{ .value = try addInstallDirDefaultNull(wc, ia.pdb_dir) },
907 .h_dir = .{ .value = try addInstallDirDefaultNull(wc, ia.h_dir) },
908 .bin_sub_path = .{ .value = try s.addOptionalString(ia.dest_sub_path) },
909 });
910 },
911 .install_file => e: {
912 const sif: *Step.InstallFile = @fieldParentPtr("step", step);
913 break :e try wc.addExtraErased(Configuration.Step.InstallFile, .{
914 .source = try s.addLazyPath(sif.source),
915 .dest_dir = try addInstallDir(wc, sif.dir),
916 .dest_sub_path = try wc.addString(sif.dest_rel_path),
917 });
918 },
919 .install_dir => e: {
920 const sid: *Step.InstallDir = @fieldParentPtr("step", step);
921 const dest_sub_path: ?[]const u8 = if (sid.options.install_subdir.len != 0)
922 sid.options.install_subdir
923 else
924 null;
925 const include_extensions = sid.options.include_extensions orelse &.{};
926 break :e try wc.addExtraErased(Configuration.Step.InstallDir, .{
927 .flags = .{
928 .dest_sub_path = dest_sub_path != null,
929 .exclude_extensions = sid.options.exclude_extensions.len != 0,
930 .include_extensions = include_extensions.len != 0,
931 .include_extensions_active = sid.options.include_extensions != null,
932 .blank_extensions = sid.options.blank_extensions.len != 0,
933 },
934 .source_dir = try s.addLazyPath(sid.options.source_dir),
935 .dest_dir = try addInstallDir(wc, sid.options.install_dir),
936 .dest_sub_path = .{ .value = try s.addOptionalString(dest_sub_path) },
937 .exclude_extensions = .{ .slice = try s.initStringList(sid.options.exclude_extensions) },
938 .include_extensions = .{ .slice = try s.initStringList(include_extensions) },
939 .blank_extensions = .{ .slice = try s.initStringList(sid.options.blank_extensions) },
940 });
941 },
942 .fail => e: {
943 const sf: *Step.Fail = @fieldParentPtr("step", step);
944 break :e try wc.addExtraErased(Configuration.Step.Fail, .{
945 .msg = sf.error_msg,
946 });
947 },
948 .find_program => e: {
949 const fp: *Step.FindProgram = @fieldParentPtr("step", step);
950 break :e try wc.addExtraErased(Configuration.Step.FindProgram, .{
951 .names = fp.names,
952 .found_path = fp.found_path,
953 });
954 },
955 .fmt => e: {
956 const sf: *Step.Fmt = @fieldParentPtr("step", step);
957 break :e try wc.addExtraErased(Configuration.Step.Fmt, .{
958 .flags = .{
959 .paths = sf.paths.len != 0,
960 .exclude_paths = sf.exclude_paths.len != 0,
961 .check = sf.check,
962 },
963 .paths = .{ .slice = try s.initLazyPathList(sf.paths) },
964 .exclude_paths = .{ .slice = try s.initLazyPathList(sf.exclude_paths) },
965 });
966 },
967 .translate_c => e: {
968 const tc: *Step.TranslateC = @fieldParentPtr("step", step);
969
970 const system_libs = try arena.alloc(Configuration.SystemLib.Index, tc.system_libs.items.len);
971 for (system_libs, tc.system_libs.items) |*dest, *src| dest.* = try s.addSystemLib(src);
972
973 break :e try wc.addExtraErased(Configuration.Step.TranslateC, .{
974 .flags = .{
975 .include_dirs = tc.include_dirs.items.len != 0,
976 .system_libs = system_libs.len != 0,
977 .c_macros = tc.c_macros.items.len != 0,
978 .link_libc = tc.link_libc,
979 .optimize = .init(tc.optimize),
980 },
981 .src_path = try s.addLazyPath(tc.source),
982 .output_file = tc.output_file,
983 .include_dirs = .init(try s.initIncludeDirList(tc.include_dirs.items)),
984 .system_libs = .{ .slice = system_libs },
985 .c_macros = .{ .slice = tc.c_macros.items },
986 .target = try addOptionalResolvedTarget(wc, tc.target),
987 });
988 },
989 .write_file => e: {
990 const wf: *Step.WriteFile = @fieldParentPtr("step", step);
991
992 const directories = try arena.alloc(
993 Configuration.Step.WriteFile.Directory,
994 wf.directories.items.len,
995 );
996 for (directories, wf.directories.items) |*dest, src| dest.* = .{
997 .sub_path = src.sub_path,
998 .src_path = try s.addLazyPath(src.src_path),
999 .exclude_extensions = src.exclude_extensions,
1000 .include_extensions = src.include_extensions,
1001 };
1002
1003 break :e try wc.addExtraErased(Configuration.Step.WriteFile, .{
1004 .flags = .{
1005 .embeds = wf.embeds.items.len != 0,
1006 .copies = wf.copies.items.len != 0,
1007 .directories = directories.len != 0,
1008 .mode = switch (wf.mode) {
1009 .whole_cached => .whole_cached,
1010 .tmp => .tmp,
1011 .mutate => .mutate,
1012 },
1013 },
1014 .generated_directory = wf.generated_directory,
1015 .embeds = .{ .slice = wf.embeds.items },
1016 .copies = .{ .slice = try s.initCopyList(wf.copies.items) },
1017 .directories = .{ .slice = directories },
1018 .mutate_path = .{ .value = switch (wf.mode) {
1019 .mutate => |lp| try s.addLazyPath(lp),
1020 .whole_cached, .tmp => null,
1021 } },
1022 });
1023 },
1024 .update_source_files => e: {
1025 const usf: *Step.UpdateSourceFiles = @fieldParentPtr("step", step);
1026 break :e try wc.addExtraErased(Configuration.Step.UpdateSourceFiles, .{
1027 .flags = .{
1028 .embeds = usf.embeds.items.len != 0,
1029 .copies = usf.copies.items.len != 0,
1030 },
1031 .embeds = .{ .slice = usf.embeds.items },
1032 .copies = .{ .slice = try s.initCopyList(usf.copies.items) },
1033 });
1034 },
1035 .run => e: {
1036 const run: *Step.Run = @fieldParentPtr("step", step);
1037 var expect_stderr_exact: ?Configuration.Bytes = null;
1038 var expect_stdout_exact: ?Configuration.Bytes = null;
1039 var expect_stderr_match: std.ArrayList(Configuration.Bytes) = .empty;
1040 var expect_stdout_match: std.ArrayList(Configuration.Bytes) = .empty;
1041 var expect_term: ?struct {
1042 status: Configuration.Step.Run.ExpectTermStatus,
1043 value: u32,
1044 } = null;
1045 var expect_stderr_snapshot: ?Configuration.LazyPath.Index = null;
1046 var expect_stdout_snapshot: ?Configuration.LazyPath.Index = null;
1047 switch (run.stdio) {
1048 .check => |checks| for (checks.items) |check| switch (check) {
1049 .expect_stderr_exact => |bytes| expect_stderr_exact = try wc.addBytes(bytes),
1050 .expect_stdout_exact => |bytes| expect_stdout_exact = try wc.addBytes(bytes),
1051 .expect_stderr_match => |bytes| {
1052 try expect_stderr_match.append(arena, try wc.addBytes(bytes));
1053 },
1054 .expect_stdout_match => |bytes| {
1055 try expect_stdout_match.append(arena, try wc.addBytes(bytes));
1056 },
1057 .expect_term => |t| expect_term = switch (t) {
1058 .exited => |x| .{ .status = .exited, .value = x },
1059 .signal => |x| .{ .status = .signal, .value = @intFromEnum(x) },
1060 .stopped => |x| .{ .status = .stopped, .value = @intFromEnum(x) },
1061 .unknown => |x| .{ .status = .unknown, .value = x },
1062 },
1063 .expect_stderr_snapshot => |path| expect_stderr_snapshot = try s.addLazyPath(path),
1064 .expect_stdout_snapshot => |path| expect_stdout_snapshot = try s.addLazyPath(path),
1065 },
1066 else => {},
1067 }
1068
1069 break :e try wc.addExtraErased(Configuration.Step.Run, .{
1070 .flags = .{
1071 .disable_zig_progress = run.disable_zig_progress,
1072 .skip_foreign_checks = run.skip_foreign_checks,
1073 .failing_to_execute_foreign_is_an_error = run.failing_to_execute_foreign_is_an_error,
1074 .has_side_effects = run.has_side_effects,
1075 .test_runner_mode = run.test_runner_mode,
1076 .color = run.color,
1077 .stdio = switch (run.stdio) {
1078 .infer_from_args => .infer_from_args,
1079 .inherit => .inherit,
1080 .check => .check,
1081 .zig_test => .zig_test,
1082 },
1083 .stdin = switch (run.stdin) {
1084 .none => .none,
1085 .bytes => .bytes,
1086 .lazy_path => .lazy_path,
1087 },
1088 .stdout_trim_whitespace = if (run.captured_stdout) |cs| cs.trim_whitespace else .none,
1089 .stderr_trim_whitespace = if (run.captured_stderr) |cs| cs.trim_whitespace else .none,
1090 .stdio_limit = run.stdio_limit != .unlimited,
1091 .producer = run.producer != null,
1092 .cwd = run.cwd != null,
1093 .captured_stdout = run.captured_stdout != null,
1094 .captured_stderr = run.captured_stderr != null,
1095 .environ_map = run.environ_map != null,
1096 },
1097 .flags2 = .{
1098 .expect_stderr_exact = expect_stderr_exact != null,
1099 .expect_stdout_exact = expect_stdout_exact != null,
1100 .expect_stderr_match = expect_stderr_match.items.len != 0,
1101 .expect_stdout_match = expect_stdout_match.items.len != 0,
1102 .expect_term = expect_term != null,
1103 .expect_term_status = if (expect_term) |t| t.status else .exited,
1104 .expect_stderr_snapshot = expect_stderr_snapshot != null,
1105 .expect_stdout_snapshot = expect_stdout_snapshot != null,
1106 },
1107 .file_inputs = .{ .slice = try s.initLazyPathList(run.file_inputs.items) },
1108 .args = .{ .slice = try s.initArgsList(run.argv.items) },
1109 .cwd = .{ .value = try s.addOptionalLazyPath(run.cwd) },
1110 .preopen_names = .{ .slice = try s.initStringList(run.preopens.keys()) },
1111 .preopen_paths = .{ .slice = try s.initLazyPathList(run.preopens.values()) },
1112 .captured_stdout = .{ .value = if (run.captured_stdout) |cs| .{
1113 .basename = try wc.addString(cs.basename),
1114 .generated_file = cs.generated_file,
1115 } else null },
1116 .captured_stderr = .{ .value = if (run.captured_stderr) |cs| .{
1117 .basename = try wc.addString(cs.basename),
1118 .generated_file = cs.generated_file,
1119 } else null },
1120 .environ_map = .{ .value = try s.addEnvironMap(run.environ_map) },
1121 .expect_term_value = .{ .value = if (expect_term) |t| t.value else null },
1122 .stdio_limit = .{ .value = run.stdio_limit.toInt64() },
1123 .producer = .{ .value = if (run.producer) |cs| s.stepIndex(&cs.step) else null },
1124 .expect_stderr_exact = .{ .value = if (expect_stderr_exact) |bytes| bytes else null },
1125 .expect_stdout_exact = .{ .value = if (expect_stdout_exact) |bytes| bytes else null },
1126 .expect_stderr_match = .{ .slice = expect_stderr_match.items },
1127 .expect_stdout_match = .{ .slice = expect_stdout_match.items },
1128 .expect_stderr_snapshot = .{ .value = expect_stderr_snapshot orelse null },
1129 .expect_stdout_snapshot = .{ .value = expect_stdout_snapshot orelse null },
1130 .stdin = .{ .u = switch (run.stdin) {
1131 .none => .none,
1132 .bytes => |bytes| .{ .bytes = try wc.addBytes(bytes) },
1133 .lazy_path => |lp| .{ .lazy_path = try s.addLazyPath(lp) },
1134 } },
1135 });
1136 },
1137 .check_file => e: {
1138 const cf: *Step.CheckFile = @fieldParentPtr("step", step);
1139 break :e try wc.addExtraErased(Configuration.Step.CheckFile, .{
1140 .flags = .{
1141 .expected_exact = cf.expected_exact != null,
1142 .expected_matches = cf.expected_matches.len != 0,
1143 .max_bytes = cf.max_bytes != null,
1144 },
1145 .file = try s.addLazyPath(cf.file),
1146 .expected_exact = .{ .value = cf.expected_exact },
1147 .expected_matches = .{ .slice = cf.expected_matches },
1148 .max_bytes = .{ .value = cf.max_bytes },
1149 });
1150 },
1151 .config_header => e: {
1152 const ch: *Step.ConfigHeader = @fieldParentPtr("step", step);
1153 const lazy_path: ?std.Build.LazyPath = ch.style.getPath();
1154 const pairs = try arena.alloc(Configuration.Step.ConfigHeader.Value.Pair, ch.values.count());
1155 for (pairs, ch.values.keys(), ch.values.values()) |*pair, key, value| pair.* = .{
1156 .key = try wc.addString(key),
1157 .index = switch (value) {
1158 .undef => .undef,
1159 .defined => .defined,
1160 .boolean => |x| switch (x) {
1161 false => .bool_false,
1162 true => .bool_true,
1163 },
1164 .int => |x| switch (x) {
1165 0 => .int_0,
1166 1 => .int_1,
1167 else => try wc.addExtra(Configuration.Step.ConfigHeader.Value, .initSigned(x)),
1168 },
1169 .ident => |x| try wc.addExtra(Configuration.Step.ConfigHeader.Value, .{
1170 .flags = .{
1171 .tag = .ident,
1172 .small = 0,
1173 },
1174 .i64 = .{ .value = null },
1175 .u64 = .{ .value = null },
1176 .ident = .{ .value = try wc.addString(x) },
1177 .string = .{ .value = null },
1178 }),
1179 .string => |x| try wc.addExtra(Configuration.Step.ConfigHeader.Value, .{
1180 .flags = .{
1181 .tag = .string,
1182 .small = 0,
1183 },
1184 .i64 = .{ .value = null },
1185 .u64 = .{ .value = null },
1186 .ident = .{ .value = null },
1187 .string = .{ .value = try wc.addString(x) },
1188 }),
1189 },
1190 };
1191 break :e try wc.addExtraErased(Configuration.Step.ConfigHeader, .{
1192 .flags = .{
1193 .template_file = lazy_path != null,
1194 .style = .init(ch.style),
1195 .input_size_limit = ch.input_size_limit != null,
1196 .include_guard = ch.include_guard != .none,
1197 },
1198 .template_file = .{ .value = try s.addOptionalLazyPath(lazy_path) },
1199 .generated_dir = ch.generated_dir,
1200 .input_size_limit = .{ .value = ch.input_size_limit },
1201 .include_path = try wc.addString(ch.include_path),
1202 .include_guard = .{ .value = ch.include_guard.unwrap() },
1203 .values = .{ .slice = pairs },
1204 });
1205 },
1206 .obj_copy => e: {
1207 const oc: *Step.ObjCopy = @fieldParentPtr("step", step);
1208
1209 const debug_basename: ?Configuration.String = if (oc.debug_file) |df|
1210 df.basename.unwrap()
1211 else
1212 null;
1213
1214 const debug_file: ?Configuration.GeneratedFileIndex = if (oc.debug_file) |df|
1215 df.output_file
1216 else
1217 null;
1218
1219 const add_sections = try arena.alloc(
1220 Configuration.Step.ObjCopy.AddSection,
1221 oc.add_sections.items.len,
1222 );
1223 for (add_sections, oc.add_sections.items) |*dest, src| dest.* = .{
1224 .section_name = src.section_name,
1225 .file_path = try s.addLazyPath(src.file_path),
1226 };
1227
1228 break :e try wc.addExtraErased(Configuration.Step.ObjCopy, .{
1229 .flags = .{
1230 .basename = oc.basename != .none,
1231 .debug_file = debug_file != null,
1232 .debug_basename = debug_basename != null,
1233 .format = .init(oc.format),
1234 .strip = oc.strip,
1235 .compress_debug = oc.compress_debug,
1236 .only_section = oc.only_section != .none,
1237 .pad_to = oc.pad_to != null,
1238 .add_section = add_sections.len != 0,
1239 .update_section = oc.update_sections.items.len != 0,
1240 },
1241 .input_file = try s.addLazyPath(oc.input_file),
1242 .output_file = oc.output_file,
1243 .basename = .{ .value = oc.basename.unwrap() },
1244 .debug_file = .{ .value = debug_file },
1245 .debug_basename = .{ .value = debug_basename },
1246 .only_section = .{ .value = oc.only_section.unwrap() },
1247 .pad_to = .{ .value = oc.pad_to },
1248 .add_section = .{ .slice = add_sections },
1249 .update_section = .{ .slice = oc.update_sections.items },
1250 });
1251 },
1252 .options => e: {
1253 const so: *Step.Options = @fieldParentPtr("step", step);
1254
1255 const args = try arena.alloc(Configuration.Step.Options.Arg, so.args.items.len);
1256 for (args, so.args.items) |*dest, src| dest.* = .{
1257 .name = src.name,
1258 .path = try s.addLazyPath(src.path),
1259 };
1260
1261 break :e try wc.addExtraErased(Configuration.Step.Options, .{
1262 .flags = .{
1263 .args = so.args.items.len != 0,
1264 },
1265 .generated_file = so.generated_file,
1266 .contents = try wc.addBytes(so.contents.items),
1267 .args = .{ .slice = args },
1268 });
1269 },
1270 }),
1271 });
1272 }
1273 }
1274
1275 try wc.unlazy_deps.ensureUnusedCapacity(gpa, graph.needed_lazy_dependencies.keys().len);
1276 for (graph.needed_lazy_dependencies.keys()) |k| {
1277 wc.unlazy_deps.appendAssumeCapacity(try wc.addString(k));
1278 }
1279
1280 try wc.write(writer, .{
1281 .default_step = s.stepIndex(b.default_step),
1282 .generated_files_len = @intCast(graph.generated_files.items.len),
1283 .poisoned = switch (graph.cache_poison) {
1284 .pure, .disallowed, .ignored => false,
1285 .poisoned => true,
1286 },
1287 });
1288}
1289
1290fn addOptionalResolvedTarget(
1291 wc: *Configuration.Wip,
1292 optional_resolved_target: ?std.Build.ResolvedTarget,
1293) !Configuration.ResolvedTarget.OptionalIndex {
1294 const resolved_target = optional_resolved_target orelse return .none;
1295 return .init(try wc.addDeduped(Configuration.ResolvedTarget, .{
1296 .query = try wc.addTargetQuery(&resolved_target.query),
1297 .result = try wc.addTarget(resolved_target.result),
1298 }));
1299}
1300
1301fn addInstallDir(wc: *Configuration.Wip, install_dir: ?std.Build.InstallDir) !Configuration.InstallDestDir {
1302 switch (install_dir orelse return .none) {
1303 .prefix => return .prefix,
1304 .lib => return .lib,
1305 .bin => return .bin,
1306 .header => return .header,
1307 .custom => |sub_path| return .initCustom(try wc.addString(sub_path)),
1308 }
1309}
1310
1311fn addInstallDirDefaultNull(wc: *Configuration.Wip, install_dir: ?std.Build.InstallDir) !?Configuration.InstallDestDir {
1312 return try addInstallDir(wc, install_dir orelse return null);
1313}
1314
1315/// If the given `Step` is a `Step.Compile`, adds any dependencies for that step which
1316/// are implied by the module graph rooted at `step.cast(Step.Compile).?.root_module`.
1317fn createModuleDependenciesForStep(step: *Step) Allocator.Error!void {
1318 const root_module = if (step.cast(Step.Compile)) |cs| root: {
1319 break :root cs.root_module;
1320 } else return; // not a compile step so no module dependencies
1321
1322 // Starting from `root_module`, discover all modules in this graph.
1323 const modules = root_module.getGraph().modules;
1324
1325 // For each of those modules, set up the implied step dependencies.
1326 for (modules) |mod| {
1327 if (mod.root_source_file) |lp| lp.addStepDependencies(step);
1328 for (mod.include_dirs.items) |include_dir| switch (include_dir) {
1329 .path,
1330 .path_system,
1331 .path_after,
1332 .framework_path,
1333 .framework_path_system,
1334 .embed_path,
1335 => |lp| lp.addStepDependencies(step),
1336
1337 .other_step => |other| {
1338 other.getEmittedIncludeTree().addStepDependencies(step);
1339 step.dependOn(&other.step);
1340 },
1341
1342 .config_header_step => |other| step.dependOn(&other.step),
1343 };
1344 for (mod.lib_paths.items) |lp| lp.addStepDependencies(step);
1345 for (mod.rpaths.items) |rpath| switch (rpath) {
1346 .lazy_path => |lp| lp.addStepDependencies(step),
1347 .special => {},
1348 };
1349 for (mod.link_objects.items) |link_object| switch (link_object) {
1350 .static_path,
1351 .assembly_file,
1352 => |lp| lp.addStepDependencies(step),
1353 .other_step => |other| step.dependOn(&other.step),
1354 .system_lib => {},
1355 .c_source_file => |source| source.file.addStepDependencies(step),
1356 .c_source_files => |source_files| source_files.root.addStepDependencies(step),
1357 .win32_resource_file => |rc_source| {
1358 rc_source.file.addStepDependencies(step);
1359 for (rc_source.include_paths) |lp| lp.addStepDependencies(step);
1360 },
1361 };
1362 }
1363}
1364
1365fn nextArg(args: []const [:0]const u8, idx: *usize) ?[:0]const u8 {158fn nextArg(args: []const [:0]const u8, idx: *usize) ?[:0]const u8 {
1366 if (idx.* >= args.len) return null;159 if (idx.* >= args.len) return null;
1367 defer idx.* += 1;160 defer idx.* += 1;
...@@ -1381,69 +174,7 @@ fn expectArgOrFatal(args: []const [:0]const u8, index_ptr: *usize, first: []cons...@@ -1381,69 +174,7 @@ fn expectArgOrFatal(args: []const [:0]const u8, index_ptr: *usize, first: []cons
1381 return arg;174 return arg;
1382}175}
1383176
1384const ErrorStyle = enum {
1385 verbose,
1386 minimal,
1387 verbose_clear,
1388 minimal_clear,
1389 fn verboseContext(s: ErrorStyle) bool {
1390 return switch (s) {
1391 .verbose, .verbose_clear => true,
1392 .minimal, .minimal_clear => false,
1393 };
1394 }
1395 fn clearOnUpdate(s: ErrorStyle) bool {
1396 return switch (s) {
1397 .verbose, .minimal => false,
1398 .verbose_clear, .minimal_clear => true,
1399 };
1400 }
1401};
1402const MultilineErrors = enum { indent, newline, none };
1403const Summary = enum { all, new, failures, line, none };
1404
1405fn fatalWithHint(comptime f: []const u8, args: anytype) noreturn {177fn fatalWithHint(comptime f: []const u8, args: anytype) noreturn {
1406 log.info("to access the help menu: zig build -h", .{});178 log.info("to access the help menu: zig build -h", .{});
1407 fatal(f, args);179 fatal(f, args);
1408}180}
1409
1410fn serializeSystemIntegrationOptions(graph: *std.Build.Graph, wc: *Configuration.Wip) Allocator.Error!void {
1411 const gpa = wc.gpa;
1412
1413 var bad = false;
1414 try wc.system_integrations.ensureTotalCapacityPrecise(gpa, graph.system_integration_options.entries.len);
1415 for (graph.system_integration_options.keys(), graph.system_integration_options.values()) |k, v| {
1416 wc.system_integrations.appendAssumeCapacity(.{
1417 .name = try wc.addString(k),
1418 .status = switch (v) {
1419 .user_disabled, .user_enabled => x: {
1420 // The user tried to enable or disable a system library integration, but
1421 // the configure script did not recognize that option.
1422 log.err("system integration name not recognized by configure script: {s}", .{k});
1423 bad = true;
1424 break :x .disabled;
1425 },
1426 .declared_disabled => .disabled,
1427 .declared_enabled => .enabled,
1428 },
1429 });
1430 }
1431 if (bad) {
1432 log.info("help menu contains available options: zig build -h", .{});
1433 process.exit(1);
1434 }
1435}
1436
1437fn serializePackageOptions(b: *std.Build, wc: *Configuration.Wip) Allocator.Error!void {
1438 const gpa = wc.gpa;
1439
1440 try wc.available_options.ensureTotalCapacityPrecise(gpa, b.available_options_map.count());
1441 for (b.available_options_map.keys(), b.available_options_map.values()) |name, *opt| {
1442 wc.available_options.appendAssumeCapacity(.{
1443 .name = try wc.addString(name),
1444 .description = try wc.addString(opt.description),
1445 .type = opt.type_id,
1446 .enum_options = if (opt.enum_options) |enum_vals| .init(try wc.addStringList(enum_vals)) else .none,
1447 });
1448 }
1449}
lib/std/Build.zig+2
...@@ -23,6 +23,8 @@ pub const Module = @import("Build/Module.zig");...@@ -23,6 +23,8 @@ pub 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("Build/Configuration.zig");25pub const Configuration = @import("Build/Configuration.zig");
26/// Logic that transforms `Build` into `Configuration`.
27pub const Serialize = @import("Build/Serialize.zig");
2628
27/// Shared state among all Build instances.29/// Shared state among all Build instances.
28graph: *Graph,30graph: *Graph,
lib/std/Build/Serialize.zig created+1252
...@@ -0,0 +1,1252 @@
1const Serialize = @This();
2
3const std = @import("std");
4const Allocator = std.mem.Allocator;
5const Configuration = std.Build.Configuration;
6const Step = std.Build.Step;
7const assert = std.debug.assert;
8const log = std.log;
9
10arena: Allocator,
11wc: *Configuration.Wip,
12module_map: std.array_hash_map.Auto(*std.Build.Module, Configuration.Module.Index) = .empty,
13package_map: std.array_hash_map.Auto(*std.Build, Configuration.Package.Index) = .empty,
14/// Index corresponds to `Configuration.steps` index.
15step_map: std.array_hash_map.Auto(*Step, void) = .empty,
16
17pub fn write(b: *std.Build, wc: *Configuration.Wip, writer: *std.Io.Writer) !void {
18 const graph = b.graph;
19 const arena = graph.arena;
20 const gpa = wc.gpa;
21
22 var s: Serialize = .{ .wc = wc, .arena = arena };
23
24 try wc.path_deps.ensureTotalCapacityPrecise(gpa, graph.configure_dependencies.items.len);
25 for (
26 graph.configure_dependencies.items,
27 wc.path_deps.addManyAsSliceAssumeCapacity(graph.configure_dependencies.items.len),
28 ) |src, *dest| {
29 dest.* = .{
30 .flags = .{
31 .base = switch (src.lazy_path) {
32 .src_path, .dependency => .build_root,
33 .generated => unreachable,
34 .cwd_relative => .cwd,
35 .relative => |r| r.base,
36 },
37 .mode = src.mode,
38 },
39 .sub = switch (src.lazy_path) {
40 .src_path => |sp| try wc.addString(sp.sub_path),
41 .generated => unreachable,
42 .cwd_relative => |sub_path| try wc.addString(sub_path),
43 .dependency => |d| try wc.addString(d.sub_path),
44 .relative => |r| try wc.addString(r.sub_path),
45 },
46 .pkg = switch (src.lazy_path) {
47 .src_path => |sp| .init(try s.builderToPackage(sp.owner)),
48 .generated => unreachable,
49 .cwd_relative, .relative => .none,
50 .dependency => |d| .init(try s.builderToPackage(d.dependency.builder)),
51 },
52 };
53 }
54
55 // Starting from all top-level steps in `b`, traverse the entire step graph
56 // and add all step dependencies implied by module graphs.
57 const top_level_steps = b.top_level_steps.values();
58 try s.step_map.ensureUnusedCapacity(arena, top_level_steps.len);
59 for (top_level_steps) |tls| {
60 s.step_map.putAssumeCapacityNoClobber(&tls.step, {});
61 }
62 {
63 while (wc.steps.items.len < s.step_map.count()) {
64 const step = s.step_map.keys()[wc.steps.items.len];
65
66 // Set up any implied dependencies for this step. It's important that we do this first, so
67 // that the loop below discovers steps implied by the module graph.
68 try createModuleDependenciesForStep(step);
69
70 try s.step_map.ensureUnusedCapacity(arena, step.dependencies.items.len);
71 for (step.dependencies.items) |other_step| {
72 s.step_map.putAssumeCapacity(other_step, {});
73 }
74
75 // Add and then de-duplicate dependencies.
76 const dep_steps = try arena.alloc(Configuration.Step.Index, step.dependencies.items.len);
77 for (dep_steps, step.dependencies.items) |*dest, src|
78 dest.* = @enumFromInt(s.step_map.getIndex(src).?);
79
80 const deps: Configuration.Deps.Index = try wc.addDeduped(Configuration.Deps, .{
81 .steps = .{ .slice = dep_steps },
82 });
83
84 try wc.steps.ensureTotalCapacity(gpa, s.step_map.entries.capacity);
85 wc.steps.appendAssumeCapacity(.{
86 .name = try wc.addString(step.name),
87 .owner = try s.builderToPackage(step.owner),
88 .deps = deps,
89 .max_rss = .fromBytes(step.max_rss),
90 .extended = @enumFromInt(switch (step.tag) {
91 .top_level => e: {
92 const top_level: *Step.TopLevel = @fieldParentPtr("step", step);
93 break :e try wc.addExtraErased(Configuration.Step.TopLevel, .{
94 .description = try wc.addString(top_level.description),
95 });
96 },
97 .compile => e: {
98 const c: *Step.Compile = @fieldParentPtr("step", step);
99 const installed_headers: []u32 = try arena.alloc(u32, c.installed_headers.items.len);
100 for (installed_headers, c.installed_headers.items) |*dst, src| switch (src) {
101 .file => |file| {
102 dst.* = try wc.addExtraErased(Configuration.Step.Compile.InstalledHeader.File, .{
103 .source = try s.addLazyPath(file.source),
104 .dest_sub_path = try wc.addString(file.dest_rel_path),
105 });
106 },
107 .directory => |directory| {
108 const include_extensions = directory.options.include_extensions orelse &.{};
109 dst.* = try wc.addExtraErased(Configuration.Step.Compile.InstalledHeader.Directory, .{
110 .flags = .{
111 .include_extensions = include_extensions.len != 0,
112 .exclude_extensions = directory.options.exclude_extensions.len != 0,
113 },
114 .source = try s.addLazyPath(directory.source),
115 .dest_sub_path = try wc.addString(directory.dest_rel_path),
116 .exclude_extensions = .{ .slice = try s.initStringList(directory.options.exclude_extensions) },
117 .include_extensions = .{ .slice = try s.initStringList(include_extensions) },
118 });
119 },
120 };
121
122 break :e try wc.addExtraErased(Configuration.Step.Compile, .{
123 .flags = .{
124 .filters_len = c.filters.len != 0,
125 .installed_headers_len = installed_headers.len != 0,
126 .force_undefined_symbols_len = c.force_undefined_symbols.entries.len != 0,
127
128 .verbose_link = c.verbose_link,
129 .verbose_cc = c.verbose_cc,
130 .rdynamic = c.rdynamic,
131 .import_memory = c.import_memory,
132 .export_memory = c.export_memory,
133 .import_symbols = c.import_symbols,
134 .import_table = c.import_table,
135 .export_table = c.export_table,
136 .shared_memory = c.shared_memory,
137 .link_eh_frame_hdr = c.link_eh_frame_hdr,
138 .link_emit_relocs = c.link_emit_relocs,
139 .link_function_sections = c.link_function_sections,
140 .link_data_sections = c.link_data_sections,
141 .linker_dynamicbase = c.linker_dynamicbase,
142 .link_z_notext = c.link_z_notext,
143 .link_z_relro = c.link_z_relro,
144 .link_z_lazy = c.link_z_lazy,
145 .link_z_defs = c.link_z_defs,
146 .headerpad_max_install_names = c.headerpad_max_install_names,
147 .dead_strip_dylibs = c.dead_strip_dylibs,
148 .force_load_objc = c.force_load_objc,
149 .discard_local_symbols = c.discard_local_symbols,
150 .mingw_unicode_entry_point = c.mingw_unicode_entry_point,
151 },
152 .flags2 = .{
153 .pie = .init(c.pie),
154 .formatted_panics = .init(c.formatted_panics),
155 .bundle_compiler_rt = .init(c.bundle_compiler_rt),
156 .bundle_ubsan_rt = .init(c.bundle_ubsan_rt),
157 .each_lib_rpath = .init(c.each_lib_rpath),
158 .link_gc_sections = .init(c.link_gc_sections),
159 .linker_allow_shlib_undefined = .init(c.linker_allow_shlib_undefined),
160 .linker_allow_undefined_version = .init(c.linker_allow_undefined_version),
161 .linker_enable_new_dtags = .init(c.linker_enable_new_dtags),
162 .dll_export_fns = .init(c.dll_export_fns),
163 .use_llvm = .init(c.use_llvm),
164 .use_lld = .init(c.use_lld),
165 .use_new_linker = .init(c.use_new_linker),
166 .allow_so_scripts = .init(c.allow_so_scripts),
167 .sanitize_coverage_trace_pc_guard = .init(c.sanitize_coverage_trace_pc_guard),
168 .linkage = .init(c.linkage),
169 },
170 .flags3 = .{
171 .is_linking_libc = c.is_linking_libc,
172 .is_linking_libcpp = c.is_linking_libcpp,
173 .version = c.version != null,
174 .compress_debug_sections = c.compress_debug_sections,
175 .initial_memory = c.initial_memory != null,
176 .max_memory = c.max_memory != null,
177 .kind = c.kind,
178 .global_base = c.global_base != null,
179 .test_runner = if (c.test_runner) |tr| switch (tr.mode) {
180 .simple => .simple,
181 .server => .server,
182 } else .default,
183 .wasi_exec_model = .init(c.wasi_exec_model),
184 .win32_manifest = c.win32_manifest != null,
185 .win32_module_definition = c.win32_module_definition != null,
186 .zig_lib_dir = c.zig_lib_dir != null,
187 .rc_includes = c.rc_includes,
188 .image_base = c.image_base != null,
189 .build_id = .init(c.build_id),
190 .entry = switch (c.entry) {
191 .default => .default,
192 .disabled => .disabled,
193 .enabled => .enabled,
194 .symbol_name => .symbol_name,
195 },
196 .lto = .init(c.lto),
197 .subsystem = .init(c.subsystem),
198 },
199 .flags4 = .{
200 .libc_file = c.libc_file != null,
201 .link_z_common_page_size = c.link_z_common_page_size != null,
202 .link_z_max_page_size = c.link_z_max_page_size != null,
203 .pagezero_size = c.pagezero_size != null,
204 .stack_size = c.stack_size != null,
205 .headerpad_size = c.headerpad_size != null,
206 .error_limit = c.error_limit != null,
207 .install_name = c.install_name != null,
208 .entitlements = c.entitlements != null,
209 .expect_errors = if (c.expect_errors) |x| switch (x) {
210 .contains => .contains,
211 .exact => .exact,
212 .starts_with => .starts_with,
213 .stderr_contains => .stderr_contains,
214 } else .none,
215 .linker_script = c.linker_script != null,
216 .version_script = c.version_script != null,
217 .emit_directory = c.emit_directory != .none,
218 .generated_docs = c.generated_docs != .none,
219 .generated_asm = c.generated_asm != .none,
220 .generated_bin = c.generated_bin != .none,
221 .generated_pdb = c.generated_pdb != .none,
222 .generated_implib = c.generated_implib != .none,
223 .generated_llvm_bc = c.generated_llvm_bc != .none,
224 .generated_llvm_ir = c.generated_llvm_ir != .none,
225 .generated_h = c.generated_h != .none,
226 .incremental = .init(c.incremental),
227 },
228 .root_module = try s.addModule(c.root_module),
229 .root_name = try wc.addString(c.name),
230 .linker_script = .{ .value = try s.addOptionalLazyPath(c.linker_script) },
231 .version_script = .{ .value = try s.addOptionalLazyPath(c.version_script) },
232 .zig_lib_dir = .{ .value = try s.addOptionalLazyPath(c.zig_lib_dir) },
233 .libc_file = .{ .value = try s.addOptionalLazyPath(c.libc_file) },
234 .win32_manifest = .{ .value = try s.addOptionalLazyPath(c.win32_manifest) },
235 .win32_module_definition = .{ .value = try s.addOptionalLazyPath(c.win32_module_definition) },
236 .entitlements = .{ .value = try s.addOptionalLazyPath(c.entitlements) },
237 .version = .{ .value = try s.addOptionalSemVer(c.version) },
238 .install_name = .{ .value = try s.addOptionalString(c.install_name) },
239 .initial_memory = .{ .value = c.initial_memory },
240 .max_memory = .{ .value = c.max_memory },
241 .global_base = .{ .value = c.global_base },
242 .image_base = .{ .value = c.image_base },
243 .link_z_common_page_size = .{ .value = c.link_z_common_page_size },
244 .link_z_max_page_size = .{ .value = c.link_z_max_page_size },
245 .pagezero_size = .{ .value = c.pagezero_size },
246 .stack_size = .{ .value = c.stack_size },
247 .headerpad_size = .{ .value = c.headerpad_size },
248 .error_limit = .{ .value = c.error_limit },
249 .entry = .{ .value = switch (c.entry) {
250 .symbol_name => |name| try wc.addString(name),
251 .default, .disabled, .enabled => null,
252 } },
253 .build_id = .{ .value = if (c.build_id) |id| switch (id) {
254 .hexstring => |*hexstring| try wc.addString(hexstring.toSlice()),
255 .none, .fast, .uuid, .sha1, .md5 => null,
256 } else null },
257 .filters = .{ .slice = try s.initStringList(c.filters) },
258 .installed_headers = .initErased(installed_headers),
259 .force_undefined_symbols = .{ .slice = try s.initStringList(c.force_undefined_symbols.keys()) },
260 .expect_errors = .{ .u = if (c.expect_errors) |x| switch (x) {
261 .contains => |slice| .{ .contains = try wc.addString(slice) },
262 .exact => |exact| .{ .exact = .{ .slice = try s.initStringList(exact) } },
263 .starts_with => |slice| .{ .starts_with = try wc.addString(slice) },
264 .stderr_contains => |slice| .{ .stderr_contains = try wc.addString(slice) },
265 } else .none },
266 .test_runner = .{ .u = if (c.test_runner) |tr| switch (tr.mode) {
267 .simple => .{ .simple = try s.addLazyPath(tr.path) },
268 .server => .{ .server = try s.addLazyPath(tr.path) },
269 } else .default },
270
271 .emit_directory = .{ .value = c.emit_directory.unwrap() },
272 .generated_docs = .{ .value = c.generated_docs.unwrap() },
273 .generated_asm = .{ .value = c.generated_asm.unwrap() },
274 .generated_bin = .{ .value = c.generated_bin.unwrap() },
275 .generated_pdb = .{ .value = c.generated_pdb.unwrap() },
276 .generated_implib = .{ .value = c.generated_implib.unwrap() },
277 .generated_llvm_bc = .{ .value = c.generated_llvm_bc.unwrap() },
278 .generated_llvm_ir = .{ .value = c.generated_llvm_ir.unwrap() },
279 .generated_h = .{ .value = c.generated_h.unwrap() },
280 });
281 },
282 .install_artifact => e: {
283 const ia: *Step.InstallArtifact = @fieldParentPtr("step", step);
284 break :e try wc.addExtraErased(Configuration.Step.InstallArtifact, .{
285 .flags = .{
286 .dylib_symlinks = ia.dylib_symlinks,
287 .bin_dir = ia.dest_dir != null,
288 .implib_dir = ia.implib_dir != null,
289 .pdb_dir = ia.pdb_dir != null,
290 .h_dir = ia.h_dir != null,
291 .bin_sub_path = ia.dest_sub_path != null,
292 },
293 .bin_dir = .{ .value = try addInstallDirDefaultNull(wc, ia.dest_dir) },
294 .implib_dir = .{ .value = try addInstallDirDefaultNull(wc, ia.implib_dir) },
295 .pdb_dir = .{ .value = try addInstallDirDefaultNull(wc, ia.pdb_dir) },
296 .h_dir = .{ .value = try addInstallDirDefaultNull(wc, ia.h_dir) },
297 .bin_sub_path = .{ .value = try s.addOptionalString(ia.dest_sub_path) },
298 });
299 },
300 .install_file => e: {
301 const sif: *Step.InstallFile = @fieldParentPtr("step", step);
302 break :e try wc.addExtraErased(Configuration.Step.InstallFile, .{
303 .source = try s.addLazyPath(sif.source),
304 .dest_dir = try addInstallDir(wc, sif.dir),
305 .dest_sub_path = try wc.addString(sif.dest_rel_path),
306 });
307 },
308 .install_dir => e: {
309 const sid: *Step.InstallDir = @fieldParentPtr("step", step);
310 const dest_sub_path: ?[]const u8 = if (sid.options.install_subdir.len != 0)
311 sid.options.install_subdir
312 else
313 null;
314 const include_extensions = sid.options.include_extensions orelse &.{};
315 break :e try wc.addExtraErased(Configuration.Step.InstallDir, .{
316 .flags = .{
317 .dest_sub_path = dest_sub_path != null,
318 .exclude_extensions = sid.options.exclude_extensions.len != 0,
319 .include_extensions = include_extensions.len != 0,
320 .include_extensions_active = sid.options.include_extensions != null,
321 .blank_extensions = sid.options.blank_extensions.len != 0,
322 },
323 .source_dir = try s.addLazyPath(sid.options.source_dir),
324 .dest_dir = try addInstallDir(wc, sid.options.install_dir),
325 .dest_sub_path = .{ .value = try s.addOptionalString(dest_sub_path) },
326 .exclude_extensions = .{ .slice = try s.initStringList(sid.options.exclude_extensions) },
327 .include_extensions = .{ .slice = try s.initStringList(include_extensions) },
328 .blank_extensions = .{ .slice = try s.initStringList(sid.options.blank_extensions) },
329 });
330 },
331 .fail => e: {
332 const sf: *Step.Fail = @fieldParentPtr("step", step);
333 break :e try wc.addExtraErased(Configuration.Step.Fail, .{
334 .msg = sf.error_msg,
335 });
336 },
337 .find_program => e: {
338 const fp: *Step.FindProgram = @fieldParentPtr("step", step);
339 break :e try wc.addExtraErased(Configuration.Step.FindProgram, .{
340 .names = fp.names,
341 .found_path = fp.found_path,
342 });
343 },
344 .fmt => e: {
345 const sf: *Step.Fmt = @fieldParentPtr("step", step);
346 break :e try wc.addExtraErased(Configuration.Step.Fmt, .{
347 .flags = .{
348 .paths = sf.paths.len != 0,
349 .exclude_paths = sf.exclude_paths.len != 0,
350 .check = sf.check,
351 },
352 .paths = .{ .slice = try s.initLazyPathList(sf.paths) },
353 .exclude_paths = .{ .slice = try s.initLazyPathList(sf.exclude_paths) },
354 });
355 },
356 .translate_c => e: {
357 const tc: *Step.TranslateC = @fieldParentPtr("step", step);
358
359 const system_libs = try arena.alloc(Configuration.SystemLib.Index, tc.system_libs.items.len);
360 for (system_libs, tc.system_libs.items) |*dest, *src| dest.* = try s.addSystemLib(src);
361
362 break :e try wc.addExtraErased(Configuration.Step.TranslateC, .{
363 .flags = .{
364 .include_dirs = tc.include_dirs.items.len != 0,
365 .system_libs = system_libs.len != 0,
366 .c_macros = tc.c_macros.items.len != 0,
367 .link_libc = tc.link_libc,
368 .optimize = .init(tc.optimize),
369 },
370 .src_path = try s.addLazyPath(tc.source),
371 .output_file = tc.output_file,
372 .include_dirs = .init(try s.initIncludeDirList(tc.include_dirs.items)),
373 .system_libs = .{ .slice = system_libs },
374 .c_macros = .{ .slice = tc.c_macros.items },
375 .target = try addOptionalResolvedTarget(wc, tc.target),
376 });
377 },
378 .write_file => e: {
379 const wf: *Step.WriteFile = @fieldParentPtr("step", step);
380
381 const directories = try arena.alloc(
382 Configuration.Step.WriteFile.Directory,
383 wf.directories.items.len,
384 );
385 for (directories, wf.directories.items) |*dest, src| dest.* = .{
386 .sub_path = src.sub_path,
387 .src_path = try s.addLazyPath(src.src_path),
388 .exclude_extensions = src.exclude_extensions,
389 .include_extensions = src.include_extensions,
390 };
391
392 break :e try wc.addExtraErased(Configuration.Step.WriteFile, .{
393 .flags = .{
394 .embeds = wf.embeds.items.len != 0,
395 .copies = wf.copies.items.len != 0,
396 .directories = directories.len != 0,
397 .mode = switch (wf.mode) {
398 .whole_cached => .whole_cached,
399 .tmp => .tmp,
400 .mutate => .mutate,
401 },
402 },
403 .generated_directory = wf.generated_directory,
404 .embeds = .{ .slice = wf.embeds.items },
405 .copies = .{ .slice = try s.initCopyList(wf.copies.items) },
406 .directories = .{ .slice = directories },
407 .mutate_path = .{ .value = switch (wf.mode) {
408 .mutate => |lp| try s.addLazyPath(lp),
409 .whole_cached, .tmp => null,
410 } },
411 });
412 },
413 .update_source_files => e: {
414 const usf: *Step.UpdateSourceFiles = @fieldParentPtr("step", step);
415 break :e try wc.addExtraErased(Configuration.Step.UpdateSourceFiles, .{
416 .flags = .{
417 .embeds = usf.embeds.items.len != 0,
418 .copies = usf.copies.items.len != 0,
419 },
420 .embeds = .{ .slice = usf.embeds.items },
421 .copies = .{ .slice = try s.initCopyList(usf.copies.items) },
422 });
423 },
424 .run => e: {
425 const run: *Step.Run = @fieldParentPtr("step", step);
426 var expect_stderr_exact: ?Configuration.Bytes = null;
427 var expect_stdout_exact: ?Configuration.Bytes = null;
428 var expect_stderr_match: std.ArrayList(Configuration.Bytes) = .empty;
429 var expect_stdout_match: std.ArrayList(Configuration.Bytes) = .empty;
430 var expect_term: ?struct {
431 status: Configuration.Step.Run.ExpectTermStatus,
432 value: u32,
433 } = null;
434 var expect_stderr_snapshot: ?Configuration.LazyPath.Index = null;
435 var expect_stdout_snapshot: ?Configuration.LazyPath.Index = null;
436 switch (run.stdio) {
437 .check => |checks| for (checks.items) |check| switch (check) {
438 .expect_stderr_exact => |bytes| expect_stderr_exact = try wc.addBytes(bytes),
439 .expect_stdout_exact => |bytes| expect_stdout_exact = try wc.addBytes(bytes),
440 .expect_stderr_match => |bytes| {
441 try expect_stderr_match.append(arena, try wc.addBytes(bytes));
442 },
443 .expect_stdout_match => |bytes| {
444 try expect_stdout_match.append(arena, try wc.addBytes(bytes));
445 },
446 .expect_term => |t| expect_term = switch (t) {
447 .exited => |x| .{ .status = .exited, .value = x },
448 .signal => |x| .{ .status = .signal, .value = @intFromEnum(x) },
449 .stopped => |x| .{ .status = .stopped, .value = @intFromEnum(x) },
450 .unknown => |x| .{ .status = .unknown, .value = x },
451 },
452 .expect_stderr_snapshot => |path| expect_stderr_snapshot = try s.addLazyPath(path),
453 .expect_stdout_snapshot => |path| expect_stdout_snapshot = try s.addLazyPath(path),
454 },
455 else => {},
456 }
457
458 break :e try wc.addExtraErased(Configuration.Step.Run, .{
459 .flags = .{
460 .disable_zig_progress = run.disable_zig_progress,
461 .skip_foreign_checks = run.skip_foreign_checks,
462 .failing_to_execute_foreign_is_an_error = run.failing_to_execute_foreign_is_an_error,
463 .has_side_effects = run.has_side_effects,
464 .test_runner_mode = run.test_runner_mode,
465 .color = run.color,
466 .stdio = switch (run.stdio) {
467 .infer_from_args => .infer_from_args,
468 .inherit => .inherit,
469 .check => .check,
470 .zig_test => .zig_test,
471 },
472 .stdin = switch (run.stdin) {
473 .none => .none,
474 .bytes => .bytes,
475 .lazy_path => .lazy_path,
476 },
477 .stdout_trim_whitespace = if (run.captured_stdout) |cs| cs.trim_whitespace else .none,
478 .stderr_trim_whitespace = if (run.captured_stderr) |cs| cs.trim_whitespace else .none,
479 .stdio_limit = run.stdio_limit != .unlimited,
480 .producer = run.producer != null,
481 .cwd = run.cwd != null,
482 .captured_stdout = run.captured_stdout != null,
483 .captured_stderr = run.captured_stderr != null,
484 .environ_map = run.environ_map != null,
485 },
486 .flags2 = .{
487 .expect_stderr_exact = expect_stderr_exact != null,
488 .expect_stdout_exact = expect_stdout_exact != null,
489 .expect_stderr_match = expect_stderr_match.items.len != 0,
490 .expect_stdout_match = expect_stdout_match.items.len != 0,
491 .expect_term = expect_term != null,
492 .expect_term_status = if (expect_term) |t| t.status else .exited,
493 .expect_stderr_snapshot = expect_stderr_snapshot != null,
494 .expect_stdout_snapshot = expect_stdout_snapshot != null,
495 },
496 .file_inputs = .{ .slice = try s.initLazyPathList(run.file_inputs.items) },
497 .args = .{ .slice = try s.initArgsList(run.argv.items) },
498 .cwd = .{ .value = try s.addOptionalLazyPath(run.cwd) },
499 .preopen_names = .{ .slice = try s.initStringList(run.preopens.keys()) },
500 .preopen_paths = .{ .slice = try s.initLazyPathList(run.preopens.values()) },
501 .captured_stdout = .{ .value = if (run.captured_stdout) |cs| .{
502 .basename = try wc.addString(cs.basename),
503 .generated_file = cs.generated_file,
504 } else null },
505 .captured_stderr = .{ .value = if (run.captured_stderr) |cs| .{
506 .basename = try wc.addString(cs.basename),
507 .generated_file = cs.generated_file,
508 } else null },
509 .environ_map = .{ .value = try s.addEnvironMap(run.environ_map) },
510 .expect_term_value = .{ .value = if (expect_term) |t| t.value else null },
511 .stdio_limit = .{ .value = run.stdio_limit.toInt64() },
512 .producer = .{ .value = if (run.producer) |cs| s.stepIndex(&cs.step) else null },
513 .expect_stderr_exact = .{ .value = if (expect_stderr_exact) |bytes| bytes else null },
514 .expect_stdout_exact = .{ .value = if (expect_stdout_exact) |bytes| bytes else null },
515 .expect_stderr_match = .{ .slice = expect_stderr_match.items },
516 .expect_stdout_match = .{ .slice = expect_stdout_match.items },
517 .expect_stderr_snapshot = .{ .value = expect_stderr_snapshot orelse null },
518 .expect_stdout_snapshot = .{ .value = expect_stdout_snapshot orelse null },
519 .stdin = .{ .u = switch (run.stdin) {
520 .none => .none,
521 .bytes => |bytes| .{ .bytes = try wc.addBytes(bytes) },
522 .lazy_path => |lp| .{ .lazy_path = try s.addLazyPath(lp) },
523 } },
524 });
525 },
526 .check_file => e: {
527 const cf: *Step.CheckFile = @fieldParentPtr("step", step);
528 break :e try wc.addExtraErased(Configuration.Step.CheckFile, .{
529 .flags = .{
530 .expected_exact = cf.expected_exact != null,
531 .expected_matches = cf.expected_matches.len != 0,
532 .max_bytes = cf.max_bytes != null,
533 },
534 .file = try s.addLazyPath(cf.file),
535 .expected_exact = .{ .value = cf.expected_exact },
536 .expected_matches = .{ .slice = cf.expected_matches },
537 .max_bytes = .{ .value = cf.max_bytes },
538 });
539 },
540 .config_header => e: {
541 const ch: *Step.ConfigHeader = @fieldParentPtr("step", step);
542 const lazy_path: ?std.Build.LazyPath = ch.style.getPath();
543 const pairs = try arena.alloc(Configuration.Step.ConfigHeader.Value.Pair, ch.values.count());
544 for (pairs, ch.values.keys(), ch.values.values()) |*pair, key, value| pair.* = .{
545 .key = try wc.addString(key),
546 .index = switch (value) {
547 .undef => .undef,
548 .defined => .defined,
549 .boolean => |x| switch (x) {
550 false => .bool_false,
551 true => .bool_true,
552 },
553 .int => |x| switch (x) {
554 0 => .int_0,
555 1 => .int_1,
556 else => try wc.addExtra(Configuration.Step.ConfigHeader.Value, .initSigned(x)),
557 },
558 .ident => |x| try wc.addExtra(Configuration.Step.ConfigHeader.Value, .{
559 .flags = .{
560 .tag = .ident,
561 .small = 0,
562 },
563 .i64 = .{ .value = null },
564 .u64 = .{ .value = null },
565 .ident = .{ .value = try wc.addString(x) },
566 .string = .{ .value = null },
567 }),
568 .string => |x| try wc.addExtra(Configuration.Step.ConfigHeader.Value, .{
569 .flags = .{
570 .tag = .string,
571 .small = 0,
572 },
573 .i64 = .{ .value = null },
574 .u64 = .{ .value = null },
575 .ident = .{ .value = null },
576 .string = .{ .value = try wc.addString(x) },
577 }),
578 },
579 };
580 break :e try wc.addExtraErased(Configuration.Step.ConfigHeader, .{
581 .flags = .{
582 .template_file = lazy_path != null,
583 .style = .init(ch.style),
584 .input_size_limit = ch.input_size_limit != null,
585 .include_guard = ch.include_guard != .none,
586 },
587 .template_file = .{ .value = try s.addOptionalLazyPath(lazy_path) },
588 .generated_dir = ch.generated_dir,
589 .input_size_limit = .{ .value = ch.input_size_limit },
590 .include_path = try wc.addString(ch.include_path),
591 .include_guard = .{ .value = ch.include_guard.unwrap() },
592 .values = .{ .slice = pairs },
593 });
594 },
595 .obj_copy => e: {
596 const oc: *Step.ObjCopy = @fieldParentPtr("step", step);
597
598 const debug_basename: ?Configuration.String = if (oc.debug_file) |df|
599 df.basename.unwrap()
600 else
601 null;
602
603 const debug_file: ?Configuration.GeneratedFileIndex = if (oc.debug_file) |df|
604 df.output_file
605 else
606 null;
607
608 const add_sections = try arena.alloc(
609 Configuration.Step.ObjCopy.AddSection,
610 oc.add_sections.items.len,
611 );
612 for (add_sections, oc.add_sections.items) |*dest, src| dest.* = .{
613 .section_name = src.section_name,
614 .file_path = try s.addLazyPath(src.file_path),
615 };
616
617 break :e try wc.addExtraErased(Configuration.Step.ObjCopy, .{
618 .flags = .{
619 .basename = oc.basename != .none,
620 .debug_file = debug_file != null,
621 .debug_basename = debug_basename != null,
622 .format = .init(oc.format),
623 .strip = oc.strip,
624 .compress_debug = oc.compress_debug,
625 .only_section = oc.only_section != .none,
626 .pad_to = oc.pad_to != null,
627 .add_section = add_sections.len != 0,
628 .update_section = oc.update_sections.items.len != 0,
629 },
630 .input_file = try s.addLazyPath(oc.input_file),
631 .output_file = oc.output_file,
632 .basename = .{ .value = oc.basename.unwrap() },
633 .debug_file = .{ .value = debug_file },
634 .debug_basename = .{ .value = debug_basename },
635 .only_section = .{ .value = oc.only_section.unwrap() },
636 .pad_to = .{ .value = oc.pad_to },
637 .add_section = .{ .slice = add_sections },
638 .update_section = .{ .slice = oc.update_sections.items },
639 });
640 },
641 .options => e: {
642 const so: *Step.Options = @fieldParentPtr("step", step);
643
644 const args = try arena.alloc(Configuration.Step.Options.Arg, so.args.items.len);
645 for (args, so.args.items) |*dest, src| dest.* = .{
646 .name = src.name,
647 .path = try s.addLazyPath(src.path),
648 };
649
650 break :e try wc.addExtraErased(Configuration.Step.Options, .{
651 .flags = .{
652 .args = so.args.items.len != 0,
653 },
654 .generated_file = so.generated_file,
655 .contents = try wc.addBytes(so.contents.items),
656 .args = .{ .slice = args },
657 });
658 },
659 }),
660 });
661 }
662 }
663
664 try wc.unlazy_deps.ensureUnusedCapacity(gpa, graph.needed_lazy_dependencies.keys().len);
665 for (graph.needed_lazy_dependencies.keys()) |k| {
666 wc.unlazy_deps.appendAssumeCapacity(try wc.addString(k));
667 }
668
669 try wc.write(writer, .{
670 .default_step = s.stepIndex(b.default_step),
671 .generated_files_len = @intCast(graph.generated_files.items.len),
672 .poisoned = switch (graph.cache_poison) {
673 .pure, .disallowed, .ignored => false,
674 .poisoned => true,
675 },
676 });
677}
678
679pub fn systemIntegrationOptions(graph: *std.Build.Graph, wc: *Configuration.Wip) Allocator.Error!void {
680 const gpa = wc.gpa;
681
682 var bad = false;
683 try wc.system_integrations.ensureTotalCapacityPrecise(gpa, graph.system_integration_options.entries.len);
684 for (graph.system_integration_options.keys(), graph.system_integration_options.values()) |k, v| {
685 wc.system_integrations.appendAssumeCapacity(.{
686 .name = try wc.addString(k),
687 .status = switch (v) {
688 .user_disabled, .user_enabled => x: {
689 // The user tried to enable or disable a system library integration, but
690 // the configure script did not recognize that option.
691 log.err("system integration name not recognized by configure script: {s}", .{k});
692 bad = true;
693 break :x .disabled;
694 },
695 .declared_disabled => .disabled,
696 .declared_enabled => .enabled,
697 },
698 });
699 }
700 if (bad) {
701 log.info("help menu contains available options: zig build -h", .{});
702 std.process.exit(1);
703 }
704}
705
706pub fn packageOptions(b: *std.Build, wc: *Configuration.Wip) Allocator.Error!void {
707 const gpa = wc.gpa;
708
709 try wc.available_options.ensureTotalCapacityPrecise(gpa, b.available_options_map.count());
710 for (b.available_options_map.keys(), b.available_options_map.values()) |name, *opt| {
711 wc.available_options.appendAssumeCapacity(.{
712 .name = try wc.addString(name),
713 .description = try wc.addString(opt.description),
714 .type = opt.type_id,
715 .enum_options = if (opt.enum_options) |enum_vals| .init(try wc.addStringList(enum_vals)) else .none,
716 });
717 }
718}
719
720fn builderToPackage(s: *Serialize, b: *std.Build) !Configuration.Package.Index {
721 if (b.pkg_hash.len == 0) return .root;
722 const arena = s.arena;
723 const wc = s.wc;
724 const gop = try s.package_map.getOrPut(arena, b);
725 if (!gop.found_existing) {
726 gop.value_ptr.* = try wc.addExtra(Configuration.Package, .{
727 .hash = try wc.addString(b.pkg_hash),
728 .dep_prefix = try wc.addString(b.dep_prefix),
729 .root_path = try wc.addString(try b.root.toString(arena)),
730 });
731 }
732 return gop.value_ptr.*;
733}
734
735fn addOptionalLazyPathEnum(s: *Serialize, lp: ?std.Build.LazyPath) !Configuration.LazyPath.OptionalIndex {
736 const wc = s.wc;
737 return @enumFromInt(switch (lp orelse return .none) {
738 .src_path => |src_path| i: {
739 const sub_path = try wc.addString(src_path.sub_path);
740 break :i try wc.addExtraErased(Configuration.LazyPath.SourcePath, .{
741 .owner = try s.builderToPackage(src_path.owner),
742 .sub_path = sub_path,
743 });
744 },
745 .generated => |generated| i: {
746 const sub_path = try wc.addString(generated.sub_path);
747 break :i try wc.addExtraErased(Configuration.LazyPath.Generated, .{
748 .flags = .{ .up = @intCast(generated.up) },
749 .index = generated.index,
750 .sub_path = sub_path,
751 });
752 },
753 .cwd_relative => |cwd_relative_sub_path| i: {
754 const sub_path = try wc.addString(cwd_relative_sub_path);
755 break :i try wc.addExtraErased(Configuration.LazyPath.Relative, .{
756 .flags = .{ .base = .cwd },
757 .sub_path = sub_path,
758 });
759 },
760 .relative => |relative| i: {
761 break :i try wc.addExtraErased(Configuration.LazyPath.Relative, .{
762 .flags = .{ .base = relative.base },
763 .sub_path = try wc.addString(relative.sub_path),
764 });
765 },
766 .dependency => |dependency| i: {
767 const sub_path = try wc.addString(dependency.sub_path);
768 break :i try wc.addExtraErased(Configuration.LazyPath.SourcePath, .{
769 .owner = try s.builderToPackage(dependency.dependency.builder),
770 .sub_path = sub_path,
771 });
772 },
773 });
774}
775
776fn addOptionalLazyPath(s: *Serialize, lp: ?std.Build.LazyPath) !?Configuration.LazyPath.Index {
777 return (try addOptionalLazyPathEnum(s, lp)).unwrap();
778}
779
780fn addLazyPath(s: *Serialize, lp: std.Build.LazyPath) !Configuration.LazyPath.Index {
781 return @enumFromInt(@intFromEnum(try addOptionalLazyPathEnum(s, lp)));
782}
783
784fn addOptionalSemVer(s: *Serialize, sem_ver: ?std.SemanticVersion) !?Configuration.String {
785 return if (sem_ver) |sv| try s.wc.addSemVer(sv) else null;
786}
787
788fn addOptionalString(s: *Serialize, opt_slice: ?[]const u8) !?Configuration.String {
789 return if (opt_slice) |slice| try s.wc.addString(slice) else null;
790}
791
792fn addSystemLib(s: *Serialize, sl: *const std.Build.Module.SystemLib) !Configuration.SystemLib.Index {
793 const wc = s.wc;
794 return try wc.addDeduped(Configuration.SystemLib, .{
795 .flags = .{
796 .needed = sl.needed,
797 .weak = sl.weak,
798 .use_pkg_config = sl.use_pkg_config,
799 .preferred_link_mode = sl.preferred_link_mode,
800 .search_strategy = sl.search_strategy,
801 },
802 .name = try wc.addString(sl.name),
803 });
804}
805
806fn addCSourceFile(s: *Serialize, csf: *const std.Build.Module.CSourceFile) !Configuration.CSourceFile.Index {
807 const wc = s.wc;
808 const args = try initStringList(s, csf.flags);
809 return try wc.addExtra(Configuration.CSourceFile, .{
810 .flags = .{
811 .args_len = @intCast(args.len),
812 .lang = .init(csf.language),
813 },
814 .file = try addLazyPath(s, csf.file),
815 .args = .{ .slice = args },
816 });
817}
818
819fn addCSourceFiles(s: *Serialize, csf: *const std.Build.Module.CSourceFiles) !Configuration.CSourceFiles.Index {
820 const wc = s.wc;
821 const sub_paths = try initStringList(s, csf.files);
822 const args = try initStringList(s, csf.flags);
823 return try wc.addExtra(Configuration.CSourceFiles, .{
824 .flags = .{
825 .args_len = @intCast(args.len),
826 .lang = .init(csf.language),
827 },
828 .root = try addLazyPath(s, csf.root),
829 .sub_paths = .{ .slice = sub_paths },
830 .args = .{ .slice = args },
831 });
832}
833
834fn addRcSourceFile(s: *Serialize, rsf: *const std.Build.Module.RcSourceFile) !Configuration.RcSourceFile.Index {
835 const wc = s.wc;
836 const include_paths = try initLazyPathList(s, rsf.include_paths);
837 const args = try initStringList(s, rsf.flags);
838 return try wc.addExtra(Configuration.RcSourceFile, .{
839 .flags = .{
840 .args_len = @intCast(args.len),
841 .include_paths = include_paths.len != 0,
842 },
843 .file = try addLazyPath(s, rsf.file),
844 .include_paths = .{ .slice = include_paths },
845 .args = .{ .slice = args },
846 });
847}
848
849fn addEnvironMap(s: *Serialize, opt_map: ?*std.process.Environ.Map) !?Configuration.EnvironMap.Index {
850 const wc = s.wc;
851 const map = opt_map orelse return null;
852 return try wc.addDeduped(Configuration.EnvironMap, .{
853 .keys = try wc.addStringList(map.array_hash_map.keys()),
854 .values = try wc.addStringList(map.array_hash_map.values()),
855 });
856}
857
858fn initArgsList(s: *Serialize, args: []const Step.Run.Arg) ![]const Configuration.Step.Run.Arg.Index {
859 const wc = s.wc;
860 const result = try s.arena.alloc(Configuration.Step.Run.Arg.Index, args.len);
861 for (result, args) |*dest, src| {
862 dest.* = try wc.addExtra(Configuration.Step.Run.Arg, switch (src) {
863 .artifact => |a| .{
864 .flags = .{
865 .tag = .artifact,
866 .prefix = a.prefix.len != 0,
867 .suffix = a.suffix.len != 0,
868 .basename = false,
869 .path = false,
870 .producer = true,
871 .generated = false,
872 .dep_file = false,
873 .make_absolute = a.make_absolute,
874 },
875 .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null },
876 .suffix = .{ .value = if (a.suffix.len != 0) try wc.addString(a.suffix) else null },
877 .basename = .{ .value = null },
878 .path = .{ .value = null },
879 .producer = .{ .value = stepIndex(s, &a.artifact.step) },
880 .generated = .{ .value = null },
881 },
882 .lazy_path => |a| .{
883 .flags = .{
884 .tag = .path_file,
885 .prefix = a.prefix.len != 0,
886 .suffix = a.suffix.len != 0,
887 .basename = false,
888 .path = true,
889 .producer = false,
890 .generated = false,
891 .dep_file = false,
892 .make_absolute = a.make_absolute,
893 },
894 .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null },
895 .suffix = .{ .value = if (a.suffix.len != 0) try wc.addString(a.suffix) else null },
896 .basename = .{ .value = null },
897 .path = .{ .value = try addLazyPath(s, a.lazy_path) },
898 .producer = .{ .value = null },
899 .generated = .{ .value = null },
900 },
901 .decorated_directory => |a| .{
902 .flags = .{
903 .tag = .path_directory,
904 .prefix = a.prefix.len != 0,
905 .suffix = a.suffix.len != 0,
906 .basename = false,
907 .path = true,
908 .producer = false,
909 .generated = false,
910 .dep_file = false,
911 .make_absolute = a.make_absolute,
912 },
913 .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null },
914 .suffix = .{ .value = if (a.suffix.len != 0) try wc.addString(a.suffix) else null },
915 .basename = .{ .value = null },
916 .path = .{ .value = try addLazyPath(s, a.lazy_path) },
917 .producer = .{ .value = null },
918 .generated = .{ .value = null },
919 },
920 .file_content => |a| .{
921 .flags = .{
922 .tag = .file_content,
923 .prefix = a.prefix.len != 0,
924 .suffix = a.suffix.len != 0,
925 .basename = false,
926 .path = true,
927 .producer = false,
928 .generated = false,
929 .dep_file = false,
930 .make_absolute = false,
931 },
932 .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null },
933 .suffix = .{ .value = if (a.suffix.len != 0) try wc.addString(a.suffix) else null },
934 .basename = .{ .value = null },
935 .path = .{ .value = try addLazyPath(s, a.lazy_path) },
936 .producer = .{ .value = null },
937 .generated = .{ .value = null },
938 },
939 .bytes => |a| .{
940 .flags = .{
941 .tag = .string,
942 .prefix = true,
943 .suffix = false,
944 .basename = false,
945 .path = false,
946 .producer = false,
947 .generated = false,
948 .dep_file = false,
949 .make_absolute = false,
950 },
951 .prefix = .{ .value = try wc.addString(a) },
952 .suffix = .{ .value = null },
953 .basename = .{ .value = null },
954 .path = .{ .value = null },
955 .producer = .{ .value = null },
956 .generated = .{ .value = null },
957 },
958 .output_file, .output_file_dep => |a, tag| .{
959 .flags = .{
960 .tag = .output_file,
961 .prefix = a.prefix.len != 0,
962 .suffix = a.suffix.len != 0,
963 .basename = a.basename.len != 0,
964 .path = false,
965 .producer = false,
966 .generated = true,
967 .dep_file = tag == .output_file_dep,
968 .make_absolute = a.make_absolute,
969 },
970 .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null },
971 .suffix = .{ .value = if (a.suffix.len != 0) try wc.addString(a.suffix) else null },
972 .basename = .{ .value = if (a.basename.len != 0) try wc.addString(a.basename) else null },
973 .path = .{ .value = null },
974 .producer = .{ .value = null },
975 .generated = .{ .value = a.generated_file },
976 },
977 .output_directory => |a| .{
978 .flags = .{
979 .tag = .output_directory,
980 .prefix = a.prefix.len != 0,
981 .suffix = a.suffix.len != 0,
982 .basename = a.basename.len != 0,
983 .path = false,
984 .producer = false,
985 .generated = true,
986 .dep_file = false,
987 .make_absolute = a.make_absolute,
988 },
989 .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null },
990 .suffix = .{ .value = if (a.suffix.len != 0) try wc.addString(a.suffix) else null },
991 .basename = .{ .value = if (a.basename.len != 0) try wc.addString(a.basename) else null },
992 .path = .{ .value = null },
993 .producer = .{ .value = null },
994 .generated = .{ .value = a.generated_file },
995 },
996 .passthru => .{
997 .flags = .{
998 .tag = .passthru,
999 .prefix = false,
1000 .suffix = false,
1001 .basename = false,
1002 .path = false,
1003 .producer = false,
1004 .generated = false,
1005 .dep_file = false,
1006 .make_absolute = false,
1007 },
1008 .prefix = .{ .value = null },
1009 .suffix = .{ .value = null },
1010 .basename = .{ .value = null },
1011 .path = .{ .value = null },
1012 .producer = .{ .value = null },
1013 .generated = .{ .value = null },
1014 },
1015 });
1016 }
1017 return result;
1018}
1019
1020fn initIncludeDirList(
1021 s: *Serialize,
1022 list: []const std.Build.Module.IncludeDir,
1023) ![]const Configuration.Module.IncludeDir {
1024 const result = try s.arena.alloc(Configuration.Module.IncludeDir, list.len);
1025 for (result, list) |*dest, src| dest.* = switch (src) {
1026 .path => |lp| .{ .path = try addLazyPath(s, lp) },
1027 .path_system => |lp| .{ .path_system = try addLazyPath(s, lp) },
1028 .path_after => |lp| .{ .path_after = try addLazyPath(s, lp) },
1029 .framework_path => |lp| .{ .framework_path = try addLazyPath(s, lp) },
1030 .framework_path_system => |lp| .{ .framework_path_system = try addLazyPath(s, lp) },
1031 .embed_path => |lp| .{ .embed_path = try addLazyPath(s, lp) },
1032 .other_step => |cs| .{ .path = try addLazyPath(s, cs.installed_headers_include_tree.?.getDirectory()) },
1033 .config_header_step => |chs| .{ .config_header_step = stepIndex(s, &chs.step) },
1034 };
1035 return result;
1036}
1037
1038fn initLazyPathList(s: *Serialize, list: []const std.Build.LazyPath) ![]const Configuration.LazyPath.Index {
1039 const result = try s.arena.alloc(Configuration.LazyPath.Index, list.len);
1040 for (result, list) |*dest, src| dest.* = try addLazyPath(s, src);
1041 return result;
1042}
1043
1044fn initStringList(s: *Serialize, list: []const []const u8) ![]const Configuration.String {
1045 const wc = s.wc;
1046 const result = try s.arena.alloc(Configuration.String, list.len);
1047 for (result, list) |*dest, src| dest.* = try wc.addString(src);
1048 return result;
1049}
1050
1051fn initCopyList(s: *Serialize, list: []const Step.WriteFile.Copy) ![]const Configuration.Step.WriteFile.Copy {
1052 const result = try s.arena.alloc(Configuration.Step.WriteFile.Copy, list.len);
1053 for (result, list) |*dest, src| dest.* = .{
1054 .sub_path = src.sub_path,
1055 .src_file = try s.addLazyPath(src.src_file),
1056 };
1057 return result;
1058}
1059
1060fn initOptionalStringList(s: *Serialize, list: []const ?[]const u8) ![]const Configuration.OptionalString {
1061 const wc = s.wc;
1062 const result = try s.arena.alloc(Configuration.OptionalString, list.len);
1063 for (result, list) |*dest, src| dest.* = try wc.addOptionalString(src);
1064 return result;
1065}
1066
1067fn addModule(s: *Serialize, m: *std.Build.Module) !Configuration.Module.Index {
1068 if (s.module_map.get(m)) |index| return index;
1069
1070 const wc = s.wc;
1071 const arena = s.arena;
1072
1073 const rpaths = try arena.alloc(Configuration.Module.RPath, m.rpaths.items.len);
1074 for (rpaths, m.rpaths.items) |*dest, src| dest.* = switch (src) {
1075 .lazy_path => |lp| .{ .lazy_path = try addLazyPath(s, lp) },
1076 .special => |slice| .{ .special = try wc.addString(slice) },
1077 };
1078
1079 const link_objects = try arena.alloc(Configuration.Module.LinkObject, m.link_objects.items.len);
1080 for (link_objects, m.link_objects.items) |*dest, *src| dest.* = switch (src.*) {
1081 .static_path => |lp| .{ .static_path = try addLazyPath(s, lp) },
1082 .other_step => |cs| .{ .other_step = stepIndex(s, &cs.step) },
1083 .system_lib => |*sl| .{ .system_lib = try addSystemLib(s, sl) },
1084 .assembly_file => |lp| .{ .assembly_file = try addLazyPath(s, lp) },
1085 .c_source_file => |csf| .{ .c_source_file = try addCSourceFile(s, csf) },
1086 .c_source_files => |csf| .{ .c_source_files = try addCSourceFiles(s, csf) },
1087 .win32_resource_file => |wrf| .{ .win32_resource_file = try addRcSourceFile(s, wrf) },
1088 };
1089
1090 const frameworks = try arena.alloc(Configuration.Module.Framework, m.frameworks.entries.len);
1091 for (frameworks, m.frameworks.keys(), m.frameworks.values()) |*dest, name, options| dest.* = .{
1092 .flags = .{
1093 .needed = options.needed,
1094 .weak = options.weak,
1095 },
1096 .name = try wc.addString(name),
1097 };
1098
1099 const lib_paths = try initLazyPathList(s, m.lib_paths.items);
1100 const c_macros = try initStringList(s, m.c_macros.items);
1101 const export_symbol_names = try initStringList(s, m.export_symbol_names);
1102
1103 const module_index: Configuration.Module.Index = try wc.addExtra(Configuration.Module, .{
1104 .flags = .{
1105 .optimize = .init(m.optimize),
1106 .strip = .init(m.strip),
1107 .unwind_tables = .init(m.unwind_tables),
1108 .dwarf_format = .init(m.dwarf_format),
1109 .single_threaded = .init(m.single_threaded),
1110 .stack_protector = .init(m.stack_protector),
1111 .stack_check = .init(m.stack_check),
1112 .sanitize_c = .init(m.sanitize_c),
1113 .sanitize_thread = .init(m.sanitize_thread),
1114 .fuzz = .init(m.fuzz),
1115 .code_model = m.code_model,
1116 .c_macros = c_macros.len != 0,
1117 .include_dirs = m.include_dirs.items.len != 0,
1118 .lib_paths = lib_paths.len != 0,
1119 .rpaths = rpaths.len != 0,
1120 .frameworks = frameworks.len != 0,
1121 .link_objects = link_objects.len != 0,
1122 .export_symbol_names = export_symbol_names.len != 0,
1123 },
1124 .flags2 = .{
1125 .valgrind = .init(m.valgrind),
1126 .pic = .init(m.pic),
1127 .red_zone = .init(m.red_zone),
1128 .omit_frame_pointer = .init(m.omit_frame_pointer),
1129 .error_tracing = .init(m.error_tracing),
1130 .link_libc = .init(m.link_libc),
1131 .link_libcpp = .init(m.link_libcpp),
1132 .no_builtin = .init(m.no_builtin),
1133 },
1134 .owner = try s.builderToPackage(m.owner),
1135 .root_source_file = try s.addOptionalLazyPathEnum(m.root_source_file),
1136 .import_table = .invalid,
1137 .resolved_target = try addOptionalResolvedTarget(wc, m.resolved_target),
1138 .c_macros = .{ .slice = c_macros },
1139 .lib_paths = .{ .slice = lib_paths },
1140 .export_symbol_names = .{ .slice = export_symbol_names },
1141 .include_dirs = .init(try s.initIncludeDirList(m.include_dirs.items)),
1142 .rpaths = .init(rpaths),
1143 .link_objects = .init(link_objects),
1144 .frameworks = .{ .slice = frameworks },
1145 });
1146
1147 // The import table is the only place that modules can form dependency
1148 // loops. Therefore, we populate the module indexes only after adding
1149 // the module to module_map.
1150 try s.module_map.putNoClobber(arena, m, module_index);
1151
1152 var imports = try std.MultiArrayList(Configuration.ImportTable.Import).initCapacity(arena, m.import_table.entries.len);
1153 imports.len = m.import_table.entries.len;
1154 for (
1155 imports.items(.name),
1156 imports.items(.module),
1157 m.import_table.keys(),
1158 m.import_table.values(),
1159 ) |*dest_name, *dest_module, src_name, src_module| {
1160 dest_name.* = try wc.addString(src_name);
1161 dest_module.* = try addModule(s, src_module);
1162 }
1163
1164 comptime assert(std.mem.eql(u8, @typeInfo(Configuration.Module).@"struct".field_names[2], "import_table"));
1165 comptime assert(@typeInfo(Configuration.Module).@"struct".field_types[2] == Configuration.ImportTable.Index);
1166 assert(wc.extra.items[@intFromEnum(module_index) + 2] == @intFromEnum(Configuration.ImportTable.Index.invalid));
1167 const import_table_index = try wc.addDeduped(Configuration.ImportTable, .{
1168 .imports = .{ .mal = imports },
1169 });
1170 wc.extra.items[@intFromEnum(module_index) + 2] = @intFromEnum(import_table_index);
1171
1172 return module_index;
1173}
1174
1175fn stepIndex(s: *const Serialize, step: *Step) Configuration.Step.Index {
1176 return @enumFromInt(s.step_map.getIndex(step).?);
1177}
1178
1179fn addOptionalResolvedTarget(
1180 wc: *Configuration.Wip,
1181 optional_resolved_target: ?std.Build.ResolvedTarget,
1182) !Configuration.ResolvedTarget.OptionalIndex {
1183 const resolved_target = optional_resolved_target orelse return .none;
1184 return .init(try wc.addDeduped(Configuration.ResolvedTarget, .{
1185 .query = try wc.addTargetQuery(&resolved_target.query),
1186 .result = try wc.addTarget(resolved_target.result),
1187 }));
1188}
1189
1190/// If the given `Step` is a `Step.Compile`, adds any dependencies for that step which
1191/// are implied by the module graph rooted at `step.cast(Step.Compile).?.root_module`.
1192fn createModuleDependenciesForStep(step: *Step) Allocator.Error!void {
1193 const root_module = if (step.cast(Step.Compile)) |cs| root: {
1194 break :root cs.root_module;
1195 } else return; // not a compile step so no module dependencies
1196
1197 // Starting from `root_module`, discover all modules in this graph.
1198 const modules = root_module.getGraph().modules;
1199
1200 // For each of those modules, set up the implied step dependencies.
1201 for (modules) |mod| {
1202 if (mod.root_source_file) |lp| lp.addStepDependencies(step);
1203 for (mod.include_dirs.items) |include_dir| switch (include_dir) {
1204 .path,
1205 .path_system,
1206 .path_after,
1207 .framework_path,
1208 .framework_path_system,
1209 .embed_path,
1210 => |lp| lp.addStepDependencies(step),
1211
1212 .other_step => |other| {
1213 other.getEmittedIncludeTree().addStepDependencies(step);
1214 step.dependOn(&other.step);
1215 },
1216
1217 .config_header_step => |other| step.dependOn(&other.step),
1218 };
1219 for (mod.lib_paths.items) |lp| lp.addStepDependencies(step);
1220 for (mod.rpaths.items) |rpath| switch (rpath) {
1221 .lazy_path => |lp| lp.addStepDependencies(step),
1222 .special => {},
1223 };
1224 for (mod.link_objects.items) |link_object| switch (link_object) {
1225 .static_path,
1226 .assembly_file,
1227 => |lp| lp.addStepDependencies(step),
1228 .other_step => |other| step.dependOn(&other.step),
1229 .system_lib => {},
1230 .c_source_file => |source| source.file.addStepDependencies(step),
1231 .c_source_files => |source_files| source_files.root.addStepDependencies(step),
1232 .win32_resource_file => |rc_source| {
1233 rc_source.file.addStepDependencies(step);
1234 for (rc_source.include_paths) |lp| lp.addStepDependencies(step);
1235 },
1236 };
1237 }
1238}
1239
1240fn addInstallDirDefaultNull(wc: *Configuration.Wip, install_dir: ?std.Build.InstallDir) !?Configuration.InstallDestDir {
1241 return try addInstallDir(wc, install_dir orelse return null);
1242}
1243
1244fn addInstallDir(wc: *Configuration.Wip, install_dir: ?std.Build.InstallDir) !Configuration.InstallDestDir {
1245 switch (install_dir orelse return .none) {
1246 .prefix => return .prefix,
1247 .lib => return .lib,
1248 .bin => return .bin,
1249 .header => return .header,
1250 .custom => |sub_path| return .initCustom(try wc.addString(sub_path)),
1251 }
1252}