From 65b8b8b27bb4671443403e3d88534c0238b3c940 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 14 Aug 2026 18:27:09 -0700 Subject: [PATCH] std.Build.Cache: remove deprecated APIs improves Path hygiene in the compiler in some places also includes an assertion that will probably nede to be removed regarding absolute paths making it into the cache manifest --- lib/std/Build/Cache.zig | 31 +++------------------- src/Compilation.zig | 32 ++++++++++++----------- src/libs/freebsd.zig | 12 ++++++--- src/libs/glibc.zig | 12 ++++++--- src/libs/mingw.zig | 45 ++++++++++++-------------------- src/libs/netbsd.zig | 6 +++-- src/libs/openbsd.zig | 6 +++-- src/link.zig | 6 ++--- src/link/Lld.zig | 8 +++--- src/link/MachO.zig | 4 +-- src/link/MachO/CodeSignature.zig | 4 +-- src/main.zig | 6 ++--- 12 files changed, 75 insertions(+), 97 deletions(-) diff --git a/lib/std/Build/Cache.zig b/lib/std/Build/Cache.zig index a66f2bb543a162ba879174434ccc10dce52597de..908f531ec328839bdb3d1c3ea9a9e0ec05c45144 100644 --- a/lib/std/Build/Cache.zig +++ b/lib/std/Build/Cache.zig @@ -417,19 +417,8 @@ pub const Manifest = struct { return addFileInner(m, prefixed_path, handle, max_file_size); } - /// Deprecated; use `addFilePath`. - pub fn addFile(self: *Manifest, file_path: []const u8, max_file_size: ?usize) !usize { - assert(self.manifest_file == null); - - const gpa = self.cache.gpa; - try self.files.ensureUnusedCapacity(gpa, 1); - const prefixed_path = try self.cache.findPrefix(file_path); - errdefer gpa.free(prefixed_path.sub_path); - - return addFileInner(self, prefixed_path, null, max_file_size); - } - fn addFileInner(self: *Manifest, prefixed_path: PrefixedPath, handle: ?Io.File, max_file_size: ?usize) usize { + assert(!std.fs.path.isAbsolute(prefixed_path.sub_path)); const gop = self.files.getOrPutAssumeCapacityAdapted(prefixed_path, FilesAdapter{}); if (gop.found_existing) { self.cache.gpa.free(prefixed_path.sub_path); @@ -452,26 +441,12 @@ pub const Manifest = struct { return gop.index; } - /// Deprecated, use `addOptionalFilePath`. - pub fn addOptionalFile(self: *Manifest, optional_file_path: ?[]const u8) !void { - self.hash.add(optional_file_path != null); - const file_path = optional_file_path orelse return; - _ = try self.addFile(file_path, null); - } - pub fn addOptionalFilePath(self: *Manifest, optional_file_path: ?Path) !void { self.hash.add(optional_file_path != null); const file_path = optional_file_path orelse return; _ = try self.addFilePath(file_path, null); } - pub fn addListOfFiles(self: *Manifest, list_of_files: []const []const u8) !void { - self.hash.add(list_of_files.len); - for (list_of_files) |file_path| { - _ = try self.addFile(file_path, null); - } - } - pub fn addDepFile(self: *Manifest, dir: Io.Dir, dep_file_sub_path: []const u8) !void { assert(self.manifest_file == null); return self.addDepFileMaybePost(dir, dep_file_sub_path); @@ -1127,13 +1102,13 @@ pub const Manifest = struct { // Clang is invoked in single-source mode but other programs may not .target, .target_must_resolve => {}, .prereq => |file_path| if (self.manifest_file == null) { - _ = try self.addFile(file_path, null); + _ = try self.addFilePath(.initCwd(file_path), null); } else try self.addFilePost(file_path), .prereq_must_resolve => { resolve_buf.clearRetainingCapacity(); try token.resolve(gpa, &resolve_buf); if (self.manifest_file == null) { - _ = try self.addFile(resolve_buf.items, null); + _ = try self.addFilePath(.initCwd(resolve_buf.items), null); } else try self.addFilePost(resolve_buf.items); }, else => |err| { diff --git a/src/Compilation.zig b/src/Compilation.zig index 3e8b2043a4d496800eacea61211e2a99eab37e11..b8ae83d05a5173b58ff700f04bae6a883725dc34 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -1278,7 +1278,7 @@ pub const cache_helpers = struct { } pub fn hashCSource(self: *Cache.Manifest, c_source: CSourceFile) !void { - _ = try self.addFile(c_source.src_path, null); + _ = try self.addFilePath(.initCwd(c_source.src_path), null); // Hash the extra flags, with special care to call addFile for file parameters. // TODO this logic can likely be improved by utilizing clang_options_data.zig. const file_args = [_][]const u8{"-include"}; @@ -1289,7 +1289,7 @@ pub const cache_helpers = struct { for (file_args) |file_arg| { if (mem.eql(u8, file_arg, arg) and arg_i + 1 < c_source.extra_flags.len) { arg_i += 1; - _ = try self.addFile(c_source.extra_flags[arg_i], null); + _ = try self.addFilePath(.initCwd(c_source.extra_flags[arg_i]), null); } } } @@ -1466,8 +1466,8 @@ pub const CreateOptions = struct { stack_report: bool = false, link_eh_frame_hdr: bool = false, link_emit_relocs: bool = false, - linker_script: ?[]const u8 = null, - version_script: ?[]const u8 = null, + linker_script: ?Cache.Path = null, + version_script: ?Cache.Path = null, linker_allow_undefined_version: bool = false, linker_enable_new_dtags: ?bool = null, soname: ?[]const u8 = null, @@ -1546,7 +1546,7 @@ pub const CreateOptions = struct { /// (Darwin) Install name of the dylib install_name: ?[]const u8 = null, /// (Darwin) Path to entitlements file - entitlements: ?[]const u8 = null, + entitlements: ?Cache.Path = null, /// (Darwin) size of the __PAGEZERO segment pagezero_size: ?u64 = null, /// (Darwin) set minimum space for future expansion of the load commands @@ -2741,7 +2741,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE // If using the whole caching strategy, we check for *everything* up front, including // C source files. - log.debug("Compilation.update for {s}, CacheMode.{s}", .{ comp.root_name, @tagName(comp.cache_use) }); + log.debug("Compilation.update for {s}, CacheMode.{t}", .{ comp.root_name, comp.cache_use }); switch (comp.cache_use) { .none => |none| { assert(none.tmp_artifact_directory == null); @@ -2750,7 +2750,9 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(tmp_dir_rand_int); const path = try comp.dirs.local_cache.join(arena, &.{tmp_dir_sub_path}); const handle = comp.dirs.local_cache.handle.createDirPathOpen(io, tmp_dir_sub_path, .{}) catch |err| { - return comp.setMiscFailure(.open_output, "failed to create output directory '{s}': {t}", .{ path, err }); + return comp.setMiscFailure(.open_output, "failed to create output directory {q}: {t}", .{ + path, err, + }); }; break :d .{ .path = path, .handle = handle }; }; @@ -3336,7 +3338,7 @@ fn addNonIncrementalStuffToCacheManifest( try link.hashInputs(man, comp.link_inputs); for (comp.c_objects.items) |c_object| { - _ = try man.addFile(c_object.src.src_path, null); + _ = try man.addFilePath(.initCwd(c_object.src.src_path), null); man.hash.addOptional(c_object.src.ext); man.hash.addListOfBytes(c_object.src.extra_flags); } @@ -3344,11 +3346,11 @@ fn addNonIncrementalStuffToCacheManifest( for (comp.win32_resources.items) |win32_resource| { switch (win32_resource.src) { .rc => |rc_src| { - _ = try man.addFile(rc_src.src_path, null); + _ = try man.addFilePath(.initCwd(rc_src.src_path), null); man.hash.addListOfBytes(rc_src.extra_flags); }, .manifest => |manifest_path| { - _ = try man.addFile(manifest_path, null); + _ = try man.addFilePath(.initCwd(manifest_path), null); }, } } @@ -3380,8 +3382,8 @@ fn addNonIncrementalStuffToCacheManifest( const opts = comp.cache_use.whole.lf_open_opts; - try man.addOptionalFile(opts.linker_script); - try man.addOptionalFile(opts.version_script); + try man.addOptionalFilePath(opts.linker_script); + try man.addOptionalFilePath(opts.version_script); man.hash.add(opts.allow_undefined_version); man.hash.addOptional(opts.enable_new_dtags); @@ -3440,7 +3442,7 @@ fn addNonIncrementalStuffToCacheManifest( // Mach-O specific stuff try link.File.MachO.hashAddFrameworks(man, opts.frameworks); - try man.addOptionalFile(opts.entitlements); + try man.addOptionalFilePath(opts.entitlements); man.hash.addOptional(opts.pagezero_size); man.hash.addOptional(opts.headerpad_size); man.hash.add(opts.headerpad_max_install_names); @@ -5818,7 +5820,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32 // the XML data as a RT_MANIFEST resource. This means we can skip preprocessing, // include paths, CLI options, etc. if (win32_resource.src == .manifest) { - _ = try man.addFile(src_path, null); + _ = try man.addFilePath(.initCwd(src_path), null); const rc_basename = try std.fmt.allocPrint(arena, "{s}.rc", .{src_basename}); const res_basename = try std.fmt.allocPrint(arena, "{s}.res", .{src_basename}); @@ -5911,7 +5913,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32 // We now know that we're compiling an .rc file const rc_src = win32_resource.src.rc; - _ = try man.addFile(rc_src.src_path, null); + _ = try man.addFilePath(.initCwd(rc_src.src_path), null); man.hash.addListOfBytes(rc_src.extra_flags); const rc_basename_noext = src_basename[0 .. src_basename.len - fs.path.extension(src_basename).len]; diff --git a/src/libs/freebsd.zig b/src/libs/freebsd.zig index 0895ef4280ed25592fbcfda9fa54960675d28271..6fb4b804525700fa7f4ce9a4f3c21363ae295fa9 100644 --- a/src/libs/freebsd.zig +++ b/src/libs/freebsd.zig @@ -458,8 +458,10 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye man.hash.add(target.abi); man.hash.add(target_os_version); - const full_abilists_path = try comp.dirs.zig_lib.join(arena, &.{abilists_path}); - const abilists_index = try man.addFile(full_abilists_path, abilists_max_size); + const abilists_index = try man.addFilePath(.{ + .root_dir = comp.dirs.zig_lib, + .sub_path = abilists_path, + }, abilists_max_size); if (try man.hit(prog_node)) { const digest = man.final(); @@ -1044,7 +1046,6 @@ fn buildSharedLib( const version: Version = .{ .major = sover, .minor = 0, .patch = 0 }; const ld_basename = path.basename(target.standardDynamicLinkerPath().get().?); const soname = if (mem.eql(u8, lib.name, "ld")) ld_basename else basename; - const map_file_path = try path.join(arena, &.{ bin_directory.path.?, all_map_basename }); const optimize_mode = comp.compilerRtOptMode(); const strip = comp.compilerRtStrip(); @@ -1113,7 +1114,10 @@ fn buildSharedLib( .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .clang_passthrough_mode = comp.clang_passthrough_mode, .version = version, - .version_script = map_file_path, + .version_script = .{ + .root_dir = bin_directory, + .sub_path = all_map_basename, + }, .soname = soname, .c_source_files = &c_source_files, .skip_linker_dependencies = true, diff --git a/src/libs/glibc.zig b/src/libs/glibc.zig index fce076dba86d74c52756d72419ed8859633992b5..7c20c33a0335fcab4b01e7da5c37c4d673e899b2 100644 --- a/src/libs/glibc.zig +++ b/src/libs/glibc.zig @@ -698,8 +698,10 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye man.hash.add(target.abi); man.hash.add(target_version); - const full_abilists_path = try comp.dirs.zig_lib.join(arena, &.{abilists_path}); - const abilists_index = try man.addFile(full_abilists_path, abilists_max_size); + const abilists_index = try man.addFilePath(.{ + .root_dir = comp.dirs.zig_lib, + .sub_path = abilists_path, + }, abilists_max_size); if (try man.hit(prog_node)) { const digest = man.final(); @@ -1188,7 +1190,6 @@ fn buildSharedLib( const version: Version = .{ .major = lib.sover, .minor = 0, .patch = 0 }; const ld_basename = path.basename(comp.getTarget().standardDynamicLinkerPath().get().?); const soname = if (mem.eql(u8, lib.name, "ld")) ld_basename else basename; - const map_file_path = try path.join(arena, &.{ bin_directory.path.?, all_map_basename }); const optimize_mode = comp.compilerRtOptMode(); const strip = comp.compilerRtStrip(); @@ -1257,7 +1258,10 @@ fn buildSharedLib( .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .clang_passthrough_mode = comp.clang_passthrough_mode, .version = version, - .version_script = map_file_path, + .version_script = .{ + .root_dir = bin_directory, + .sub_path = all_map_basename, + }, .soname = soname, .c_source_files = &c_source_files, .skip_linker_dependencies = true, diff --git a/src/libs/mingw.zig b/src/libs/mingw.zig index 224b5ec27b4c0e8dac994ec4a54f85a689a11449..73e741c4fa4e97fa2622ed9e13c43d59568bd89c 100644 --- a/src/libs/mingw.zig +++ b/src/libs/mingw.zig @@ -243,7 +243,10 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8, prog_node: std.P var man = cache.obtain(); defer man.deinit(); - _ = try man.addFile(def_file_path, null); + _ = try man.addFilePath(.{ + .root_dir = comp.dirs.zig_lib, + .sub_path = def_file_path, + }, null); const final_lib_basename = try std.fmt.allocPrint(gpa, "{s}.lib", .{lib_name}); errdefer gpa.free(final_lib_basename); @@ -384,7 +387,7 @@ pub fn libExists( /// This function body is verbose but all it does is test 3 different paths and /// see if a .def file exists. fn findDef( - allocator: Allocator, + gpa: Allocator, io: Io, target: *const std.Target, zig_lib_directory: Cache.Directory, @@ -398,21 +401,17 @@ fn findDef( else => unreachable, }; - var override_path = std.array_list.Managed(u8).init(allocator); - defer override_path.deinit(); + var override_path: std.ArrayList(u8) = .empty; + defer override_path.deinit(gpa); const s = path.sep_str; { // Try the archtecture-specific path first. - const fmt_path = "libc" ++ s ++ "mingw" ++ s ++ "{s}" ++ s ++ "{s}.def"; - if (zig_lib_directory.path) |p| { - try override_path.print("{s}" ++ s ++ fmt_path, .{ p, lib_path, lib_name }); - } else { - try override_path.print(fmt_path, .{ lib_path, lib_name }); - } - if (Io.Dir.cwd().access(io, override_path.items, .{})) |_| { - return override_path.toOwnedSlice(); + override_path.shrinkRetainingCapacity(0); + try override_path.print(gpa, "libc" ++ s ++ "mingw" ++ s ++ "{s}" ++ s ++ "{s}.def", .{ lib_path, lib_name }); + if (zig_lib_directory.handle.access(io, override_path.items, .{})) |_| { + return override_path.toOwnedSlice(gpa); } else |err| switch (err) { error.FileNotFound => {}, else => |e| return e, @@ -422,14 +421,9 @@ fn findDef( { // Try the generic version. override_path.shrinkRetainingCapacity(0); - const fmt_path = "libc" ++ s ++ "mingw" ++ s ++ "lib-common" ++ s ++ "{s}.def"; - if (zig_lib_directory.path) |p| { - try override_path.print("{s}" ++ s ++ fmt_path, .{ p, lib_name }); - } else { - try override_path.print(fmt_path, .{lib_name}); - } - if (Io.Dir.cwd().access(io, override_path.items, .{})) |_| { - return override_path.toOwnedSlice(); + try override_path.print(gpa, "libc" ++ s ++ "mingw" ++ s ++ "lib-common" ++ s ++ "{s}.def", .{lib_name}); + if (zig_lib_directory.handle.access(io, override_path.items, .{})) |_| { + return override_path.toOwnedSlice(gpa); } else |err| switch (err) { error.FileNotFound => {}, else => |e| return e, @@ -439,14 +433,9 @@ fn findDef( { // Try the generic version and preprocess it. override_path.shrinkRetainingCapacity(0); - const fmt_path = "libc" ++ s ++ "mingw" ++ s ++ "lib-common" ++ s ++ "{s}.def.in"; - if (zig_lib_directory.path) |p| { - try override_path.print("{s}" ++ s ++ fmt_path, .{ p, lib_name }); - } else { - try override_path.print(fmt_path, .{lib_name}); - } - if (Io.Dir.cwd().access(io, override_path.items, .{})) |_| { - return override_path.toOwnedSlice(); + try override_path.print(gpa, "libc" ++ s ++ "mingw" ++ s ++ "lib-common" ++ s ++ "{s}.def.in", .{lib_name}); + if (zig_lib_directory.handle.access(io, override_path.items, .{})) |_| { + return override_path.toOwnedSlice(gpa); } else |err| switch (err) { error.FileNotFound => {}, else => |e| return e, diff --git a/src/libs/netbsd.zig b/src/libs/netbsd.zig index fb811df536ed7fa55f2ec630534e1c995ef978f7..3d7c94ce4974bb8f9fb926cad43ca99c1919cfc7 100644 --- a/src/libs/netbsd.zig +++ b/src/libs/netbsd.zig @@ -406,8 +406,10 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye man.hash.add(target.abi); man.hash.add(target_version); - const full_abilists_path = try comp.dirs.zig_lib.join(arena, &.{abilists_path}); - const abilists_index = try man.addFile(full_abilists_path, abilists_max_size); + const abilists_index = try man.addFilePath(.{ + .root_dir = comp.dirs.zig_lib, + .sub_path = abilists_path, + }, abilists_max_size); if (try man.hit(prog_node)) { const digest = man.final(); diff --git a/src/libs/openbsd.zig b/src/libs/openbsd.zig index e38183ab75db6a29eae22695f52550f69b35858c..2e0159b677de2ff86d57ac27e130c63f341e898f 100644 --- a/src/libs/openbsd.zig +++ b/src/libs/openbsd.zig @@ -327,8 +327,10 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye man.hash.add(target.abi); man.hash.add(target_version); - const full_abilists_path = try comp.dirs.zig_lib.join(arena, &.{abilists_path}); - const abilists_index = try man.addFile(full_abilists_path, abilists_max_size); + const abilists_index = try man.addFilePath(.{ + .root_dir = comp.dirs.zig_lib, + .sub_path = abilists_path, + }, abilists_max_size); if (try man.hit(prog_node)) { const digest = man.final(); diff --git a/src/link.zig b/src/link.zig index 836621f3fea4a25a1f37d5d313d942f8229fcfad..eeab7e4f56f441070fc8817c7d8969c0558a4ee0 100644 --- a/src/link.zig +++ b/src/link.zig @@ -461,8 +461,8 @@ pub const File = struct { allow_undefined_version: bool, enable_new_dtags: ?bool, subsystem: ?std.zig.Subsystem, - linker_script: ?[]const u8, - version_script: ?[]const u8, + linker_script: ?Path, + version_script: ?Path, soname: ?[]const u8, print_gc_sections: bool, print_icf_sections: bool, @@ -493,7 +493,7 @@ pub const File = struct { /// Install name for the dylib install_name: ?[]const u8, /// Path to entitlements file - entitlements: ?[]const u8, + entitlements: ?Path, /// size of the __PAGEZERO segment pagezero_size: ?u64, /// Set minimum space for future expansion of the load commands diff --git a/src/link/Lld.zig b/src/link/Lld.zig index b1ac4a2834bf7ba5992d658304e40e0ccf2a9a18..90bf4e3966a0dc6400df2c3d56db63d287f19aa3 100644 --- a/src/link/Lld.zig +++ b/src/link/Lld.zig @@ -75,8 +75,8 @@ pub const Elf = struct { entry_name: ?[]const u8, hash_style: HashStyle, image_base: u64, - linker_script: ?[]const u8, - version_script: ?[]const u8, + linker_script: ?Cache.Path, + version_script: ?Cache.Path, sort_section: ?SortSection, print_icf_sections: bool, print_map: bool, @@ -930,7 +930,7 @@ fn elfLink(lld: *Lld, arena: Allocator) !void { if (elf.linker_script) |linker_script| { try argv.append("-T"); - try argv.append(linker_script); + try argv.append(try linker_script.toString(arena)); } if (elf.sort_section) |how| { @@ -1086,7 +1086,7 @@ fn elfLink(lld: *Lld, arena: Allocator) !void { } if (elf.version_script) |version_script| { try argv.append("-version-script"); - try argv.append(version_script); + try argv.append(try version_script.toString(arena)); } if (elf.allow_undefined_version) { try argv.append("--undefined-version"); diff --git a/src/link/MachO.zig b/src/link/MachO.zig index c03d4eac74b73b293e66bf08258a69fea466b721..0a2c0c9c50c14065f77e166fac72b68ef6820bb0 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -127,7 +127,7 @@ frameworks: []const Framework, /// TODO: unify with soname install_name: ?[]const u8, /// Path to entitlements file. -entitlements: ?[]const u8, +entitlements: ?Path, compatibility_version: ?std.SemanticVersion, /// Entry name entry_name: ?[]const u8, @@ -580,7 +580,7 @@ pub fn flush( var codesig = CodeSignature.init(self.getPageSize()); codesig.code_directory.ident = fs.path.basename(self.base.emit.sub_path); if (self.entitlements) |path| codesig.addEntitlements(gpa, io, path) catch |err| - return diags.fail("failed to add entitlements from {s}: {t}", .{ path, err }); + return diags.fail("failed to add entitlements from {f}: {t}", .{ path, err }); try self.writeCodeSignaturePadding(&codesig); break :blk codesig; } else null; diff --git a/src/link/MachO/CodeSignature.zig b/src/link/MachO/CodeSignature.zig index 88fae25e73f87e944e4dcf0b9cb522bee6db4936..8cad16f12990538304dfc084515afe8174c18aea 100644 --- a/src/link/MachO/CodeSignature.zig +++ b/src/link/MachO/CodeSignature.zig @@ -246,8 +246,8 @@ pub fn deinit(self: *CodeSignature, allocator: Allocator) void { } } -pub fn addEntitlements(self: *CodeSignature, allocator: Allocator, io: Io, path: []const u8) !void { - const inner = try Io.Dir.cwd().readFileAlloc(io, path, allocator, .limited(std.math.maxInt(u32))); +pub fn addEntitlements(self: *CodeSignature, allocator: Allocator, io: Io, path: std.Build.Cache.Path) !void { + const inner = try path.root_dir.handle.readFileAlloc(io, path.sub_path, allocator, .limited(std.math.maxInt(u32))); self.entitlements = .{ .inner = inner }; } diff --git a/src/main.zig b/src/main.zig index 733620bd34eb552cb1784a2f36bfb70cab1f864c..e25a96714ae8e903fdfd016af0fb3be7d30bda7f 100644 --- a/src/main.zig +++ b/src/main.zig @@ -3666,8 +3666,8 @@ fn buildOutputType( .want_compiler_rt = if (zig_cc_explicitly_link_compiler_rt) true else want_compiler_rt, .want_ubsan_rt = want_ubsan_rt, .hash_style = hash_style, - .linker_script = linker_script, - .version_script = version_script, + .linker_script = if (linker_script) |p| .initCwd(p) else null, + .version_script = if (version_script) |p| .initCwd(p) else null, .linker_allow_undefined_version = linker_allow_undefined_version, .linker_enable_new_dtags = linker_enable_new_dtags, .disable_c_depfile = disable_c_depfile, @@ -3740,7 +3740,7 @@ fn buildOutputType( .debug_incremental = debug_incremental, .enable_link_snapshots = enable_link_snapshots, .install_name = install_name, - .entitlements = entitlements, + .entitlements = if (entitlements) |p| .initCwd(p) else null, .pagezero_size = pagezero_size, .headerpad_size = headerpad_size, .headerpad_max_install_names = headerpad_max_install_names, -- 2.54.0