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