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
This commit is contained in:
Andrew Kelley
2026-03-17 19:05:13 -07:00
parent 4e75f97040
commit 11c770c570
9 changed files with 173 additions and 161 deletions
+1 -1
View File
@@ -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
+22 -24
View File
@@ -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
+38 -37
View File
@@ -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),
} },
};
}
-7
View File
@@ -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) {
+4 -3
View File
@@ -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);
}
+35 -31
View File
@@ -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;
}
+57 -43
View File
@@ -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");
}
+15 -15
View File
@@ -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);
+1
View File
@@ -5369,6 +5369,7 @@ fn cmdBuild(
.cc_argv = &.{},
.inherited = .{
.resolved_target = resolved_target,
.single_threaded = true,
},
.global = config,
.parent = null,