authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-08-20 11:25:43+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-08-20 11:25:43+02:00
log73b010e2216331b0b87240b05ea061294749383b
treec7d08b440f359918ca3842eecb5e026a952d8c0e
parentefd227eca2e2013b4e540ab2ba44664668a5253b
parent5ee54cd52ad5f03ce24ec8c0ffee35972df3a5f3

Merge pull request 'make frontend and build system more resistant to absolute paths' (#36548) from absolutely-not into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/36548 Reviewed-by: mlugg <mlugg@mlugg.co.uk>

23 files changed, 380 insertions(+), 312 deletions(-)

lib/compiler/Maker.zig+4-1
......@@ -614,6 +614,8 @@ pub fn main(init: process.Init.Minimal) !void {
614614 comptime assert(1 == @backingInt(std.zig.Server.Message.PathPrefix.zig_lib));
615615 comptime assert(2 == @backingInt(std.zig.Server.Message.PathPrefix.local_cache));
616616 comptime assert(3 == @backingInt(std.zig.Server.Message.PathPrefix.global_cache));
617 comptime assert(4 == @backingInt(std.zig.Server.Message.PathPrefix.build_root));
618 comptime assert(@typeInfo(std.zig.Server.Message.PathPrefix).@"enum".field_names.len == 5);
617619
618620 graph.cache.hash.addBytes(builtin.zig_version_string);
619621
......@@ -1118,6 +1120,7 @@ fn configure(graph: *Graph, options: ConfigureOptions) !ScannedConfig {
11181120 graph.zig_exe, "build-exe", //
11191121 "--cache-dir", graph.local_cache_root.path orelse ".", //
11201122 "--global-cache-dir", graph.global_cache_root.path orelse ".", //
1123 "--build-root", graph.build_root_directory.path orelse ".", //
11211124 "--zig-lib-dir", graph.zig_lib_directory.path orelse ".", //
11221125 "--name", configurer_exe_name, //
11231126 "-fsingle-threaded", //
......@@ -1412,7 +1415,6 @@ fn configure(graph: *Graph, options: ConfigureOptions) !ScannedConfig {
14121415
14131416 if (config_man) |man| {
14141417 if (try man.hit(compile_prog_node)) {
1415 log.debug("configuration cache hit", .{});
14161418 const digest = man.final();
14171419 const path: Path = .{
14181420 .root_dir = graph.local_cache_root,
......@@ -1422,6 +1424,7 @@ fn configure(graph: *Graph, options: ConfigureOptions) !ScannedConfig {
14221424 break :cp .{ path, man.toOwnedLock() };
14231425 }
14241426 }
1427 try graph.handleVerbose(null, null, build_configurer_argv.items);
14251428 const configure_exe_path: Path = if (std.zig.buildExeSubprocess(gpa, io, .{
14261429 .argv = build_configurer_argv.items,
14271430 .cache_root = graph.local_cache_root,
lib/compiler/Maker/Step.zig+7
......@@ -656,6 +656,13 @@ fn zigProcessUpdate(step_index: Configuration.Step.Index, maker: *Maker, zp: *Zi
656656 };
657657 try addWatchInputFromPath(s, maker, path, Dir.path.basename(sub_path));
658658 },
659 .build_root => {
660 const path: Path = .{
661 .root_dir = graph.build_root_directory,
662 .sub_path = sub_path_dirname,
663 };
664 try addWatchInputFromPath(s, maker, path, Dir.path.basename(sub_path));
665 },
659666 }
660667 }
661668 },
lib/compiler/Maker/Step/Compile.zig+2-1
......@@ -658,9 +658,10 @@ fn lowerZigArgs(
658658 zig_args.appendAssumeCapacity(libc_file);
659659 }
660660
661 (try zig_args.addManyAsArray(gpa, 4)).* = .{
661 (try zig_args.addManyAsArray(gpa, 6)).* = .{
662662 "--cache-dir", graph.local_cache_root.path orelse ".",
663663 "--global-cache-dir", graph.global_cache_root.path orelse ".",
664 "--build-root", graph.build_root_directory.path orelse ".",
664665 };
665666
666667 try zig_args.ensureUnusedCapacity(gpa, 1);
lib/std/Build/Cache.zig+34-51
......@@ -417,18 +417,6 @@ pub const Manifest = struct {
417417 return addFileInner(m, prefixed_path, handle, max_file_size);
418418 }
419419
420 /// Deprecated; use `addFilePath`.
421 pub fn addFile(self: *Manifest, file_path: []const u8, max_file_size: ?usize) !usize {
422 assert(self.manifest_file == null);
423
424 const gpa = self.cache.gpa;
425 try self.files.ensureUnusedCapacity(gpa, 1);
426 const prefixed_path = try self.cache.findPrefix(file_path);
427 errdefer gpa.free(prefixed_path.sub_path);
428
429 return addFileInner(self, prefixed_path, null, max_file_size);
430 }
431
432420 fn addFileInner(self: *Manifest, prefixed_path: PrefixedPath, handle: ?Io.File, max_file_size: ?usize) usize {
433421 const gop = self.files.getOrPutAssumeCapacityAdapted(prefixed_path, FilesAdapter{});
434422 if (gop.found_existing) {
......@@ -452,26 +440,12 @@ pub const Manifest = struct {
452440 return gop.index;
453441 }
454442
455 /// Deprecated, use `addOptionalFilePath`.
456 pub fn addOptionalFile(self: *Manifest, optional_file_path: ?[]const u8) !void {
457 self.hash.add(optional_file_path != null);
458 const file_path = optional_file_path orelse return;
459 _ = try self.addFile(file_path, null);
460 }
461
462443 pub fn addOptionalFilePath(self: *Manifest, optional_file_path: ?Path) !void {
463444 self.hash.add(optional_file_path != null);
464445 const file_path = optional_file_path orelse return;
465446 _ = try self.addFilePath(file_path, null);
466447 }
467448
468 pub fn addListOfFiles(self: *Manifest, list_of_files: []const []const u8) !void {
469 self.hash.add(list_of_files.len);
470 for (list_of_files) |file_path| {
471 _ = try self.addFile(file_path, null);
472 }
473 }
474
475449 pub fn addDepFile(self: *Manifest, dir: Io.Dir, dep_file_sub_path: []const u8) !void {
476450 assert(self.manifest_file == null);
477451 return self.addDepFileMaybePost(dir, dep_file_sub_path);
......@@ -1058,24 +1032,32 @@ pub const Manifest = struct {
10581032
10591033 /// Like `addFilePost` but when the file contents have already been loaded from disk.
10601034 pub fn addFilePostContents(
1061 self: *Manifest,
1035 man: *Manifest,
10621036 file_path: []const u8,
10631037 bytes: []const u8,
10641038 stat: File.Stat,
10651039 ) !void {
1066 assert(self.manifest_file != null);
1067 const gpa = self.cache.gpa;
1068
1069 const prefixed_path = try self.cache.findPrefix(file_path);
1070 errdefer gpa.free(prefixed_path.sub_path);
1040 assert(man.manifest_file != null);
1041 const gpa = man.cache.gpa;
1042 const prefixed_path = try man.cache.findPrefix(file_path);
1043 var keep = false;
1044 defer if (!keep) gpa.free(prefixed_path.sub_path);
1045 keep = try addPrefixedPathPostContents(man, prefixed_path, bytes, stat);
1046 }
10711047
1072 const gop = try self.files.getOrPutAdapted(gpa, prefixed_path, FilesAdapter{});
1073 errdefer _ = self.files.pop();
1048 /// Low level function. `prefixed_path` references cloned memory. Returns
1049 /// whether or not `prefixed_path.sub_path` should be kept.
1050 pub fn addPrefixedPathPostContents(
1051 man: *Manifest,
1052 prefixed_path: PrefixedPath,
1053 bytes: []const u8,
1054 stat: File.Stat,
1055 ) !bool {
1056 const gpa = man.cache.gpa;
1057 const gop = try man.files.getOrPutAdapted(gpa, prefixed_path, FilesAdapter{});
1058 errdefer _ = man.files.pop();
10741059
1075 if (gop.found_existing) {
1076 gpa.free(prefixed_path.sub_path);
1077 return;
1078 }
1060 if (gop.found_existing) return false;
10791061
10801062 const new_file = gop.key_ptr;
10811063
......@@ -1088,7 +1070,7 @@ pub const Manifest = struct {
10881070 .contents = null,
10891071 };
10901072
1091 if (try self.isProblematicTimestamp(new_file.stat.mtime)) {
1073 if (try man.isProblematicTimestamp(new_file.stat.mtime)) {
10921074 // The actual file has an unreliable timestamp, force it to be hashed
10931075 new_file.stat.mtime = .zero;
10941076 new_file.stat.inode = 0;
......@@ -1100,7 +1082,8 @@ pub const Manifest = struct {
11001082 hasher.final(&new_file.bin_digest);
11011083 }
11021084
1103 self.hash.hasher.update(&new_file.bin_digest);
1085 man.hash.hasher.update(&new_file.bin_digest);
1086 return true;
11041087 }
11051088
11061089 pub fn addDepFilePost(self: *Manifest, dir: Io.Dir, dep_file_sub_path: []const u8) !void {
......@@ -1127,13 +1110,13 @@ pub const Manifest = struct {
11271110 // Clang is invoked in single-source mode but other programs may not
11281111 .target, .target_must_resolve => {},
11291112 .prereq => |file_path| if (self.manifest_file == null) {
1130 _ = try self.addFile(file_path, null);
1113 _ = try self.addFilePath(.initCwd(file_path), null);
11311114 } else try self.addFilePost(file_path),
11321115 .prereq_must_resolve => {
11331116 resolve_buf.clearRetainingCapacity();
11341117 try token.resolve(gpa, &resolve_buf);
11351118 if (self.manifest_file == null) {
1136 _ = try self.addFile(resolve_buf.items, null);
1119 _ = try self.addFilePath(.initCwd(resolve_buf.items), null);
11371120 } else try self.addFilePost(resolve_buf.items);
11381121 },
11391122 else => |err| {
......@@ -1290,10 +1273,10 @@ pub const Manifest = struct {
12901273 }
12911274 }
12921275
1293 pub fn populateOtherManifest(man: *Manifest, other: *Manifest, prefix_map: [4]u8) Allocator.Error!void {
1276 pub fn populateOtherManifest(man: *Manifest, other: *Manifest, prefix_map: [5]u8) Allocator.Error!void {
12941277 const gpa = other.cache.gpa;
12951278 assert(@typeInfo(std.zig.Server.Message.PathPrefix).@"enum".field_names.len == man.cache.prefixes_len);
1296 assert(man.cache.prefixes_len == 4);
1279 assert(man.cache.prefixes_len == 5);
12971280 for (man.files.keys()) |file| {
12981281 const prefixed_path: PrefixedPath = .{
12991282 .prefix = prefix_map[file.prefixed_path.prefix],
......@@ -1392,7 +1375,7 @@ test "cache file and then recall it" {
13921375 ch.hash.add(true);
13931376 ch.hash.add(@as(u16, 1234));
13941377 ch.hash.addBytes("1234");
1395 _ = try ch.addFile(temp_file, null);
1378 _ = try ch.addFilePath(.initCwd(temp_file), null);
13961379
13971380 // There should be nothing in the cache
13981381 try testing.expectEqual(false, try ch.hit(.none));
......@@ -1407,7 +1390,7 @@ test "cache file and then recall it" {
14071390 ch.hash.add(true);
14081391 ch.hash.add(@as(u16, 1234));
14091392 ch.hash.addBytes("1234");
1410 _ = try ch.addFile(temp_file, null);
1393 _ = try ch.addFilePath(.initCwd(temp_file), null);
14111394
14121395 // Cache hit! We just "built" the same file
14131396 try testing.expect(try ch.hit(.none));
......@@ -1460,7 +1443,7 @@ test "check that changing a file makes cache fail" {
14601443 defer ch.deinit();
14611444
14621445 ch.hash.addBytes("1234");
1463 const temp_file_idx = try ch.addFile(temp_file, 100);
1446 const temp_file_idx = try ch.addFilePath(.initCwd(temp_file), 100);
14641447
14651448 // There should be nothing in the cache
14661449 try testing.expectEqual(false, try ch.hit(.none));
......@@ -1479,7 +1462,7 @@ test "check that changing a file makes cache fail" {
14791462 defer ch.deinit();
14801463
14811464 ch.hash.addBytes("1234");
1482 const temp_file_idx = try ch.addFile(temp_file, 100);
1465 const temp_file_idx = try ch.addFilePath(.initCwd(temp_file), 100);
14831466
14841467 // A file that we depend on has been updated, so the cache should not contain an entry for it
14851468 try testing.expectEqual(false, try ch.hit(.none));
......@@ -1587,7 +1570,7 @@ test "Manifest with files added after initial hash work" {
15871570 defer ch.deinit();
15881571
15891572 ch.hash.addBytes("1234");
1590 _ = try ch.addFile(temp_file1, null);
1573 _ = try ch.addFilePath(.initCwd(temp_file1), null);
15911574
15921575 // There should be nothing in the cache
15931576 try testing.expectEqual(false, try ch.hit(.none));
......@@ -1602,7 +1585,7 @@ test "Manifest with files added after initial hash work" {
16021585 defer ch.deinit();
16031586
16041587 ch.hash.addBytes("1234");
1605 _ = try ch.addFile(temp_file1, null);
1588 _ = try ch.addFilePath(.initCwd(temp_file1), null);
16061589
16071590 try testing.expect(try ch.hit(.none));
16081591 digest2 = ch.final();
......@@ -1625,7 +1608,7 @@ test "Manifest with files added after initial hash work" {
16251608 defer ch.deinit();
16261609
16271610 ch.hash.addBytes("1234");
1628 _ = try ch.addFile(temp_file1, null);
1611 _ = try ch.addFilePath(.initCwd(temp_file1), null);
16291612
16301613 // A file that we depend on has been updated, so the cache should not contain an entry for it
16311614 try testing.expectEqual(false, try ch.hit(.none));
lib/std/fs/path.zig+16-16
......@@ -1093,23 +1093,23 @@ pub fn resolveWindows(allocator: Allocator, paths: []const []const u8) Allocator
10931093 return result.toOwnedSlice(allocator);
10941094}
10951095
1096/// This function is like a series of `cd` statements executed one after another.
1097///
1098/// It resolves "." and ".." to the best of its ability, but will not convert relative paths to
1099/// an absolute path, use Io.Dir.realpath instead.
1096/// Simulates a series of relative directory changes on a virtual filesystem
1097/// that has no symlinks.
11001098///
1101/// ".." components may persist in the resolved path if the resolved path is relative.
1099/// "." and ".." are resolved but will not make relative paths absolute. ".."
1100/// components remain in the resolved path when the resolved path is relative
1101/// and there are not previous components to cancel out.
11021102///
11031103/// The result does not have a trailing path separator.
11041104///
11051105/// This function does not perform any syscalls. Executing this series of path
1106/// lookups on the actual filesystem may produce different results due to
1106/// lookups on an actual filesystem may produce different results due to
11071107/// symlinks.
1108pub fn resolvePosix(allocator: Allocator, paths: []const []const u8) Allocator.Error![]u8 {
1108pub fn resolvePosix(gpa: Allocator, paths: []const []const u8) Allocator.Error![]u8 {
11091109 assert(paths.len > 0);
11101110
1111 var result = std.array_list.Managed(u8).init(allocator);
1112 defer result.deinit();
1111 var result: std.ArrayList(u8) = .empty;
1112 defer result.deinit(gpa);
11131113
11141114 var negative_count: usize = 0;
11151115 var is_abs = false;
......@@ -1135,23 +1135,23 @@ pub fn resolvePosix(allocator: Allocator, paths: []const []const u8) Allocator.E
11351135 if (ends_with_slash or result.items.len == 0) break;
11361136 }
11371137 } else if (result.items.len > 0 or is_abs) {
1138 try result.ensureUnusedCapacity(1 + component.len);
1138 try result.ensureUnusedCapacity(gpa, 1 + component.len);
11391139 result.appendAssumeCapacity('/');
11401140 result.appendSliceAssumeCapacity(component);
11411141 } else {
1142 try result.appendSlice(component);
1142 try result.appendSlice(gpa, component);
11431143 }
11441144 }
11451145 }
11461146
11471147 if (result.items.len == 0) {
11481148 if (is_abs) {
1149 return allocator.dupe(u8, "/");
1149 return gpa.dupe(u8, "/");
11501150 }
11511151 if (negative_count == 0) {
1152 return allocator.dupe(u8, ".");
1152 return gpa.dupe(u8, ".");
11531153 } else {
1154 const real_result = try allocator.alloc(u8, 3 * negative_count - 1);
1154 const real_result = try gpa.alloc(u8, 3 * negative_count - 1);
11551155 var count = negative_count - 1;
11561156 var i: usize = 0;
11571157 while (count > 0) : (count -= 1) {
......@@ -1164,9 +1164,9 @@ pub fn resolvePosix(allocator: Allocator, paths: []const []const u8) Allocator.E
11641164 }
11651165
11661166 if (negative_count == 0) {
1167 return result.toOwnedSlice();
1167 return result.toOwnedSlice(gpa);
11681168 } else {
1169 const real_result = try allocator.alloc(u8, 3 * negative_count + result.items.len);
1169 const real_result = try gpa.alloc(u8, 3 * negative_count + result.items.len);
11701170 var count = negative_count;
11711171 var i: usize = 0;
11721172 while (count > 0) : (count -= 1) {
lib/std/zig.zig+31-15
......@@ -1283,14 +1283,20 @@ pub const Directories = struct {
12831283 /// `local_cache.path` is resolved (`resolvePath`) or `null` for cwd.
12841284 /// This may be the same as `global_cache`.
12851285 local_cache: Cache.Directory,
1286 /// The directory that contains build.zig. This path is provided by the
1287 /// build system, when the build system is used, otherwise, it is `null`
1288 /// for cwd.
1289 build_root: Cache.Directory,
12861290
12871291 pub fn deinit(dirs: *Directories, io: Io) void {
12881292 // The local and global caches could be the same.
12891293 const close_local = dirs.local_cache.handle.handle != dirs.global_cache.handle.handle;
1294 const close_build_root = dirs.build_root.handle.handle != Io.Dir.cwd().handle;
12901295
12911296 dirs.global_cache.handle.close(io);
12921297 if (close_local) dirs.local_cache.handle.close(io);
12931298 dirs.zig_lib.handle.close(io);
1299 if (close_build_root) dirs.build_root.handle.close(io);
12941300 }
12951301
12961302 /// Returns a `Directories` where `local_cache` is replaced with `global_cache`, intended for
......@@ -1302,6 +1308,7 @@ pub const Directories = struct {
13021308 .zig_lib = dirs.zig_lib,
13031309 .global_cache = dirs.global_cache,
13041310 .local_cache = dirs.global_cache,
1311 .build_root = dirs.build_root,
13051312 };
13061313 }
13071314
......@@ -1311,12 +1318,10 @@ pub const Directories = struct {
13111318 global,
13121319 };
13131320
1314 /// Uses `std.process.fatal` on error conditions.
1315 pub fn init(
1316 arena: Allocator,
1317 io: Io,
1321 pub const InitOptions = struct {
13181322 override_zig_lib: ?[]const u8,
13191323 override_global_cache: ?[]const u8,
1324 build_root: ?[]const u8,
13201325 local_cache_strat: LocalCacheStrategy,
13211326 preopens: std.process.Preopens,
13221327 self_exe_path: switch (builtin.target.os.tag) {
......@@ -1325,27 +1330,37 @@ pub const Directories = struct {
13251330 },
13261331 environ_map: *const std.process.Environ.Map,
13271332 cwd: []const u8,
1328 ) Directories {
1333 };
1334
1335 /// Uses `std.process.fatal` on error conditions.
1336 pub fn init(arena: Allocator, io: Io, options: InitOptions) Directories {
13291337 const wasi = builtin.target.os.tag == .wasi;
1338 const cwd = options.cwd;
13301339
13311340 const zig_lib: Cache.Directory = d: {
1332 if (override_zig_lib) |path| break :d openUnresolved(arena, io, cwd, path, .@"zig lib");
1333 if (wasi) break :d getPreopen(preopens, "/lib");
1334 break :d findZigLibDirFromSelfExe(arena, io, cwd, self_exe_path) catch |err| {
1335 fatal("unable to find zig installation directory from executable path {q}: {t}", .{ self_exe_path, err });
1341 if (options.override_zig_lib) |path| break :d openUnresolved(arena, io, cwd, path, .@"zig lib");
1342 if (wasi) break :d getPreopen(options.preopens, "/lib");
1343 break :d findZigLibDirFromSelfExe(arena, io, cwd, options.self_exe_path) catch |err| {
1344 fatal("unable to find zig installation directory from executable path {q}: {t}", .{
1345 options.self_exe_path, err,
1346 });
13361347 };
13371348 };
1349 const build_root: Cache.Directory = if (options.build_root) |s|
1350 openUnresolved(arena, io, cwd, s, .@"build root")
1351 else
1352 .cwd();
13381353
13391354 const global_cache: Cache.Directory = d: {
1340 if (override_global_cache) |path| break :d openUnresolved(arena, io, cwd, path, .@"global cache");
1341 if (wasi) break :d getPreopen(preopens, "/cache");
1342 const path = resolveGlobalCacheDir(arena, environ_map) catch |err| {
1355 if (options.override_global_cache) |path| break :d openUnresolved(arena, io, cwd, path, .@"global cache");
1356 if (wasi) break :d getPreopen(options.preopens, "/cache");
1357 const path = resolveGlobalCacheDir(arena, options.environ_map) catch |err| {
13431358 fatal("unable to resolve zig cache directory: {t}", .{err});
13441359 };
13451360 break :d openUnresolved(arena, io, cwd, path, .@"global cache");
13461361 };
13471362
1348 const local_cache = getLocalCacheDirectory(arena, io, cwd, global_cache, local_cache_strat);
1363 const local_cache = getLocalCacheDirectory(arena, io, cwd, global_cache, options.local_cache_strat);
13491364
13501365 if (mem.eql(u8, zig_lib.path orelse "", global_cache.path orelse "")) {
13511366 fatal("zig lib directory '{f}' cannot be equal to global cache directory '{f}'", .{ zig_lib, global_cache });
......@@ -1359,6 +1374,7 @@ pub const Directories = struct {
13591374 .zig_lib = zig_lib,
13601375 .global_cache = global_cache,
13611376 .local_cache = local_cache,
1377 .build_root = build_root,
13621378 };
13631379 }
13641380
......@@ -1395,14 +1411,14 @@ pub const Directories = struct {
13951411 io: Io,
13961412 cwd: []const u8,
13971413 unresolved_path: []const u8,
1398 thing: enum { @"zig lib", @"global cache", @"local cache" },
1414 thing: enum { @"zig lib", @"global cache", @"local cache", @"build root" },
13991415 ) Cache.Directory {
14001416 const path = resolvePath(arena, cwd, &.{unresolved_path}) catch |err| {
14011417 fatal("unable to resolve {t} directory: {t}", .{ thing, err });
14021418 };
14031419 const nonempty_path = if (path.len == 0) "." else path;
14041420 const handle_or_err = switch (thing) {
1405 .@"zig lib" => Dir.cwd().openDir(io, nonempty_path, .{}),
1421 .@"zig lib", .@"build root" => Dir.cwd().openDir(io, nonempty_path, .{}),
14061422 .@"global cache", .@"local cache" => Dir.cwd().createDirPathOpen(io, nonempty_path, .{}),
14071423 };
14081424 return .{
lib/std/zig/Server.zig+1
......@@ -135,6 +135,7 @@ pub const Message = struct {
135135 zig_lib,
136136 local_cache,
137137 global_cache,
138 build_root,
138139 };
139140
140141 /// Trailing:
src/Compilation.zig+126-68
......@@ -397,6 +397,7 @@ pub const Path = struct {
397397 global_cache,
398398 /// `sub_path` is relative to the local cache directory on `Compilation`.
399399 local_cache,
400 build_root,
400401 /// `sub_path` is not relative to any of the roots listed above.
401402 /// It is resolved starting with `Directories.cwd`; so it is an absolute path on most
402403 /// targets, but cwd-relative on WASI. We do not make it cwd-relative on other targets
......@@ -434,11 +435,12 @@ pub const Path = struct {
434435 const dir = switch (p.root) {
435436 .none => {
436437 const cwd_sub_path = absToCwdRelative(p.sub_path, dirs.cwd);
437 return .{ Io.Dir.cwd(), cwd_sub_path };
438 return .{ Io.Dir.cwd(), if (cwd_sub_path.len == 0) "." else cwd_sub_path };
438439 },
439440 .zig_lib => dirs.zig_lib.handle,
440441 .global_cache => dirs.global_cache.handle,
441442 .local_cache => dirs.local_cache.handle,
443 .build_root => dirs.build_root.handle,
442444 };
443445 if (p.sub_path.len == 0) return .{ dir, "." };
444446 assert(!fs.path.isAbsolute(p.sub_path));
......@@ -454,19 +456,18 @@ pub const Path = struct {
454456 comp: *Compilation,
455457 pub fn format(f: Formatter, w: *Writer) Writer.Error!void {
456458 const root_path: []const u8 = switch (f.p.root) {
457 .zig_lib => f.comp.dirs.zig_lib.path orelse ".",
458 .global_cache => f.comp.dirs.global_cache.path orelse ".",
459 .local_cache => f.comp.dirs.local_cache.path orelse ".",
459 .zig_lib => f.comp.dirs.zig_lib.path orelse "",
460 .global_cache => f.comp.dirs.global_cache.path orelse "",
461 .local_cache => f.comp.dirs.local_cache.path orelse "",
462 .build_root => f.comp.dirs.build_root.path orelse "",
460463 .none => {
461 const cwd_sub_path = absToCwdRelative(f.p.sub_path, f.comp.dirs.cwd);
462 try w.writeAll(cwd_sub_path);
464 try w.writeAll(absToCwdRelative(f.p.sub_path, f.comp.dirs.cwd));
463465 return;
464466 },
465467 };
466 assert(root_path.len != 0);
467468 try w.writeAll(root_path);
468469 if (f.p.sub_path.len > 0) {
469 try w.writeByte(fs.path.sep);
470 if (root_path.len != 0) try w.writeByte(fs.path.sep);
470471 try w.writeAll(f.p.sub_path);
471472 }
472473 }
......@@ -474,16 +475,16 @@ pub const Path = struct {
474475
475476 /// Given the `sub_path` of a `Path` with `Path.root == .none`, attempts to convert
476477 /// the (absolute) path to a cwd-relative path. Otherwise, returns the absolute path
477 /// unmodified. The returned string is never empty: "" is converted to ".".
478 /// unmodified. The returned string is never "."; empty string will be returned instead.
478479 fn absToCwdRelative(sub_path: []const u8, cwd_path: []const u8) []const u8 {
479480 if (builtin.target.os.tag == .wasi) {
480 if (sub_path.len == 0) return ".";
481 if (sub_path.len == 0) return "";
481482 assert(!fs.path.isAbsolute(sub_path));
482483 return sub_path;
483484 }
484485 assert(fs.path.isAbsolute(sub_path));
485486 if (!std.mem.startsWith(u8, sub_path, cwd_path)) return sub_path;
486 if (sub_path.len == cwd_path.len) return "."; // the strings are equal
487 if (sub_path.len == cwd_path.len) return ""; // the strings are equal
487488 const path_sep_index = path_sep_index: {
488489 // cwd is just a root, e.g. / or C:\
489490 if (cwd_path[cwd_path.len - 1] == fs.path.sep) break :path_sep_index cwd_path.len - 1;
......@@ -503,10 +504,11 @@ pub const Path = struct {
503504 // so that we prefer `.root = .local_cache` over `.root = .zig_lib`. The easiest way to do
504505 // this is simply to prioritize the longest root path.
505506 const PathAndRoot = struct { ?[]const u8, Root };
506 var roots: [3]PathAndRoot = .{
507 var roots: [4]PathAndRoot = .{
507508 .{ dirs.zig_lib.path, .zig_lib },
508509 .{ dirs.global_cache.path, .global_cache },
509510 .{ dirs.local_cache.path, .local_cache },
511 .{ dirs.build_root.path, .build_root },
510512 };
511513 // This must be a stable sort, because the global and local cache directories may be the same, in
512514 // which case we need to make a consistent choice.
......@@ -581,6 +583,7 @@ pub const Path = struct {
581583 .zig_lib => dirs.zig_lib.path orelse "",
582584 .global_cache => dirs.global_cache.path orelse "",
583585 .local_cache => dirs.local_cache.path orelse "",
586 .build_root => dirs.build_root.path orelse "",
584587 .none => "",
585588 },
586589 sub_path,
......@@ -603,6 +606,7 @@ pub const Path = struct {
603606 .zig_lib => dirs.zig_lib.path orelse "",
604607 .global_cache => dirs.global_cache.path orelse "",
605608 .local_cache => dirs.local_cache.path orelse "",
609 .build_root => dirs.build_root.path orelse "",
606610 .none => "",
607611 },
608612 p.sub_path,
......@@ -622,6 +626,7 @@ pub const Path = struct {
622626 .zig_lib => dirs.zig_lib.path orelse "",
623627 .global_cache => dirs.global_cache.path orelse "",
624628 .local_cache => dirs.local_cache.path orelse "",
629 .build_root => dirs.build_root.path orelse "",
625630 .none => "",
626631 },
627632 p.sub_path,
......@@ -635,11 +640,12 @@ pub const Path = struct {
635640 .zig_lib => dirs.zig_lib,
636641 .global_cache => dirs.global_cache,
637642 .local_cache => dirs.local_cache,
643 .build_root => dirs.build_root,
638644 else => {
639645 const cwd_sub_path = absToCwdRelative(p.sub_path, dirs.cwd);
640646 return .{
641647 .root_dir = .cwd(),
642 .sub_path = cwd_sub_path,
648 .sub_path = if (cwd_sub_path.len == 0) null else cwd_sub_path,
643649 };
644650 },
645651 };
......@@ -653,18 +659,15 @@ pub const Path = struct {
653659 /// This should not be used for most of the compiler pipeline, but is useful when emitting
654660 /// paths from the compilation (e.g. in debug info), because they will not depend on the cwd.
655661 /// The returned path is owned by the caller and allocated into `gpa`.
656 pub fn toAbsolute(p: Path, dirs: std.zig.Directories, gpa: Allocator) Allocator.Error![]u8 {
662 pub fn toAbsolute(p: Path, dirs: *const std.zig.Directories, gpa: Allocator) Allocator.Error![]u8 {
657663 const root_path: []const u8 = switch (p.root) {
658664 .zig_lib => dirs.zig_lib.path orelse "",
659665 .global_cache => dirs.global_cache.path orelse "",
660666 .local_cache => dirs.local_cache.path orelse "",
667 .build_root => dirs.build_root.path orelse "",
661668 .none => "",
662669 };
663 return fs.path.resolve(gpa, &.{
664 dirs.cwd,
665 root_path,
666 p.sub_path,
667 });
670 return fs.path.resolve(gpa, &.{ dirs.cwd, root_path, p.sub_path });
668671 }
669672
670673 pub fn isNested(inner: Path, outer: Path) union(enum) {
......@@ -697,6 +700,66 @@ pub const Path = struct {
697700 .no, .different_roots => false,
698701 };
699702 }
703
704 pub fn addToCacheManifestPostHit(p: Path, man: *Cache.Manifest, dirs: *const std.zig.Directories) !void {
705 comptime assert(0 == @backingInt(std.zig.Server.Message.PathPrefix.cwd));
706 comptime assert(1 == @backingInt(std.zig.Server.Message.PathPrefix.zig_lib));
707 comptime assert(2 == @backingInt(std.zig.Server.Message.PathPrefix.local_cache));
708 comptime assert(3 == @backingInt(std.zig.Server.Message.PathPrefix.global_cache));
709 comptime assert(4 == @backingInt(std.zig.Server.Message.PathPrefix.build_root));
710 comptime assert(@typeInfo(std.zig.Server.Message.PathPrefix).@"enum".field_names.len == 5);
711 const gpa = man.cache.gpa;
712 const prefixed_path: Cache.PrefixedPath = .{
713 .prefix = switch (p.root) {
714 .none => {
715 const path = try p.toAbsolute(dirs, gpa);
716 defer gpa.free(path);
717 return man.addFilePost(path);
718 },
719 .zig_lib => 1,
720 .local_cache => 2,
721 .global_cache => 3,
722 .build_root => 4,
723 },
724 .sub_path = try gpa.dupe(u8, p.sub_path),
725 };
726 var keep = false;
727 defer if (!keep) gpa.free(prefixed_path.sub_path);
728 keep = try man.addPrefixedPathPost(prefixed_path);
729 }
730
731 pub fn addToCacheManifestPostHitContents(
732 p: Path,
733 man: *Cache.Manifest,
734 dirs: *const std.zig.Directories,
735 bytes: []const u8,
736 stat: Cache.File.Stat,
737 ) !void {
738 comptime assert(0 == @backingInt(std.zig.Server.Message.PathPrefix.cwd));
739 comptime assert(1 == @backingInt(std.zig.Server.Message.PathPrefix.zig_lib));
740 comptime assert(2 == @backingInt(std.zig.Server.Message.PathPrefix.local_cache));
741 comptime assert(3 == @backingInt(std.zig.Server.Message.PathPrefix.global_cache));
742 comptime assert(4 == @backingInt(std.zig.Server.Message.PathPrefix.build_root));
743 comptime assert(@typeInfo(std.zig.Server.Message.PathPrefix).@"enum".field_names.len == 5);
744 const gpa = man.cache.gpa;
745 const prefixed_path: Cache.PrefixedPath = .{
746 .prefix = switch (p.root) {
747 .none => {
748 const path = try p.toAbsolute(dirs, gpa);
749 defer gpa.free(path);
750 return man.addFilePostContents(path, bytes, stat);
751 },
752 .zig_lib => 1,
753 .local_cache => 2,
754 .global_cache => 3,
755 .build_root => 4,
756 },
757 .sub_path = try gpa.dupe(u8, p.sub_path),
758 };
759 var keep = false;
760 defer if (!keep) gpa.free(prefixed_path.sub_path);
761 keep = try man.addPrefixedPathPostContents(prefixed_path, bytes, stat);
762 }
700763};
701764
702765/// This small wrapper function just checks whether debug extensions are enabled before checking
......@@ -1278,7 +1341,7 @@ pub const cache_helpers = struct {
12781341 }
12791342
12801343 pub fn hashCSource(self: *Cache.Manifest, c_source: CSourceFile) !void {
1281 _ = try self.addFile(c_source.src_path, null);
1344 _ = try self.addFilePath(.initCwd(c_source.src_path), null);
12821345 // Hash the extra flags, with special care to call addFile for file parameters.
12831346 // TODO this logic can likely be improved by utilizing clang_options_data.zig.
12841347 const file_args = [_][]const u8{"-include"};
......@@ -1289,7 +1352,7 @@ pub const cache_helpers = struct {
12891352 for (file_args) |file_arg| {
12901353 if (mem.eql(u8, file_arg, arg) and arg_i + 1 < c_source.extra_flags.len) {
12911354 arg_i += 1;
1292 _ = try self.addFile(c_source.extra_flags[arg_i], null);
1355 _ = try self.addFilePath(.initCwd(c_source.extra_flags[arg_i]), null);
12931356 }
12941357 }
12951358 }
......@@ -1348,7 +1411,7 @@ pub const CacheMode = enum {
13481411pub const ParentWholeCache = struct {
13491412 manifest: *Cache.Manifest,
13501413 mutex: *std.Io.Mutex,
1351 prefix_map: [4]u8,
1414 prefix_map: [5]u8,
13521415};
13531416
13541417const CacheUse = union(CacheMode) {
......@@ -1466,8 +1529,8 @@ pub const CreateOptions = struct {
14661529 stack_report: bool = false,
14671530 link_eh_frame_hdr: bool = false,
14681531 link_emit_relocs: bool = false,
1469 linker_script: ?[]const u8 = null,
1470 version_script: ?[]const u8 = null,
1532 linker_script: ?Cache.Path = null,
1533 version_script: ?Cache.Path = null,
14711534 linker_allow_undefined_version: bool = false,
14721535 linker_enable_new_dtags: ?bool = null,
14731536 soname: ?[]const u8 = null,
......@@ -1546,7 +1609,7 @@ pub const CreateOptions = struct {
15461609 /// (Darwin) Install name of the dylib
15471610 install_name: ?[]const u8 = null,
15481611 /// (Darwin) Path to entitlements file
1549 entitlements: ?[]const u8 = null,
1612 entitlements: ?Cache.Path = null,
15501613 /// (Darwin) size of the __PAGEZERO segment
15511614 pagezero_size: ?u64 = null,
15521615 /// (Darwin) set minimum space for future expansion of the load commands
......@@ -1613,15 +1676,7 @@ pub const CreateOptions = struct {
16131676 };
16141677};
16151678
1616fn addModuleTableToCacheHash(
1617 zcu: *Zcu,
1618 arena: Allocator,
1619 hash: *Cache.HashHelper,
1620 hash_type: union(enum) { path_bytes, files: *Cache.Manifest },
1621) error{
1622 OutOfMemory,
1623 Unexpected,
1624}!void {
1679fn addModuleTableToCacheHash(zcu: *Zcu, hash: *Cache.HashHelper) error{ OutOfMemory, Unexpected }!void {
16251680 assert(zcu.module_roots.count() != 0); // module_roots is populated
16261681
16271682 for (zcu.module_roots.keys(), zcu.module_roots.values()) |mod, opt_mod_root_file| {
......@@ -1630,17 +1685,9 @@ fn addModuleTableToCacheHash(
16301685 if (zcu.fileByIndex(mod_root_file).is_builtin) continue; // redundant
16311686 }
16321687 cache_helpers.addModule(hash, mod);
1633 switch (hash_type) {
1634 .path_bytes => {
1635 hash.add(mod.root.root);
1636 hash.addBytes(mod.root.sub_path);
1637 hash.addBytes(mod.root_src_path);
1638 },
1639 .files => |man| if (mod.root_src_path.len != 0) {
1640 const root_src_path = try mod.root.toCachePath(zcu.comp.dirs).join(arena, mod.root_src_path);
1641 _ = try man.addFilePath(root_src_path, null);
1642 },
1643 }
1688 hash.add(mod.root.root);
1689 hash.addBytes(mod.root.sub_path);
1690 hash.addBytes(mod.root_src_path);
16441691 hash.addListOfBytes(mod.deps.keys());
16451692 }
16461693}
......@@ -1926,6 +1973,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
19261973 }
19271974
19281975 const error_limit = options.error_limit orelse (std.math.maxInt(u16) - 1);
1976 const main_mod = options.main_mod orelse options.root_mod;
19291977
19301978 // We put everything into the cache hash that *cannot be modified
19311979 // during an incremental update*. For example, one cannot change the
......@@ -1944,11 +1992,17 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
19441992 },
19451993 .cwd = options.dirs.cwd,
19461994 };
1947 // These correspond to std.zig.Server.Message.PathPrefix.
1995 comptime assert(0 == @backingInt(std.zig.Server.Message.PathPrefix.cwd));
1996 comptime assert(1 == @backingInt(std.zig.Server.Message.PathPrefix.zig_lib));
1997 comptime assert(2 == @backingInt(std.zig.Server.Message.PathPrefix.local_cache));
1998 comptime assert(3 == @backingInt(std.zig.Server.Message.PathPrefix.global_cache));
1999 comptime assert(4 == @backingInt(std.zig.Server.Message.PathPrefix.build_root));
2000 comptime assert(@typeInfo(std.zig.Server.Message.PathPrefix).@"enum".field_names.len == 5);
19482001 cache.addPrefix(.{ .path = null, .handle = Io.Dir.cwd() });
19492002 cache.addPrefix(options.dirs.zig_lib);
19502003 cache.addPrefix(options.dirs.local_cache);
19512004 cache.addPrefix(options.dirs.global_cache);
2005 cache.addPrefix(options.dirs.build_root);
19522006 errdefer cache.manifest_dir.close(io);
19532007
19542008 // This is shared hasher state common to zig source and all C source files.
......@@ -1984,7 +2038,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
19842038 cache.hash.add(options.emit_docs != .no);
19852039 // TODO audit this and make sure everything is in it
19862040
1987 const main_mod = options.main_mod orelse options.root_mod;
19882041 const comp = try arena.create(Compilation);
19892042 const opt_zcu: ?*Zcu = if (have_zcu) blk: {
19902043 // Pre-open the directory handles for cached ZIR code so that it does not need
......@@ -2265,7 +2318,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
22652318 // likely different compilations and therefore this would be likely to
22662319 // cause cache hits.
22672320 if (comp.zcu) |zcu| {
2268 try addModuleTableToCacheHash(zcu, arena, &hash, .path_bytes);
2321 try addModuleTableToCacheHash(zcu, &hash);
22692322 } else {
22702323 cache_helpers.addModule(&hash, options.root_mod);
22712324 }
......@@ -2741,7 +2794,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
27412794
27422795 // If using the whole caching strategy, we check for *everything* up front, including
27432796 // C source files.
2744 log.debug("Compilation.update for {s}, CacheMode.{s}", .{ comp.root_name, @tagName(comp.cache_use) });
2797 log.debug("Compilation.update for {s}, CacheMode.{t}", .{ comp.root_name, comp.cache_use });
27452798 switch (comp.cache_use) {
27462799 .none => |none| {
27472800 assert(none.tmp_artifact_directory == null);
......@@ -2750,7 +2803,9 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
27502803 const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(tmp_dir_rand_int);
27512804 const path = try comp.dirs.local_cache.join(arena, &.{tmp_dir_sub_path});
27522805 const handle = comp.dirs.local_cache.handle.createDirPathOpen(io, tmp_dir_sub_path, .{}) catch |err| {
2753 return comp.setMiscFailure(.open_output, "failed to create output directory '{s}': {t}", .{ path, err });
2806 return comp.setMiscFailure(.open_output, "failed to create output directory {q}: {t}", .{
2807 path, err,
2808 });
27542809 };
27552810 break :d .{ .path = path, .handle = handle };
27562811 };
......@@ -2763,7 +2818,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
27632818
27642819 man = comp.cache_parent.obtain();
27652820 whole.cache_manifest = &man;
2766 try addNonIncrementalStuffToCacheManifest(comp, arena, &man);
2821 try addNonIncrementalStuffToCacheManifest(comp, &man);
27672822
27682823 // Under `--time-report`, ignore cache hits; do the work anyway for those juicy numbers.
27692824 const ignore_hit = comp.time_report != null;
......@@ -3114,6 +3169,7 @@ pub fn appendFileSystemInput(comp: *Compilation, path: Compilation.Path) Allocat
31143169 .zig_lib => comp.dirs.zig_lib,
31153170 .global_cache => comp.dirs.global_cache,
31163171 .local_cache => comp.dirs.local_cache,
3172 .build_root => comp.dirs.build_root,
31173173 .none => .cwd(),
31183174 };
31193175 const prefix: u8 = for (prefixes, 1..) |prefix_dir, i| {
......@@ -3121,8 +3177,8 @@ pub fn appendFileSystemInput(comp: *Compilation, path: Compilation.Path) Allocat
31213177 break @intCast(i);
31223178 }
31233179 } else std.debug.panic(
3124 "missing prefix directory '{s}' ('{f}') for '{s}'",
3125 .{ @tagName(path.root), want_prefix_dir, path.sub_path },
3180 "missing prefix directory {t} ('{f}') for {q}",
3181 .{ path.root, want_prefix_dir, path.sub_path },
31263182 );
31273183
31283184 // There may be concurrent calls to this function from C object workers and/or the main thread.
......@@ -3314,15 +3370,15 @@ fn renameTmpIntoCache(
33143370/// anything from the link cache manifest.
33153371pub const link_hash_implementation_version = 14;
33163372
3317fn addNonIncrementalStuffToCacheManifest(
3318 comp: *Compilation,
3319 arena: Allocator,
3320 man: *Cache.Manifest,
3321) !void {
3373fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifest) !void {
33223374 comptime assert(link_hash_implementation_version == 14);
33233375
33243376 if (comp.zcu) |zcu| {
3325 try addModuleTableToCacheHash(zcu, arena, &man.hash, .{ .files = man });
3377 // No need to hash the actual file contents here because it is
3378 // redundant with the logic in `PerThread.update` which iterates over
3379 // `zcu.alive_files` and adds those files discovered via `@import` to
3380 // the whole cache manifest.
3381 try addModuleTableToCacheHash(zcu, &man.hash);
33263382
33273383 // Synchronize with other matching comments: ZigOnlyHashStuff
33283384 man.hash.addListOfBytes(comp.test_filters);
......@@ -3336,7 +3392,7 @@ fn addNonIncrementalStuffToCacheManifest(
33363392 try link.hashInputs(man, comp.link_inputs);
33373393
33383394 for (comp.c_objects.items) |c_object| {
3339 _ = try man.addFile(c_object.src.src_path, null);
3395 _ = try man.addFilePath(.initCwd(c_object.src.src_path), null);
33403396 man.hash.addOptional(c_object.src.ext);
33413397 man.hash.addListOfBytes(c_object.src.extra_flags);
33423398 }
......@@ -3344,11 +3400,11 @@ fn addNonIncrementalStuffToCacheManifest(
33443400 for (comp.win32_resources.items) |win32_resource| {
33453401 switch (win32_resource.src) {
33463402 .rc => |rc_src| {
3347 _ = try man.addFile(rc_src.src_path, null);
3403 _ = try man.addFilePath(.initCwd(rc_src.src_path), null);
33483404 man.hash.addListOfBytes(rc_src.extra_flags);
33493405 },
33503406 .manifest => |manifest_path| {
3351 _ = try man.addFile(manifest_path, null);
3407 _ = try man.addFilePath(.initCwd(manifest_path), null);
33523408 },
33533409 }
33543410 }
......@@ -3380,8 +3436,8 @@ fn addNonIncrementalStuffToCacheManifest(
33803436
33813437 const opts = comp.cache_use.whole.lf_open_opts;
33823438
3383 try man.addOptionalFile(opts.linker_script);
3384 try man.addOptionalFile(opts.version_script);
3439 try man.addOptionalFilePath(opts.linker_script);
3440 try man.addOptionalFilePath(opts.version_script);
33853441 man.hash.add(opts.allow_undefined_version);
33863442 man.hash.addOptional(opts.enable_new_dtags);
33873443
......@@ -3440,7 +3496,7 @@ fn addNonIncrementalStuffToCacheManifest(
34403496
34413497 // Mach-O specific stuff
34423498 try link.File.MachO.hashAddFrameworks(man, opts.frameworks);
3443 try man.addOptionalFile(opts.entitlements);
3499 try man.addOptionalFilePath(opts.entitlements);
34443500 man.hash.addOptional(opts.pagezero_size);
34453501 man.hash.addOptional(opts.headerpad_size);
34463502 man.hash.add(opts.headerpad_max_install_names);
......@@ -5278,6 +5334,7 @@ fn buildMingwCrtFile(comp: *Compilation, crt_file: mingw.CrtFile, prog_node: std
52785334
52795335fn buildMingwImportLib(comp: *Compilation, lib_name: []const u8, is_prelink: bool, prog_node: std.Progress.Node) void {
52805336 const crt_file_path = mingw.buildImportLib(comp, lib_name, prog_node) catch |err| switch (err) {
5337 error.AlreadyReported => return,
52815338 // TODO: This isn't actually true for self-hosted
52825339 // In the non-prelink case we will end up putting foo.lib onto the linker line and letting the linker
52835340 // use its library paths to look for libraries and report any problems.
......@@ -5291,7 +5348,7 @@ fn buildMingwImportLib(comp: *Compilation, lib_name: []const u8, is_prelink: boo
52915348 // TODO Surface more error details.
52925349 else => |e| return comp.lockAndSetMiscFailure(
52935350 .windows_import_lib,
5294 "unable to generate mingw DLL import .lib file for {s}: {t}",
5351 "generating mingw DLL import .lib file for {s} failed: {t}",
52955352 .{ lib_name, e },
52965353 ),
52975354 };
......@@ -5818,7 +5875,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
58185875 // the XML data as a RT_MANIFEST resource. This means we can skip preprocessing,
58195876 // include paths, CLI options, etc.
58205877 if (win32_resource.src == .manifest) {
5821 _ = try man.addFile(src_path, null);
5878 _ = try man.addFilePath(.initCwd(src_path), null);
58225879
58235880 const rc_basename = try std.fmt.allocPrint(arena, "{s}.rc", .{src_basename});
58245881 const res_basename = try std.fmt.allocPrint(arena, "{s}.res", .{src_basename});
......@@ -5911,7 +5968,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
59115968 // We now know that we're compiling an .rc file
59125969 const rc_src = win32_resource.src.rc;
59135970
5914 _ = try man.addFile(rc_src.src_path, null);
5971 _ = try man.addFilePath(.initCwd(rc_src.src_path), null);
59155972 man.hash.addListOfBytes(rc_src.extra_flags);
59165973
59175974 const rc_basename_noext = src_basename[0 .. src_basename.len - fs.path.extension(src_basename).len];
......@@ -7321,6 +7378,7 @@ fn buildOutputFromZig(
73217378 1, // zig lib dir is the same
73227379 3, // local cache is mapped to global cache
73237380 3, // global cache is the same
7381 0, // build root is not provided
73247382 },
73257383 },
73267384 .incremental, .none => null,
src/Zcu/PerThread.zig+5-11
......@@ -221,22 +221,19 @@ pub fn update(
221221 .astgen_failure, .success => {}, // the file was read successfully
222222 }
223223
224 const path = try file.path.toAbsolute(comp.dirs, gpa);
225 defer gpa.free(path);
226
227224 const result = res: {
228225 try whole.cache_manifest_mutex.lock(io);
229226 defer whole.cache_manifest_mutex.unlock(io);
230227 if (file.source) |source| {
231 break :res man.addFilePostContents(path, source, file.stat);
228 break :res file.path.addToCacheManifestPostHitContents(man, &comp.dirs, source, file.stat);
232229 } else {
233 break :res man.addFilePost(path);
230 break :res file.path.addToCacheManifestPostHit(man, &comp.dirs);
234231 }
235232 };
236233 result catch |err| switch (err) {
237234 error.OutOfMemory => |e| return e,
238235 else => {
239 try pt.reportRetryableFileError(file_index, "unable to update cache: {s}", .{@errorName(err)});
236 try pt.reportRetryableFileError(file_index, "unable to update cache: {t}", .{err});
240237 continue;
241238 },
242239 };
......@@ -481,7 +478,7 @@ pub fn updateFile(
481478 const stat = try source_file.stat(io);
482479
483480 const want_local_cache = switch (file.path.root) {
484 .none, .local_cache => true,
481 .none, .local_cache, .build_root => true,
485482 .global_cache, .zig_lib => false,
486483 };
487484
......@@ -2965,13 +2962,10 @@ fn newEmbedFile(
29652962 const array_len = Value.fromInterned(new_file.val).typeOf(zcu).childType(zcu).arrayLen(zcu);
29662963 const contents = ip_str.toSlice(array_len, ip);
29672964
2968 const path_str = try path.toAbsolute(comp.dirs, gpa);
2969 defer gpa.free(path_str);
2970
29712965 try whole.cache_manifest_mutex.lock(io);
29722966 defer whole.cache_manifest_mutex.unlock(io);
29732967
2974 try man.addFilePostContents(path_str, contents, new_file.stat);
2968 try path.addToCacheManifestPostHitContents(man, &comp.dirs, contents, new_file.stat);
29752969 }
29762970
29772971 return new_file;
src/codegen/llvm.zig+2-1
......@@ -481,7 +481,7 @@ pub const Object = struct {
481481 // way already, but here we throw all that sweet information
482482 // into the garbage can by converting into absolute paths. What
483483 // a terrible tragedy.
484 const compile_unit_dir = try zcu.main_mod.root.toAbsolute(comp.dirs, arena);
484 const compile_unit_dir = try zcu.main_mod.root.toAbsolute(&comp.dirs, arena);
485485
486486 const debug_file = try builder.debugFile(
487487 try builder.metadataString(comp.root_name),
......@@ -1701,6 +1701,7 @@ pub const Object = struct {
17011701 .zig_lib => dirs.zig_lib.path,
17021702 .global_cache => dirs.global_cache.path,
17031703 .local_cache => dirs.local_cache.path,
1704 .build_root => dirs.build_root.path,
17041705 .none => null,
17051706 };
17061707
src/libs/freebsd.zig+8-4
......@@ -458,8 +458,10 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
458458 man.hash.add(target.abi);
459459 man.hash.add(target_os_version);
460460
461 const full_abilists_path = try comp.dirs.zig_lib.join(arena, &.{abilists_path});
462 const abilists_index = try man.addFile(full_abilists_path, abilists_max_size);
461 const abilists_index = try man.addFilePath(.{
462 .root_dir = comp.dirs.zig_lib,
463 .sub_path = abilists_path,
464 }, abilists_max_size);
463465
464466 if (try man.hit(prog_node)) {
465467 const digest = man.final();
......@@ -1044,7 +1046,6 @@ fn buildSharedLib(
10441046 const version: Version = .{ .major = sover, .minor = 0, .patch = 0 };
10451047 const ld_basename = path.basename(target.standardDynamicLinkerPath().get().?);
10461048 const soname = if (mem.eql(u8, lib.name, "ld")) ld_basename else basename;
1047 const map_file_path = try path.join(arena, &.{ bin_directory.path.?, all_map_basename });
10481049
10491050 const optimize_mode = comp.compilerRtOptMode();
10501051 const strip = comp.compilerRtStrip();
......@@ -1113,7 +1114,10 @@ fn buildSharedLib(
11131114 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
11141115 .clang_passthrough_mode = comp.clang_passthrough_mode,
11151116 .version = version,
1116 .version_script = map_file_path,
1117 .version_script = .{
1118 .root_dir = bin_directory,
1119 .sub_path = all_map_basename,
1120 },
11171121 .soname = soname,
11181122 .c_source_files = &c_source_files,
11191123 .skip_linker_dependencies = true,
src/libs/glibc.zig+8-4
......@@ -698,8 +698,10 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
698698 man.hash.add(target.abi);
699699 man.hash.add(target_version);
700700
701 const full_abilists_path = try comp.dirs.zig_lib.join(arena, &.{abilists_path});
702 const abilists_index = try man.addFile(full_abilists_path, abilists_max_size);
701 const abilists_index = try man.addFilePath(.{
702 .root_dir = comp.dirs.zig_lib,
703 .sub_path = abilists_path,
704 }, abilists_max_size);
703705
704706 if (try man.hit(prog_node)) {
705707 const digest = man.final();
......@@ -1188,7 +1190,6 @@ fn buildSharedLib(
11881190 const version: Version = .{ .major = lib.sover, .minor = 0, .patch = 0 };
11891191 const ld_basename = path.basename(comp.getTarget().standardDynamicLinkerPath().get().?);
11901192 const soname = if (mem.eql(u8, lib.name, "ld")) ld_basename else basename;
1191 const map_file_path = try path.join(arena, &.{ bin_directory.path.?, all_map_basename });
11921193
11931194 const optimize_mode = comp.compilerRtOptMode();
11941195 const strip = comp.compilerRtStrip();
......@@ -1257,7 +1258,10 @@ fn buildSharedLib(
12571258 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
12581259 .clang_passthrough_mode = comp.clang_passthrough_mode,
12591260 .version = version,
1260 .version_script = map_file_path,
1261 .version_script = .{
1262 .root_dir = bin_directory,
1263 .sub_path = all_map_basename,
1264 },
12611265 .soname = soname,
12621266 .c_source_files = &c_source_files,
12631267 .skip_linker_dependencies = true,
src/libs/mingw.zig+50-48
......@@ -215,12 +215,15 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8, prog_node: std.P
215215 defer arena_allocator.deinit();
216216 const arena = arena_allocator.allocator();
217217
218 const def_file_path = findDef(arena, io, comp.getTarget(), comp.dirs.zig_lib, lib_name) catch |err| switch (err) {
219 error.FileNotFound => return error.DefNotFound,
220 else => |e| return e,
218 const def_file_path: Cache.Path = .{
219 .root_dir = comp.dirs.zig_lib,
220 .sub_path = findDef(arena, io, comp.getTarget(), comp.dirs.zig_lib, lib_name) catch |err| switch (err) {
221 error.FileNotFound => return error.DefNotFound,
222 else => |e| return e,
223 },
221224 };
222225 // Only .def.in files need preprocessing
223 const def_needs_preprocessing = mem.endsWith(u8, def_file_path, ".def.in");
226 const def_needs_preprocessing = mem.endsWith(u8, def_file_path.sub_path, ".def.in");
224227
225228 const target = comp.getTarget();
226229
......@@ -243,12 +246,34 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8, prog_node: std.P
243246 var man = cache.obtain();
244247 defer man.deinit();
245248
246 _ = try man.addFile(def_file_path, null);
249 _ = try man.addFilePath(def_file_path, null);
247250
248251 const final_lib_basename = try std.fmt.allocPrint(gpa, "{s}.lib", .{lib_name});
249252 errdefer gpa.free(final_lib_basename);
250253
251 if (try man.hit(prog_node)) {
254 const is_hit = man.hit(prog_node) catch |err| switch (err) {
255 error.CacheCheckFailed => switch (man.diagnostic) {
256 .none => unreachable,
257 .manifest_create, .manifest_read, .manifest_lock => |e| {
258 comp.setMiscFailure(.windows_import_lib, "checking cache failed: {t} {t}", .{ man.diagnostic, e });
259 return error.AlreadyReported;
260 },
261 .file_open, .file_stat, .file_read, .file_hash => |op| {
262 const pp = man.files.keys()[op.file_index].prefixed_path;
263 const prefix = man.cache.prefixes()[pp.prefix];
264 comp.setMiscFailure(.windows_import_lib, "checking cache failed: {f}{s} {t} {t}", .{
265 prefix, pp.sub_path, man.diagnostic, op.err,
266 });
267 return error.AlreadyReported;
268 },
269 },
270 error.OutOfMemory, error.Canceled => |e| return e,
271 error.InvalidFormat => {
272 comp.setMiscFailure(.windows_import_lib, "checking cache failed: invalid manifest file format", .{});
273 return error.AlreadyReported;
274 },
275 };
276 if (is_hit) {
252277 const digest = man.final();
253278 const sub_path = try std.fs.path.join(gpa, &.{ "o", &digest, final_lib_basename });
254279 errdefer gpa.free(sub_path);
......@@ -273,20 +298,11 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8, prog_node: std.P
273298 var o_dir = try comp.dirs.global_cache.handle.createDirPathOpen(io, o_sub_path, .{});
274299 defer o_dir.close(io);
275300
276 const include_dir = try comp.dirs.zig_lib.join(arena, &.{ "libc", "mingw", "def-include" });
277
278 if (comp.verbose_cc) {
279 var buffer: [256]u8 = undefined;
280 const stderr = try io.lockStderr(&buffer, null);
281 defer io.unlockStderr();
282 const w = &stderr.file_writer.interface;
283 w.print("def file: {s}\n", .{def_file_path}) catch |err| switch (err) {
284 error.WriteFailed => return stderr.file_writer.err.?,
285 };
286 w.print("include dir: {s}\n", .{include_dir}) catch |err| switch (err) {
287 error.WriteFailed => return stderr.file_writer.err.?,
288 };
289 }
301 const sep = path.sep_str;
302 const include_dir: Cache.Path = .{
303 .root_dir = comp.dirs.zig_lib,
304 .sub_path = "libc" ++ sep ++ "mingw" ++ sep ++ "def-include",
305 };
290306
291307 const members = members: {
292308 const members_node = sub_node.start("Members", 0);
......@@ -310,7 +326,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8, prog_node: std.P
310326
311327 break :pp try aw.toOwnedSliceSentinel(0);
312328 },
313 false => try Io.Dir.cwd().readFileAllocOptions(io, def_file_path, gpa, .unlimited, .of(u8), 0),
329 false => try def_file_path.root_dir.handle.readFileAllocOptions(io, def_file_path.sub_path, gpa, .unlimited, .of(u8), 0),
314330 };
315331 defer gpa.free(input);
316332
......@@ -384,7 +400,7 @@ pub fn libExists(
384400/// This function body is verbose but all it does is test 3 different paths and
385401/// see if a .def file exists.
386402fn findDef(
387 allocator: Allocator,
403 gpa: Allocator,
388404 io: Io,
389405 target: *const std.Target,
390406 zig_lib_directory: Cache.Directory,
......@@ -398,21 +414,17 @@ fn findDef(
398414 else => unreachable,
399415 };
400416
401 var override_path = std.array_list.Managed(u8).init(allocator);
402 defer override_path.deinit();
417 var override_path: std.ArrayList(u8) = .empty;
418 defer override_path.deinit(gpa);
403419
404420 const s = path.sep_str;
405421
406422 {
407423 // Try the archtecture-specific path first.
408 const fmt_path = "libc" ++ s ++ "mingw" ++ s ++ "{s}" ++ s ++ "{s}.def";
409 if (zig_lib_directory.path) |p| {
410 try override_path.print("{s}" ++ s ++ fmt_path, .{ p, lib_path, lib_name });
411 } else {
412 try override_path.print(fmt_path, .{ lib_path, lib_name });
413 }
414 if (Io.Dir.cwd().access(io, override_path.items, .{})) |_| {
415 return override_path.toOwnedSlice();
424 override_path.shrinkRetainingCapacity(0);
425 try override_path.print(gpa, "libc" ++ s ++ "mingw" ++ s ++ "{s}" ++ s ++ "{s}.def", .{ lib_path, lib_name });
426 if (zig_lib_directory.handle.access(io, override_path.items, .{})) |_| {
427 return override_path.toOwnedSlice(gpa);
416428 } else |err| switch (err) {
417429 error.FileNotFound => {},
418430 else => |e| return e,
......@@ -422,14 +434,9 @@ fn findDef(
422434 {
423435 // Try the generic version.
424436 override_path.shrinkRetainingCapacity(0);
425 const fmt_path = "libc" ++ s ++ "mingw" ++ s ++ "lib-common" ++ s ++ "{s}.def";
426 if (zig_lib_directory.path) |p| {
427 try override_path.print("{s}" ++ s ++ fmt_path, .{ p, lib_name });
428 } else {
429 try override_path.print(fmt_path, .{lib_name});
430 }
431 if (Io.Dir.cwd().access(io, override_path.items, .{})) |_| {
432 return override_path.toOwnedSlice();
437 try override_path.print(gpa, "libc" ++ s ++ "mingw" ++ s ++ "lib-common" ++ s ++ "{s}.def", .{lib_name});
438 if (zig_lib_directory.handle.access(io, override_path.items, .{})) |_| {
439 return override_path.toOwnedSlice(gpa);
433440 } else |err| switch (err) {
434441 error.FileNotFound => {},
435442 else => |e| return e,
......@@ -439,14 +446,9 @@ fn findDef(
439446 {
440447 // Try the generic version and preprocess it.
441448 override_path.shrinkRetainingCapacity(0);
442 const fmt_path = "libc" ++ s ++ "mingw" ++ s ++ "lib-common" ++ s ++ "{s}.def.in";
443 if (zig_lib_directory.path) |p| {
444 try override_path.print("{s}" ++ s ++ fmt_path, .{ p, lib_name });
445 } else {
446 try override_path.print(fmt_path, .{lib_name});
447 }
448 if (Io.Dir.cwd().access(io, override_path.items, .{})) |_| {
449 return override_path.toOwnedSlice();
449 try override_path.print(gpa, "libc" ++ s ++ "mingw" ++ s ++ "lib-common" ++ s ++ "{s}.def.in", .{lib_name});
450 if (zig_lib_directory.handle.access(io, override_path.items, .{})) |_| {
451 return override_path.toOwnedSlice(gpa);
450452 } else |err| switch (err) {
451453 error.FileNotFound => {},
452454 else => |e| return e,
src/libs/mingw/Preprocessor.zig+12-22
......@@ -4,6 +4,7 @@ const Allocator = std.mem.Allocator;
44const Token = Tokenizer.Token;
55const mem = std.mem;
66const assert = std.debug.assert;
7const Path = std.Build.Cache.Path;
78
89test {
910 _ = Tokenizer;
......@@ -25,15 +26,15 @@ pub const Source = struct {
2526 pub const generated: Source.Id = std.math.maxInt(usize);
2627 pub const Id = usize;
2728 id: Id = generated,
28 path: []const u8,
29 path: Path,
2930 buf: []const u8,
3031};
3132
32sources: std.array_hash_map.String(Source) = .empty,
33sources: std.array_hash_map.Custom(Path, Source, Path.TableAdapter, false) = .empty,
3334
3435arena: Allocator,
3536io: std.Io,
36include_dir: []const u8,
37include_dir: Path,
3738
3839top_expansion_buf: ExpandBuf = .empty,
3940add_expansion_nl: usize = 0,
......@@ -132,7 +133,7 @@ fn defineBuiltin(pp: *Preprocessor, name: []const u8) !void {
132133 });
133134}
134135
135pub fn preprocess(pp: *Preprocessor, file_path: []const u8) !void {
136pub fn preprocess(pp: *Preprocessor, file_path: Path) !void {
136137 const source = try pp.addSourceFromPath(file_path);
137138 try pp.preprocessFile(source);
138139}
......@@ -789,13 +790,9 @@ fn makeGeneratedToken(
789790 return pasted_token;
790791}
791792
792fn findInclude(
793 pp: *Preprocessor,
794 filename: []const u8,
795 includer_token: Token,
796) !?Source {
793fn findInclude(pp: *Preprocessor, filename: []const u8, includer_token: Token) !?Source {
797794 const other_file = pp.sources.values()[includer_token.source].path;
798 const dir = std.fs.path.dirname(other_file) orelse ".";
795 const dir: Path = other_file.dirname() orelse .cwd();
799796 if (try pp.checkIncludeDir(filename, dir)) |res| return res;
800797
801798 return pp.checkIncludeDir(filename, pp.include_dir);
......@@ -804,31 +801,24 @@ fn findInclude(
804801fn checkIncludeDir(
805802 pp: *Preprocessor,
806803 include_path: []const u8,
807 include_dir: []const u8,
804 include_dir: Path,
808805) !?Source {
809 const format = "{s}{c}{s}";
810806 var bfa_buf: [1024]u8 = undefined;
811807 var bfa_state: std.heap.BufferFirstAllocator = .init(&bfa_buf, pp.arena);
812808 const bfa = bfa_state.allocator();
813 const header_path = try std.fmt.allocPrint(bfa, format, .{
814 include_dir,
815 std.fs.path.sep,
816 include_path,
817 });
818 defer bfa.free(header_path);
819
809 const header_path = try include_dir.join(bfa, include_path);
820810 return pp.addSourceFromPath(header_path) catch |err| switch (err) {
821811 error.OutOfMemory => |e| return e,
822812 else => return null,
823813 };
824814}
825815
826pub fn addSourceFromPath(pp: *Preprocessor, path: []const u8) !Source {
816pub fn addSourceFromPath(pp: *Preprocessor, path: Path) !Source {
827817 if (pp.sources.get(path)) |src| return src;
828818 try pp.sources.ensureUnusedCapacity(pp.arena, 1);
829819
830 const contents = try std.Io.Dir.cwd().readFileAlloc(pp.io, path, pp.arena, .limited(std.math.maxInt(u32)));
831 const duped_path = try pp.arena.dupe(u8, path);
820 const contents = try path.root_dir.handle.readFileAlloc(pp.io, path.sub_path, pp.arena, .limited(std.math.maxInt(u32)));
821 const duped_path = try path.clone(pp.arena);
832822
833823 const src: Source = .{
834824 .buf = contents,
src/libs/netbsd.zig+4-2
......@@ -406,8 +406,10 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
406406 man.hash.add(target.abi);
407407 man.hash.add(target_version);
408408
409 const full_abilists_path = try comp.dirs.zig_lib.join(arena, &.{abilists_path});
410 const abilists_index = try man.addFile(full_abilists_path, abilists_max_size);
409 const abilists_index = try man.addFilePath(.{
410 .root_dir = comp.dirs.zig_lib,
411 .sub_path = abilists_path,
412 }, abilists_max_size);
411413
412414 if (try man.hit(prog_node)) {
413415 const digest = man.final();
src/libs/openbsd.zig+4-2
......@@ -327,8 +327,10 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
327327 man.hash.add(target.abi);
328328 man.hash.add(target_version);
329329
330 const full_abilists_path = try comp.dirs.zig_lib.join(arena, &.{abilists_path});
331 const abilists_index = try man.addFile(full_abilists_path, abilists_max_size);
330 const abilists_index = try man.addFilePath(.{
331 .root_dir = comp.dirs.zig_lib,
332 .sub_path = abilists_path,
333 }, abilists_max_size);
332334
333335 if (try man.hit(prog_node)) {
334336 const digest = man.final();
src/link.zig+3-3
......@@ -461,8 +461,8 @@ pub const File = struct {
461461 allow_undefined_version: bool,
462462 enable_new_dtags: ?bool,
463463 subsystem: ?std.zig.Subsystem,
464 linker_script: ?[]const u8,
465 version_script: ?[]const u8,
464 linker_script: ?Path,
465 version_script: ?Path,
466466 soname: ?[]const u8,
467467 print_gc_sections: bool,
468468 print_icf_sections: bool,
......@@ -493,7 +493,7 @@ pub const File = struct {
493493 /// Install name for the dylib
494494 install_name: ?[]const u8,
495495 /// Path to entitlements file
496 entitlements: ?[]const u8,
496 entitlements: ?Path,
497497 /// size of the __PAGEZERO segment
498498 pagezero_size: ?u64,
499499 /// Set minimum space for future expansion of the load commands
src/link/Dwarf.zig+1-1
......@@ -4735,7 +4735,7 @@ fn flushWriterError(dwarf: *Dwarf, pt: Zcu.PerThread) (UpdateError || Writer.Err
47354735 }
47364736
47374737 for (dwarf.mods.keys(), dwarf.mods.values()) |mod, *mod_info| {
4738 const root_dir_path = try mod.root.toAbsolute(zcu.comp.dirs, dwarf.gpa);
4738 const root_dir_path = try mod.root.toAbsolute(&zcu.comp.dirs, dwarf.gpa);
47394739 defer dwarf.gpa.free(root_dir_path);
47404740 mod_info.root_dir_path = try dwarf.debug_line_str.addString(dwarf, root_dir_path);
47414741 }
src/link/Lld.zig+4-4
......@@ -75,8 +75,8 @@ pub const Elf = struct {
7575 entry_name: ?[]const u8,
7676 hash_style: HashStyle,
7777 image_base: u64,
78 linker_script: ?[]const u8,
79 version_script: ?[]const u8,
78 linker_script: ?Cache.Path,
79 version_script: ?Cache.Path,
8080 sort_section: ?SortSection,
8181 print_icf_sections: bool,
8282 print_map: bool,
......@@ -930,7 +930,7 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {
930930
931931 if (elf.linker_script) |linker_script| {
932932 try argv.append("-T");
933 try argv.append(linker_script);
933 try argv.append(try linker_script.toString(arena));
934934 }
935935
936936 if (elf.sort_section) |how| {
......@@ -1086,7 +1086,7 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {
10861086 }
10871087 if (elf.version_script) |version_script| {
10881088 try argv.append("-version-script");
1089 try argv.append(version_script);
1089 try argv.append(try version_script.toString(arena));
10901090 }
10911091 if (elf.allow_undefined_version) {
10921092 try argv.append("--undefined-version");
src/link/MachO.zig+2-2
......@@ -127,7 +127,7 @@ frameworks: []const Framework,
127127/// TODO: unify with soname
128128install_name: ?[]const u8,
129129/// Path to entitlements file.
130entitlements: ?[]const u8,
130entitlements: ?Path,
131131compatibility_version: ?std.SemanticVersion,
132132/// Entry name
133133entry_name: ?[]const u8,
......@@ -580,7 +580,7 @@ pub fn flush(
580580 var codesig = CodeSignature.init(self.getPageSize());
581581 codesig.code_directory.ident = fs.path.basename(self.base.emit.sub_path);
582582 if (self.entitlements) |path| codesig.addEntitlements(gpa, io, path) catch |err|
583 return diags.fail("failed to add entitlements from {s}: {t}", .{ path, err });
583 return diags.fail("failed to add entitlements from {f}: {t}", .{ path, err });
584584 try self.writeCodeSignaturePadding(&codesig);
585585 break :blk codesig;
586586 } else null;
src/link/MachO/CodeSignature.zig+2-2
......@@ -246,8 +246,8 @@ pub fn deinit(self: *CodeSignature, allocator: Allocator) void {
246246 }
247247}
248248
249pub fn addEntitlements(self: *CodeSignature, allocator: Allocator, io: Io, path: []const u8) !void {
250 const inner = try Io.Dir.cwd().readFileAlloc(io, path, allocator, .limited(std.math.maxInt(u32)));
249pub fn addEntitlements(self: *CodeSignature, allocator: Allocator, io: Io, path: std.Build.Cache.Path) !void {
250 const inner = try path.root_dir.handle.readFileAlloc(io, path.sub_path, allocator, .limited(std.math.maxInt(u32)));
251251 self.entitlements = .{ .inner = inner };
252252}
253253
src/main.zig+52-52
......@@ -423,17 +423,16 @@ fn mainArgs(
423423 .wasi => {},
424424 else => process.executablePathAlloc(io, arena) catch |err| fatal("unable to find zig self exe path: {t}", .{err}),
425425 };
426 var dirs: std.zig.Directories = .init(
427 arena,
428 io,
429 EnvVar.ZIG_LIB_DIR.get(environ_map),
430 EnvVar.ZIG_GLOBAL_CACHE_DIR.get(environ_map),
431 .global,
432 preopens,
433 self_exe_path,
434 environ_map,
435 try std.zig.getResolvedCwd(io, arena),
436 );
426 var dirs: std.zig.Directories = .init(arena, io, .{
427 .override_zig_lib = EnvVar.ZIG_LIB_DIR.get(environ_map),
428 .override_global_cache = EnvVar.ZIG_GLOBAL_CACHE_DIR.get(environ_map),
429 .build_root = null,
430 .local_cache_strat = .global,
431 .preopens = preopens,
432 .self_exe_path = self_exe_path,
433 .environ_map = environ_map,
434 .cwd = try std.zig.getResolvedCwd(io, arena),
435 });
437436 defer dirs.deinit(io);
438437 const host = std.zig.resolveTargetQueryOrFatal(io, .{});
439438 var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer);
......@@ -458,17 +457,16 @@ fn mainArgs(
458457 .wasi => args[0],
459458 else => process.executablePathAlloc(io, arena) catch |err| fatal("unable to find zig self exe path: {t}", .{err}),
460459 };
461 var dirs: std.zig.Directories = .init(
462 arena,
463 io,
464 EnvVar.ZIG_LIB_DIR.get(environ_map),
465 EnvVar.ZIG_GLOBAL_CACHE_DIR.get(environ_map),
466 .global,
467 preopens,
468 if (native_os != .wasi) self_exe_path,
469 environ_map,
470 try std.zig.getResolvedCwd(io, arena),
471 );
460 var dirs: std.zig.Directories = .init(arena, io, .{
461 .override_zig_lib = EnvVar.ZIG_LIB_DIR.get(environ_map),
462 .override_global_cache = EnvVar.ZIG_GLOBAL_CACHE_DIR.get(environ_map),
463 .build_root = null,
464 .local_cache_strat = .global,
465 .preopens = preopens,
466 .self_exe_path = if (native_os != .wasi) self_exe_path,
467 .environ_map = environ_map,
468 .cwd = try std.zig.getResolvedCwd(io, arena),
469 });
472470 defer dirs.deinit(io);
473471 const host = std.zig.resolveTargetQueryOrFatal(io, .{});
474472 var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer);
......@@ -511,7 +509,7 @@ fn mainArgs(
511509 }
512510}
513511
514const usage_build_generic =
512const compile_usage =
515513 \\Usage: zig build-exe [options] [files]
516514 \\ zig build-lib [options] [files]
517515 \\ zig build-obj [options] [files]
......@@ -565,16 +563,16 @@ const usage_build_generic =
565563 \\ --cache-dir [path] Override the local cache directory
566564 \\ --global-cache-dir [path] Override the global cache directory
567565 \\ --zig-lib-dir [path] Override path to Zig installation lib directory
566 \\ --build-root [path] Override path to project source files
568567 \\
569568 \\Global Compile Options:
570569 \\ --name [name] Compilation unit name (not a file path)
571 \\ --libc [file] Provide a file which specifies libc paths
572 \\ -x language Treat subsequent input files as having type <language>
573 \\ --dep [[import=]name] Add an entry to the next module's import table
574570 \\ -M[name][=src] Create a module based on the current per-module settings.
575571 \\ The first module is the main module.
576572 \\ "std" can be configured by omitting src
577573 \\ After a -M argument, per-module settings are reset.
574 \\ --libc [file] Provide a file which specifies libc paths
575 \\ -x [language] Treat subsequent input files as having type <language>
578576 \\ --error-limit [num] Set the maximum amount of distinct error values
579577 \\ -fllvm Force using LLVM as the codegen backend
580578 \\ -fno-llvm Prevent using LLVM as the codegen backend
......@@ -599,6 +597,7 @@ const usage_build_generic =
599597 \\ --time-report Send timing diagnostics to '--listen' clients
600598 \\
601599 \\Per-Module Compile Options:
600 \\ --dep [[import=]name] Add an entry to the next module's import table
602601 \\ -target [name] <arch><sub>-<os>-<abi> see the targets command
603602 \\ -O [mode] Choose what to optimize for
604603 \\ debug (default) Prioritize bug detection, accurate debug info, compilation speed
......@@ -1054,6 +1053,7 @@ fn buildOutputType(
10541053 var rc_includes: std.zig.RcIncludes = .any;
10551054 var manifest_file: ?[]const u8 = null;
10561055 var linker_export_symbol_names: std.ArrayList([]const u8) = .empty;
1056 var build_root_path: ?[]const u8 = null;
10571057
10581058 // Tracks the position in c_source_files which have already their owner populated.
10591059 var c_source_files_owner_index: usize = 0;
......@@ -1167,7 +1167,7 @@ fn buildOutputType(
11671167 fatal("unable to read response file {q}: {t}", .{ resp_file_path, err });
11681168 } else if (mem.startsWith(u8, arg, "-")) {
11691169 if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
1170 try Io.File.stdout().writeStreamingAll(io, usage_build_generic);
1170 try Io.File.stdout().writeStreamingAll(io, compile_usage);
11711171 return cleanExit(io);
11721172 } else if (mem.eql(u8, arg, "--")) {
11731173 if (arg_mode == .run) {
......@@ -1440,6 +1440,8 @@ fn buildOutputType(
14401440 override_global_cache_dir = args_iter.nextOrFatal();
14411441 } else if (mem.eql(u8, arg, "--zig-lib-dir")) {
14421442 override_lib_dir = args_iter.nextOrFatal();
1443 } else if (mem.eql(u8, arg, "--build-root")) {
1444 build_root_path = args_iter.nextOrFatal();
14431445 } else if (mem.eql(u8, arg, "--debug-log")) {
14441446 try addDebugLog(arena, args_iter.nextOrFatal());
14451447 } else if (mem.eql(u8, arg, "--listen")) {
......@@ -3254,23 +3256,22 @@ fn buildOutputType(
32543256 const cwd_path = try std.zig.getResolvedCwd(io, arena);
32553257
32563258 // This `init` calls `fatal` on error.
3257 var dirs: std.zig.Directories = .init(
3258 arena,
3259 io,
3260 override_lib_dir,
3261 override_global_cache_dir,
3262 s: {
3259 var dirs: std.zig.Directories = .init(arena, io, .{
3260 .override_zig_lib = override_lib_dir,
3261 .override_global_cache = override_global_cache_dir,
3262 .build_root = build_root_path,
3263 .local_cache_strat = s: {
32633264 if (override_local_cache_dir) |p| break :s .{ .override = p };
32643265 break :s switch (arg_mode) {
32653266 .run => .global,
32663267 else => .search,
32673268 };
32683269 },
3269 preopens,
3270 self_exe_path,
3271 environ_map,
3272 cwd_path,
3273 );
3270 .preopens = preopens,
3271 .self_exe_path = self_exe_path,
3272 .environ_map = environ_map,
3273 .cwd = cwd_path,
3274 });
32743275 defer dirs.deinit(io);
32753276
32763277 if (linker_optimization) |o| warn("ignoring deprecated linker optimization setting {q}", .{o});
......@@ -3666,8 +3667,8 @@ fn buildOutputType(
36663667 .want_compiler_rt = if (zig_cc_explicitly_link_compiler_rt) true else want_compiler_rt,
36673668 .want_ubsan_rt = want_ubsan_rt,
36683669 .hash_style = hash_style,
3669 .linker_script = linker_script,
3670 .version_script = version_script,
3670 .linker_script = if (linker_script) |p| .initCwd(p) else null,
3671 .version_script = if (version_script) |p| .initCwd(p) else null,
36713672 .linker_allow_undefined_version = linker_allow_undefined_version,
36723673 .linker_enable_new_dtags = linker_enable_new_dtags,
36733674 .disable_c_depfile = disable_c_depfile,
......@@ -3740,7 +3741,7 @@ fn buildOutputType(
37403741 .debug_incremental = debug_incremental,
37413742 .enable_link_snapshots = enable_link_snapshots,
37423743 .install_name = install_name,
3743 .entitlements = entitlements,
3744 .entitlements = if (entitlements) |p| .initCwd(p) else null,
37443745 .pagezero_size = pagezero_size,
37453746 .headerpad_size = headerpad_size,
37463747 .headerpad_max_install_names = headerpad_max_install_names,
......@@ -5020,17 +5021,16 @@ fn jitCmdInner(
50205021 const cwd_path = try std.zig.getResolvedCwd(io, arena);
50215022
50225023 // This `init` calls `fatal` on error.
5023 var dirs: std.zig.Directories = .init(
5024 arena,
5025 io,
5026 override_lib_dir,
5027 override_global_cache_dir,
5028 .global,
5029 preopens,
5030 self_exe_path,
5031 environ_map,
5032 cwd_path,
5033 );
5024 var dirs: std.zig.Directories = .init(arena, io, .{
5025 .override_zig_lib = override_lib_dir,
5026 .override_global_cache = override_global_cache_dir,
5027 .build_root = null,
5028 .local_cache_strat = .global,
5029 .preopens = preopens,
5030 .self_exe_path = self_exe_path,
5031 .environ_map = environ_map,
5032 .cwd = cwd_path,
5033 });
50345034 defer dirs.deinit(io);
50355035
50365036 var child_argv: std.ArrayList([]const u8) = .empty;
tools/check_mingw.zig+2-2
......@@ -71,11 +71,11 @@ pub fn main(init: std.process.Init) !void {
7171 var pp: Preprocessor = .{
7272 .io = io,
7373 .arena = pp_arena,
74 .include_dir = mingw_include_path,
74 .include_dir = .initCwd(mingw_include_path),
7575 .target = target,
7676 };
7777
78 pp.preprocess(file_path) catch |err| {
78 pp.preprocess(.initCwd(file_path)) catch |err| {
7979 std.log.err("error preprocessing file {s} for target {t}: {t}", .{ entry.path, target.cpu.arch, err });
8080 fail = true;
8181 continue;