authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-08-14 21:12:32-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-08-19 12:39:36-07:00
log83d41cf04dcec3d66a84b6c2a727621c076e971e
treee160c6e76a6f7e23f67af7cd0357123b38ffae8b
parent0c4dcb12b93d88028c032d76241aac83b0958efd

add build_root to cache prefix directories


10 files changed, 117 insertions(+), 79 deletions(-)

lib/compiler/Maker.zig+2
...@@ -614,6 +614,8 @@ pub fn main(init: process.Init.Minimal) !void {...@@ -614,6 +614,8 @@ pub fn main(init: process.Init.Minimal) !void {
614 comptime assert(1 == @backingInt(std.zig.Server.Message.PathPrefix.zig_lib));614 comptime assert(1 == @backingInt(std.zig.Server.Message.PathPrefix.zig_lib));
615 comptime assert(2 == @backingInt(std.zig.Server.Message.PathPrefix.local_cache));615 comptime assert(2 == @backingInt(std.zig.Server.Message.PathPrefix.local_cache));
616 comptime assert(3 == @backingInt(std.zig.Server.Message.PathPrefix.global_cache));616 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
618 graph.cache.hash.addBytes(builtin.zig_version_string);620 graph.cache.hash.addBytes(builtin.zig_version_string);
619621
lib/compiler/Maker/Step.zig+7
...@@ -656,6 +656,13 @@ fn zigProcessUpdate(step_index: Configuration.Step.Index, maker: *Maker, zp: *Zi...@@ -656,6 +656,13 @@ fn zigProcessUpdate(step_index: Configuration.Step.Index, maker: *Maker, zp: *Zi
656 };656 };
657 try addWatchInputFromPath(s, maker, path, Dir.path.basename(sub_path));657 try addWatchInputFromPath(s, maker, path, Dir.path.basename(sub_path));
658 },658 },
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 },
659 }666 }
660 }667 }
661 },668 },
lib/compiler/Maker/Step/Compile.zig+2-1
...@@ -658,9 +658,10 @@ fn lowerZigArgs(...@@ -658,9 +658,10 @@ fn lowerZigArgs(
658 zig_args.appendAssumeCapacity(libc_file);658 zig_args.appendAssumeCapacity(libc_file);
659 }659 }
660660
661 (try zig_args.addManyAsArray(gpa, 4)).* = .{661 (try zig_args.addManyAsArray(gpa, 6)).* = .{
662 "--cache-dir", graph.local_cache_root.path orelse ".",662 "--cache-dir", graph.local_cache_root.path orelse ".",
663 "--global-cache-dir", graph.global_cache_root.path orelse ".",663 "--global-cache-dir", graph.global_cache_root.path orelse ".",
664 "--build-root", graph.build_root_directory.path orelse ".",
664 };665 };
665666
666 try zig_args.ensureUnusedCapacity(gpa, 1);667 try zig_args.ensureUnusedCapacity(gpa, 1);
lib/std/Build/Cache.zig+2-6
...@@ -418,7 +418,6 @@ pub const Manifest = struct {...@@ -418,7 +418,6 @@ pub const Manifest = struct {
418 }418 }
419419
420 fn addFileInner(self: *Manifest, prefixed_path: PrefixedPath, handle: ?Io.File, max_file_size: ?usize) usize {420 fn addFileInner(self: *Manifest, prefixed_path: PrefixedPath, handle: ?Io.File, max_file_size: ?usize) usize {
421 assert(!std.fs.path.isAbsolute(prefixed_path.sub_path));
422 const gop = self.files.getOrPutAssumeCapacityAdapted(prefixed_path, FilesAdapter{});421 const gop = self.files.getOrPutAssumeCapacityAdapted(prefixed_path, FilesAdapter{});
423 if (gop.found_existing) {422 if (gop.found_existing) {
424 self.cache.gpa.free(prefixed_path.sub_path);423 self.cache.gpa.free(prefixed_path.sub_path);
...@@ -951,7 +950,6 @@ pub const Manifest = struct {...@@ -951,7 +950,6 @@ pub const Manifest = struct {
951 /// will need to be recompiled if the imported file is changed.950 /// will need to be recompiled if the imported file is changed.
952 pub fn addFilePostFetch(self: *Manifest, file_path: []const u8, max_file_size: usize) ![]const u8 {951 pub fn addFilePostFetch(self: *Manifest, file_path: []const u8, max_file_size: usize) ![]const u8 {
953 assert(self.manifest_file != null);952 assert(self.manifest_file != null);
954 assert(!std.fs.path.isAbsolute(file_path));
955953
956 const gpa = self.cache.gpa;954 const gpa = self.cache.gpa;
957 const prefixed_path = try self.cache.findPrefix(file_path);955 const prefixed_path = try self.cache.findPrefix(file_path);
...@@ -1009,7 +1007,6 @@ pub const Manifest = struct {...@@ -1009,7 +1007,6 @@ pub const Manifest = struct {
1009 /// whether or not `prefixed_path.sub_path` should be kept.1007 /// whether or not `prefixed_path.sub_path` should be kept.
1010 pub fn addPrefixedPathPost(man: *Manifest, prefixed_path: PrefixedPath) !bool {1008 pub fn addPrefixedPathPost(man: *Manifest, prefixed_path: PrefixedPath) !bool {
1011 assert(man.manifest_file != null);1009 assert(man.manifest_file != null);
1012 assert(!std.fs.path.isAbsolute(prefixed_path.sub_path));
1013 const gpa = man.cache.gpa;1010 const gpa = man.cache.gpa;
10141011
1015 const gop = try man.files.getOrPutAdapted(gpa, prefixed_path, FilesAdapter{});1012 const gop = try man.files.getOrPutAdapted(gpa, prefixed_path, FilesAdapter{});
...@@ -1041,7 +1038,6 @@ pub const Manifest = struct {...@@ -1041,7 +1038,6 @@ pub const Manifest = struct {
1041 stat: File.Stat,1038 stat: File.Stat,
1042 ) !void {1039 ) !void {
1043 assert(self.manifest_file != null);1040 assert(self.manifest_file != null);
1044 assert(!std.fs.path.isAbsolute(file_path));
1045 const gpa = self.cache.gpa;1041 const gpa = self.cache.gpa;
10461042
1047 const prefixed_path = try self.cache.findPrefix(file_path);1043 const prefixed_path = try self.cache.findPrefix(file_path);
...@@ -1268,10 +1264,10 @@ pub const Manifest = struct {...@@ -1268,10 +1264,10 @@ pub const Manifest = struct {
1268 }1264 }
1269 }1265 }
12701266
1271 pub fn populateOtherManifest(man: *Manifest, other: *Manifest, prefix_map: [4]u8) Allocator.Error!void {1267 pub fn populateOtherManifest(man: *Manifest, other: *Manifest, prefix_map: [5]u8) Allocator.Error!void {
1272 const gpa = other.cache.gpa;1268 const gpa = other.cache.gpa;
1273 assert(@typeInfo(std.zig.Server.Message.PathPrefix).@"enum".field_names.len == man.cache.prefixes_len);1269 assert(@typeInfo(std.zig.Server.Message.PathPrefix).@"enum".field_names.len == man.cache.prefixes_len);
1274 assert(man.cache.prefixes_len == 4);1270 assert(man.cache.prefixes_len == 5);
1275 for (man.files.keys()) |file| {1271 for (man.files.keys()) |file| {
1276 const prefixed_path: PrefixedPath = .{1272 const prefixed_path: PrefixedPath = .{
1277 .prefix = prefix_map[file.prefixed_path.prefix],1273 .prefix = prefix_map[file.prefixed_path.prefix],
lib/std/zig.zig+32-15
...@@ -1283,6 +1283,10 @@ pub const Directories = struct {...@@ -1283,6 +1283,10 @@ pub const Directories = struct {
1283 /// `local_cache.path` is resolved (`resolvePath`) or `null` for cwd.1283 /// `local_cache.path` is resolved (`resolvePath`) or `null` for cwd.
1284 /// This may be the same as `global_cache`.1284 /// This may be the same as `global_cache`.
1285 local_cache: Cache.Directory,1285 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
1287 pub fn deinit(dirs: *Directories, io: Io) void {1291 pub fn deinit(dirs: *Directories, io: Io) void {
1288 // The local and global caches could be the same.1292 // The local and global caches could be the same.
...@@ -1291,6 +1295,7 @@ pub const Directories = struct {...@@ -1291,6 +1295,7 @@ pub const Directories = struct {
1291 dirs.global_cache.handle.close(io);1295 dirs.global_cache.handle.close(io);
1292 if (close_local) dirs.local_cache.handle.close(io);1296 if (close_local) dirs.local_cache.handle.close(io);
1293 dirs.zig_lib.handle.close(io);1297 dirs.zig_lib.handle.close(io);
1298 if (dirs.build_root.path != null) dirs.build_root.handle.close(io);
1294 }1299 }
12951300
1296 /// Returns a `Directories` where `local_cache` is replaced with `global_cache`, intended for1301 /// Returns a `Directories` where `local_cache` is replaced with `global_cache`, intended for
...@@ -1302,6 +1307,7 @@ pub const Directories = struct {...@@ -1302,6 +1307,7 @@ pub const Directories = struct {
1302 .zig_lib = dirs.zig_lib,1307 .zig_lib = dirs.zig_lib,
1303 .global_cache = dirs.global_cache,1308 .global_cache = dirs.global_cache,
1304 .local_cache = dirs.global_cache,1309 .local_cache = dirs.global_cache,
1310 .build_root = dirs.build_root,
1305 };1311 };
1306 }1312 }
13071313
...@@ -1311,12 +1317,10 @@ pub const Directories = struct {...@@ -1311,12 +1317,10 @@ pub const Directories = struct {
1311 global,1317 global,
1312 };1318 };
13131319
1314 /// Uses `std.process.fatal` on error conditions.1320 pub const InitOptions = struct {
1315 pub fn init(
1316 arena: Allocator,
1317 io: Io,
1318 override_zig_lib: ?[]const u8,1321 override_zig_lib: ?[]const u8,
1319 override_global_cache: ?[]const u8,1322 override_global_cache: ?[]const u8,
1323 build_root: ?[]const u8,
1320 local_cache_strat: LocalCacheStrategy,1324 local_cache_strat: LocalCacheStrategy,
1321 preopens: std.process.Preopens,1325 preopens: std.process.Preopens,
1322 self_exe_path: switch (builtin.target.os.tag) {1326 self_exe_path: switch (builtin.target.os.tag) {
...@@ -1325,27 +1329,38 @@ pub const Directories = struct {...@@ -1325,27 +1329,38 @@ pub const Directories = struct {
1325 },1329 },
1326 environ_map: *const std.process.Environ.Map,1330 environ_map: *const std.process.Environ.Map,
1327 cwd: []const u8,1331 cwd: []const u8,
1328 ) Directories {1332 };
1333
1334 /// Uses `std.process.fatal` on error conditions.
1335 pub fn init(arena: Allocator, io: Io, options: InitOptions) Directories {
1329 const wasi = builtin.target.os.tag == .wasi;1336 const wasi = builtin.target.os.tag == .wasi;
1337 const cwd = options.cwd;
13301338
1331 const zig_lib: Cache.Directory = d: {1339 const zig_lib: Cache.Directory = d: {
1332 if (override_zig_lib) |path| break :d openUnresolved(arena, io, cwd, path, .@"zig lib");1340 if (options.override_zig_lib) |path| break :d openUnresolved(arena, io, cwd, path, .@"zig lib");
1333 if (wasi) break :d getPreopen(preopens, "/lib");1341 if (wasi) break :d getPreopen(options.preopens, "/lib");
1334 break :d findZigLibDirFromSelfExe(arena, io, cwd, self_exe_path) catch |err| {1342 break :d findZigLibDirFromSelfExe(arena, io, cwd, options.self_exe_path) catch |err| {
1335 fatal("unable to find zig installation directory from executable path {q}: {t}", .{ self_exe_path, err });1343 fatal("unable to find zig installation directory from executable path {q}: {t}", .{
1344 options.self_exe_path, err,
1345 });
1336 };1346 };
1337 };1347 };
1348 const build_root: Cache.Directory = if (options.build_root) |s|
1349 // TODO this ends up setting path to null, leaking the fd in deinit
1350 openUnresolved(arena, io, cwd, s, .@"build root")
1351 else
1352 .cwd();
13381353
1339 const global_cache: Cache.Directory = d: {1354 const global_cache: Cache.Directory = d: {
1340 if (override_global_cache) |path| break :d openUnresolved(arena, io, cwd, path, .@"global cache");1355 if (options.override_global_cache) |path| break :d openUnresolved(arena, io, cwd, path, .@"global cache");
1341 if (wasi) break :d getPreopen(preopens, "/cache");1356 if (wasi) break :d getPreopen(options.preopens, "/cache");
1342 const path = resolveGlobalCacheDir(arena, environ_map) catch |err| {1357 const path = resolveGlobalCacheDir(arena, options.environ_map) catch |err| {
1343 fatal("unable to resolve zig cache directory: {t}", .{err});1358 fatal("unable to resolve zig cache directory: {t}", .{err});
1344 };1359 };
1345 break :d openUnresolved(arena, io, cwd, path, .@"global cache");1360 break :d openUnresolved(arena, io, cwd, path, .@"global cache");
1346 };1361 };
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
1350 if (mem.eql(u8, zig_lib.path orelse "", global_cache.path orelse "")) {1365 if (mem.eql(u8, zig_lib.path orelse "", global_cache.path orelse "")) {
1351 fatal("zig lib directory '{f}' cannot be equal to global cache directory '{f}'", .{ zig_lib, global_cache });1366 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 {...@@ -1359,6 +1374,7 @@ pub const Directories = struct {
1359 .zig_lib = zig_lib,1374 .zig_lib = zig_lib,
1360 .global_cache = global_cache,1375 .global_cache = global_cache,
1361 .local_cache = local_cache,1376 .local_cache = local_cache,
1377 .build_root = build_root,
1362 };1378 };
1363 }1379 }
13641380
...@@ -1395,14 +1411,14 @@ pub const Directories = struct {...@@ -1395,14 +1411,14 @@ pub const Directories = struct {
1395 io: Io,1411 io: Io,
1396 cwd: []const u8,1412 cwd: []const u8,
1397 unresolved_path: []const u8,1413 unresolved_path: []const u8,
1398 thing: enum { @"zig lib", @"global cache", @"local cache" },1414 thing: enum { @"zig lib", @"global cache", @"local cache", @"build root" },
1399 ) Cache.Directory {1415 ) Cache.Directory {
1400 const path = resolvePath(arena, cwd, &.{unresolved_path}) catch |err| {1416 const path = resolvePath(arena, cwd, &.{unresolved_path}) catch |err| {
1401 fatal("unable to resolve {t} directory: {t}", .{ thing, err });1417 fatal("unable to resolve {t} directory: {t}", .{ thing, err });
1402 };1418 };
1403 const nonempty_path = if (path.len == 0) "." else path;1419 const nonempty_path = if (path.len == 0) "." else path;
1404 const handle_or_err = switch (thing) {1420 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, .{}),
1406 .@"global cache", .@"local cache" => Dir.cwd().createDirPathOpen(io, nonempty_path, .{}),1422 .@"global cache", .@"local cache" => Dir.cwd().createDirPathOpen(io, nonempty_path, .{}),
1407 };1423 };
1408 return .{1424 return .{
...@@ -1747,6 +1763,7 @@ pub fn buildExeSubprocess(...@@ -1747,6 +1763,7 @@ pub fn buildExeSubprocess(
1747 const sub_path = try gpa.dupe(u8, prefixed_path[1..]);1763 const sub_path = try gpa.dupe(u8, prefixed_path[1..]);
1748 var keep = false;1764 var keep = false;
1749 defer if (!keep) gpa.free(sub_path);1765 defer if (!keep) gpa.free(sub_path);
1766 log.debug("file system input: {t} {s}", .{ prefix, sub_path });
1750 keep = man.addPrefixedPathPost(.{1767 keep = man.addPrefixedPathPost(.{
1751 .prefix = @backingInt(prefix),1768 .prefix = @backingInt(prefix),
1752 .sub_path = sub_path,1769 .sub_path = sub_path,
lib/std/zig/Server.zig+1
...@@ -135,6 +135,7 @@ pub const Message = struct {...@@ -135,6 +135,7 @@ pub const Message = struct {
135 zig_lib,135 zig_lib,
136 local_cache,136 local_cache,
137 global_cache,137 global_cache,
138 build_root,
138 };139 };
139140
140 /// Trailing:141 /// Trailing:
src/Compilation.zig+23-10
...@@ -397,6 +397,7 @@ pub const Path = struct {...@@ -397,6 +397,7 @@ pub const Path = struct {
397 global_cache,397 global_cache,
398 /// `sub_path` is relative to the local cache directory on `Compilation`.398 /// `sub_path` is relative to the local cache directory on `Compilation`.
399 local_cache,399 local_cache,
400 build_root,
400 /// `sub_path` is not relative to any of the roots listed above.401 /// `sub_path` is not relative to any of the roots listed above.
401 /// It is resolved starting with `Directories.cwd`; so it is an absolute path on most402 /// It is resolved starting with `Directories.cwd`; so it is an absolute path on most
402 /// targets, but cwd-relative on WASI. We do not make it cwd-relative on other targets403 /// targets, but cwd-relative on WASI. We do not make it cwd-relative on other targets
...@@ -439,6 +440,7 @@ pub const Path = struct {...@@ -439,6 +440,7 @@ pub const Path = struct {
439 .zig_lib => dirs.zig_lib.handle,440 .zig_lib => dirs.zig_lib.handle,
440 .global_cache => dirs.global_cache.handle,441 .global_cache => dirs.global_cache.handle,
441 .local_cache => dirs.local_cache.handle,442 .local_cache => dirs.local_cache.handle,
443 .build_root => dirs.build_root.handle,
442 };444 };
443 if (p.sub_path.len == 0) return .{ dir, "." };445 if (p.sub_path.len == 0) return .{ dir, "." };
444 assert(!fs.path.isAbsolute(p.sub_path));446 assert(!fs.path.isAbsolute(p.sub_path));
...@@ -457,6 +459,7 @@ pub const Path = struct {...@@ -457,6 +459,7 @@ pub const Path = struct {
457 .zig_lib => f.comp.dirs.zig_lib.path orelse ".",459 .zig_lib => f.comp.dirs.zig_lib.path orelse ".",
458 .global_cache => f.comp.dirs.global_cache.path orelse ".",460 .global_cache => f.comp.dirs.global_cache.path orelse ".",
459 .local_cache => f.comp.dirs.local_cache.path orelse ".",461 .local_cache => f.comp.dirs.local_cache.path orelse ".",
462 .build_root => f.comp.dirs.build_root.path orelse ".",
460 .none => {463 .none => {
461 const cwd_sub_path = absToCwdRelative(f.p.sub_path, f.comp.dirs.cwd);464 const cwd_sub_path = absToCwdRelative(f.p.sub_path, f.comp.dirs.cwd);
462 try w.writeAll(cwd_sub_path);465 try w.writeAll(cwd_sub_path);
...@@ -581,6 +584,7 @@ pub const Path = struct {...@@ -581,6 +584,7 @@ pub const Path = struct {
581 .zig_lib => dirs.zig_lib.path orelse "",584 .zig_lib => dirs.zig_lib.path orelse "",
582 .global_cache => dirs.global_cache.path orelse "",585 .global_cache => dirs.global_cache.path orelse "",
583 .local_cache => dirs.local_cache.path orelse "",586 .local_cache => dirs.local_cache.path orelse "",
587 .build_root => dirs.build_root.path orelse "",
584 .none => "",588 .none => "",
585 },589 },
586 sub_path,590 sub_path,
...@@ -603,6 +607,7 @@ pub const Path = struct {...@@ -603,6 +607,7 @@ pub const Path = struct {
603 .zig_lib => dirs.zig_lib.path orelse "",607 .zig_lib => dirs.zig_lib.path orelse "",
604 .global_cache => dirs.global_cache.path orelse "",608 .global_cache => dirs.global_cache.path orelse "",
605 .local_cache => dirs.local_cache.path orelse "",609 .local_cache => dirs.local_cache.path orelse "",
610 .build_root => dirs.build_root.path orelse "",
606 .none => "",611 .none => "",
607 },612 },
608 p.sub_path,613 p.sub_path,
...@@ -622,6 +627,7 @@ pub const Path = struct {...@@ -622,6 +627,7 @@ pub const Path = struct {
622 .zig_lib => dirs.zig_lib.path orelse "",627 .zig_lib => dirs.zig_lib.path orelse "",
623 .global_cache => dirs.global_cache.path orelse "",628 .global_cache => dirs.global_cache.path orelse "",
624 .local_cache => dirs.local_cache.path orelse "",629 .local_cache => dirs.local_cache.path orelse "",
630 .build_root => dirs.build_root.path orelse "",
625 .none => "",631 .none => "",
626 },632 },
627 p.sub_path,633 p.sub_path,
...@@ -635,6 +641,7 @@ pub const Path = struct {...@@ -635,6 +641,7 @@ pub const Path = struct {
635 .zig_lib => dirs.zig_lib,641 .zig_lib => dirs.zig_lib,
636 .global_cache => dirs.global_cache,642 .global_cache => dirs.global_cache,
637 .local_cache => dirs.local_cache,643 .local_cache => dirs.local_cache,
644 .build_root => dirs.build_root,
638 else => {645 else => {
639 const cwd_sub_path = absToCwdRelative(p.sub_path, dirs.cwd);646 const cwd_sub_path = absToCwdRelative(p.sub_path, dirs.cwd);
640 return .{647 return .{
...@@ -658,13 +665,10 @@ pub const Path = struct {...@@ -658,13 +665,10 @@ pub const Path = struct {
658 .zig_lib => dirs.zig_lib.path orelse "",665 .zig_lib => dirs.zig_lib.path orelse "",
659 .global_cache => dirs.global_cache.path orelse "",666 .global_cache => dirs.global_cache.path orelse "",
660 .local_cache => dirs.local_cache.path orelse "",667 .local_cache => dirs.local_cache.path orelse "",
668 .build_root => dirs.build_root.path orelse "",
661 .none => "",669 .none => "",
662 };670 };
663 return fs.path.resolve(gpa, &.{671 return fs.path.resolve(gpa, &.{ dirs.cwd, root_path, p.sub_path });
664 dirs.cwd,
665 root_path,
666 p.sub_path,
667 });
668 }672 }
669673
670 pub fn isNested(inner: Path, outer: Path) union(enum) {674 pub fn isNested(inner: Path, outer: Path) union(enum) {
...@@ -1348,7 +1352,7 @@ pub const CacheMode = enum {...@@ -1348,7 +1352,7 @@ pub const CacheMode = enum {
1348pub const ParentWholeCache = struct {1352pub const ParentWholeCache = struct {
1349 manifest: *Cache.Manifest,1353 manifest: *Cache.Manifest,
1350 mutex: *std.Io.Mutex,1354 mutex: *std.Io.Mutex,
1351 prefix_map: [4]u8,1355 prefix_map: [5]u8,
1352};1356};
13531357
1354const CacheUse = union(CacheMode) {1358const CacheUse = union(CacheMode) {
...@@ -1926,6 +1930,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,...@@ -1926,6 +1930,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
1926 }1930 }
19271931
1928 const error_limit = options.error_limit orelse (std.math.maxInt(u16) - 1);1932 const error_limit = options.error_limit orelse (std.math.maxInt(u16) - 1);
1933 const main_mod = options.main_mod orelse options.root_mod;
19291934
1930 // We put everything into the cache hash that *cannot be modified1935 // We put everything into the cache hash that *cannot be modified
1931 // during an incremental update*. For example, one cannot change the1936 // during an incremental update*. For example, one cannot change the
...@@ -1944,11 +1949,18 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,...@@ -1944,11 +1949,18 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
1944 },1949 },
1945 .cwd = options.dirs.cwd,1950 .cwd = options.dirs.cwd,
1946 };1951 };
1947 // These correspond to std.zig.Server.Message.PathPrefix.1952 comptime assert(0 == @backingInt(std.zig.Server.Message.PathPrefix.cwd));
1953 comptime assert(1 == @backingInt(std.zig.Server.Message.PathPrefix.zig_lib));
1954 comptime assert(2 == @backingInt(std.zig.Server.Message.PathPrefix.local_cache));
1955 comptime assert(3 == @backingInt(std.zig.Server.Message.PathPrefix.global_cache));
1956 comptime assert(4 == @backingInt(std.zig.Server.Message.PathPrefix.build_root));
1957 comptime assert(@typeInfo(std.zig.Server.Message.PathPrefix).@"enum".field_names.len == 5);
1948 cache.addPrefix(.{ .path = null, .handle = Io.Dir.cwd() });1958 cache.addPrefix(.{ .path = null, .handle = Io.Dir.cwd() });
1949 cache.addPrefix(options.dirs.zig_lib);1959 cache.addPrefix(options.dirs.zig_lib);
1950 cache.addPrefix(options.dirs.local_cache);1960 cache.addPrefix(options.dirs.local_cache);
1951 cache.addPrefix(options.dirs.global_cache);1961 cache.addPrefix(options.dirs.global_cache);
1962 log.debug("addPrefix build_root {s}", .{options.dirs.build_root.path orelse "(null)"});
1963 cache.addPrefix(options.dirs.build_root);
1952 errdefer cache.manifest_dir.close(io);1964 errdefer cache.manifest_dir.close(io);
19531965
1954 // This is shared hasher state common to zig source and all C source files.1966 // This is shared hasher state common to zig source and all C source files.
...@@ -1984,7 +1996,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,...@@ -1984,7 +1996,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
1984 cache.hash.add(options.emit_docs != .no);1996 cache.hash.add(options.emit_docs != .no);
1985 // TODO audit this and make sure everything is in it1997 // TODO audit this and make sure everything is in it
19861998
1987 const main_mod = options.main_mod orelse options.root_mod;
1988 const comp = try arena.create(Compilation);1999 const comp = try arena.create(Compilation);
1989 const opt_zcu: ?*Zcu = if (have_zcu) blk: {2000 const opt_zcu: ?*Zcu = if (have_zcu) blk: {
1990 // Pre-open the directory handles for cached ZIR code so that it does not need2001 // Pre-open the directory handles for cached ZIR code so that it does not need
...@@ -3116,6 +3127,7 @@ pub fn appendFileSystemInput(comp: *Compilation, path: Compilation.Path) Allocat...@@ -3116,6 +3127,7 @@ pub fn appendFileSystemInput(comp: *Compilation, path: Compilation.Path) Allocat
3116 .zig_lib => comp.dirs.zig_lib,3127 .zig_lib => comp.dirs.zig_lib,
3117 .global_cache => comp.dirs.global_cache,3128 .global_cache => comp.dirs.global_cache,
3118 .local_cache => comp.dirs.local_cache,3129 .local_cache => comp.dirs.local_cache,
3130 .build_root => comp.dirs.build_root,
3119 .none => .cwd(),3131 .none => .cwd(),
3120 };3132 };
3121 const prefix: u8 = for (prefixes, 1..) |prefix_dir, i| {3133 const prefix: u8 = for (prefixes, 1..) |prefix_dir, i| {
...@@ -3123,8 +3135,8 @@ pub fn appendFileSystemInput(comp: *Compilation, path: Compilation.Path) Allocat...@@ -3123,8 +3135,8 @@ pub fn appendFileSystemInput(comp: *Compilation, path: Compilation.Path) Allocat
3123 break @intCast(i);3135 break @intCast(i);
3124 }3136 }
3125 } else std.debug.panic(3137 } else std.debug.panic(
3126 "missing prefix directory '{s}' ('{f}') for '{s}'",3138 "missing prefix directory {t} ('{f}') for {q}",
3127 .{ @tagName(path.root), want_prefix_dir, path.sub_path },3139 .{ path.root, want_prefix_dir, path.sub_path },
3128 );3140 );
31293141
3130 // There may be concurrent calls to this function from C object workers and/or the main thread.3142 // There may be concurrent calls to this function from C object workers and/or the main thread.
...@@ -7323,6 +7335,7 @@ fn buildOutputFromZig(...@@ -7323,6 +7335,7 @@ fn buildOutputFromZig(
7323 1, // zig lib dir is the same7335 1, // zig lib dir is the same
7324 3, // local cache is mapped to global cache7336 3, // local cache is mapped to global cache
7325 3, // global cache is the same7337 3, // global cache is the same
7338 0, // build root is not provided
7326 },7339 },
7327 },7340 },
7328 .incremental, .none => null,7341 .incremental, .none => null,
src/Zcu/PerThread.zig+1-1
...@@ -481,7 +481,7 @@ pub fn updateFile(...@@ -481,7 +481,7 @@ pub fn updateFile(
481 const stat = try source_file.stat(io);481 const stat = try source_file.stat(io);
482482
483 const want_local_cache = switch (file.path.root) {483 const want_local_cache = switch (file.path.root) {
484 .none, .local_cache => true,484 .none, .local_cache, .build_root => true,
485 .global_cache, .zig_lib => false,485 .global_cache, .zig_lib => false,
486 };486 };
487487
src/codegen/llvm.zig+1
...@@ -1701,6 +1701,7 @@ pub const Object = struct {...@@ -1701,6 +1701,7 @@ pub const Object = struct {
1701 .zig_lib => dirs.zig_lib.path,1701 .zig_lib => dirs.zig_lib.path,
1702 .global_cache => dirs.global_cache.path,1702 .global_cache => dirs.global_cache.path,
1703 .local_cache => dirs.local_cache.path,1703 .local_cache => dirs.local_cache.path,
1704 .build_root => dirs.build_root.path,
1704 .none => null,1705 .none => null,
1705 };1706 };
17061707
src/main.zig+46-46
...@@ -423,17 +423,16 @@ fn mainArgs(...@@ -423,17 +423,16 @@ fn mainArgs(
423 .wasi => {},423 .wasi => {},
424 else => process.executablePathAlloc(io, arena) catch |err| fatal("unable to find zig self exe path: {t}", .{err}),424 else => process.executablePathAlloc(io, arena) catch |err| fatal("unable to find zig self exe path: {t}", .{err}),
425 };425 };
426 var dirs: std.zig.Directories = .init(426 var dirs: std.zig.Directories = .init(arena, io, .{
427 arena,427 .override_zig_lib = EnvVar.ZIG_LIB_DIR.get(environ_map),
428 io,428 .override_global_cache = EnvVar.ZIG_GLOBAL_CACHE_DIR.get(environ_map),
429 EnvVar.ZIG_LIB_DIR.get(environ_map),429 .build_root = null,
430 EnvVar.ZIG_GLOBAL_CACHE_DIR.get(environ_map),430 .local_cache_strat = .global,
431 .global,431 .preopens = preopens,
432 preopens,432 .self_exe_path = self_exe_path,
433 self_exe_path,433 .environ_map = environ_map,
434 environ_map,434 .cwd = try std.zig.getResolvedCwd(io, arena),
435 try std.zig.getResolvedCwd(io, arena),435 });
436 );
437 defer dirs.deinit(io);436 defer dirs.deinit(io);
438 const host = std.zig.resolveTargetQueryOrFatal(io, .{});437 const host = std.zig.resolveTargetQueryOrFatal(io, .{});
439 var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer);438 var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer);
...@@ -458,17 +457,16 @@ fn mainArgs(...@@ -458,17 +457,16 @@ fn mainArgs(
458 .wasi => args[0],457 .wasi => args[0],
459 else => process.executablePathAlloc(io, arena) catch |err| fatal("unable to find zig self exe path: {t}", .{err}),458 else => process.executablePathAlloc(io, arena) catch |err| fatal("unable to find zig self exe path: {t}", .{err}),
460 };459 };
461 var dirs: std.zig.Directories = .init(460 var dirs: std.zig.Directories = .init(arena, io, .{
462 arena,461 .override_zig_lib = EnvVar.ZIG_LIB_DIR.get(environ_map),
463 io,462 .override_global_cache = EnvVar.ZIG_GLOBAL_CACHE_DIR.get(environ_map),
464 EnvVar.ZIG_LIB_DIR.get(environ_map),463 .build_root = null,
465 EnvVar.ZIG_GLOBAL_CACHE_DIR.get(environ_map),464 .local_cache_strat = .global,
466 .global,465 .preopens = preopens,
467 preopens,466 .self_exe_path = if (native_os != .wasi) self_exe_path,
468 if (native_os != .wasi) self_exe_path,467 .environ_map = environ_map,
469 environ_map,468 .cwd = try std.zig.getResolvedCwd(io, arena),
470 try std.zig.getResolvedCwd(io, arena),469 });
471 );
472 defer dirs.deinit(io);470 defer dirs.deinit(io);
473 const host = std.zig.resolveTargetQueryOrFatal(io, .{});471 const host = std.zig.resolveTargetQueryOrFatal(io, .{});
474 var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer);472 var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer);
...@@ -511,7 +509,7 @@ fn mainArgs(...@@ -511,7 +509,7 @@ fn mainArgs(
511 }509 }
512}510}
513511
514const usage_build_generic =512const compile_usage =
515 \\Usage: zig build-exe [options] [files]513 \\Usage: zig build-exe [options] [files]
516 \\ zig build-lib [options] [files]514 \\ zig build-lib [options] [files]
517 \\ zig build-obj [options] [files]515 \\ zig build-obj [options] [files]
...@@ -565,6 +563,7 @@ const usage_build_generic =...@@ -565,6 +563,7 @@ const usage_build_generic =
565 \\ --cache-dir [path] Override the local cache directory563 \\ --cache-dir [path] Override the local cache directory
566 \\ --global-cache-dir [path] Override the global cache directory564 \\ --global-cache-dir [path] Override the global cache directory
567 \\ --zig-lib-dir [path] Override path to Zig installation lib directory565 \\ --zig-lib-dir [path] Override path to Zig installation lib directory
566 \\ --build-root [path] Override path to project source files
568 \\567 \\
569 \\Global Compile Options:568 \\Global Compile Options:
570 \\ --name [name] Compilation unit name (not a file path)569 \\ --name [name] Compilation unit name (not a file path)
...@@ -1054,6 +1053,7 @@ fn buildOutputType(...@@ -1054,6 +1053,7 @@ fn buildOutputType(
1054 var rc_includes: std.zig.RcIncludes = .any;1053 var rc_includes: std.zig.RcIncludes = .any;
1055 var manifest_file: ?[]const u8 = null;1054 var manifest_file: ?[]const u8 = null;
1056 var linker_export_symbol_names: std.ArrayList([]const u8) = .empty;1055 var linker_export_symbol_names: std.ArrayList([]const u8) = .empty;
1056 var build_root_path: ?[]const u8 = null;
10571057
1058 // Tracks the position in c_source_files which have already their owner populated.1058 // Tracks the position in c_source_files which have already their owner populated.
1059 var c_source_files_owner_index: usize = 0;1059 var c_source_files_owner_index: usize = 0;
...@@ -1167,7 +1167,7 @@ fn buildOutputType(...@@ -1167,7 +1167,7 @@ fn buildOutputType(
1167 fatal("unable to read response file {q}: {t}", .{ resp_file_path, err });1167 fatal("unable to read response file {q}: {t}", .{ resp_file_path, err });
1168 } else if (mem.startsWith(u8, arg, "-")) {1168 } else if (mem.startsWith(u8, arg, "-")) {
1169 if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {1169 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);
1171 return cleanExit(io);1171 return cleanExit(io);
1172 } else if (mem.eql(u8, arg, "--")) {1172 } else if (mem.eql(u8, arg, "--")) {
1173 if (arg_mode == .run) {1173 if (arg_mode == .run) {
...@@ -1440,6 +1440,8 @@ fn buildOutputType(...@@ -1440,6 +1440,8 @@ fn buildOutputType(
1440 override_global_cache_dir = args_iter.nextOrFatal();1440 override_global_cache_dir = args_iter.nextOrFatal();
1441 } else if (mem.eql(u8, arg, "--zig-lib-dir")) {1441 } else if (mem.eql(u8, arg, "--zig-lib-dir")) {
1442 override_lib_dir = args_iter.nextOrFatal();1442 override_lib_dir = args_iter.nextOrFatal();
1443 } else if (mem.eql(u8, arg, "--build-root")) {
1444 build_root_path = args_iter.nextOrFatal();
1443 } else if (mem.eql(u8, arg, "--debug-log")) {1445 } else if (mem.eql(u8, arg, "--debug-log")) {
1444 try addDebugLog(arena, args_iter.nextOrFatal());1446 try addDebugLog(arena, args_iter.nextOrFatal());
1445 } else if (mem.eql(u8, arg, "--listen")) {1447 } else if (mem.eql(u8, arg, "--listen")) {
...@@ -3254,23 +3256,22 @@ fn buildOutputType(...@@ -3254,23 +3256,22 @@ fn buildOutputType(
3254 const cwd_path = try std.zig.getResolvedCwd(io, arena);3256 const cwd_path = try std.zig.getResolvedCwd(io, arena);
32553257
3256 // This `init` calls `fatal` on error.3258 // This `init` calls `fatal` on error.
3257 var dirs: std.zig.Directories = .init(3259 var dirs: std.zig.Directories = .init(arena, io, .{
3258 arena,3260 .override_zig_lib = override_lib_dir,
3259 io,3261 .override_global_cache = override_global_cache_dir,
3260 override_lib_dir,3262 .build_root = build_root_path,
3261 override_global_cache_dir,3263 .local_cache_strat = s: {
3262 s: {
3263 if (override_local_cache_dir) |p| break :s .{ .override = p };3264 if (override_local_cache_dir) |p| break :s .{ .override = p };
3264 break :s switch (arg_mode) {3265 break :s switch (arg_mode) {
3265 .run => .global,3266 .run => .global,
3266 else => .search,3267 else => .search,
3267 };3268 };
3268 },3269 },
3269 preopens,3270 .preopens = preopens,
3270 self_exe_path,3271 .self_exe_path = self_exe_path,
3271 environ_map,3272 .environ_map = environ_map,
3272 cwd_path,3273 .cwd = cwd_path,
3273 );3274 });
3274 defer dirs.deinit(io);3275 defer dirs.deinit(io);
32753276
3276 if (linker_optimization) |o| warn("ignoring deprecated linker optimization setting {q}", .{o});3277 if (linker_optimization) |o| warn("ignoring deprecated linker optimization setting {q}", .{o});
...@@ -5020,17 +5021,16 @@ fn jitCmdInner(...@@ -5020,17 +5021,16 @@ fn jitCmdInner(
5020 const cwd_path = try std.zig.getResolvedCwd(io, arena);5021 const cwd_path = try std.zig.getResolvedCwd(io, arena);
50215022
5022 // This `init` calls `fatal` on error.5023 // This `init` calls `fatal` on error.
5023 var dirs: std.zig.Directories = .init(5024 var dirs: std.zig.Directories = .init(arena, io, .{
5024 arena,5025 .override_zig_lib = override_lib_dir,
5025 io,5026 .override_global_cache = override_global_cache_dir,
5026 override_lib_dir,5027 .build_root = null,
5027 override_global_cache_dir,5028 .local_cache_strat = .global,
5028 .global,5029 .preopens = preopens,
5029 preopens,5030 .self_exe_path = self_exe_path,
5030 self_exe_path,5031 .environ_map = environ_map,
5031 environ_map,5032 .cwd = cwd_path,
5032 cwd_path,5033 });
5033 );
5034 defer dirs.deinit(io);5034 defer dirs.deinit(io);
50355035
5036 var child_argv: std.ArrayList([]const u8) = .empty;5036 var child_argv: std.ArrayList([]const u8) = .empty;