authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-03-17 19:05:13-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-05-25 18:54:34-07:00
logc6d37f389591e722f59ca7f2b719ec8cfc0a9984
tree797d146e58652575739b35c824d5bbe16c2227b6
parent1a63d26836f5c87e45280772b8ba9c822ba75b78

configurer: make string duplication also intern

I had this idea to make b.dupe() also intern the strings since they will be ultimately serialized to Configuration. Unfortunately the idea does not work, because although a process-lived arena is used for the string_bytes ArrayList of the Configuration.Wip, when the ArrayList is resized, Allocator.free() memsets the freed memory to undefined, even though it still technically lives due to being in a process-scoped arena. So this commit will need to be partially reverted. However, I kept it for posterity, and there are some more changes which I will now note below. - dupePaths: don't rewrite backslashes to forward slashes. backslashes are valid in filenames on non-windows systems. - always compile configurer in single-threaded mode - use arena allocator for everything, no gpa for anything - construct the Configuration.Wip instance earlier, so some stuff can be prepopulated as desired. - don't forget to flush

9 files changed, 174 insertions(+), 162 deletions(-)

BRANCH_TODO+1-1
...@@ -1,10 +1,10 @@...@@ -1,10 +1,10 @@
1* remove Cache from configurer
1* implement the build options2* implement the build options
2* don't forget to add -listen arg back3* don't forget to add -listen arg back
3* get zig init template working4* get zig init template working
4* finish migrating the rest of the build steps5* finish migrating the rest of the build steps
5* make zig-pkg path root configurable in maker (make sure --system still works)6* make zig-pkg path root configurable in maker (make sure --system still works)
6* eliminate calls to getPath, getPath2, getPath37* eliminate calls to getPath, getPath2, getPath3
7* replace b.dupe() with string internment
8* solve the TODOs added in this branch8* solve the TODOs added in this branch
9* get zig tests passing9* get zig tests passing
10* test a bunch of third party projects / help people migrate10* test a bunch of third party projects / help people migrate
lib/compiler/configurer.zig+23-25
...@@ -24,31 +24,22 @@ pub const std_options: std.Options = .{...@@ -24,31 +24,22 @@ pub const std_options: std.Options = .{
24};24};
2525
26pub fn main(init: process.Init.Minimal) !void {26pub fn main(init: process.Init.Minimal) !void {
27 // The build runner is often short-lived, but thanks to `--watch` and `--webui`, that's not27 var arena_allocator: std.heap.ArenaAllocator = .init(std.heap.page_allocator);
28 // always the case. So, we do need a true gpa for some things.28 defer arena_allocator.deinit();
29 var debug_gpa_state: std.heap.DebugAllocator(.{29 const arena = arena_allocator.allocator();
30 // We'd rather have `zig build` run faster than catch harmless leaks in30
31 // the user's build.zig script.31 // The configurer is always short-lived because all it does is serialize
32 .stack_trace_frames = 0,32 // the configuration, which is picked up by a separate maker process.
33 }) = .init;33 var threaded: std.Io.Threaded = .init(arena, .{
34 defer _ = debug_gpa_state.deinit();
35 const gpa = debug_gpa_state.allocator();
36
37 var threaded: std.Io.Threaded = .init(gpa, .{
38 .environ = init.environ,34 .environ = init.environ,
39 .argv0 = .init(init.args),35 .argv0 = .init(init.args),
40 });36 });
41 defer threaded.deinit();37 defer threaded.deinit();
42 const io = threaded.io();38 const io = threaded.io();
4339
44 // ...but we'll back our arena by `std.heap.page_allocator` for efficiency.
45 var arena_allocator: std.heap.ArenaAllocator = .init(std.heap.page_allocator);
46 defer arena_allocator.deinit();
47 const arena = arena_allocator.allocator();
48
49 const args = try init.args.toSlice(arena);40 const args = try init.args.toSlice(arena);
5041
51 // skip my own exe name42 // Skip own executable name.
52 var arg_idx: usize = 1;43 var arg_idx: usize = 1;
5344
54 const zig_exe = expectArgOrFatal(args, &arg_idx, "--zig");45 const zig_exe = expectArgOrFatal(args, &arg_idx, "--zig");
...@@ -84,7 +75,7 @@ pub fn main(init: process.Init.Minimal) !void {...@@ -84,7 +75,7 @@ pub fn main(init: process.Init.Minimal) !void {
84 .arena = arena,75 .arena = arena,
85 .cache = .{76 .cache = .{
86 .io = io,77 .io = io,
87 .gpa = gpa,78 .gpa = arena,
88 .manifest_dir = try local_cache_directory.handle.createDirPathOpen(io, "h", .{}),79 .manifest_dir = try local_cache_directory.handle.createDirPathOpen(io, "h", .{}),
89 .cwd = try process.currentPathAlloc(io, arena),80 .cwd = try process.currentPathAlloc(io, arena),
90 },81 },
...@@ -97,7 +88,18 @@ pub fn main(init: process.Init.Minimal) !void {...@@ -97,7 +88,18 @@ pub fn main(init: process.Init.Minimal) !void {
97 .result = try std.zig.system.resolveTargetQuery(io, .{}),88 .result = try std.zig.system.resolveTargetQuery(io, .{}),
98 },89 },
99 .generated_files = .empty,90 .generated_files = .empty,
91
92 // Created before running the user's configure script so that some things
93 // can be added during script execution such as strings.
94 //
95 // Use of arena here is load-bearing because `std.Build.dupe` is
96 // implemented by string internment, and then returning the interned
97 // slice. When the string bytes array is reallocated, that reference
98 // must stay alive.
99 .wip_configuration = .init(arena),
100 };100 };
101 assert(try graph.wip_configuration.addString("") == .empty);
102 assert(try graph.wip_configuration.addString("root") == .root);
101103
102 graph.cache.addPrefix(.{ .path = null, .handle = cwd });104 graph.cache.addPrefix(.{ .path = null, .handle = cwd });
103 graph.cache.addPrefix(build_root_directory);105 graph.cache.addPrefix(build_root_directory);
...@@ -200,19 +202,15 @@ pub fn main(init: process.Init.Minimal) !void {...@@ -200,19 +202,15 @@ pub fn main(init: process.Init.Minimal) !void {
200 fatal(" access the help menu with 'zig build -h'", .{});202 fatal(" access the help menu with 'zig build -h'", .{});
201 }203 }
202204
203 var wc: Configuration.Wip = .init(gpa);205 try serializeSystemIntegrationOptions(&graph, &graph.wip_configuration);
204 defer wc.deinit();
205 assert(try wc.addString("") == .empty);
206 assert(try wc.addString("root") == .root);
207
208 try serializeSystemIntegrationOptions(&graph, &wc);
209206
210 var stdout_buffer: [1024]u8 = undefined;207 var stdout_buffer: [1024]u8 = undefined;
211 var file_writer = Io.File.stdout().writerStreaming(io, &stdout_buffer);208 var file_writer = Io.File.stdout().writerStreaming(io, &stdout_buffer);
212 serialize(builder, &wc, &file_writer.interface) catch |err| switch (err) {209 serialize(builder, &graph.wip_configuration, &file_writer.interface) catch |err| switch (err) {
213 error.WriteFailed => fatal("failed to write configuration output: {t}", .{file_writer.err.?}),210 error.WriteFailed => fatal("failed to write configuration output: {t}", .{file_writer.err.?}),
214 error.OutOfMemory => |e| return e,211 error.OutOfMemory => |e| return e,
215 };212 };
213 file_writer.flush() catch |err| fatal("failed to write configuration output: {t}", .{err});
216214
217 // This executable is short-lived and run in Debug mode, so we'd rather215 // This executable is short-lived and run in Debug mode, so we'd rather
218 // have `zig build` run faster than catch resource leaks in the user's216 // have `zig build` run faster than catch resource leaks in the user's
lib/std/Build.zig+38-37
...@@ -115,11 +115,37 @@ pub const Graph = struct {...@@ -115,11 +115,37 @@ pub const Graph = struct {
115115
116 /// Indexes correspond to `Configuration.GeneratedFileIndex`.116 /// Indexes correspond to `Configuration.GeneratedFileIndex`.
117 generated_files: std.ArrayList(*Step),117 generated_files: std.ArrayList(*Step),
118 wip_configuration: Configuration.Wip,
118119
119 pub fn addGeneratedFile(graph: *Graph, owner: *Step) Configuration.GeneratedFileIndex {120 pub fn addGeneratedFile(graph: *Graph, owner: *Step) Configuration.GeneratedFileIndex {
120 graph.generated_files.append(graph.arena, owner) catch @panic("OOM");121 graph.generated_files.append(graph.arena, owner) catch @panic("OOM");
121 return @enumFromInt(graph.generated_files.items.len - 1);122 return @enumFromInt(graph.generated_files.items.len - 1);
122 }123 }
124
125 pub fn dupeString(graph: *Graph, bytes: []const u8) [:0]const u8 {
126 // This code assumes the `Configuration.Wip` uses arena allocation such
127 // that references to string_bytes never die even when the ArrayList is
128 // reallocated.
129 const wc = &graph.wip_configuration;
130 const i = wc.addString(bytes) catch @panic("OOM");
131 return wc.string_bytes.items[@intFromEnum(i)..][0..bytes.len :0];
132 }
133
134 pub fn dupePath(graph: *Graph, bytes: []const u8) [:0]const u8 {
135 if (builtin.os.tag != .windows) return dupeString(graph, bytes);
136 const arena = graph.arena;
137 const the_copy = arena.dupe(u8, bytes) catch @panic("OOM");
138 defer arena.free(the_copy);
139 mem.replaceScalar(u8, the_copy, '/', '\\');
140 return dupeString(graph, the_copy);
141 }
142
143 pub fn dupeStrings(graph: *Graph, strings: []const []const u8) []const []const u8 {
144 const arena = graph.arena;
145 const array = arena.alloc([]const u8, strings.len) catch @panic("OOM");
146 for (array, strings) |*dest, source| dest.* = dupeString(graph, source);
147 return array;
148 }
123};149};
124150
125const AvailableDeps = []const struct { []const u8, []const u8 };151const AvailableDeps = []const struct { []const u8, []const u8 };
...@@ -869,36 +895,18 @@ pub fn addConfigHeader(...@@ -869,36 +895,18 @@ pub fn addConfigHeader(
869 return config_header_step;895 return config_header_step;
870}896}
871897
872/// Allocator.dupe without the need to handle out of memory.898pub fn dupe(b: *Build, bytes: []const u8) [:0]const u8 {
873pub fn dupe(b: *Build, bytes: []const u8) []u8 {899 return b.graph.dupeString(bytes);
874 return dupeInner(b.allocator, bytes);
875}
876
877pub fn dupeInner(allocator: Allocator, bytes: []const u8) []u8 {
878 return allocator.dupe(u8, bytes) catch @panic("OOM");
879}900}
880901
881/// Duplicates an array of strings without the need to handle out of memory.902/// Duplicates an array of strings without the need to handle out of memory.
882pub fn dupeStrings(b: *Build, strings: []const []const u8) [][]u8 {903pub fn dupeStrings(b: *Build, strings: []const []const u8) []const []const u8 {
883 const array = b.allocator.alloc([]u8, strings.len) catch @panic("OOM");904 return b.graph.dupeStrings(strings);
884 for (array, strings) |*dest, source| dest.* = b.dupe(source);
885 return array;
886}
887
888/// Duplicates a path and converts all slashes to the OS's canonical path separator.
889pub fn dupePath(b: *Build, bytes: []const u8) []u8 {
890 return dupePathInner(b.allocator, bytes);
891}905}
892906
893fn dupePathInner(allocator: Allocator, bytes: []const u8) []u8 {907/// Duplicates a path, canonicalizing path separators.
894 const the_copy = dupeInner(allocator, bytes);908pub fn dupePath(b: *Build, bytes: []const u8) [:0]const u8 {
895 for (the_copy) |*byte| {909 return b.graph.dupePath(bytes);
896 switch (byte.*) {
897 '/', '\\' => byte.* = fs.path.sep,
898 else => {},
899 }
900 }
901 return the_copy;
902}910}
903911
904pub fn addWriteFile(b: *Build, file_path: []const u8, data: []const u8) *Step.WriteFile {912pub fn addWriteFile(b: *Build, file_path: []const u8, data: []const u8) *Step.WriteFile {
...@@ -2268,25 +2276,18 @@ pub const LazyPath = union(enum) {...@@ -2268,25 +2276,18 @@ pub const LazyPath = union(enum) {
2268 ///2276 ///
2269 /// The `b` parameter is only used for its allocator. All *Build instances2277 /// The `b` parameter is only used for its allocator. All *Build instances
2270 /// share the same allocator.2278 /// share the same allocator.
2271 pub fn dupe(lazy_path: LazyPath, b: *Build) LazyPath {2279 pub fn dupe(lazy_path: LazyPath, graph: *Graph) LazyPath {
2272 return lazy_path.dupeInner(b.allocator);
2273 }
2274
2275 fn dupeInner(lazy_path: LazyPath, allocator: Allocator) LazyPath {
2276 return switch (lazy_path) {2280 return switch (lazy_path) {
2277 .src_path => |sp| .{ .src_path = .{2281 .src_path => |sp| .{ .src_path = .{ .owner = sp.owner, .sub_path = sp.owner.dupePath(sp.sub_path) } },
2278 .owner = sp.owner,2282 .cwd_relative => |p| .{ .cwd_relative = graph.dupePath(p) },
2279 .sub_path = sp.owner.dupePath(sp.sub_path),
2280 } },
2281 .cwd_relative => |p| .{ .cwd_relative = dupePathInner(allocator, p) },
2282 .generated => |gen| .{ .generated = .{2283 .generated => |gen| .{ .generated = .{
2283 .index = gen.index,2284 .index = gen.index,
2284 .up = gen.up,2285 .up = gen.up,
2285 .sub_path = dupePathInner(allocator, gen.sub_path),2286 .sub_path = graph.dupePath(gen.sub_path),
2286 } },2287 } },
2287 .dependency => |dep| .{ .dependency = .{2288 .dependency => |dep| .{ .dependency = .{
2288 .dependency = dep.dependency,2289 .dependency = dep.dependency,
2289 .sub_path = dupePathInner(allocator, dep.sub_path),2290 .sub_path = graph.dupePath(dep.sub_path),
2290 } },2291 } },
2291 };2292 };
2292 }2293 }
lib/std/Build/Configuration.zig-7
...@@ -1419,13 +1419,6 @@ pub const Path = extern struct {...@@ -1419,13 +1419,6 @@ pub const Path = extern struct {
1419 global_cache,1419 global_cache,
1420 build_root,1420 build_root,
1421 };1421 };
1422
1423 pub fn toCachePath(path: Path, c: *const Configuration, arena: Allocator) std.Build.Cache.Path {
1424 _ = c;
1425 _ = arena;
1426 _ = path;
1427 @panic("TODO");
1428 }
1429};1422};
14301423
1431pub const InstallDestDir = enum(u32) {1424pub const InstallDestDir = enum(u32) {
lib/std/Build/Module.zig+4-3
...@@ -240,13 +240,14 @@ pub fn init(...@@ -240,13 +240,14 @@ pub fn init(
240 owner: *std.Build,240 owner: *std.Build,
241 value: union(enum) { options: CreateOptions, existing: *const Module },241 value: union(enum) { options: CreateOptions, existing: *const Module },
242) void {242) void {
243 const allocator = owner.allocator;243 const graph = owner.graph;
244 const arena = graph.arena;
244245
245 switch (value) {246 switch (value) {
246 .options => |options| {247 .options => |options| {
247 m.* = .{248 m.* = .{
248 .owner = owner,249 .owner = owner,
249 .root_source_file = if (options.root_source_file) |lp| lp.dupe(owner) else null,250 .root_source_file = if (options.root_source_file) |lp| lp.dupe(graph) else null,
250 .import_table = .empty,251 .import_table = .empty,
251 .resolved_target = options.target,252 .resolved_target = options.target,
252 .optimize = options.optimize,253 .optimize = options.optimize,
...@@ -277,7 +278,7 @@ pub fn init(...@@ -277,7 +278,7 @@ pub fn init(
277 .no_builtin = options.no_builtin,278 .no_builtin = options.no_builtin,
278 };279 };
279280
280 m.import_table.ensureUnusedCapacity(allocator, options.imports.len) catch @panic("OOM");281 m.import_table.ensureUnusedCapacity(arena, options.imports.len) catch @panic("OOM");
281 for (options.imports) |dep| {282 for (options.imports) |dep| {
282 m.import_table.putAssumeCapacity(dep.name, dep.module);283 m.import_table.putAssumeCapacity(dep.name, dep.module);
283 }284 }
lib/std/Build/Step/Compile.zig+35-31
...@@ -296,10 +296,10 @@ pub const HeaderInstallation = union(enum) {...@@ -296,10 +296,10 @@ pub const HeaderInstallation = union(enum) {
296 source: LazyPath,296 source: LazyPath,
297 dest_rel_path: []const u8,297 dest_rel_path: []const u8,
298298
299 pub fn dupe(file: File, b: *std.Build) File {299 pub fn dupe(file: File, graph: *std.Build.Graph) File {
300 return .{300 return .{
301 .source = file.source.dupe(b),301 .source = file.source.dupe(graph),
302 .dest_rel_path = b.dupePath(file.dest_rel_path),302 .dest_rel_path = graph.dupePath(file.dest_rel_path),
303 };303 };
304 }304 }
305 };305 };
...@@ -424,13 +424,13 @@ pub fn create(owner: *std.Build, options: Options) *Compile {...@@ -424,13 +424,13 @@ pub fn create(owner: *std.Build, options: Options) *Compile {
424 };424 };
425425
426 if (options.zig_lib_dir) |lp| {426 if (options.zig_lib_dir) |lp| {
427 compile.zig_lib_dir = lp.dupe(compile.step.owner);427 compile.zig_lib_dir = lp.dupe(graph);
428 lp.addStepDependencies(&compile.step);428 lp.addStepDependencies(&compile.step);
429 }429 }
430430
431 if (options.test_runner) |runner| {431 if (options.test_runner) |runner| {
432 compile.test_runner = .{432 compile.test_runner = .{
433 .path = runner.path.dupe(compile.step.owner),433 .path = runner.path.dupe(graph),
434 .mode = runner.mode,434 .mode = runner.mode,
435 };435 };
436 runner.path.addStepDependencies(&compile.step);436 runner.path.addStepDependencies(&compile.step);
...@@ -440,20 +440,20 @@ pub fn create(owner: *std.Build, options: Options) *Compile {...@@ -440,20 +440,20 @@ pub fn create(owner: *std.Build, options: Options) *Compile {
440 // gets embedded, so for any other target the manifest file is just ignored.440 // gets embedded, so for any other target the manifest file is just ignored.
441 if (target.ofmt == .coff) {441 if (target.ofmt == .coff) {
442 if (options.win32_manifest) |lp| {442 if (options.win32_manifest) |lp| {
443 compile.win32_manifest = lp.dupe(compile.step.owner);443 compile.win32_manifest = lp.dupe(graph);
444 lp.addStepDependencies(&compile.step);444 lp.addStepDependencies(&compile.step);
445 }445 }
446 if (compile.kind == .lib and compile.linkage != null and compile.linkage.? == .dynamic) {446 if (compile.kind == .lib and compile.linkage != null and compile.linkage.? == .dynamic) {
447 // Building a Win32 DLL, check for win32 .def file.447 // Building a Win32 DLL, check for win32 .def file.
448 if (options.win32_module_definition) |lp| {448 if (options.win32_module_definition) |lp| {
449 compile.win32_module_definition = lp.dupe(compile.step.owner);449 compile.win32_module_definition = lp.dupe(graph);
450 lp.addStepDependencies(&compile.step);450 lp.addStepDependencies(&compile.step);
451 }451 }
452 }452 }
453 }453 }
454454
455 if (options.entitlements) |lp| {455 if (options.entitlements) |lp| {
456 compile.entitlements = lp.dupe(compile.step.owner);456 compile.entitlements = lp.dupe(graph);
457 lp.addStepDependencies(&compile.step);457 lp.addStepDependencies(&compile.step);
458 }458 }
459459
...@@ -464,12 +464,13 @@ pub fn create(owner: *std.Build, options: Options) *Compile {...@@ -464,12 +464,13 @@ pub fn create(owner: *std.Build, options: Options) *Compile {
464/// When a module links with this artifact, all headers marked for installation are added to that464/// When a module links with this artifact, all headers marked for installation are added to that
465/// module's include search path.465/// module's include search path.
466pub fn installHeader(cs: *Compile, source: LazyPath, dest_rel_path: []const u8) void {466pub fn installHeader(cs: *Compile, source: LazyPath, dest_rel_path: []const u8) void {
467 const b = cs.step.owner;467 const graph = cs.step.owner.graph;
468 const arena = graph.arena;
468 const installation: HeaderInstallation = .{ .file = .{469 const installation: HeaderInstallation = .{ .file = .{
469 .source = source.dupe(b),470 .source = source.dupe(graph),
470 .dest_rel_path = b.dupePath(dest_rel_path),471 .dest_rel_path = graph.dupePath(dest_rel_path),
471 } };472 } };
472 cs.installed_headers.append(b.allocator, installation) catch @panic("OOM");473 cs.installed_headers.append(arena, installation) catch @panic("OOM");
473 cs.addHeaderInstallationToIncludeTree(installation);474 cs.addHeaderInstallationToIncludeTree(installation);
474 installation.getSource().addStepDependencies(&cs.step);475 installation.getSource().addStepDependencies(&cs.step);
475}476}
...@@ -483,13 +484,14 @@ pub fn installHeadersDirectory(...@@ -483,13 +484,14 @@ pub fn installHeadersDirectory(
483 dest_rel_path: []const u8,484 dest_rel_path: []const u8,
484 options: HeaderInstallation.Directory.Options,485 options: HeaderInstallation.Directory.Options,
485) void {486) void {
486 const b = cs.step.owner;487 const graph = cs.step.owner.graph;
488 const arena = graph.arena;
487 const installation: HeaderInstallation = .{ .directory = .{489 const installation: HeaderInstallation = .{ .directory = .{
488 .source = source.dupe(b),490 .source = source.dupe(graph),
489 .dest_rel_path = b.dupePath(dest_rel_path),491 .dest_rel_path = graph.dupePath(dest_rel_path),
490 .options = options.dupe(b),492 .options = options.dupe(graph),
491 } };493 } };
492 cs.installed_headers.append(b.allocator, installation) catch @panic("OOM");494 cs.installed_headers.append(arena, installation) catch @panic("OOM");
493 cs.addHeaderInstallationToIncludeTree(installation);495 cs.addHeaderInstallationToIncludeTree(installation);
494 installation.getSource().addStepDependencies(&cs.step);496 installation.getSource().addStepDependencies(&cs.step);
495}497}
...@@ -506,9 +508,10 @@ pub fn installConfigHeader(cs: *Compile, config_header: *Step.ConfigHeader) void...@@ -506,9 +508,10 @@ pub fn installConfigHeader(cs: *Compile, config_header: *Step.ConfigHeader) void
506/// module's include search path.508/// module's include search path.
507pub fn installLibraryHeaders(cs: *Compile, lib: *Compile) void {509pub fn installLibraryHeaders(cs: *Compile, lib: *Compile) void {
508 assert(lib.kind == .lib);510 assert(lib.kind == .lib);
509 const arena = cs.owner.allocator;511 const graph = cs.step.owner.graph;
512 const arena = graph.arena;
510 for (lib.installed_headers.items) |installation| {513 for (lib.installed_headers.items) |installation| {
511 const installation_copy = installation.dupe(lib.step.owner);514 const installation_copy = installation.dupe(graph);
512 cs.installed_headers.append(arena, installation_copy) catch @panic("OOM");515 cs.installed_headers.append(arena, installation_copy) catch @panic("OOM");
513 cs.addHeaderInstallationToIncludeTree(installation_copy);516 cs.addHeaderInstallationToIncludeTree(installation_copy);
514 installation_copy.getSource().addStepDependencies(&cs.step);517 installation_copy.getSource().addStepDependencies(&cs.step);
...@@ -556,21 +559,21 @@ pub fn addObjCopy(cs: *Compile, options: Step.ObjCopy.Options) *Step.ObjCopy {...@@ -556,21 +559,21 @@ pub fn addObjCopy(cs: *Compile, options: Step.ObjCopy.Options) *Step.ObjCopy {
556}559}
557560
558pub fn setLinkerScript(compile: *Compile, source: LazyPath) void {561pub fn setLinkerScript(compile: *Compile, source: LazyPath) void {
559 const b = compile.step.owner;562 const graph = compile.step.owner.graph;
560 compile.linker_script = source.dupe(b);563 compile.linker_script = source.dupe(graph);
561 source.addStepDependencies(&compile.step);564 source.addStepDependencies(&compile.step);
562}565}
563566
564pub fn setVersionScript(compile: *Compile, source: LazyPath) void {567pub fn setVersionScript(compile: *Compile, source: LazyPath) void {
565 const b = compile.step.owner;568 const graph = compile.step.owner.graph;
566 compile.version_script = source.dupe(b);569 compile.version_script = source.dupe(graph);
567 source.addStepDependencies(&compile.step);570 source.addStepDependencies(&compile.step);
568}571}
569572
570pub fn forceUndefinedSymbol(compile: *Compile, symbol_name: []const u8) void {573pub fn forceUndefinedSymbol(compile: *Compile, symbol_name: []const u8) void {
571 const b = compile.step.owner;574 const graph = compile.step.owner.graph;
572 const arena = b.allocator;575 const arena = graph.allocator;
573 compile.force_undefined_symbols.put(arena, b.dupe(symbol_name), {}) catch @panic("OOM");576 compile.force_undefined_symbols.put(arena, graph.dupeString(symbol_name), {}) catch @panic("OOM");
574}577}
575578
576/// Returns whether the library, executable, or object depends on a particular system library.579/// Returns whether the library, executable, or object depends on a particular system library.
...@@ -655,9 +658,9 @@ pub fn setVerboseCC(compile: *Compile, value: bool) void {...@@ -655,9 +658,9 @@ pub fn setVerboseCC(compile: *Compile, value: bool) void {
655}658}
656659
657pub fn setLibCFile(compile: *Compile, libc_file: ?LazyPath) void {660pub fn setLibCFile(compile: *Compile, libc_file: ?LazyPath) void {
658 const b = compile.step.owner;661 const graph = compile.step.owner.graph;
659 if (libc_file) |f| {662 if (libc_file) |f| {
660 compile.libc_file = f.dupe(b);663 compile.libc_file = f.dupe(graph);
661 f.addStepDependencies(&compile.step);664 f.addStepDependencies(&compile.step);
662 } else {665 } else {
663 compile.libc_file = null;666 compile.libc_file = null;
...@@ -733,11 +736,12 @@ pub fn getEmittedLlvmBc(compile: *Compile) LazyPath {...@@ -733,11 +736,12 @@ pub fn getEmittedLlvmBc(compile: *Compile) LazyPath {
733}736}
734737
735pub fn setExecCmd(compile: *Compile, args: []const ?[]const u8) void {738pub fn setExecCmd(compile: *Compile, args: []const ?[]const u8) void {
736 const b = compile.step.owner;739 const graph = compile.step.owner.graph;
740 const arena = graph.arena;
737 assert(compile.kind == .@"test");741 assert(compile.kind == .@"test");
738 const duped_args = b.allocator.alloc(?[]u8, args.len) catch @panic("OOM");742 const duped_args = arena.alloc(?[]u8, args.len) catch @panic("OOM");
739 for (args, 0..) |arg, i| {743 for (args, 0..) |arg, i| {
740 duped_args[i] = if (arg) |a| b.dupe(a) else null;744 duped_args[i] = if (arg) |a| graph.dupeString(a) else null;
741 }745 }
742 compile.exec_cmd_args = duped_args;746 compile.exec_cmd_args = duped_args;
743}747}
lib/std/Build/Step/Run.zig+57-43
...@@ -139,7 +139,7 @@ pub const Arg = union(enum) {...@@ -139,7 +139,7 @@ pub const Arg = union(enum) {
139 lazy_path: PrefixedLazyPath,139 lazy_path: PrefixedLazyPath,
140 decorated_directory: DecoratedLazyPath,140 decorated_directory: DecoratedLazyPath,
141 file_content: PrefixedLazyPath,141 file_content: PrefixedLazyPath,
142 bytes: []u8,142 bytes: [:0]const u8,
143 output_file: *Output,143 output_file: *Output,
144 output_directory: *Output,144 output_directory: *Output,
145 /// The arguments passed after "--" on the "zig build" CLI.145 /// The arguments passed after "--" on the "zig build" CLI.
...@@ -228,13 +228,14 @@ pub fn addArtifactArg(run: *Run, artifact: *Step.Compile) void {...@@ -228,13 +228,14 @@ pub fn addArtifactArg(run: *Run, artifact: *Step.Compile) void {
228}228}
229229
230pub fn addPrefixedArtifactArg(run: *Run, prefix: []const u8, artifact: *Step.Compile) void {230pub fn addPrefixedArtifactArg(run: *Run, prefix: []const u8, artifact: *Step.Compile) void {
231 const b = run.step.owner;231 const graph = run.step.owner.graph;
232 const arena = graph.arena;
232233
233 const prefixed_artifact: PrefixedArtifact = .{234 const prefixed_artifact: PrefixedArtifact = .{
234 .prefix = b.dupe(prefix),235 .prefix = graph.dupeString(prefix),
235 .artifact = artifact,236 .artifact = artifact,
236 };237 };
237 run.argv.append(b.allocator, .{ .artifact = prefixed_artifact }) catch @panic("OOM");238 run.argv.append(arena, .{ .artifact = prefixed_artifact }) catch @panic("OOM");
238239
239 const bin_file = artifact.getEmittedBin();240 const bin_file = artifact.getEmittedBin();
240 bin_file.addStepDependencies(&run.step);241 bin_file.addStepDependencies(&run.step);
...@@ -279,8 +280,8 @@ pub fn addPrefixedOutputFileArg(...@@ -279,8 +280,8 @@ pub fn addPrefixedOutputFileArg(
279280
280 const output = arena.create(Output) catch @panic("OOM");281 const output = arena.create(Output) catch @panic("OOM");
281 output.* = .{282 output.* = .{
282 .prefix = b.dupe(prefix),283 .prefix = graph.dupeString(prefix),
283 .basename = b.dupe(basename),284 .basename = graph.dupeString(basename),
284 .generated_file = graph.addGeneratedFile(&run.step),285 .generated_file = graph.addGeneratedFile(&run.step),
285 };286 };
286 run.argv.append(arena, .{ .output_file = output }) catch @panic("OOM");287 run.argv.append(arena, .{ .output_file = output }) catch @panic("OOM");
...@@ -318,13 +319,14 @@ pub fn addFileArg(run: *Run, lp: std.Build.LazyPath) void {...@@ -318,13 +319,14 @@ pub fn addFileArg(run: *Run, lp: std.Build.LazyPath) void {
318/// * `addFileArg` - same thing but without the prefix319/// * `addFileArg` - same thing but without the prefix
319/// * `addOutputFileArg` - for files generated by the child process320/// * `addOutputFileArg` - for files generated by the child process
320pub fn addPrefixedFileArg(run: *Run, prefix: []const u8, lp: std.Build.LazyPath) void {321pub fn addPrefixedFileArg(run: *Run, prefix: []const u8, lp: std.Build.LazyPath) void {
321 const b = run.step.owner;322 const graph = run.step.owner.graph;
323 const arena = graph.arena;
322324
323 const prefixed_file_source: PrefixedLazyPath = .{325 const prefixed_file_source: PrefixedLazyPath = .{
324 .prefix = b.dupe(prefix),326 .prefix = graph.dupeString(prefix),
325 .lazy_path = lp.dupe(b),327 .lazy_path = lp.dupe(graph),
326 };328 };
327 run.argv.append(b.allocator, .{ .lazy_path = prefixed_file_source }) catch @panic("OOM");329 run.argv.append(arena, .{ .lazy_path = prefixed_file_source }) catch @panic("OOM");
328 lp.addStepDependencies(&run.step);330 lp.addStepDependencies(&run.step);
329}331}
330332
...@@ -365,7 +367,8 @@ pub fn addFileContentArg(run: *Run, lp: std.Build.LazyPath) void {...@@ -365,7 +367,8 @@ pub fn addFileContentArg(run: *Run, lp: std.Build.LazyPath) void {
365/// Related:367/// Related:
366/// * `addFileContentArg` - same thing but without the prefix368/// * `addFileContentArg` - same thing but without the prefix
367pub fn addPrefixedFileContentArg(run: *Run, prefix: []const u8, lp: std.Build.LazyPath) void {369pub fn addPrefixedFileContentArg(run: *Run, prefix: []const u8, lp: std.Build.LazyPath) void {
368 const b = run.step.owner;370 const graph = run.step.owner.graph;
371 const arena = graph.arena;
369372
370 // Some parts of this step's configure phase API rely on the first argument being somewhat373 // Some parts of this step's configure phase API rely on the first argument being somewhat
371 // transparent/readable, but the content of the file specified by `lp` remains completely374 // transparent/readable, but the content of the file specified by `lp` remains completely
...@@ -375,10 +378,10 @@ pub fn addPrefixedFileContentArg(run: *Run, prefix: []const u8, lp: std.Build.La...@@ -375,10 +378,10 @@ pub fn addPrefixedFileContentArg(run: *Run, prefix: []const u8, lp: std.Build.La
375 }378 }
376379
377 const prefixed_file_source: PrefixedLazyPath = .{380 const prefixed_file_source: PrefixedLazyPath = .{
378 .prefix = b.dupe(prefix),381 .prefix = graph.dupeString(prefix),
379 .lazy_path = lp.dupe(b),382 .lazy_path = lp.dupe(graph),
380 };383 };
381 run.argv.append(b.allocator, .{ .file_content = prefixed_file_source }) catch @panic("OOM");384 run.argv.append(arena, .{ .file_content = prefixed_file_source }) catch @panic("OOM");
382 lp.addStepDependencies(&run.step);385 lp.addStepDependencies(&run.step);
383}386}
384387
...@@ -415,18 +418,19 @@ pub fn addPrefixedOutputDirectoryArg(...@@ -415,18 +418,19 @@ pub fn addPrefixedOutputDirectoryArg(
415 basename: []const u8,418 basename: []const u8,
416) std.Build.LazyPath {419) std.Build.LazyPath {
417 if (basename.len == 0) @panic("basename must not be empty");420 if (basename.len == 0) @panic("basename must not be empty");
418 const b = run.step.owner;421 const graph = run.step.owner.graph;
422 const arena = graph.arena;
419423
420 const output = b.allocator.create(Output) catch @panic("OOM");424 const output = arena.create(Output) catch @panic("OOM");
421 output.* = .{425 output.* = .{
422 .prefix = b.dupe(prefix),426 .prefix = graph.dupeString(prefix),
423 .basename = b.dupe(basename),427 .basename = graph.dupeString(basename),
424 .generated_file = .{ .step = &run.step },428 .generated_file = .{ .step = &run.step },
425 };429 };
426 run.argv.append(b.allocator, .{ .output_directory = output }) catch @panic("OOM");430 run.argv.append(arena, .{ .output_directory = output }) catch @panic("OOM");
427431
428 if (run.rename_step_with_output_arg) {432 if (run.rename_step_with_output_arg) {
429 run.setName(b.fmt("{s} ({s})", .{ run.step.name, basename }));433 run.setName(std.fmt.allocPrint(arena, "{s} ({s})", .{ run.step.name, basename }) catch @panic("OOM"));
430 }434 }
431435
432 return .{ .generated = .{ .file = &output.generated_file } };436 return .{ .generated = .{ .file = &output.generated_file } };
...@@ -437,10 +441,11 @@ pub fn addDirectoryArg(run: *Run, lazy_directory: std.Build.LazyPath) void {...@@ -437,10 +441,11 @@ pub fn addDirectoryArg(run: *Run, lazy_directory: std.Build.LazyPath) void {
437}441}
438442
439pub fn addPrefixedDirectoryArg(run: *Run, prefix: []const u8, lazy_directory: std.Build.LazyPath) void {443pub fn addPrefixedDirectoryArg(run: *Run, prefix: []const u8, lazy_directory: std.Build.LazyPath) void {
440 const b = run.step.owner;444 const graph = run.step.owner.graph;
441 run.argv.append(b.allocator, .{ .decorated_directory = .{445 const arena = graph.arena;
442 .prefix = b.dupe(prefix),446 run.argv.append(arena, .{ .decorated_directory = .{
443 .lazy_path = lazy_directory.dupe(b),447 .prefix = graph.dupeString(prefix),
448 .lazy_path = lazy_directory.dupe(graph),
444 .suffix = "",449 .suffix = "",
445 } }) catch @panic("OOM");450 } }) catch @panic("OOM");
446 lazy_directory.addStepDependencies(&run.step);451 lazy_directory.addStepDependencies(&run.step);
...@@ -452,11 +457,12 @@ pub fn addDecoratedDirectoryArg(...@@ -452,11 +457,12 @@ pub fn addDecoratedDirectoryArg(
452 lazy_directory: std.Build.LazyPath,457 lazy_directory: std.Build.LazyPath,
453 suffix: []const u8,458 suffix: []const u8,
454) void {459) void {
455 const b = run.step.owner;460 const graph = run.step.owner.graph;
456 run.argv.append(b.allocator, .{ .decorated_directory = .{461 const arena = graph.arena;
457 .prefix = b.dupe(prefix),462 run.argv.append(arena, .{ .decorated_directory = .{
458 .lazy_path = lazy_directory.dupe(b),463 .prefix = graph.dupeString(prefix),
459 .suffix = b.dupe(suffix),464 .lazy_path = lazy_directory.dupe(graph),
465 .suffix = graph.dupeString(suffix),
460 } }) catch @panic("OOM");466 } }) catch @panic("OOM");
461 lazy_directory.addStepDependencies(&run.step);467 lazy_directory.addStepDependencies(&run.step);
462}468}
...@@ -479,8 +485,8 @@ pub fn addPrefixedDepFileOutputArg(run: *Run, prefix: []const u8, basename: []co...@@ -479,8 +485,8 @@ pub fn addPrefixedDepFileOutputArg(run: *Run, prefix: []const u8, basename: []co
479485
480 const dep_file = arena.create(Output) catch @panic("OOM");486 const dep_file = arena.create(Output) catch @panic("OOM");
481 dep_file.* = .{487 dep_file.* = .{
482 .prefix = b.dupe(prefix),488 .prefix = graph.dupeString(prefix),
483 .basename = b.dupe(basename),489 .basename = graph.dupeString(basename),
484 .generated_file = graph.addGeneratedFile(&run.step),490 .generated_file = graph.addGeneratedFile(&run.step),
485 };491 };
486492
...@@ -492,8 +498,9 @@ pub fn addPrefixedDepFileOutputArg(run: *Run, prefix: []const u8, basename: []co...@@ -492,8 +498,9 @@ pub fn addPrefixedDepFileOutputArg(run: *Run, prefix: []const u8, basename: []co
492}498}
493499
494pub fn addArg(run: *Run, arg: []const u8) void {500pub fn addArg(run: *Run, arg: []const u8) void {
495 const b = run.step.owner;501 const graph = run.step.owner.graph;
496 run.argv.append(b.allocator, .{ .bytes = b.dupe(arg) }) catch @panic("OOM");502 const arena = graph.arena;
503 run.argv.append(arena, .{ .bytes = graph.dupeString(arg) }) catch @panic("OOM");
497}504}
498505
499pub fn addArgs(run: *Run, args: []const []const u8) void {506pub fn addArgs(run: *Run, args: []const []const u8) void {
...@@ -509,8 +516,9 @@ pub fn setStdIn(run: *Run, stdin: StdIn) void {...@@ -509,8 +516,9 @@ pub fn setStdIn(run: *Run, stdin: StdIn) void {
509}516}
510517
511pub fn setCwd(run: *Run, cwd: Build.LazyPath) void {518pub fn setCwd(run: *Run, cwd: Build.LazyPath) void {
519 const graph = run.step.owner.graph;
512 cwd.addStepDependencies(&run.step);520 cwd.addStepDependencies(&run.step);
513 run.cwd = cwd.dupe(run.step.owner);521 run.cwd = cwd.dupe(graph);
514}522}
515523
516pub fn clearEnvironment(run: *Run) void {524pub fn clearEnvironment(run: *Run) void {
...@@ -580,24 +588,28 @@ pub fn removeEnvironmentVariable(run: *Run, key: []const u8) void {...@@ -580,24 +588,28 @@ pub fn removeEnvironmentVariable(run: *Run, key: []const u8) void {
580588
581/// Adds a check for exact stderr match. Does not add any other checks.589/// Adds a check for exact stderr match. Does not add any other checks.
582pub fn expectStdErrEqual(run: *Run, bytes: []const u8) void {590pub fn expectStdErrEqual(run: *Run, bytes: []const u8) void {
583 run.addCheck(.{ .expect_stderr_exact = run.step.owner.dupe(bytes) });591 const graph = run.step.owner.graph;
592 run.addCheck(.{ .expect_stderr_exact = graph.dupeString(bytes) });
584}593}
585594
586pub fn expectStdErrMatch(run: *Run, bytes: []const u8) void {595pub fn expectStdErrMatch(run: *Run, bytes: []const u8) void {
587 run.addCheck(.{ .expect_stderr_match = run.step.owner.dupe(bytes) });596 const graph = run.step.owner.graph;
597 run.addCheck(.{ .expect_stderr_match = graph.dupeString(bytes) });
588}598}
589599
590/// Adds a check for exact stdout match as well as a check for exit code 0, if600/// Adds a check for exact stdout match as well as a check for exit code 0, if
591/// there is not already an expected termination check.601/// there is not already an expected termination check.
592pub fn expectStdOutEqual(run: *Run, bytes: []const u8) void {602pub fn expectStdOutEqual(run: *Run, bytes: []const u8) void {
593 run.addCheck(.{ .expect_stdout_exact = run.step.owner.dupe(bytes) });603 const graph = run.step.owner.graph;
604 run.addCheck(.{ .expect_stdout_exact = graph.dupeString(bytes) });
594 if (!run.hasTermCheck()) run.expectExitCode(0);605 if (!run.hasTermCheck()) run.expectExitCode(0);
595}606}
596607
597/// Adds a check for stdout match as well as a check for exit code 0, if there608/// Adds a check for stdout match as well as a check for exit code 0, if there
598/// is not already an expected termination check.609/// is not already an expected termination check.
599pub fn expectStdOutMatch(run: *Run, bytes: []const u8) void {610pub fn expectStdOutMatch(run: *Run, bytes: []const u8) void {
600 run.addCheck(.{ .expect_stdout_match = run.step.owner.dupe(bytes) });611 const graph = run.step.owner.graph;
612 run.addCheck(.{ .expect_stdout_match = graph.dupeString(bytes) });
601 if (!run.hasTermCheck()) run.expectExitCode(0);613 if (!run.hasTermCheck()) run.expectExitCode(0);
602}614}
603615
...@@ -641,7 +653,7 @@ pub fn captureStdErr(run: *Run, options: CapturedStdIo.Options) std.Build.LazyPa...@@ -641,7 +653,7 @@ pub fn captureStdErr(run: *Run, options: CapturedStdIo.Options) std.Build.LazyPa
641 captured.* = .{653 captured.* = .{
642 .output = .{654 .output = .{
643 .prefix = "",655 .prefix = "",
644 .basename = if (options.basename) |basename| b.dupe(basename) else "stderr",656 .basename = if (options.basename) |basename| graph.dupeString(basename) else "stderr",
645 .generated_file = graph.addGeneratedFile(&run.step),657 .generated_file = graph.addGeneratedFile(&run.step),
646 },658 },
647 .trim_whitespace = options.trim_whitespace,659 .trim_whitespace = options.trim_whitespace,
...@@ -664,7 +676,7 @@ pub fn captureStdOut(run: *Run, options: CapturedStdIo.Options) std.Build.LazyPa...@@ -664,7 +676,7 @@ pub fn captureStdOut(run: *Run, options: CapturedStdIo.Options) std.Build.LazyPa
664 captured.* = .{676 captured.* = .{
665 .output = .{677 .output = .{
666 .prefix = "",678 .prefix = "",
667 .basename = if (options.basename) |basename| b.dupe(basename) else "stdout",679 .basename = if (options.basename) |basename| graph.dupeString(basename) else "stdout",
668 .generated_file = graph.addGeneratedFile(&run.step),680 .generated_file = graph.addGeneratedFile(&run.step),
669 },681 },
670 .trim_whitespace = options.trim_whitespace,682 .trim_whitespace = options.trim_whitespace,
...@@ -678,7 +690,9 @@ pub fn captureStdOut(run: *Run, options: CapturedStdIo.Options) std.Build.LazyPa...@@ -678,7 +690,9 @@ pub fn captureStdOut(run: *Run, options: CapturedStdIo.Options) std.Build.LazyPa
678/// If the Run step is determined to have side-effects, the Run step is always690/// If the Run step is determined to have side-effects, the Run step is always
679/// executed when it appears in the build graph, regardless of whether this691/// executed when it appears in the build graph, regardless of whether this
680/// file has been modified.692/// file has been modified.
681pub fn addFileInput(self: *Run, file_input: std.Build.LazyPath) void {693pub fn addFileInput(run: *Run, file_input: std.Build.LazyPath) void {
682 file_input.addStepDependencies(&self.step);694 const graph = run.step.owner.graph;
683 self.file_inputs.append(self.step.owner.allocator, file_input.dupe(self.step.owner)) catch @panic("OOM");695 const arena = graph.arena;
696 file_input.addStepDependencies(&run.step);
697 run.file_inputs.append(arena, file_input.dupe(graph)) catch @panic("OOM");
684}698}
lib/std/Build/Step/WriteFile.zig+15-15
...@@ -55,10 +55,10 @@ pub const Directory = struct {...@@ -55,10 +55,10 @@ pub const Directory = struct {
55 /// `exclude_extensions` takes precedence over `include_extensions`.55 /// `exclude_extensions` takes precedence over `include_extensions`.
56 include_extensions: ?[]const []const u8 = null,56 include_extensions: ?[]const []const u8 = null,
5757
58 pub fn dupe(opts: Options, b: *std.Build) Options {58 pub fn dupe(opts: Options, graph: *std.Build.Graph) Options {
59 return .{59 return .{
60 .exclude_extensions = b.dupeStrings(opts.exclude_extensions),60 .exclude_extensions = graph.dupeStrings(opts.exclude_extensions),
61 .include_extensions = if (opts.include_extensions) |incs| b.dupeStrings(incs) else null,61 .include_extensions = if (opts.include_extensions) |incs| graph.dupeStrings(incs) else null,
62 };62 };
63 }63 }
6464
...@@ -103,13 +103,13 @@ pub fn create(owner: *std.Build) *WriteFile {...@@ -103,13 +103,13 @@ pub fn create(owner: *std.Build) *WriteFile {
103}103}
104104
105pub fn add(write_file: *WriteFile, sub_path: []const u8, bytes: []const u8) std.Build.LazyPath {105pub fn add(write_file: *WriteFile, sub_path: []const u8, bytes: []const u8) std.Build.LazyPath {
106 const b = write_file.step.owner;106 const graph = write_file.step.owner.graph;
107 const gpa = b.allocator;107 const arena = graph.arena;
108 const file = File{108 const file: File = .{
109 .sub_path = b.dupePath(sub_path),109 .sub_path = graph.dupePath(sub_path),
110 .contents = .{ .bytes = b.dupe(bytes) },110 .contents = .{ .bytes = graph.dupeString(bytes) },
111 };111 };
112 write_file.files.append(gpa, file) catch @panic("OOM");112 write_file.files.append(arena, file) catch @panic("OOM");
113 write_file.maybeUpdateName();113 write_file.maybeUpdateName();
114 return .{114 return .{
115 .generated = .{115 .generated = .{
...@@ -154,14 +154,14 @@ pub fn addCopyDirectory(...@@ -154,14 +154,14 @@ pub fn addCopyDirectory(
154 sub_path: []const u8,154 sub_path: []const u8,
155 options: Directory.Options,155 options: Directory.Options,
156) std.Build.LazyPath {156) std.Build.LazyPath {
157 const b = write_file.step.owner;157 const graph = write_file.step.owner.graph;
158 const gpa = b.allocator;158 const arena = graph.arena;
159 const dir = Directory{159 const dir = Directory{
160 .source = source.dupe(b),160 .source = source.dupe(graph),
161 .sub_path = b.dupePath(sub_path),161 .sub_path = graph.dupePath(sub_path),
162 .options = options.dupe(b),162 .options = options.dupe(graph),
163 };163 };
164 write_file.directories.append(gpa, dir) catch @panic("OOM");164 write_file.directories.append(arena, dir) catch @panic("OOM");
165165
166 write_file.maybeUpdateName();166 write_file.maybeUpdateName();
167 source.addStepDependencies(&write_file.step);167 source.addStepDependencies(&write_file.step);
src/main.zig+1
...@@ -5356,6 +5356,7 @@ fn cmdBuild(...@@ -5356,6 +5356,7 @@ fn cmdBuild(
5356 .cc_argv = &.{},5356 .cc_argv = &.{},
5357 .inherited = .{5357 .inherited = .{
5358 .resolved_target = resolved_target,5358 .resolved_target = resolved_target,
5359 .single_threaded = true,
5359 },5360 },
5360 .global = config,5361 .global = config,
5361 .parent = null,5362 .parent = null,