diff --git a/BRANCH_TODO b/BRANCH_TODO index 5ddc34a099..29cafe75c4 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -1,10 +1,10 @@ +* remove Cache from configurer * implement the build options * don't forget to add -listen arg back * get zig init template working * finish migrating the rest of the build steps * make zig-pkg path root configurable in maker (make sure --system still works) * eliminate calls to getPath, getPath2, getPath3 -* replace b.dupe() with string internment * solve the TODOs added in this branch * get zig tests passing * test a bunch of third party projects / help people migrate diff --git a/lib/compiler/configurer.zig b/lib/compiler/configurer.zig index 816f71158c..ad59f57f91 100644 --- a/lib/compiler/configurer.zig +++ b/lib/compiler/configurer.zig @@ -24,31 +24,22 @@ pub const std_options: std.Options = .{ }; pub fn main(init: process.Init.Minimal) !void { - // The build runner is often short-lived, but thanks to `--watch` and `--webui`, that's not - // always the case. So, we do need a true gpa for some things. - var debug_gpa_state: std.heap.DebugAllocator(.{ - // We'd rather have `zig build` run faster than catch harmless leaks in - // the user's build.zig script. - .stack_trace_frames = 0, - }) = .init; - defer _ = debug_gpa_state.deinit(); - const gpa = debug_gpa_state.allocator(); + var arena_allocator: std.heap.ArenaAllocator = .init(std.heap.page_allocator); + defer arena_allocator.deinit(); + const arena = arena_allocator.allocator(); - var threaded: std.Io.Threaded = .init(gpa, .{ + // The configurer is always short-lived because all it does is serialize + // the configuration, which is picked up by a separate maker process. + var threaded: std.Io.Threaded = .init(arena, .{ .environ = init.environ, .argv0 = .init(init.args), }); defer threaded.deinit(); const io = threaded.io(); - // ...but we'll back our arena by `std.heap.page_allocator` for efficiency. - var arena_allocator: std.heap.ArenaAllocator = .init(std.heap.page_allocator); - defer arena_allocator.deinit(); - const arena = arena_allocator.allocator(); - const args = try init.args.toSlice(arena); - // skip my own exe name + // Skip own executable name. var arg_idx: usize = 1; const zig_exe = expectArgOrFatal(args, &arg_idx, "--zig"); @@ -84,7 +75,7 @@ pub fn main(init: process.Init.Minimal) !void { .arena = arena, .cache = .{ .io = io, - .gpa = gpa, + .gpa = arena, .manifest_dir = try local_cache_directory.handle.createDirPathOpen(io, "h", .{}), .cwd = try process.currentPathAlloc(io, arena), }, @@ -97,7 +88,18 @@ pub fn main(init: process.Init.Minimal) !void { .result = try std.zig.system.resolveTargetQuery(io, .{}), }, .generated_files = .empty, + + // Created before running the user's configure script so that some things + // can be added during script execution such as strings. + // + // Use of arena here is load-bearing because `std.Build.dupe` is + // implemented by string internment, and then returning the interned + // slice. When the string bytes array is reallocated, that reference + // must stay alive. + .wip_configuration = .init(arena), }; + assert(try graph.wip_configuration.addString("") == .empty); + assert(try graph.wip_configuration.addString("root") == .root); graph.cache.addPrefix(.{ .path = null, .handle = cwd }); graph.cache.addPrefix(build_root_directory); @@ -200,19 +202,15 @@ pub fn main(init: process.Init.Minimal) !void { fatal(" access the help menu with 'zig build -h'", .{}); } - var wc: Configuration.Wip = .init(gpa); - defer wc.deinit(); - assert(try wc.addString("") == .empty); - assert(try wc.addString("root") == .root); - - try serializeSystemIntegrationOptions(&graph, &wc); + try serializeSystemIntegrationOptions(&graph, &graph.wip_configuration); var stdout_buffer: [1024]u8 = undefined; var file_writer = Io.File.stdout().writerStreaming(io, &stdout_buffer); - serialize(builder, &wc, &file_writer.interface) catch |err| switch (err) { + serialize(builder, &graph.wip_configuration, &file_writer.interface) catch |err| switch (err) { error.WriteFailed => fatal("failed to write configuration output: {t}", .{file_writer.err.?}), error.OutOfMemory => |e| return e, }; + file_writer.flush() catch |err| fatal("failed to write configuration output: {t}", .{err}); // This executable is short-lived and run in Debug mode, so we'd rather // have `zig build` run faster than catch resource leaks in the user's diff --git a/lib/std/Build.zig b/lib/std/Build.zig index cfe9dfa946..bc9e1e98a0 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -115,11 +115,37 @@ pub const Graph = struct { /// Indexes correspond to `Configuration.GeneratedFileIndex`. generated_files: std.ArrayList(*Step), + wip_configuration: Configuration.Wip, pub fn addGeneratedFile(graph: *Graph, owner: *Step) Configuration.GeneratedFileIndex { graph.generated_files.append(graph.arena, owner) catch @panic("OOM"); return @enumFromInt(graph.generated_files.items.len - 1); } + + pub fn dupeString(graph: *Graph, bytes: []const u8) [:0]const u8 { + // This code assumes the `Configuration.Wip` uses arena allocation such + // that references to string_bytes never die even when the ArrayList is + // reallocated. + const wc = &graph.wip_configuration; + const i = wc.addString(bytes) catch @panic("OOM"); + return wc.string_bytes.items[@intFromEnum(i)..][0..bytes.len :0]; + } + + pub fn dupePath(graph: *Graph, bytes: []const u8) [:0]const u8 { + if (builtin.os.tag != .windows) return dupeString(graph, bytes); + const arena = graph.arena; + const the_copy = arena.dupe(u8, bytes) catch @panic("OOM"); + defer arena.free(the_copy); + mem.replaceScalar(u8, the_copy, '/', '\\'); + return dupeString(graph, the_copy); + } + + pub fn dupeStrings(graph: *Graph, strings: []const []const u8) []const []const u8 { + const arena = graph.arena; + const array = arena.alloc([]const u8, strings.len) catch @panic("OOM"); + for (array, strings) |*dest, source| dest.* = dupeString(graph, source); + return array; + } }; const AvailableDeps = []const struct { []const u8, []const u8 }; @@ -869,36 +895,18 @@ pub fn addConfigHeader( return config_header_step; } -/// Allocator.dupe without the need to handle out of memory. -pub fn dupe(b: *Build, bytes: []const u8) []u8 { - return dupeInner(b.allocator, bytes); -} - -pub fn dupeInner(allocator: Allocator, bytes: []const u8) []u8 { - return allocator.dupe(u8, bytes) catch @panic("OOM"); +pub fn dupe(b: *Build, bytes: []const u8) [:0]const u8 { + return b.graph.dupeString(bytes); } /// Duplicates an array of strings without the need to handle out of memory. -pub fn dupeStrings(b: *Build, strings: []const []const u8) [][]u8 { - const array = b.allocator.alloc([]u8, strings.len) catch @panic("OOM"); - for (array, strings) |*dest, source| dest.* = b.dupe(source); - return array; +pub fn dupeStrings(b: *Build, strings: []const []const u8) []const []const u8 { + return b.graph.dupeStrings(strings); } -/// Duplicates a path and converts all slashes to the OS's canonical path separator. -pub fn dupePath(b: *Build, bytes: []const u8) []u8 { - return dupePathInner(b.allocator, bytes); -} - -fn dupePathInner(allocator: Allocator, bytes: []const u8) []u8 { - const the_copy = dupeInner(allocator, bytes); - for (the_copy) |*byte| { - switch (byte.*) { - '/', '\\' => byte.* = fs.path.sep, - else => {}, - } - } - return the_copy; +/// Duplicates a path, canonicalizing path separators. +pub fn dupePath(b: *Build, bytes: []const u8) [:0]const u8 { + return b.graph.dupePath(bytes); } pub fn addWriteFile(b: *Build, file_path: []const u8, data: []const u8) *Step.WriteFile { @@ -2268,25 +2276,18 @@ pub const LazyPath = union(enum) { /// /// The `b` parameter is only used for its allocator. All *Build instances /// share the same allocator. - pub fn dupe(lazy_path: LazyPath, b: *Build) LazyPath { - return lazy_path.dupeInner(b.allocator); - } - - fn dupeInner(lazy_path: LazyPath, allocator: Allocator) LazyPath { + pub fn dupe(lazy_path: LazyPath, graph: *Graph) LazyPath { return switch (lazy_path) { - .src_path => |sp| .{ .src_path = .{ - .owner = sp.owner, - .sub_path = sp.owner.dupePath(sp.sub_path), - } }, - .cwd_relative => |p| .{ .cwd_relative = dupePathInner(allocator, p) }, + .src_path => |sp| .{ .src_path = .{ .owner = sp.owner, .sub_path = sp.owner.dupePath(sp.sub_path) } }, + .cwd_relative => |p| .{ .cwd_relative = graph.dupePath(p) }, .generated => |gen| .{ .generated = .{ .index = gen.index, .up = gen.up, - .sub_path = dupePathInner(allocator, gen.sub_path), + .sub_path = graph.dupePath(gen.sub_path), } }, .dependency => |dep| .{ .dependency = .{ .dependency = dep.dependency, - .sub_path = dupePathInner(allocator, dep.sub_path), + .sub_path = graph.dupePath(dep.sub_path), } }, }; } diff --git a/lib/std/Build/Configuration.zig b/lib/std/Build/Configuration.zig index 7c4f06562d..47fe0009a6 100644 --- a/lib/std/Build/Configuration.zig +++ b/lib/std/Build/Configuration.zig @@ -1419,13 +1419,6 @@ pub const Path = extern struct { global_cache, build_root, }; - - pub fn toCachePath(path: Path, c: *const Configuration, arena: Allocator) std.Build.Cache.Path { - _ = c; - _ = arena; - _ = path; - @panic("TODO"); - } }; pub const InstallDestDir = enum(u32) { diff --git a/lib/std/Build/Module.zig b/lib/std/Build/Module.zig index 22100e1b2e..1c271023ef 100644 --- a/lib/std/Build/Module.zig +++ b/lib/std/Build/Module.zig @@ -240,13 +240,14 @@ pub fn init( owner: *std.Build, value: union(enum) { options: CreateOptions, existing: *const Module }, ) void { - const allocator = owner.allocator; + const graph = owner.graph; + const arena = graph.arena; switch (value) { .options => |options| { m.* = .{ .owner = owner, - .root_source_file = if (options.root_source_file) |lp| lp.dupe(owner) else null, + .root_source_file = if (options.root_source_file) |lp| lp.dupe(graph) else null, .import_table = .empty, .resolved_target = options.target, .optimize = options.optimize, @@ -277,7 +278,7 @@ pub fn init( .no_builtin = options.no_builtin, }; - m.import_table.ensureUnusedCapacity(allocator, options.imports.len) catch @panic("OOM"); + m.import_table.ensureUnusedCapacity(arena, options.imports.len) catch @panic("OOM"); for (options.imports) |dep| { m.import_table.putAssumeCapacity(dep.name, dep.module); } diff --git a/lib/std/Build/Step/Compile.zig b/lib/std/Build/Step/Compile.zig index d9c1a283e1..b48a3c114e 100644 --- a/lib/std/Build/Step/Compile.zig +++ b/lib/std/Build/Step/Compile.zig @@ -296,10 +296,10 @@ pub const HeaderInstallation = union(enum) { source: LazyPath, dest_rel_path: []const u8, - pub fn dupe(file: File, b: *std.Build) File { + pub fn dupe(file: File, graph: *std.Build.Graph) File { return .{ - .source = file.source.dupe(b), - .dest_rel_path = b.dupePath(file.dest_rel_path), + .source = file.source.dupe(graph), + .dest_rel_path = graph.dupePath(file.dest_rel_path), }; } }; @@ -424,13 +424,13 @@ pub fn create(owner: *std.Build, options: Options) *Compile { }; if (options.zig_lib_dir) |lp| { - compile.zig_lib_dir = lp.dupe(compile.step.owner); + compile.zig_lib_dir = lp.dupe(graph); lp.addStepDependencies(&compile.step); } if (options.test_runner) |runner| { compile.test_runner = .{ - .path = runner.path.dupe(compile.step.owner), + .path = runner.path.dupe(graph), .mode = runner.mode, }; runner.path.addStepDependencies(&compile.step); @@ -440,20 +440,20 @@ pub fn create(owner: *std.Build, options: Options) *Compile { // gets embedded, so for any other target the manifest file is just ignored. if (target.ofmt == .coff) { if (options.win32_manifest) |lp| { - compile.win32_manifest = lp.dupe(compile.step.owner); + compile.win32_manifest = lp.dupe(graph); lp.addStepDependencies(&compile.step); } if (compile.kind == .lib and compile.linkage != null and compile.linkage.? == .dynamic) { // Building a Win32 DLL, check for win32 .def file. if (options.win32_module_definition) |lp| { - compile.win32_module_definition = lp.dupe(compile.step.owner); + compile.win32_module_definition = lp.dupe(graph); lp.addStepDependencies(&compile.step); } } } if (options.entitlements) |lp| { - compile.entitlements = lp.dupe(compile.step.owner); + compile.entitlements = lp.dupe(graph); lp.addStepDependencies(&compile.step); } @@ -464,12 +464,13 @@ pub fn create(owner: *std.Build, options: Options) *Compile { /// When a module links with this artifact, all headers marked for installation are added to that /// module's include search path. pub fn installHeader(cs: *Compile, source: LazyPath, dest_rel_path: []const u8) void { - const b = cs.step.owner; + const graph = cs.step.owner.graph; + const arena = graph.arena; const installation: HeaderInstallation = .{ .file = .{ - .source = source.dupe(b), - .dest_rel_path = b.dupePath(dest_rel_path), + .source = source.dupe(graph), + .dest_rel_path = graph.dupePath(dest_rel_path), } }; - cs.installed_headers.append(b.allocator, installation) catch @panic("OOM"); + cs.installed_headers.append(arena, installation) catch @panic("OOM"); cs.addHeaderInstallationToIncludeTree(installation); installation.getSource().addStepDependencies(&cs.step); } @@ -483,13 +484,14 @@ pub fn installHeadersDirectory( dest_rel_path: []const u8, options: HeaderInstallation.Directory.Options, ) void { - const b = cs.step.owner; + const graph = cs.step.owner.graph; + const arena = graph.arena; const installation: HeaderInstallation = .{ .directory = .{ - .source = source.dupe(b), - .dest_rel_path = b.dupePath(dest_rel_path), - .options = options.dupe(b), + .source = source.dupe(graph), + .dest_rel_path = graph.dupePath(dest_rel_path), + .options = options.dupe(graph), } }; - cs.installed_headers.append(b.allocator, installation) catch @panic("OOM"); + cs.installed_headers.append(arena, installation) catch @panic("OOM"); cs.addHeaderInstallationToIncludeTree(installation); installation.getSource().addStepDependencies(&cs.step); } @@ -506,9 +508,10 @@ pub fn installConfigHeader(cs: *Compile, config_header: *Step.ConfigHeader) void /// module's include search path. pub fn installLibraryHeaders(cs: *Compile, lib: *Compile) void { assert(lib.kind == .lib); - const arena = cs.owner.allocator; + const graph = cs.step.owner.graph; + const arena = graph.arena; for (lib.installed_headers.items) |installation| { - const installation_copy = installation.dupe(lib.step.owner); + const installation_copy = installation.dupe(graph); cs.installed_headers.append(arena, installation_copy) catch @panic("OOM"); cs.addHeaderInstallationToIncludeTree(installation_copy); installation_copy.getSource().addStepDependencies(&cs.step); @@ -560,21 +563,21 @@ pub fn checkObject(compile: *Compile) *Step.CheckObject { } pub fn setLinkerScript(compile: *Compile, source: LazyPath) void { - const b = compile.step.owner; - compile.linker_script = source.dupe(b); + const graph = compile.step.owner.graph; + compile.linker_script = source.dupe(graph); source.addStepDependencies(&compile.step); } pub fn setVersionScript(compile: *Compile, source: LazyPath) void { - const b = compile.step.owner; - compile.version_script = source.dupe(b); + const graph = compile.step.owner.graph; + compile.version_script = source.dupe(graph); source.addStepDependencies(&compile.step); } pub fn forceUndefinedSymbol(compile: *Compile, symbol_name: []const u8) void { - const b = compile.step.owner; - const arena = b.allocator; - compile.force_undefined_symbols.put(arena, b.dupe(symbol_name), {}) catch @panic("OOM"); + const graph = compile.step.owner.graph; + const arena = graph.allocator; + compile.force_undefined_symbols.put(arena, graph.dupeString(symbol_name), {}) catch @panic("OOM"); } /// Returns whether the library, executable, or object depends on a particular system library. @@ -659,9 +662,9 @@ pub fn setVerboseCC(compile: *Compile, value: bool) void { } pub fn setLibCFile(compile: *Compile, libc_file: ?LazyPath) void { - const b = compile.step.owner; + const graph = compile.step.owner.graph; if (libc_file) |f| { - compile.libc_file = f.dupe(b); + compile.libc_file = f.dupe(graph); f.addStepDependencies(&compile.step); } else { compile.libc_file = null; @@ -737,11 +740,12 @@ pub fn getEmittedLlvmBc(compile: *Compile) LazyPath { } pub fn setExecCmd(compile: *Compile, args: []const ?[]const u8) void { - const b = compile.step.owner; + const graph = compile.step.owner.graph; + const arena = graph.arena; assert(compile.kind == .@"test"); - const duped_args = b.allocator.alloc(?[]u8, args.len) catch @panic("OOM"); + const duped_args = arena.alloc(?[]u8, args.len) catch @panic("OOM"); for (args, 0..) |arg, i| { - duped_args[i] = if (arg) |a| b.dupe(a) else null; + duped_args[i] = if (arg) |a| graph.dupeString(a) else null; } compile.exec_cmd_args = duped_args; } diff --git a/lib/std/Build/Step/Run.zig b/lib/std/Build/Step/Run.zig index e51be09242..f55074109c 100644 --- a/lib/std/Build/Step/Run.zig +++ b/lib/std/Build/Step/Run.zig @@ -139,7 +139,7 @@ pub const Arg = union(enum) { lazy_path: PrefixedLazyPath, decorated_directory: DecoratedLazyPath, file_content: PrefixedLazyPath, - bytes: []u8, + bytes: [:0]const u8, output_file: *Output, output_directory: *Output, /// The arguments passed after "--" on the "zig build" CLI. @@ -228,13 +228,14 @@ pub fn addArtifactArg(run: *Run, artifact: *Step.Compile) void { } pub fn addPrefixedArtifactArg(run: *Run, prefix: []const u8, artifact: *Step.Compile) void { - const b = run.step.owner; + const graph = run.step.owner.graph; + const arena = graph.arena; const prefixed_artifact: PrefixedArtifact = .{ - .prefix = b.dupe(prefix), + .prefix = graph.dupeString(prefix), .artifact = artifact, }; - run.argv.append(b.allocator, .{ .artifact = prefixed_artifact }) catch @panic("OOM"); + run.argv.append(arena, .{ .artifact = prefixed_artifact }) catch @panic("OOM"); const bin_file = artifact.getEmittedBin(); bin_file.addStepDependencies(&run.step); @@ -279,8 +280,8 @@ pub fn addPrefixedOutputFileArg( const output = arena.create(Output) catch @panic("OOM"); output.* = .{ - .prefix = b.dupe(prefix), - .basename = b.dupe(basename), + .prefix = graph.dupeString(prefix), + .basename = graph.dupeString(basename), .generated_file = graph.addGeneratedFile(&run.step), }; run.argv.append(arena, .{ .output_file = output }) catch @panic("OOM"); @@ -318,13 +319,14 @@ pub fn addFileArg(run: *Run, lp: std.Build.LazyPath) void { /// * `addFileArg` - same thing but without the prefix /// * `addOutputFileArg` - for files generated by the child process pub fn addPrefixedFileArg(run: *Run, prefix: []const u8, lp: std.Build.LazyPath) void { - const b = run.step.owner; + const graph = run.step.owner.graph; + const arena = graph.arena; const prefixed_file_source: PrefixedLazyPath = .{ - .prefix = b.dupe(prefix), - .lazy_path = lp.dupe(b), + .prefix = graph.dupeString(prefix), + .lazy_path = lp.dupe(graph), }; - run.argv.append(b.allocator, .{ .lazy_path = prefixed_file_source }) catch @panic("OOM"); + run.argv.append(arena, .{ .lazy_path = prefixed_file_source }) catch @panic("OOM"); lp.addStepDependencies(&run.step); } @@ -365,7 +367,8 @@ pub fn addFileContentArg(run: *Run, lp: std.Build.LazyPath) void { /// Related: /// * `addFileContentArg` - same thing but without the prefix pub fn addPrefixedFileContentArg(run: *Run, prefix: []const u8, lp: std.Build.LazyPath) void { - const b = run.step.owner; + const graph = run.step.owner.graph; + const arena = graph.arena; // Some parts of this step's configure phase API rely on the first argument being somewhat // 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 } const prefixed_file_source: PrefixedLazyPath = .{ - .prefix = b.dupe(prefix), - .lazy_path = lp.dupe(b), + .prefix = graph.dupeString(prefix), + .lazy_path = lp.dupe(graph), }; - run.argv.append(b.allocator, .{ .file_content = prefixed_file_source }) catch @panic("OOM"); + run.argv.append(arena, .{ .file_content = prefixed_file_source }) catch @panic("OOM"); lp.addStepDependencies(&run.step); } @@ -415,18 +418,19 @@ pub fn addPrefixedOutputDirectoryArg( basename: []const u8, ) std.Build.LazyPath { if (basename.len == 0) @panic("basename must not be empty"); - const b = run.step.owner; + const graph = run.step.owner.graph; + const arena = graph.arena; - const output = b.allocator.create(Output) catch @panic("OOM"); + const output = arena.create(Output) catch @panic("OOM"); output.* = .{ - .prefix = b.dupe(prefix), - .basename = b.dupe(basename), + .prefix = graph.dupeString(prefix), + .basename = graph.dupeString(basename), .generated_file = .{ .step = &run.step }, }; - run.argv.append(b.allocator, .{ .output_directory = output }) catch @panic("OOM"); + run.argv.append(arena, .{ .output_directory = output }) catch @panic("OOM"); if (run.rename_step_with_output_arg) { - run.setName(b.fmt("{s} ({s})", .{ run.step.name, basename })); + run.setName(std.fmt.allocPrint(arena, "{s} ({s})", .{ run.step.name, basename }) catch @panic("OOM")); } return .{ .generated = .{ .file = &output.generated_file } }; @@ -437,10 +441,11 @@ pub fn addDirectoryArg(run: *Run, lazy_directory: std.Build.LazyPath) void { } pub fn addPrefixedDirectoryArg(run: *Run, prefix: []const u8, lazy_directory: std.Build.LazyPath) void { - const b = run.step.owner; - run.argv.append(b.allocator, .{ .decorated_directory = .{ - .prefix = b.dupe(prefix), - .lazy_path = lazy_directory.dupe(b), + const graph = run.step.owner.graph; + const arena = graph.arena; + run.argv.append(arena, .{ .decorated_directory = .{ + .prefix = graph.dupeString(prefix), + .lazy_path = lazy_directory.dupe(graph), .suffix = "", } }) catch @panic("OOM"); lazy_directory.addStepDependencies(&run.step); @@ -452,11 +457,12 @@ pub fn addDecoratedDirectoryArg( lazy_directory: std.Build.LazyPath, suffix: []const u8, ) void { - const b = run.step.owner; - run.argv.append(b.allocator, .{ .decorated_directory = .{ - .prefix = b.dupe(prefix), - .lazy_path = lazy_directory.dupe(b), - .suffix = b.dupe(suffix), + const graph = run.step.owner.graph; + const arena = graph.arena; + run.argv.append(arena, .{ .decorated_directory = .{ + .prefix = graph.dupeString(prefix), + .lazy_path = lazy_directory.dupe(graph), + .suffix = graph.dupeString(suffix), } }) catch @panic("OOM"); lazy_directory.addStepDependencies(&run.step); } @@ -479,8 +485,8 @@ pub fn addPrefixedDepFileOutputArg(run: *Run, prefix: []const u8, basename: []co const dep_file = arena.create(Output) catch @panic("OOM"); dep_file.* = .{ - .prefix = b.dupe(prefix), - .basename = b.dupe(basename), + .prefix = graph.dupeString(prefix), + .basename = graph.dupeString(basename), .generated_file = graph.addGeneratedFile(&run.step), }; @@ -492,8 +498,9 @@ pub fn addPrefixedDepFileOutputArg(run: *Run, prefix: []const u8, basename: []co } pub fn addArg(run: *Run, arg: []const u8) void { - const b = run.step.owner; - run.argv.append(b.allocator, .{ .bytes = b.dupe(arg) }) catch @panic("OOM"); + const graph = run.step.owner.graph; + const arena = graph.arena; + run.argv.append(arena, .{ .bytes = graph.dupeString(arg) }) catch @panic("OOM"); } pub fn addArgs(run: *Run, args: []const []const u8) void { @@ -509,8 +516,9 @@ pub fn setStdIn(run: *Run, stdin: StdIn) void { } pub fn setCwd(run: *Run, cwd: Build.LazyPath) void { + const graph = run.step.owner.graph; cwd.addStepDependencies(&run.step); - run.cwd = cwd.dupe(run.step.owner); + run.cwd = cwd.dupe(graph); } pub fn clearEnvironment(run: *Run) void { @@ -580,24 +588,28 @@ pub fn removeEnvironmentVariable(run: *Run, key: []const u8) void { /// Adds a check for exact stderr match. Does not add any other checks. pub fn expectStdErrEqual(run: *Run, bytes: []const u8) void { - run.addCheck(.{ .expect_stderr_exact = run.step.owner.dupe(bytes) }); + const graph = run.step.owner.graph; + run.addCheck(.{ .expect_stderr_exact = graph.dupeString(bytes) }); } pub fn expectStdErrMatch(run: *Run, bytes: []const u8) void { - run.addCheck(.{ .expect_stderr_match = run.step.owner.dupe(bytes) }); + const graph = run.step.owner.graph; + run.addCheck(.{ .expect_stderr_match = graph.dupeString(bytes) }); } /// Adds a check for exact stdout match as well as a check for exit code 0, if /// there is not already an expected termination check. pub fn expectStdOutEqual(run: *Run, bytes: []const u8) void { - run.addCheck(.{ .expect_stdout_exact = run.step.owner.dupe(bytes) }); + const graph = run.step.owner.graph; + run.addCheck(.{ .expect_stdout_exact = graph.dupeString(bytes) }); if (!run.hasTermCheck()) run.expectExitCode(0); } /// Adds a check for stdout match as well as a check for exit code 0, if there /// is not already an expected termination check. pub fn expectStdOutMatch(run: *Run, bytes: []const u8) void { - run.addCheck(.{ .expect_stdout_match = run.step.owner.dupe(bytes) }); + const graph = run.step.owner.graph; + run.addCheck(.{ .expect_stdout_match = graph.dupeString(bytes) }); if (!run.hasTermCheck()) run.expectExitCode(0); } @@ -641,7 +653,7 @@ pub fn captureStdErr(run: *Run, options: CapturedStdIo.Options) std.Build.LazyPa captured.* = .{ .output = .{ .prefix = "", - .basename = if (options.basename) |basename| b.dupe(basename) else "stderr", + .basename = if (options.basename) |basename| graph.dupeString(basename) else "stderr", .generated_file = graph.addGeneratedFile(&run.step), }, .trim_whitespace = options.trim_whitespace, @@ -664,7 +676,7 @@ pub fn captureStdOut(run: *Run, options: CapturedStdIo.Options) std.Build.LazyPa captured.* = .{ .output = .{ .prefix = "", - .basename = if (options.basename) |basename| b.dupe(basename) else "stdout", + .basename = if (options.basename) |basename| graph.dupeString(basename) else "stdout", .generated_file = graph.addGeneratedFile(&run.step), }, .trim_whitespace = options.trim_whitespace, @@ -678,7 +690,9 @@ pub fn captureStdOut(run: *Run, options: CapturedStdIo.Options) std.Build.LazyPa /// If the Run step is determined to have side-effects, the Run step is always /// executed when it appears in the build graph, regardless of whether this /// file has been modified. -pub fn addFileInput(self: *Run, file_input: std.Build.LazyPath) void { - file_input.addStepDependencies(&self.step); - self.file_inputs.append(self.step.owner.allocator, file_input.dupe(self.step.owner)) catch @panic("OOM"); +pub fn addFileInput(run: *Run, file_input: std.Build.LazyPath) void { + const graph = run.step.owner.graph; + const arena = graph.arena; + file_input.addStepDependencies(&run.step); + run.file_inputs.append(arena, file_input.dupe(graph)) catch @panic("OOM"); } diff --git a/lib/std/Build/Step/WriteFile.zig b/lib/std/Build/Step/WriteFile.zig index 14097a76ed..3e269ded6d 100644 --- a/lib/std/Build/Step/WriteFile.zig +++ b/lib/std/Build/Step/WriteFile.zig @@ -55,10 +55,10 @@ pub const Directory = struct { /// `exclude_extensions` takes precedence over `include_extensions`. include_extensions: ?[]const []const u8 = null, - pub fn dupe(opts: Options, b: *std.Build) Options { + pub fn dupe(opts: Options, graph: *std.Build.Graph) Options { return .{ - .exclude_extensions = b.dupeStrings(opts.exclude_extensions), - .include_extensions = if (opts.include_extensions) |incs| b.dupeStrings(incs) else null, + .exclude_extensions = graph.dupeStrings(opts.exclude_extensions), + .include_extensions = if (opts.include_extensions) |incs| graph.dupeStrings(incs) else null, }; } @@ -103,13 +103,13 @@ pub fn create(owner: *std.Build) *WriteFile { } pub fn add(write_file: *WriteFile, sub_path: []const u8, bytes: []const u8) std.Build.LazyPath { - const b = write_file.step.owner; - const gpa = b.allocator; - const file = File{ - .sub_path = b.dupePath(sub_path), - .contents = .{ .bytes = b.dupe(bytes) }, + const graph = write_file.step.owner.graph; + const arena = graph.arena; + const file: File = .{ + .sub_path = graph.dupePath(sub_path), + .contents = .{ .bytes = graph.dupeString(bytes) }, }; - write_file.files.append(gpa, file) catch @panic("OOM"); + write_file.files.append(arena, file) catch @panic("OOM"); write_file.maybeUpdateName(); return .{ .generated = .{ @@ -154,14 +154,14 @@ pub fn addCopyDirectory( sub_path: []const u8, options: Directory.Options, ) std.Build.LazyPath { - const b = write_file.step.owner; - const gpa = b.allocator; + const graph = write_file.step.owner.graph; + const arena = graph.arena; const dir = Directory{ - .source = source.dupe(b), - .sub_path = b.dupePath(sub_path), - .options = options.dupe(b), + .source = source.dupe(graph), + .sub_path = graph.dupePath(sub_path), + .options = options.dupe(graph), }; - write_file.directories.append(gpa, dir) catch @panic("OOM"); + write_file.directories.append(arena, dir) catch @panic("OOM"); write_file.maybeUpdateName(); source.addStepDependencies(&write_file.step); diff --git a/src/main.zig b/src/main.zig index fd9c64b0f9..bc4843748d 100644 --- a/src/main.zig +++ b/src/main.zig @@ -5369,6 +5369,7 @@ fn cmdBuild( .cc_argv = &.{}, .inherited = .{ .resolved_target = resolved_target, + .single_threaded = true, }, .global = config, .parent = null,