diff --git a/lib/std/build.zig b/lib/std/build.zig index 725ce694ac..0db9d4c24e 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -345,6 +345,14 @@ pub const Builder = struct { return self.allocator.dupe(u8, bytes) catch unreachable; } + pub fn dupeStrings(self: *Builder, strings: []const []const u8) [][]u8 { + const array = self.allocator.alloc([]u8, strings.len) catch unreachable; + for (strings) |s, i| { + array[i] = self.dupe(s); + } + return array; + } + pub fn dupePath(self: *Builder, bytes: []const u8) []u8 { const the_copy = self.dupe(bytes); for (the_copy) |*byte| { @@ -490,7 +498,9 @@ pub const Builder = struct { return error.InvalidStepName; } - pub fn option(self: *Builder, comptime T: type, name: []const u8, description: []const u8) ?T { + pub fn option(self: *Builder, comptime T: type, name_raw: []const u8, description_raw: []const u8) ?T { + const name = self.dupe(name_raw); + const description = self.dupe(description_raw); const type_id = comptime typeToEnum(T); const available_option = AvailableOption{ .name = name, @@ -623,7 +633,7 @@ pub const Builder = struct { const step_info = self.allocator.create(TopLevelStep) catch unreachable; step_info.* = TopLevelStep{ .step = Step.initNoOp(.TopLevel, name, self.allocator), - .description = description, + .description = self.dupe(description), }; self.top_level_steps.append(step_info) catch unreachable; return &step_info.step; @@ -760,7 +770,9 @@ pub const Builder = struct { return selected_target; } - pub fn addUserInputOption(self: *Builder, name: []const u8, value: []const u8) !bool { + pub fn addUserInputOption(self: *Builder, name_raw: []const u8, value_raw: []const u8) !bool { + const name = self.dupe(name_raw); + const value = self.dupe(value_raw); const gop = try self.user_input_options.getOrPut(name); if (!gop.found_existing) { gop.entry.value = UserInputOption{ @@ -801,7 +813,8 @@ pub const Builder = struct { return false; } - pub fn addUserInputFlag(self: *Builder, name: []const u8) !bool { + pub fn addUserInputFlag(self: *Builder, name_raw: []const u8) !bool { + const name = self.dupe(name_raw); const gop = try self.user_input_options.getOrPut(name); if (!gop.found_existing) { gop.entry.value = UserInputOption{ @@ -993,10 +1006,11 @@ pub const Builder = struct { } pub fn pushInstalledFile(self: *Builder, dir: InstallDir, dest_rel_path: []const u8) void { - self.installed_files.append(InstalledFile{ + const file = InstalledFile{ .dir = dir, .path = dest_rel_path, - }) catch unreachable; + }; + self.installed_files.append(file.dupe(self)) catch unreachable; } pub fn updateFile(self: *Builder, source_path: []const u8, dest_path: []const u8) !void { @@ -1139,7 +1153,7 @@ pub const Builder = struct { } pub fn addSearchPrefix(self: *Builder, search_prefix: []const u8) void { - self.search_prefixes.append(search_prefix) catch unreachable; + self.search_prefixes.append(self.dupePath(search_prefix)) catch unreachable; } pub fn getInstallPath(self: *Builder, dir: InstallDir, dest_rel_path: []const u8) []const u8 { @@ -1160,6 +1174,7 @@ pub const Builder = struct { fn execPkgConfigList(self: *Builder, out_code: *u8) ![]const PkgConfigPkg { const stdout = try self.execAllowFail(&[_][]const u8{ "pkg-config", "--list-all" }, out_code, .Ignore); var list = ArrayList(PkgConfigPkg).init(self.allocator); + errdefer list.deinit(); var line_it = mem.tokenize(stdout, "\r\n"); while (line_it.next()) |line| { if (mem.trim(u8, line, " \t").len == 0) continue; @@ -1169,7 +1184,7 @@ pub const Builder = struct { .desc = tok_it.rest(), }); } - return list.items; + return list.toOwnedSlice(); } fn getPkgConfigList(self: *Builder) ![]const PkgConfigPkg { @@ -1224,9 +1239,16 @@ pub const Pkg = struct { dependencies: ?[]const Pkg = null, }; -const CSourceFile = struct { +pub const CSourceFile = struct { source: FileSource, args: []const []const u8, + + fn dupe(self: CSourceFile, b: *Builder) CSourceFile { + return .{ + .source = self.source.dupe(b), + .args = b.dupeStrings(self.args), + }; + } }; const CSourceFiles = struct { @@ -1268,6 +1290,17 @@ pub const FileSource = union(enum) { .translate_c => |tc| tc.getOutputPath(), }; } + + pub fn dupe(self: FileSource, b: *Builder) FileSource { + return switch (self) { + .path => |p| .{ .path = b.dupe(p) }, + .write_file => |wf| .{ .write_file = .{ + .step = wf.step, + .basename = b.dupe(wf.basename), + } }, + .translate_c => |tc| .{ .translate_c = tc }, + }; + } }; const BuildOptionArtifactArg = struct { @@ -1443,12 +1476,14 @@ pub const LibExeObjStep = struct { fn initExtraArgs( builder: *Builder, - name: []const u8, - root_src: ?FileSource, + name_raw: []const u8, + root_src_raw: ?FileSource, kind: Kind, is_dynamic: bool, ver: ?Version, ) LibExeObjStep { + const name = builder.dupe(name_raw); + const root_src: ?FileSource = if (root_src_raw) |rsrc| rsrc.dupe(builder) else null; if (mem.indexOf(u8, name, "/") != null or mem.indexOf(u8, name, "\\") != null) { panic("invalid name: '{s}'. It looks like a file path, but it is supposed to be the library or application name.", .{name}); } @@ -1585,12 +1620,12 @@ pub const LibExeObjStep = struct { } pub fn setLinkerScriptPath(self: *LibExeObjStep, path: []const u8) void { - self.linker_script = path; + self.linker_script = self.builder.dupePath(path); } pub fn linkFramework(self: *LibExeObjStep, framework_name: []const u8) void { assert(self.target.isDarwin()); - self.frameworks.put(framework_name) catch unreachable; + self.frameworks.put(self.builder.dupe(framework_name)) catch unreachable; } /// Returns whether the library, executable, or object depends on a particular system library. @@ -1754,25 +1789,23 @@ pub const LibExeObjStep = struct { pub fn setNamePrefix(self: *LibExeObjStep, text: []const u8) void { assert(self.kind == Kind.Test); - self.name_prefix = text; + self.name_prefix = self.builder.dupe(text); } pub fn setFilter(self: *LibExeObjStep, text: ?[]const u8) void { assert(self.kind == Kind.Test); - self.filter = text; + self.filter = if (text) |t| self.builder.dupe(t) else null; } /// Handy when you have many C/C++ source files and want them all to have the same flags. pub fn addCSourceFiles(self: *LibExeObjStep, files: []const []const u8, flags: []const []const u8) void { const c_source_files = self.builder.allocator.create(CSourceFiles) catch unreachable; - const flags_copy = self.builder.allocator.alloc([]u8, flags.len) catch unreachable; - for (flags) |flag, i| { - flags_copy[i] = self.builder.dupe(flag); - } + const files_copy = self.builder.dupeStrings(files); + const flags_copy = self.builder.dupeStrings(flags); c_source_files.* = .{ - .files = files, + .files = files_copy, .flags = flags_copy, }; self.link_objects.append(LinkObject{ .CSourceFiles = c_source_files }) catch unreachable; @@ -1787,14 +1820,7 @@ pub const LibExeObjStep = struct { pub fn addCSourceFileSource(self: *LibExeObjStep, source: CSourceFile) void { const c_source_file = self.builder.allocator.create(CSourceFile) catch unreachable; - - const args_copy = self.builder.allocator.alloc([]u8, source.args.len) catch unreachable; - for (source.args) |arg, i| { - args_copy[i] = self.builder.dupe(arg); - } - - c_source_file.* = source; - c_source_file.args = args_copy; + c_source_file.* = source.dupe(self.builder); self.link_objects.append(LinkObject{ .CSourceFile = c_source_file }) catch unreachable; } @@ -1811,15 +1837,15 @@ pub const LibExeObjStep = struct { } pub fn overrideZigLibDir(self: *LibExeObjStep, dir_path: []const u8) void { - self.override_lib_dir = self.builder.dupe(dir_path); + self.override_lib_dir = self.builder.dupePath(dir_path); } pub fn setMainPkgPath(self: *LibExeObjStep, dir_path: []const u8) void { - self.main_pkg_path = dir_path; + self.main_pkg_path = self.builder.dupePath(dir_path); } pub fn setLibCFile(self: *LibExeObjStep, libc_file: ?[]const u8) void { - self.libc_file = libc_file; + self.libc_file = if (libc_file) |f| self.builder.dupe(f) else null; } /// Unless setOutputDir was called, this function must be called only in @@ -1879,8 +1905,9 @@ pub const LibExeObjStep = struct { } pub fn addAssemblyFileSource(self: *LibExeObjStep, source: FileSource) void { - self.link_objects.append(LinkObject{ .AssemblyFile = source }) catch unreachable; - source.addStepDependencies(&self.step); + const source_duped = source.dupe(self.builder); + self.link_objects.append(LinkObject{ .AssemblyFile = source_duped }) catch unreachable; + source_duped.addStepDependencies(&self.step); } pub fn addObjectFile(self: *LibExeObjStep, path: []const u8) void { @@ -1977,7 +2004,7 @@ pub const LibExeObjStep = struct { /// The value is the path in the cache dir. /// Adds a dependency automatically. pub fn addBuildOptionArtifact(self: *LibExeObjStep, name: []const u8, artifact: *LibExeObjStep) void { - self.build_options_artifact_args.append(.{ .name = name, .artifact = artifact }) catch unreachable; + self.build_options_artifact_args.append(.{ .name = self.builder.dupe(name), .artifact = artifact }) catch unreachable; self.step.dependOn(&artifact.step); } @@ -2047,7 +2074,11 @@ pub const LibExeObjStep = struct { pub fn setExecCmd(self: *LibExeObjStep, args: []const ?[]const u8) void { assert(self.kind == Kind.Test); - self.exec_cmd_args = args; + const duped_args = self.builder.allocator.alloc(?[]u8, args.len) catch unreachable; + for (args) |arg, i| { + duped_args[i] = if (arg) |a| self.builder.dupe(a) else null; + } + self.exec_cmd_args = duped_args; } fn linkLibraryOrObject(self: *LibExeObjStep, other: *LibExeObjStep) void { @@ -2665,9 +2696,9 @@ pub const InstallFileStep = struct { return InstallFileStep{ .builder = builder, .step = Step.init(.InstallFile, builder.fmt("install {s}", .{src_path}), builder.allocator, make), - .src_path = src_path, - .dir = dir, - .dest_rel_path = dest_rel_path, + .src_path = builder.dupePath(src_path), + .dir = dir.dupe(builder), + .dest_rel_path = builder.dupePath(dest_rel_path), }; } @@ -2684,6 +2715,16 @@ pub const InstallDirectoryOptions = struct { install_dir: InstallDir, install_subdir: []const u8, exclude_extensions: ?[]const []const u8 = null, + + fn dupe(self: InstallDirectoryOptions, b: *Builder) InstallDirectoryOptions { + return .{ + .source_dir = b.dupe(self.source_dir), + .install_dir = self.install_dir.dupe(b), + .install_subdir = b.dupe(self.install_subdir), + .exclude_extensions = if (self.exclude_extensions) |extensions| + b.dupeStrings(extensions) else null, + }; + } }; pub const InstallDirStep = struct { @@ -2699,7 +2740,7 @@ pub const InstallDirStep = struct { return InstallDirStep{ .builder = builder, .step = Step.init(.InstallDir, builder.fmt("install {s}/", .{options.source_dir}), builder.allocator, make), - .options = options, + .options = options.dupe(builder), }; } @@ -2735,7 +2776,7 @@ pub const LogStep = struct { return LogStep{ .builder = builder, .step = Step.init(.Log, builder.fmt("log {s}", .{data}), builder.allocator, make), - .data = data, + .data = builder.dupe(data), }; } @@ -2754,7 +2795,7 @@ pub const RemoveDirStep = struct { return RemoveDirStep{ .builder = builder, .step = Step.init(.RemoveDir, builder.fmt("RemoveDir {s}", .{dir_path}), builder.allocator, make), - .dir_path = dir_path, + .dir_path = builder.dupePath(dir_path), }; } @@ -2798,7 +2839,7 @@ pub const Step = struct { pub fn init(id: Id, name: []const u8, allocator: *Allocator, makeFn: fn (*Step) anyerror!void) Step { return Step{ .id = id, - .name = name, + .name = allocator.dupe(u8, name) catch unreachable, .makeFn = makeFn, .dependencies = ArrayList(*Step).init(allocator), .loop_flag = false, @@ -2905,11 +2946,28 @@ pub const InstallDir = union(enum) { Header: void, /// A path relative to the prefix Custom: []const u8, + + fn dupe(self: InstallDir, builder: *Builder) InstallDir { + if (self == .Custom) { + // Written with this temporary to avoid RLS problems + const duped_path = builder.dupe(self.Custom); + return .{ .Custom = duped_path }; + } else { + return self; + } + } }; pub const InstalledFile = struct { dir: InstallDir, path: []const u8, + + pub fn dupe(self: InstalledFile, builder: *Builder) InstalledFile { + return .{ + .dir = self.dir.dupe(builder), + .path = builder.dupe(self.path), + }; + } }; test "Builder.dupePkg()" { diff --git a/lib/std/build/check_file.zig b/lib/std/build/check_file.zig index 31966fad52..28c98547b7 100644 --- a/lib/std/build/check_file.zig +++ b/lib/std/build/check_file.zig @@ -27,8 +27,8 @@ pub const CheckFileStep = struct { self.* = CheckFileStep{ .builder = builder, .step = Step.init(.CheckFile, "CheckFile", builder.allocator, make), - .source = source, - .expected_matches = expected_matches, + .source = source.dupe(builder), + .expected_matches = builder.dupeStrings(expected_matches), }; self.source.addStepDependencies(&self.step); return self; diff --git a/lib/std/build/run.zig b/lib/std/build/run.zig index 8f8fa2eba0..ca39b0216e 100644 --- a/lib/std/build/run.zig +++ b/lib/std/build/run.zig @@ -76,7 +76,7 @@ pub const RunStep = struct { self.argv.append(Arg{ .WriteFile = .{ .step = write_file, - .file_name = file_name, + .file_name = self.builder.dupePath(file_name), }, }) catch unreachable; self.step.dependOn(&write_file.step); @@ -119,7 +119,7 @@ pub const RunStep = struct { const new_path = self.builder.fmt("{s}" ++ [1]u8{fs.path.delimiter} ++ "{s}", .{ pp, search_path }); env_map.set(key, new_path) catch unreachable; } else { - env_map.set(key, search_path) catch unreachable; + env_map.set(key, self.builder.dupePath(search_path)) catch unreachable; } } @@ -134,15 +134,18 @@ pub const RunStep = struct { pub fn setEnvironmentVariable(self: *RunStep, key: []const u8, value: []const u8) void { const env_map = self.getEnvMap(); - env_map.set(key, value) catch unreachable; + env_map.set( + self.builder.dupe(key), + self.builder.dupe(value), + ) catch unreachable; } pub fn expectStdErrEqual(self: *RunStep, bytes: []const u8) void { - self.stderr_action = .{ .expect_exact = bytes }; + self.stderr_action = .{ .expect_exact = self.builder.dupe(bytes) }; } pub fn expectStdOutEqual(self: *RunStep, bytes: []const u8) void { - self.stdout_action = .{ .expect_exact = bytes }; + self.stdout_action = .{ .expect_exact = self.builder.dupe(bytes) }; } fn stdIoActionToBehavior(action: StdIoAction) std.ChildProcess.StdIo { diff --git a/lib/std/build/translate_c.zig b/lib/std/build/translate_c.zig index b98b0ae9eb..4009079e3d 100644 --- a/lib/std/build/translate_c.zig +++ b/lib/std/build/translate_c.zig @@ -57,11 +57,11 @@ pub const TranslateCStep = struct { } pub fn addIncludeDir(self: *TranslateCStep, include_dir: []const u8) void { - self.include_dirs.append(include_dir) catch unreachable; + self.include_dirs.append(self.builder.dupePath(include_dir)) catch unreachable; } pub fn addCheckFile(self: *TranslateCStep, expected_matches: []const []const u8) *CheckFileStep { - return CheckFileStep.create(self.builder, .{ .translate_c = self }, expected_matches); + return CheckFileStep.create(self.builder, .{ .translate_c = self }, self.builder.dupeStrings(expected_matches)); } fn make(step: *Step) !void { diff --git a/lib/std/build/write_file.zig b/lib/std/build/write_file.zig index bbe6ec5086..6e88aa5633 100644 --- a/lib/std/build/write_file.zig +++ b/lib/std/build/write_file.zig @@ -32,7 +32,10 @@ pub const WriteFileStep = struct { } pub fn add(self: *WriteFileStep, basename: []const u8, bytes: []const u8) void { - self.files.append(.{ .basename = basename, .bytes = bytes }) catch unreachable; + self.files.append(.{ + .basename = self.builder.dupePath(basename), + .bytes = self.builder.dupe(bytes), + }) catch unreachable; } /// Unless setOutputDir was called, this function must be called only in