diff --git a/lib/compiler/Maker.zig b/lib/compiler/Maker.zig index 92db208cbc7e299ee0282a504ca1dd372f83a604..b5132c6ad05787c9318d649beb2549b7282de07f 100644 --- a/lib/compiler/Maker.zig +++ b/lib/compiler/Maker.zig @@ -614,6 +614,8 @@ pub fn main(init: process.Init.Minimal) !void { comptime assert(1 == @backingInt(std.zig.Server.Message.PathPrefix.zig_lib)); comptime assert(2 == @backingInt(std.zig.Server.Message.PathPrefix.local_cache)); comptime assert(3 == @backingInt(std.zig.Server.Message.PathPrefix.global_cache)); + comptime assert(4 == @backingInt(std.zig.Server.Message.PathPrefix.build_root)); + comptime assert(@typeInfo(std.zig.Server.Message.PathPrefix).@"enum".field_names.len == 5); graph.cache.hash.addBytes(builtin.zig_version_string); @@ -1118,6 +1120,7 @@ fn configure(graph: *Graph, options: ConfigureOptions) !ScannedConfig { graph.zig_exe, "build-exe", // "--cache-dir", graph.local_cache_root.path orelse ".", // "--global-cache-dir", graph.global_cache_root.path orelse ".", // + "--build-root", graph.build_root_directory.path orelse ".", // "--zig-lib-dir", graph.zig_lib_directory.path orelse ".", // "--name", configurer_exe_name, // "-fsingle-threaded", // @@ -1412,7 +1415,6 @@ fn configure(graph: *Graph, options: ConfigureOptions) !ScannedConfig { if (config_man) |man| { if (try man.hit(compile_prog_node)) { - log.debug("configuration cache hit", .{}); const digest = man.final(); const path: Path = .{ .root_dir = graph.local_cache_root, @@ -1422,6 +1424,7 @@ fn configure(graph: *Graph, options: ConfigureOptions) !ScannedConfig { break :cp .{ path, man.toOwnedLock() }; } } + try graph.handleVerbose(null, null, build_configurer_argv.items); const configure_exe_path: Path = if (std.zig.buildExeSubprocess(gpa, io, .{ .argv = build_configurer_argv.items, .cache_root = graph.local_cache_root, diff --git a/lib/compiler/Maker/Step.zig b/lib/compiler/Maker/Step.zig index 2ce90b5a9b7725d452258af167de82b60b973a6b..0fd82226cce06989c0acea46f4f22e4dcd6d6e58 100644 --- a/lib/compiler/Maker/Step.zig +++ b/lib/compiler/Maker/Step.zig @@ -656,6 +656,13 @@ fn zigProcessUpdate(step_index: Configuration.Step.Index, maker: *Maker, zp: *Zi }; try addWatchInputFromPath(s, maker, path, Dir.path.basename(sub_path)); }, + .build_root => { + const path: Path = .{ + .root_dir = graph.build_root_directory, + .sub_path = sub_path_dirname, + }; + try addWatchInputFromPath(s, maker, path, Dir.path.basename(sub_path)); + }, } } }, diff --git a/lib/compiler/Maker/Step/Compile.zig b/lib/compiler/Maker/Step/Compile.zig index 1e60ad77a30a78bf0f903527430ac76b7af4fdd4..bca0df4de84cc95c42b2067d3ec1f5d65176488b 100644 --- a/lib/compiler/Maker/Step/Compile.zig +++ b/lib/compiler/Maker/Step/Compile.zig @@ -658,9 +658,10 @@ fn lowerZigArgs( zig_args.appendAssumeCapacity(libc_file); } - (try zig_args.addManyAsArray(gpa, 4)).* = .{ + (try zig_args.addManyAsArray(gpa, 6)).* = .{ "--cache-dir", graph.local_cache_root.path orelse ".", "--global-cache-dir", graph.global_cache_root.path orelse ".", + "--build-root", graph.build_root_directory.path orelse ".", }; try zig_args.ensureUnusedCapacity(gpa, 1); diff --git a/lib/std/Build/Cache.zig b/lib/std/Build/Cache.zig index a66f2bb543a162ba879174434ccc10dce52597de..94051c51658796081d413cc18133a97c93814d55 100644 --- a/lib/std/Build/Cache.zig +++ b/lib/std/Build/Cache.zig @@ -417,18 +417,6 @@ pub const Manifest = struct { return addFileInner(m, prefixed_path, handle, max_file_size); } - /// Deprecated; use `addFilePath`. - pub fn addFile(self: *Manifest, file_path: []const u8, max_file_size: ?usize) !usize { - assert(self.manifest_file == null); - - const gpa = self.cache.gpa; - try self.files.ensureUnusedCapacity(gpa, 1); - const prefixed_path = try self.cache.findPrefix(file_path); - errdefer gpa.free(prefixed_path.sub_path); - - return addFileInner(self, prefixed_path, null, max_file_size); - } - fn addFileInner(self: *Manifest, prefixed_path: PrefixedPath, handle: ?Io.File, max_file_size: ?usize) usize { const gop = self.files.getOrPutAssumeCapacityAdapted(prefixed_path, FilesAdapter{}); if (gop.found_existing) { @@ -452,26 +440,12 @@ pub const Manifest = struct { return gop.index; } - /// Deprecated, use `addOptionalFilePath`. - pub fn addOptionalFile(self: *Manifest, optional_file_path: ?[]const u8) !void { - self.hash.add(optional_file_path != null); - const file_path = optional_file_path orelse return; - _ = try self.addFile(file_path, null); - } - pub fn addOptionalFilePath(self: *Manifest, optional_file_path: ?Path) !void { self.hash.add(optional_file_path != null); const file_path = optional_file_path orelse return; _ = try self.addFilePath(file_path, null); } - pub fn addListOfFiles(self: *Manifest, list_of_files: []const []const u8) !void { - self.hash.add(list_of_files.len); - for (list_of_files) |file_path| { - _ = try self.addFile(file_path, null); - } - } - pub fn addDepFile(self: *Manifest, dir: Io.Dir, dep_file_sub_path: []const u8) !void { assert(self.manifest_file == null); return self.addDepFileMaybePost(dir, dep_file_sub_path); @@ -1058,24 +1032,32 @@ pub const Manifest = struct { /// Like `addFilePost` but when the file contents have already been loaded from disk. pub fn addFilePostContents( - self: *Manifest, + man: *Manifest, file_path: []const u8, bytes: []const u8, stat: File.Stat, ) !void { - assert(self.manifest_file != null); - const gpa = self.cache.gpa; + assert(man.manifest_file != null); + const gpa = man.cache.gpa; + const prefixed_path = try man.cache.findPrefix(file_path); + var keep = false; + defer if (!keep) gpa.free(prefixed_path.sub_path); + keep = try addPrefixedPathPostContents(man, prefixed_path, bytes, stat); + } - const prefixed_path = try self.cache.findPrefix(file_path); - errdefer gpa.free(prefixed_path.sub_path); + /// Low level function. `prefixed_path` references cloned memory. Returns + /// whether or not `prefixed_path.sub_path` should be kept. + pub fn addPrefixedPathPostContents( + man: *Manifest, + prefixed_path: PrefixedPath, + bytes: []const u8, + stat: File.Stat, + ) !bool { + const gpa = man.cache.gpa; + const gop = try man.files.getOrPutAdapted(gpa, prefixed_path, FilesAdapter{}); + errdefer _ = man.files.pop(); - const gop = try self.files.getOrPutAdapted(gpa, prefixed_path, FilesAdapter{}); - errdefer _ = self.files.pop(); - - if (gop.found_existing) { - gpa.free(prefixed_path.sub_path); - return; - } + if (gop.found_existing) return false; const new_file = gop.key_ptr; @@ -1088,7 +1070,7 @@ pub const Manifest = struct { .contents = null, }; - if (try self.isProblematicTimestamp(new_file.stat.mtime)) { + if (try man.isProblematicTimestamp(new_file.stat.mtime)) { // The actual file has an unreliable timestamp, force it to be hashed new_file.stat.mtime = .zero; new_file.stat.inode = 0; @@ -1100,7 +1082,8 @@ pub const Manifest = struct { hasher.final(&new_file.bin_digest); } - self.hash.hasher.update(&new_file.bin_digest); + man.hash.hasher.update(&new_file.bin_digest); + return true; } pub fn addDepFilePost(self: *Manifest, dir: Io.Dir, dep_file_sub_path: []const u8) !void { @@ -1127,13 +1110,13 @@ pub const Manifest = struct { // Clang is invoked in single-source mode but other programs may not .target, .target_must_resolve => {}, .prereq => |file_path| if (self.manifest_file == null) { - _ = try self.addFile(file_path, null); + _ = try self.addFilePath(.initCwd(file_path), null); } else try self.addFilePost(file_path), .prereq_must_resolve => { resolve_buf.clearRetainingCapacity(); try token.resolve(gpa, &resolve_buf); if (self.manifest_file == null) { - _ = try self.addFile(resolve_buf.items, null); + _ = try self.addFilePath(.initCwd(resolve_buf.items), null); } else try self.addFilePost(resolve_buf.items); }, else => |err| { @@ -1290,10 +1273,10 @@ pub const Manifest = struct { } } - pub fn populateOtherManifest(man: *Manifest, other: *Manifest, prefix_map: [4]u8) Allocator.Error!void { + pub fn populateOtherManifest(man: *Manifest, other: *Manifest, prefix_map: [5]u8) Allocator.Error!void { const gpa = other.cache.gpa; assert(@typeInfo(std.zig.Server.Message.PathPrefix).@"enum".field_names.len == man.cache.prefixes_len); - assert(man.cache.prefixes_len == 4); + assert(man.cache.prefixes_len == 5); for (man.files.keys()) |file| { const prefixed_path: PrefixedPath = .{ .prefix = prefix_map[file.prefixed_path.prefix], @@ -1392,7 +1375,7 @@ test "cache file and then recall it" { ch.hash.add(true); ch.hash.add(@as(u16, 1234)); ch.hash.addBytes("1234"); - _ = try ch.addFile(temp_file, null); + _ = try ch.addFilePath(.initCwd(temp_file), null); // There should be nothing in the cache try testing.expectEqual(false, try ch.hit(.none)); @@ -1407,7 +1390,7 @@ test "cache file and then recall it" { ch.hash.add(true); ch.hash.add(@as(u16, 1234)); ch.hash.addBytes("1234"); - _ = try ch.addFile(temp_file, null); + _ = try ch.addFilePath(.initCwd(temp_file), null); // Cache hit! We just "built" the same file try testing.expect(try ch.hit(.none)); @@ -1460,7 +1443,7 @@ test "check that changing a file makes cache fail" { defer ch.deinit(); ch.hash.addBytes("1234"); - const temp_file_idx = try ch.addFile(temp_file, 100); + const temp_file_idx = try ch.addFilePath(.initCwd(temp_file), 100); // There should be nothing in the cache try testing.expectEqual(false, try ch.hit(.none)); @@ -1479,7 +1462,7 @@ test "check that changing a file makes cache fail" { defer ch.deinit(); ch.hash.addBytes("1234"); - const temp_file_idx = try ch.addFile(temp_file, 100); + const temp_file_idx = try ch.addFilePath(.initCwd(temp_file), 100); // A file that we depend on has been updated, so the cache should not contain an entry for it try testing.expectEqual(false, try ch.hit(.none)); @@ -1587,7 +1570,7 @@ test "Manifest with files added after initial hash work" { defer ch.deinit(); ch.hash.addBytes("1234"); - _ = try ch.addFile(temp_file1, null); + _ = try ch.addFilePath(.initCwd(temp_file1), null); // There should be nothing in the cache try testing.expectEqual(false, try ch.hit(.none)); @@ -1602,7 +1585,7 @@ test "Manifest with files added after initial hash work" { defer ch.deinit(); ch.hash.addBytes("1234"); - _ = try ch.addFile(temp_file1, null); + _ = try ch.addFilePath(.initCwd(temp_file1), null); try testing.expect(try ch.hit(.none)); digest2 = ch.final(); @@ -1625,7 +1608,7 @@ test "Manifest with files added after initial hash work" { defer ch.deinit(); ch.hash.addBytes("1234"); - _ = try ch.addFile(temp_file1, null); + _ = try ch.addFilePath(.initCwd(temp_file1), null); // A file that we depend on has been updated, so the cache should not contain an entry for it try testing.expectEqual(false, try ch.hit(.none)); diff --git a/lib/std/fs/path.zig b/lib/std/fs/path.zig index d5b7f751acf77f6a4b98951f8039bbbf4c20b752..55e362f456e88f6cc36715f04260e160a17a31cd 100644 --- a/lib/std/fs/path.zig +++ b/lib/std/fs/path.zig @@ -1093,23 +1093,23 @@ pub fn resolveWindows(allocator: Allocator, paths: []const []const u8) Allocator return result.toOwnedSlice(allocator); } -/// This function is like a series of `cd` statements executed one after another. +/// Simulates a series of relative directory changes on a virtual filesystem +/// that has no symlinks. /// -/// It resolves "." and ".." to the best of its ability, but will not convert relative paths to -/// an absolute path, use Io.Dir.realpath instead. -/// -/// ".." components may persist in the resolved path if the resolved path is relative. +/// "." and ".." are resolved but will not make relative paths absolute. ".." +/// components remain in the resolved path when the resolved path is relative +/// and there are not previous components to cancel out. /// /// The result does not have a trailing path separator. /// /// This function does not perform any syscalls. Executing this series of path -/// lookups on the actual filesystem may produce different results due to +/// lookups on an actual filesystem may produce different results due to /// symlinks. -pub fn resolvePosix(allocator: Allocator, paths: []const []const u8) Allocator.Error![]u8 { +pub fn resolvePosix(gpa: Allocator, paths: []const []const u8) Allocator.Error![]u8 { assert(paths.len > 0); - var result = std.array_list.Managed(u8).init(allocator); - defer result.deinit(); + var result: std.ArrayList(u8) = .empty; + defer result.deinit(gpa); var negative_count: usize = 0; var is_abs = false; @@ -1135,23 +1135,23 @@ pub fn resolvePosix(allocator: Allocator, paths: []const []const u8) Allocator.E if (ends_with_slash or result.items.len == 0) break; } } else if (result.items.len > 0 or is_abs) { - try result.ensureUnusedCapacity(1 + component.len); + try result.ensureUnusedCapacity(gpa, 1 + component.len); result.appendAssumeCapacity('/'); result.appendSliceAssumeCapacity(component); } else { - try result.appendSlice(component); + try result.appendSlice(gpa, component); } } } if (result.items.len == 0) { if (is_abs) { - return allocator.dupe(u8, "/"); + return gpa.dupe(u8, "/"); } if (negative_count == 0) { - return allocator.dupe(u8, "."); + return gpa.dupe(u8, "."); } else { - const real_result = try allocator.alloc(u8, 3 * negative_count - 1); + const real_result = try gpa.alloc(u8, 3 * negative_count - 1); var count = negative_count - 1; var i: usize = 0; while (count > 0) : (count -= 1) { @@ -1164,9 +1164,9 @@ pub fn resolvePosix(allocator: Allocator, paths: []const []const u8) Allocator.E } if (negative_count == 0) { - return result.toOwnedSlice(); + return result.toOwnedSlice(gpa); } else { - const real_result = try allocator.alloc(u8, 3 * negative_count + result.items.len); + const real_result = try gpa.alloc(u8, 3 * negative_count + result.items.len); var count = negative_count; var i: usize = 0; while (count > 0) : (count -= 1) { diff --git a/lib/std/zig.zig b/lib/std/zig.zig index ec6fc7d630a92133751c8ae481ff193d3fc0dfff..81baffb36bc70dd6551b4acfd360d2a811db2629 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -1283,14 +1283,20 @@ pub const Directories = struct { /// `local_cache.path` is resolved (`resolvePath`) or `null` for cwd. /// This may be the same as `global_cache`. local_cache: Cache.Directory, + /// The directory that contains build.zig. This path is provided by the + /// build system, when the build system is used, otherwise, it is `null` + /// for cwd. + build_root: Cache.Directory, pub fn deinit(dirs: *Directories, io: Io) void { // The local and global caches could be the same. const close_local = dirs.local_cache.handle.handle != dirs.global_cache.handle.handle; + const close_build_root = dirs.build_root.handle.handle != Io.Dir.cwd().handle; dirs.global_cache.handle.close(io); if (close_local) dirs.local_cache.handle.close(io); dirs.zig_lib.handle.close(io); + if (close_build_root) dirs.build_root.handle.close(io); } /// Returns a `Directories` where `local_cache` is replaced with `global_cache`, intended for @@ -1302,6 +1308,7 @@ pub const Directories = struct { .zig_lib = dirs.zig_lib, .global_cache = dirs.global_cache, .local_cache = dirs.global_cache, + .build_root = dirs.build_root, }; } @@ -1311,12 +1318,10 @@ pub const Directories = struct { global, }; - /// Uses `std.process.fatal` on error conditions. - pub fn init( - arena: Allocator, - io: Io, + pub const InitOptions = struct { override_zig_lib: ?[]const u8, override_global_cache: ?[]const u8, + build_root: ?[]const u8, local_cache_strat: LocalCacheStrategy, preopens: std.process.Preopens, self_exe_path: switch (builtin.target.os.tag) { @@ -1325,27 +1330,37 @@ pub const Directories = struct { }, environ_map: *const std.process.Environ.Map, cwd: []const u8, - ) Directories { + }; + + /// Uses `std.process.fatal` on error conditions. + pub fn init(arena: Allocator, io: Io, options: InitOptions) Directories { const wasi = builtin.target.os.tag == .wasi; + const cwd = options.cwd; const zig_lib: Cache.Directory = d: { - if (override_zig_lib) |path| break :d openUnresolved(arena, io, cwd, path, .@"zig lib"); - if (wasi) break :d getPreopen(preopens, "/lib"); - break :d findZigLibDirFromSelfExe(arena, io, cwd, self_exe_path) catch |err| { - fatal("unable to find zig installation directory from executable path {q}: {t}", .{ self_exe_path, err }); + if (options.override_zig_lib) |path| break :d openUnresolved(arena, io, cwd, path, .@"zig lib"); + if (wasi) break :d getPreopen(options.preopens, "/lib"); + break :d findZigLibDirFromSelfExe(arena, io, cwd, options.self_exe_path) catch |err| { + fatal("unable to find zig installation directory from executable path {q}: {t}", .{ + options.self_exe_path, err, + }); }; }; + const build_root: Cache.Directory = if (options.build_root) |s| + openUnresolved(arena, io, cwd, s, .@"build root") + else + .cwd(); const global_cache: Cache.Directory = d: { - if (override_global_cache) |path| break :d openUnresolved(arena, io, cwd, path, .@"global cache"); - if (wasi) break :d getPreopen(preopens, "/cache"); - const path = resolveGlobalCacheDir(arena, environ_map) catch |err| { + if (options.override_global_cache) |path| break :d openUnresolved(arena, io, cwd, path, .@"global cache"); + if (wasi) break :d getPreopen(options.preopens, "/cache"); + const path = resolveGlobalCacheDir(arena, options.environ_map) catch |err| { fatal("unable to resolve zig cache directory: {t}", .{err}); }; break :d openUnresolved(arena, io, cwd, path, .@"global cache"); }; - const local_cache = getLocalCacheDirectory(arena, io, cwd, global_cache, local_cache_strat); + const local_cache = getLocalCacheDirectory(arena, io, cwd, global_cache, options.local_cache_strat); if (mem.eql(u8, zig_lib.path orelse "", global_cache.path orelse "")) { 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 { .zig_lib = zig_lib, .global_cache = global_cache, .local_cache = local_cache, + .build_root = build_root, }; } @@ -1395,14 +1411,14 @@ pub const Directories = struct { io: Io, cwd: []const u8, unresolved_path: []const u8, - thing: enum { @"zig lib", @"global cache", @"local cache" }, + thing: enum { @"zig lib", @"global cache", @"local cache", @"build root" }, ) Cache.Directory { const path = resolvePath(arena, cwd, &.{unresolved_path}) catch |err| { fatal("unable to resolve {t} directory: {t}", .{ thing, err }); }; const nonempty_path = if (path.len == 0) "." else path; const handle_or_err = switch (thing) { - .@"zig lib" => Dir.cwd().openDir(io, nonempty_path, .{}), + .@"zig lib", .@"build root" => Dir.cwd().openDir(io, nonempty_path, .{}), .@"global cache", .@"local cache" => Dir.cwd().createDirPathOpen(io, nonempty_path, .{}), }; return .{ diff --git a/lib/std/zig/Server.zig b/lib/std/zig/Server.zig index 1f6d208084abdcc9d93ef33929e36aa0239549af..eac3555acf7074a174f333401e0f79c70c23ab7e 100644 --- a/lib/std/zig/Server.zig +++ b/lib/std/zig/Server.zig @@ -135,6 +135,7 @@ pub const Message = struct { zig_lib, local_cache, global_cache, + build_root, }; /// Trailing: diff --git a/src/Compilation.zig b/src/Compilation.zig index 3e8b2043a4d496800eacea61211e2a99eab37e11..fcb65eb66d89daedb4a2cd9e168a1461ad1486af 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -397,6 +397,7 @@ pub const Path = struct { global_cache, /// `sub_path` is relative to the local cache directory on `Compilation`. local_cache, + build_root, /// `sub_path` is not relative to any of the roots listed above. /// It is resolved starting with `Directories.cwd`; so it is an absolute path on most /// targets, but cwd-relative on WASI. We do not make it cwd-relative on other targets @@ -434,11 +435,12 @@ pub const Path = struct { const dir = switch (p.root) { .none => { const cwd_sub_path = absToCwdRelative(p.sub_path, dirs.cwd); - return .{ Io.Dir.cwd(), cwd_sub_path }; + return .{ Io.Dir.cwd(), if (cwd_sub_path.len == 0) "." else cwd_sub_path }; }, .zig_lib => dirs.zig_lib.handle, .global_cache => dirs.global_cache.handle, .local_cache => dirs.local_cache.handle, + .build_root => dirs.build_root.handle, }; if (p.sub_path.len == 0) return .{ dir, "." }; assert(!fs.path.isAbsolute(p.sub_path)); @@ -454,19 +456,18 @@ pub const Path = struct { comp: *Compilation, pub fn format(f: Formatter, w: *Writer) Writer.Error!void { const root_path: []const u8 = switch (f.p.root) { - .zig_lib => f.comp.dirs.zig_lib.path orelse ".", - .global_cache => f.comp.dirs.global_cache.path orelse ".", - .local_cache => f.comp.dirs.local_cache.path orelse ".", + .zig_lib => f.comp.dirs.zig_lib.path orelse "", + .global_cache => f.comp.dirs.global_cache.path orelse "", + .local_cache => f.comp.dirs.local_cache.path orelse "", + .build_root => f.comp.dirs.build_root.path orelse "", .none => { - const cwd_sub_path = absToCwdRelative(f.p.sub_path, f.comp.dirs.cwd); - try w.writeAll(cwd_sub_path); + try w.writeAll(absToCwdRelative(f.p.sub_path, f.comp.dirs.cwd)); return; }, }; - assert(root_path.len != 0); try w.writeAll(root_path); if (f.p.sub_path.len > 0) { - try w.writeByte(fs.path.sep); + if (root_path.len != 0) try w.writeByte(fs.path.sep); try w.writeAll(f.p.sub_path); } } @@ -474,16 +475,16 @@ pub const Path = struct { /// Given the `sub_path` of a `Path` with `Path.root == .none`, attempts to convert /// the (absolute) path to a cwd-relative path. Otherwise, returns the absolute path - /// unmodified. The returned string is never empty: "" is converted to ".". + /// unmodified. The returned string is never "."; empty string will be returned instead. fn absToCwdRelative(sub_path: []const u8, cwd_path: []const u8) []const u8 { if (builtin.target.os.tag == .wasi) { - if (sub_path.len == 0) return "."; + if (sub_path.len == 0) return ""; assert(!fs.path.isAbsolute(sub_path)); return sub_path; } assert(fs.path.isAbsolute(sub_path)); if (!std.mem.startsWith(u8, sub_path, cwd_path)) return sub_path; - if (sub_path.len == cwd_path.len) return "."; // the strings are equal + if (sub_path.len == cwd_path.len) return ""; // the strings are equal const path_sep_index = path_sep_index: { // cwd is just a root, e.g. / or C:\ 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 { // so that we prefer `.root = .local_cache` over `.root = .zig_lib`. The easiest way to do // this is simply to prioritize the longest root path. const PathAndRoot = struct { ?[]const u8, Root }; - var roots: [3]PathAndRoot = .{ + var roots: [4]PathAndRoot = .{ .{ dirs.zig_lib.path, .zig_lib }, .{ dirs.global_cache.path, .global_cache }, .{ dirs.local_cache.path, .local_cache }, + .{ dirs.build_root.path, .build_root }, }; // This must be a stable sort, because the global and local cache directories may be the same, in // which case we need to make a consistent choice. @@ -581,6 +583,7 @@ pub const Path = struct { .zig_lib => dirs.zig_lib.path orelse "", .global_cache => dirs.global_cache.path orelse "", .local_cache => dirs.local_cache.path orelse "", + .build_root => dirs.build_root.path orelse "", .none => "", }, sub_path, @@ -603,6 +606,7 @@ pub const Path = struct { .zig_lib => dirs.zig_lib.path orelse "", .global_cache => dirs.global_cache.path orelse "", .local_cache => dirs.local_cache.path orelse "", + .build_root => dirs.build_root.path orelse "", .none => "", }, p.sub_path, @@ -622,6 +626,7 @@ pub const Path = struct { .zig_lib => dirs.zig_lib.path orelse "", .global_cache => dirs.global_cache.path orelse "", .local_cache => dirs.local_cache.path orelse "", + .build_root => dirs.build_root.path orelse "", .none => "", }, p.sub_path, @@ -635,11 +640,12 @@ pub const Path = struct { .zig_lib => dirs.zig_lib, .global_cache => dirs.global_cache, .local_cache => dirs.local_cache, + .build_root => dirs.build_root, else => { const cwd_sub_path = absToCwdRelative(p.sub_path, dirs.cwd); return .{ .root_dir = .cwd(), - .sub_path = cwd_sub_path, + .sub_path = if (cwd_sub_path.len == 0) null else cwd_sub_path, }; }, }; @@ -653,18 +659,15 @@ pub const Path = struct { /// This should not be used for most of the compiler pipeline, but is useful when emitting /// paths from the compilation (e.g. in debug info), because they will not depend on the cwd. /// The returned path is owned by the caller and allocated into `gpa`. - pub fn toAbsolute(p: Path, dirs: std.zig.Directories, gpa: Allocator) Allocator.Error![]u8 { + pub fn toAbsolute(p: Path, dirs: *const std.zig.Directories, gpa: Allocator) Allocator.Error![]u8 { const root_path: []const u8 = switch (p.root) { .zig_lib => dirs.zig_lib.path orelse "", .global_cache => dirs.global_cache.path orelse "", .local_cache => dirs.local_cache.path orelse "", + .build_root => dirs.build_root.path orelse "", .none => "", }; - return fs.path.resolve(gpa, &.{ - dirs.cwd, - root_path, - p.sub_path, - }); + return fs.path.resolve(gpa, &.{ dirs.cwd, root_path, p.sub_path }); } pub fn isNested(inner: Path, outer: Path) union(enum) { @@ -697,6 +700,66 @@ pub const Path = struct { .no, .different_roots => false, }; } + + pub fn addToCacheManifestPostHit(p: Path, man: *Cache.Manifest, dirs: *const std.zig.Directories) !void { + comptime assert(0 == @backingInt(std.zig.Server.Message.PathPrefix.cwd)); + comptime assert(1 == @backingInt(std.zig.Server.Message.PathPrefix.zig_lib)); + comptime assert(2 == @backingInt(std.zig.Server.Message.PathPrefix.local_cache)); + comptime assert(3 == @backingInt(std.zig.Server.Message.PathPrefix.global_cache)); + comptime assert(4 == @backingInt(std.zig.Server.Message.PathPrefix.build_root)); + comptime assert(@typeInfo(std.zig.Server.Message.PathPrefix).@"enum".field_names.len == 5); + const gpa = man.cache.gpa; + const prefixed_path: Cache.PrefixedPath = .{ + .prefix = switch (p.root) { + .none => { + const path = try p.toAbsolute(dirs, gpa); + defer gpa.free(path); + return man.addFilePost(path); + }, + .zig_lib => 1, + .local_cache => 2, + .global_cache => 3, + .build_root => 4, + }, + .sub_path = try gpa.dupe(u8, p.sub_path), + }; + var keep = false; + defer if (!keep) gpa.free(prefixed_path.sub_path); + keep = try man.addPrefixedPathPost(prefixed_path); + } + + pub fn addToCacheManifestPostHitContents( + p: Path, + man: *Cache.Manifest, + dirs: *const std.zig.Directories, + bytes: []const u8, + stat: Cache.File.Stat, + ) !void { + comptime assert(0 == @backingInt(std.zig.Server.Message.PathPrefix.cwd)); + comptime assert(1 == @backingInt(std.zig.Server.Message.PathPrefix.zig_lib)); + comptime assert(2 == @backingInt(std.zig.Server.Message.PathPrefix.local_cache)); + comptime assert(3 == @backingInt(std.zig.Server.Message.PathPrefix.global_cache)); + comptime assert(4 == @backingInt(std.zig.Server.Message.PathPrefix.build_root)); + comptime assert(@typeInfo(std.zig.Server.Message.PathPrefix).@"enum".field_names.len == 5); + const gpa = man.cache.gpa; + const prefixed_path: Cache.PrefixedPath = .{ + .prefix = switch (p.root) { + .none => { + const path = try p.toAbsolute(dirs, gpa); + defer gpa.free(path); + return man.addFilePostContents(path, bytes, stat); + }, + .zig_lib => 1, + .local_cache => 2, + .global_cache => 3, + .build_root => 4, + }, + .sub_path = try gpa.dupe(u8, p.sub_path), + }; + var keep = false; + defer if (!keep) gpa.free(prefixed_path.sub_path); + keep = try man.addPrefixedPathPostContents(prefixed_path, bytes, stat); + } }; /// This small wrapper function just checks whether debug extensions are enabled before checking @@ -1278,7 +1341,7 @@ pub const cache_helpers = struct { } pub fn hashCSource(self: *Cache.Manifest, c_source: CSourceFile) !void { - _ = try self.addFile(c_source.src_path, null); + _ = try self.addFilePath(.initCwd(c_source.src_path), null); // Hash the extra flags, with special care to call addFile for file parameters. // TODO this logic can likely be improved by utilizing clang_options_data.zig. const file_args = [_][]const u8{"-include"}; @@ -1289,7 +1352,7 @@ pub const cache_helpers = struct { for (file_args) |file_arg| { if (mem.eql(u8, file_arg, arg) and arg_i + 1 < c_source.extra_flags.len) { arg_i += 1; - _ = try self.addFile(c_source.extra_flags[arg_i], null); + _ = try self.addFilePath(.initCwd(c_source.extra_flags[arg_i]), null); } } } @@ -1348,7 +1411,7 @@ pub const CacheMode = enum { pub const ParentWholeCache = struct { manifest: *Cache.Manifest, mutex: *std.Io.Mutex, - prefix_map: [4]u8, + prefix_map: [5]u8, }; const CacheUse = union(CacheMode) { @@ -1466,8 +1529,8 @@ pub const CreateOptions = struct { stack_report: bool = false, link_eh_frame_hdr: bool = false, link_emit_relocs: bool = false, - linker_script: ?[]const u8 = null, - version_script: ?[]const u8 = null, + linker_script: ?Cache.Path = null, + version_script: ?Cache.Path = null, linker_allow_undefined_version: bool = false, linker_enable_new_dtags: ?bool = null, soname: ?[]const u8 = null, @@ -1546,7 +1609,7 @@ pub const CreateOptions = struct { /// (Darwin) Install name of the dylib install_name: ?[]const u8 = null, /// (Darwin) Path to entitlements file - entitlements: ?[]const u8 = null, + entitlements: ?Cache.Path = null, /// (Darwin) size of the __PAGEZERO segment pagezero_size: ?u64 = null, /// (Darwin) set minimum space for future expansion of the load commands @@ -1613,15 +1676,7 @@ pub const CreateOptions = struct { }; }; -fn addModuleTableToCacheHash( - zcu: *Zcu, - arena: Allocator, - hash: *Cache.HashHelper, - hash_type: union(enum) { path_bytes, files: *Cache.Manifest }, -) error{ - OutOfMemory, - Unexpected, -}!void { +fn addModuleTableToCacheHash(zcu: *Zcu, hash: *Cache.HashHelper) error{ OutOfMemory, Unexpected }!void { assert(zcu.module_roots.count() != 0); // module_roots is populated for (zcu.module_roots.keys(), zcu.module_roots.values()) |mod, opt_mod_root_file| { @@ -1630,17 +1685,9 @@ fn addModuleTableToCacheHash( if (zcu.fileByIndex(mod_root_file).is_builtin) continue; // redundant } cache_helpers.addModule(hash, mod); - switch (hash_type) { - .path_bytes => { - hash.add(mod.root.root); - hash.addBytes(mod.root.sub_path); - hash.addBytes(mod.root_src_path); - }, - .files => |man| if (mod.root_src_path.len != 0) { - const root_src_path = try mod.root.toCachePath(zcu.comp.dirs).join(arena, mod.root_src_path); - _ = try man.addFilePath(root_src_path, null); - }, - } + hash.add(mod.root.root); + hash.addBytes(mod.root.sub_path); + hash.addBytes(mod.root_src_path); hash.addListOfBytes(mod.deps.keys()); } } @@ -1926,6 +1973,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, } const error_limit = options.error_limit orelse (std.math.maxInt(u16) - 1); + const main_mod = options.main_mod orelse options.root_mod; // We put everything into the cache hash that *cannot be modified // 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, }, .cwd = options.dirs.cwd, }; - // These correspond to std.zig.Server.Message.PathPrefix. + comptime assert(0 == @backingInt(std.zig.Server.Message.PathPrefix.cwd)); + comptime assert(1 == @backingInt(std.zig.Server.Message.PathPrefix.zig_lib)); + comptime assert(2 == @backingInt(std.zig.Server.Message.PathPrefix.local_cache)); + comptime assert(3 == @backingInt(std.zig.Server.Message.PathPrefix.global_cache)); + comptime assert(4 == @backingInt(std.zig.Server.Message.PathPrefix.build_root)); + comptime assert(@typeInfo(std.zig.Server.Message.PathPrefix).@"enum".field_names.len == 5); cache.addPrefix(.{ .path = null, .handle = Io.Dir.cwd() }); cache.addPrefix(options.dirs.zig_lib); cache.addPrefix(options.dirs.local_cache); cache.addPrefix(options.dirs.global_cache); + cache.addPrefix(options.dirs.build_root); errdefer cache.manifest_dir.close(io); // 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, cache.hash.add(options.emit_docs != .no); // TODO audit this and make sure everything is in it - const main_mod = options.main_mod orelse options.root_mod; const comp = try arena.create(Compilation); const opt_zcu: ?*Zcu = if (have_zcu) blk: { // 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, // likely different compilations and therefore this would be likely to // cause cache hits. if (comp.zcu) |zcu| { - try addModuleTableToCacheHash(zcu, arena, &hash, .path_bytes); + try addModuleTableToCacheHash(zcu, &hash); } else { cache_helpers.addModule(&hash, options.root_mod); } @@ -2741,7 +2794,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE // If using the whole caching strategy, we check for *everything* up front, including // C source files. - log.debug("Compilation.update for {s}, CacheMode.{s}", .{ comp.root_name, @tagName(comp.cache_use) }); + log.debug("Compilation.update for {s}, CacheMode.{t}", .{ comp.root_name, comp.cache_use }); switch (comp.cache_use) { .none => |none| { assert(none.tmp_artifact_directory == null); @@ -2750,7 +2803,9 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(tmp_dir_rand_int); const path = try comp.dirs.local_cache.join(arena, &.{tmp_dir_sub_path}); const handle = comp.dirs.local_cache.handle.createDirPathOpen(io, tmp_dir_sub_path, .{}) catch |err| { - return comp.setMiscFailure(.open_output, "failed to create output directory '{s}': {t}", .{ path, err }); + return comp.setMiscFailure(.open_output, "failed to create output directory {q}: {t}", .{ + path, err, + }); }; break :d .{ .path = path, .handle = handle }; }; @@ -2763,7 +2818,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE man = comp.cache_parent.obtain(); whole.cache_manifest = &man; - try addNonIncrementalStuffToCacheManifest(comp, arena, &man); + try addNonIncrementalStuffToCacheManifest(comp, &man); // Under `--time-report`, ignore cache hits; do the work anyway for those juicy numbers. const ignore_hit = comp.time_report != null; @@ -3114,6 +3169,7 @@ pub fn appendFileSystemInput(comp: *Compilation, path: Compilation.Path) Allocat .zig_lib => comp.dirs.zig_lib, .global_cache => comp.dirs.global_cache, .local_cache => comp.dirs.local_cache, + .build_root => comp.dirs.build_root, .none => .cwd(), }; const prefix: u8 = for (prefixes, 1..) |prefix_dir, i| { @@ -3121,8 +3177,8 @@ pub fn appendFileSystemInput(comp: *Compilation, path: Compilation.Path) Allocat break @intCast(i); } } else std.debug.panic( - "missing prefix directory '{s}' ('{f}') for '{s}'", - .{ @tagName(path.root), want_prefix_dir, path.sub_path }, + "missing prefix directory {t} ('{f}') for {q}", + .{ path.root, want_prefix_dir, path.sub_path }, ); // There may be concurrent calls to this function from C object workers and/or the main thread. @@ -3314,15 +3370,15 @@ fn renameTmpIntoCache( /// anything from the link cache manifest. pub const link_hash_implementation_version = 14; -fn addNonIncrementalStuffToCacheManifest( - comp: *Compilation, - arena: Allocator, - man: *Cache.Manifest, -) !void { +fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifest) !void { comptime assert(link_hash_implementation_version == 14); if (comp.zcu) |zcu| { - try addModuleTableToCacheHash(zcu, arena, &man.hash, .{ .files = man }); + // No need to hash the actual file contents here because it is + // redundant with the logic in `PerThread.update` which iterates over + // `zcu.alive_files` and adds those files discovered via `@import` to + // the whole cache manifest. + try addModuleTableToCacheHash(zcu, &man.hash); // Synchronize with other matching comments: ZigOnlyHashStuff man.hash.addListOfBytes(comp.test_filters); @@ -3336,7 +3392,7 @@ fn addNonIncrementalStuffToCacheManifest( try link.hashInputs(man, comp.link_inputs); for (comp.c_objects.items) |c_object| { - _ = try man.addFile(c_object.src.src_path, null); + _ = try man.addFilePath(.initCwd(c_object.src.src_path), null); man.hash.addOptional(c_object.src.ext); man.hash.addListOfBytes(c_object.src.extra_flags); } @@ -3344,11 +3400,11 @@ fn addNonIncrementalStuffToCacheManifest( for (comp.win32_resources.items) |win32_resource| { switch (win32_resource.src) { .rc => |rc_src| { - _ = try man.addFile(rc_src.src_path, null); + _ = try man.addFilePath(.initCwd(rc_src.src_path), null); man.hash.addListOfBytes(rc_src.extra_flags); }, .manifest => |manifest_path| { - _ = try man.addFile(manifest_path, null); + _ = try man.addFilePath(.initCwd(manifest_path), null); }, } } @@ -3380,8 +3436,8 @@ fn addNonIncrementalStuffToCacheManifest( const opts = comp.cache_use.whole.lf_open_opts; - try man.addOptionalFile(opts.linker_script); - try man.addOptionalFile(opts.version_script); + try man.addOptionalFilePath(opts.linker_script); + try man.addOptionalFilePath(opts.version_script); man.hash.add(opts.allow_undefined_version); man.hash.addOptional(opts.enable_new_dtags); @@ -3440,7 +3496,7 @@ fn addNonIncrementalStuffToCacheManifest( // Mach-O specific stuff try link.File.MachO.hashAddFrameworks(man, opts.frameworks); - try man.addOptionalFile(opts.entitlements); + try man.addOptionalFilePath(opts.entitlements); man.hash.addOptional(opts.pagezero_size); man.hash.addOptional(opts.headerpad_size); man.hash.add(opts.headerpad_max_install_names); @@ -5278,6 +5334,7 @@ fn buildMingwCrtFile(comp: *Compilation, crt_file: mingw.CrtFile, prog_node: std fn buildMingwImportLib(comp: *Compilation, lib_name: []const u8, is_prelink: bool, prog_node: std.Progress.Node) void { const crt_file_path = mingw.buildImportLib(comp, lib_name, prog_node) catch |err| switch (err) { + error.AlreadyReported => return, // TODO: This isn't actually true for self-hosted // In the non-prelink case we will end up putting foo.lib onto the linker line and letting the linker // 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 // TODO Surface more error details. else => |e| return comp.lockAndSetMiscFailure( .windows_import_lib, - "unable to generate mingw DLL import .lib file for {s}: {t}", + "generating mingw DLL import .lib file for {s} failed: {t}", .{ lib_name, e }, ), }; @@ -5818,7 +5875,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32 // the XML data as a RT_MANIFEST resource. This means we can skip preprocessing, // include paths, CLI options, etc. if (win32_resource.src == .manifest) { - _ = try man.addFile(src_path, null); + _ = try man.addFilePath(.initCwd(src_path), null); const rc_basename = try std.fmt.allocPrint(arena, "{s}.rc", .{src_basename}); const res_basename = try std.fmt.allocPrint(arena, "{s}.res", .{src_basename}); @@ -5911,7 +5968,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32 // We now know that we're compiling an .rc file const rc_src = win32_resource.src.rc; - _ = try man.addFile(rc_src.src_path, null); + _ = try man.addFilePath(.initCwd(rc_src.src_path), null); man.hash.addListOfBytes(rc_src.extra_flags); const rc_basename_noext = src_basename[0 .. src_basename.len - fs.path.extension(src_basename).len]; @@ -7321,6 +7378,7 @@ fn buildOutputFromZig( 1, // zig lib dir is the same 3, // local cache is mapped to global cache 3, // global cache is the same + 0, // build root is not provided }, }, .incremental, .none => null, diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig index 56de07bed5a44a25590f77de9ed10b2ae420d8b0..0e4962985a566aa611a326ea1aeb2b61e9928ae4 100644 --- a/src/Zcu/PerThread.zig +++ b/src/Zcu/PerThread.zig @@ -221,22 +221,19 @@ pub fn update( .astgen_failure, .success => {}, // the file was read successfully } - const path = try file.path.toAbsolute(comp.dirs, gpa); - defer gpa.free(path); - const result = res: { try whole.cache_manifest_mutex.lock(io); defer whole.cache_manifest_mutex.unlock(io); if (file.source) |source| { - break :res man.addFilePostContents(path, source, file.stat); + break :res file.path.addToCacheManifestPostHitContents(man, &comp.dirs, source, file.stat); } else { - break :res man.addFilePost(path); + break :res file.path.addToCacheManifestPostHit(man, &comp.dirs); } }; result catch |err| switch (err) { error.OutOfMemory => |e| return e, else => { - try pt.reportRetryableFileError(file_index, "unable to update cache: {s}", .{@errorName(err)}); + try pt.reportRetryableFileError(file_index, "unable to update cache: {t}", .{err}); continue; }, }; @@ -481,7 +478,7 @@ pub fn updateFile( const stat = try source_file.stat(io); const want_local_cache = switch (file.path.root) { - .none, .local_cache => true, + .none, .local_cache, .build_root => true, .global_cache, .zig_lib => false, }; @@ -2965,13 +2962,10 @@ fn newEmbedFile( const array_len = Value.fromInterned(new_file.val).typeOf(zcu).childType(zcu).arrayLen(zcu); const contents = ip_str.toSlice(array_len, ip); - const path_str = try path.toAbsolute(comp.dirs, gpa); - defer gpa.free(path_str); - try whole.cache_manifest_mutex.lock(io); defer whole.cache_manifest_mutex.unlock(io); - try man.addFilePostContents(path_str, contents, new_file.stat); + try path.addToCacheManifestPostHitContents(man, &comp.dirs, contents, new_file.stat); } return new_file; diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 8bb33f83e0d0911b2f427ede147964df5c73cf9a..4022a2b901c77443b977a4461e044de40a8230c9 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -481,7 +481,7 @@ pub const Object = struct { // way already, but here we throw all that sweet information // into the garbage can by converting into absolute paths. What // a terrible tragedy. - const compile_unit_dir = try zcu.main_mod.root.toAbsolute(comp.dirs, arena); + const compile_unit_dir = try zcu.main_mod.root.toAbsolute(&comp.dirs, arena); const debug_file = try builder.debugFile( try builder.metadataString(comp.root_name), @@ -1701,6 +1701,7 @@ pub const Object = struct { .zig_lib => dirs.zig_lib.path, .global_cache => dirs.global_cache.path, .local_cache => dirs.local_cache.path, + .build_root => dirs.build_root.path, .none => null, }; diff --git a/src/libs/freebsd.zig b/src/libs/freebsd.zig index 0895ef4280ed25592fbcfda9fa54960675d28271..6fb4b804525700fa7f4ce9a4f3c21363ae295fa9 100644 --- a/src/libs/freebsd.zig +++ b/src/libs/freebsd.zig @@ -458,8 +458,10 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye man.hash.add(target.abi); man.hash.add(target_os_version); - const full_abilists_path = try comp.dirs.zig_lib.join(arena, &.{abilists_path}); - const abilists_index = try man.addFile(full_abilists_path, abilists_max_size); + const abilists_index = try man.addFilePath(.{ + .root_dir = comp.dirs.zig_lib, + .sub_path = abilists_path, + }, abilists_max_size); if (try man.hit(prog_node)) { const digest = man.final(); @@ -1044,7 +1046,6 @@ fn buildSharedLib( const version: Version = .{ .major = sover, .minor = 0, .patch = 0 }; const ld_basename = path.basename(target.standardDynamicLinkerPath().get().?); const soname = if (mem.eql(u8, lib.name, "ld")) ld_basename else basename; - const map_file_path = try path.join(arena, &.{ bin_directory.path.?, all_map_basename }); const optimize_mode = comp.compilerRtOptMode(); const strip = comp.compilerRtStrip(); @@ -1113,7 +1114,10 @@ fn buildSharedLib( .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .clang_passthrough_mode = comp.clang_passthrough_mode, .version = version, - .version_script = map_file_path, + .version_script = .{ + .root_dir = bin_directory, + .sub_path = all_map_basename, + }, .soname = soname, .c_source_files = &c_source_files, .skip_linker_dependencies = true, diff --git a/src/libs/glibc.zig b/src/libs/glibc.zig index fce076dba86d74c52756d72419ed8859633992b5..7c20c33a0335fcab4b01e7da5c37c4d673e899b2 100644 --- a/src/libs/glibc.zig +++ b/src/libs/glibc.zig @@ -698,8 +698,10 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye man.hash.add(target.abi); man.hash.add(target_version); - const full_abilists_path = try comp.dirs.zig_lib.join(arena, &.{abilists_path}); - const abilists_index = try man.addFile(full_abilists_path, abilists_max_size); + const abilists_index = try man.addFilePath(.{ + .root_dir = comp.dirs.zig_lib, + .sub_path = abilists_path, + }, abilists_max_size); if (try man.hit(prog_node)) { const digest = man.final(); @@ -1188,7 +1190,6 @@ fn buildSharedLib( const version: Version = .{ .major = lib.sover, .minor = 0, .patch = 0 }; const ld_basename = path.basename(comp.getTarget().standardDynamicLinkerPath().get().?); const soname = if (mem.eql(u8, lib.name, "ld")) ld_basename else basename; - const map_file_path = try path.join(arena, &.{ bin_directory.path.?, all_map_basename }); const optimize_mode = comp.compilerRtOptMode(); const strip = comp.compilerRtStrip(); @@ -1257,7 +1258,10 @@ fn buildSharedLib( .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .clang_passthrough_mode = comp.clang_passthrough_mode, .version = version, - .version_script = map_file_path, + .version_script = .{ + .root_dir = bin_directory, + .sub_path = all_map_basename, + }, .soname = soname, .c_source_files = &c_source_files, .skip_linker_dependencies = true, diff --git a/src/libs/mingw.zig b/src/libs/mingw.zig index 224b5ec27b4c0e8dac994ec4a54f85a689a11449..a91c24291d0a395b189712c4d8f199bf13cd57d0 100644 --- a/src/libs/mingw.zig +++ b/src/libs/mingw.zig @@ -215,12 +215,15 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8, prog_node: std.P defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); - const def_file_path = findDef(arena, io, comp.getTarget(), comp.dirs.zig_lib, lib_name) catch |err| switch (err) { - error.FileNotFound => return error.DefNotFound, - else => |e| return e, + const def_file_path: Cache.Path = .{ + .root_dir = comp.dirs.zig_lib, + .sub_path = findDef(arena, io, comp.getTarget(), comp.dirs.zig_lib, lib_name) catch |err| switch (err) { + error.FileNotFound => return error.DefNotFound, + else => |e| return e, + }, }; // Only .def.in files need preprocessing - const def_needs_preprocessing = mem.endsWith(u8, def_file_path, ".def.in"); + const def_needs_preprocessing = mem.endsWith(u8, def_file_path.sub_path, ".def.in"); const target = comp.getTarget(); @@ -243,12 +246,34 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8, prog_node: std.P var man = cache.obtain(); defer man.deinit(); - _ = try man.addFile(def_file_path, null); + _ = try man.addFilePath(def_file_path, null); const final_lib_basename = try std.fmt.allocPrint(gpa, "{s}.lib", .{lib_name}); errdefer gpa.free(final_lib_basename); - if (try man.hit(prog_node)) { + const is_hit = man.hit(prog_node) catch |err| switch (err) { + error.CacheCheckFailed => switch (man.diagnostic) { + .none => unreachable, + .manifest_create, .manifest_read, .manifest_lock => |e| { + comp.setMiscFailure(.windows_import_lib, "checking cache failed: {t} {t}", .{ man.diagnostic, e }); + return error.AlreadyReported; + }, + .file_open, .file_stat, .file_read, .file_hash => |op| { + const pp = man.files.keys()[op.file_index].prefixed_path; + const prefix = man.cache.prefixes()[pp.prefix]; + comp.setMiscFailure(.windows_import_lib, "checking cache failed: {f}{s} {t} {t}", .{ + prefix, pp.sub_path, man.diagnostic, op.err, + }); + return error.AlreadyReported; + }, + }, + error.OutOfMemory, error.Canceled => |e| return e, + error.InvalidFormat => { + comp.setMiscFailure(.windows_import_lib, "checking cache failed: invalid manifest file format", .{}); + return error.AlreadyReported; + }, + }; + if (is_hit) { const digest = man.final(); const sub_path = try std.fs.path.join(gpa, &.{ "o", &digest, final_lib_basename }); errdefer gpa.free(sub_path); @@ -273,20 +298,11 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8, prog_node: std.P var o_dir = try comp.dirs.global_cache.handle.createDirPathOpen(io, o_sub_path, .{}); defer o_dir.close(io); - const include_dir = try comp.dirs.zig_lib.join(arena, &.{ "libc", "mingw", "def-include" }); - - if (comp.verbose_cc) { - var buffer: [256]u8 = undefined; - const stderr = try io.lockStderr(&buffer, null); - defer io.unlockStderr(); - const w = &stderr.file_writer.interface; - w.print("def file: {s}\n", .{def_file_path}) catch |err| switch (err) { - error.WriteFailed => return stderr.file_writer.err.?, - }; - w.print("include dir: {s}\n", .{include_dir}) catch |err| switch (err) { - error.WriteFailed => return stderr.file_writer.err.?, - }; - } + const sep = path.sep_str; + const include_dir: Cache.Path = .{ + .root_dir = comp.dirs.zig_lib, + .sub_path = "libc" ++ sep ++ "mingw" ++ sep ++ "def-include", + }; const members = members: { 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 break :pp try aw.toOwnedSliceSentinel(0); }, - false => try Io.Dir.cwd().readFileAllocOptions(io, def_file_path, gpa, .unlimited, .of(u8), 0), + false => try def_file_path.root_dir.handle.readFileAllocOptions(io, def_file_path.sub_path, gpa, .unlimited, .of(u8), 0), }; defer gpa.free(input); @@ -384,7 +400,7 @@ pub fn libExists( /// This function body is verbose but all it does is test 3 different paths and /// see if a .def file exists. fn findDef( - allocator: Allocator, + gpa: Allocator, io: Io, target: *const std.Target, zig_lib_directory: Cache.Directory, @@ -398,21 +414,17 @@ fn findDef( else => unreachable, }; - var override_path = std.array_list.Managed(u8).init(allocator); - defer override_path.deinit(); + var override_path: std.ArrayList(u8) = .empty; + defer override_path.deinit(gpa); const s = path.sep_str; { // Try the archtecture-specific path first. - const fmt_path = "libc" ++ s ++ "mingw" ++ s ++ "{s}" ++ s ++ "{s}.def"; - if (zig_lib_directory.path) |p| { - try override_path.print("{s}" ++ s ++ fmt_path, .{ p, lib_path, lib_name }); - } else { - try override_path.print(fmt_path, .{ lib_path, lib_name }); - } - if (Io.Dir.cwd().access(io, override_path.items, .{})) |_| { - return override_path.toOwnedSlice(); + override_path.shrinkRetainingCapacity(0); + try override_path.print(gpa, "libc" ++ s ++ "mingw" ++ s ++ "{s}" ++ s ++ "{s}.def", .{ lib_path, lib_name }); + if (zig_lib_directory.handle.access(io, override_path.items, .{})) |_| { + return override_path.toOwnedSlice(gpa); } else |err| switch (err) { error.FileNotFound => {}, else => |e| return e, @@ -422,14 +434,9 @@ fn findDef( { // Try the generic version. override_path.shrinkRetainingCapacity(0); - const fmt_path = "libc" ++ s ++ "mingw" ++ s ++ "lib-common" ++ s ++ "{s}.def"; - if (zig_lib_directory.path) |p| { - try override_path.print("{s}" ++ s ++ fmt_path, .{ p, lib_name }); - } else { - try override_path.print(fmt_path, .{lib_name}); - } - if (Io.Dir.cwd().access(io, override_path.items, .{})) |_| { - return override_path.toOwnedSlice(); + try override_path.print(gpa, "libc" ++ s ++ "mingw" ++ s ++ "lib-common" ++ s ++ "{s}.def", .{lib_name}); + if (zig_lib_directory.handle.access(io, override_path.items, .{})) |_| { + return override_path.toOwnedSlice(gpa); } else |err| switch (err) { error.FileNotFound => {}, else => |e| return e, @@ -439,14 +446,9 @@ fn findDef( { // Try the generic version and preprocess it. override_path.shrinkRetainingCapacity(0); - const fmt_path = "libc" ++ s ++ "mingw" ++ s ++ "lib-common" ++ s ++ "{s}.def.in"; - if (zig_lib_directory.path) |p| { - try override_path.print("{s}" ++ s ++ fmt_path, .{ p, lib_name }); - } else { - try override_path.print(fmt_path, .{lib_name}); - } - if (Io.Dir.cwd().access(io, override_path.items, .{})) |_| { - return override_path.toOwnedSlice(); + try override_path.print(gpa, "libc" ++ s ++ "mingw" ++ s ++ "lib-common" ++ s ++ "{s}.def.in", .{lib_name}); + if (zig_lib_directory.handle.access(io, override_path.items, .{})) |_| { + return override_path.toOwnedSlice(gpa); } else |err| switch (err) { error.FileNotFound => {}, else => |e| return e, diff --git a/src/libs/mingw/Preprocessor.zig b/src/libs/mingw/Preprocessor.zig index f6606eb54cd0f2ea46a85194dd79674115256499..f10cb33d39853efb6455e74937a75a7c34296cca 100644 --- a/src/libs/mingw/Preprocessor.zig +++ b/src/libs/mingw/Preprocessor.zig @@ -4,6 +4,7 @@ const Allocator = std.mem.Allocator; const Token = Tokenizer.Token; const mem = std.mem; const assert = std.debug.assert; +const Path = std.Build.Cache.Path; test { _ = Tokenizer; @@ -25,15 +26,15 @@ pub const Source = struct { pub const generated: Source.Id = std.math.maxInt(usize); pub const Id = usize; id: Id = generated, - path: []const u8, + path: Path, buf: []const u8, }; -sources: std.array_hash_map.String(Source) = .empty, +sources: std.array_hash_map.Custom(Path, Source, Path.TableAdapter, false) = .empty, arena: Allocator, io: std.Io, -include_dir: []const u8, +include_dir: Path, top_expansion_buf: ExpandBuf = .empty, add_expansion_nl: usize = 0, @@ -132,7 +133,7 @@ fn defineBuiltin(pp: *Preprocessor, name: []const u8) !void { }); } -pub fn preprocess(pp: *Preprocessor, file_path: []const u8) !void { +pub fn preprocess(pp: *Preprocessor, file_path: Path) !void { const source = try pp.addSourceFromPath(file_path); try pp.preprocessFile(source); } @@ -789,13 +790,9 @@ fn makeGeneratedToken( return pasted_token; } -fn findInclude( - pp: *Preprocessor, - filename: []const u8, - includer_token: Token, -) !?Source { +fn findInclude(pp: *Preprocessor, filename: []const u8, includer_token: Token) !?Source { const other_file = pp.sources.values()[includer_token.source].path; - const dir = std.fs.path.dirname(other_file) orelse "."; + const dir: Path = other_file.dirname() orelse .cwd(); if (try pp.checkIncludeDir(filename, dir)) |res| return res; return pp.checkIncludeDir(filename, pp.include_dir); @@ -804,31 +801,24 @@ fn findInclude( fn checkIncludeDir( pp: *Preprocessor, include_path: []const u8, - include_dir: []const u8, + include_dir: Path, ) !?Source { - const format = "{s}{c}{s}"; var bfa_buf: [1024]u8 = undefined; var bfa_state: std.heap.BufferFirstAllocator = .init(&bfa_buf, pp.arena); const bfa = bfa_state.allocator(); - const header_path = try std.fmt.allocPrint(bfa, format, .{ - include_dir, - std.fs.path.sep, - include_path, - }); - defer bfa.free(header_path); - + const header_path = try include_dir.join(bfa, include_path); return pp.addSourceFromPath(header_path) catch |err| switch (err) { error.OutOfMemory => |e| return e, else => return null, }; } -pub fn addSourceFromPath(pp: *Preprocessor, path: []const u8) !Source { +pub fn addSourceFromPath(pp: *Preprocessor, path: Path) !Source { if (pp.sources.get(path)) |src| return src; try pp.sources.ensureUnusedCapacity(pp.arena, 1); - const contents = try std.Io.Dir.cwd().readFileAlloc(pp.io, path, pp.arena, .limited(std.math.maxInt(u32))); - const duped_path = try pp.arena.dupe(u8, path); + const contents = try path.root_dir.handle.readFileAlloc(pp.io, path.sub_path, pp.arena, .limited(std.math.maxInt(u32))); + const duped_path = try path.clone(pp.arena); const src: Source = .{ .buf = contents, diff --git a/src/libs/netbsd.zig b/src/libs/netbsd.zig index fb811df536ed7fa55f2ec630534e1c995ef978f7..3d7c94ce4974bb8f9fb926cad43ca99c1919cfc7 100644 --- a/src/libs/netbsd.zig +++ b/src/libs/netbsd.zig @@ -406,8 +406,10 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye man.hash.add(target.abi); man.hash.add(target_version); - const full_abilists_path = try comp.dirs.zig_lib.join(arena, &.{abilists_path}); - const abilists_index = try man.addFile(full_abilists_path, abilists_max_size); + const abilists_index = try man.addFilePath(.{ + .root_dir = comp.dirs.zig_lib, + .sub_path = abilists_path, + }, abilists_max_size); if (try man.hit(prog_node)) { const digest = man.final(); diff --git a/src/libs/openbsd.zig b/src/libs/openbsd.zig index e38183ab75db6a29eae22695f52550f69b35858c..2e0159b677de2ff86d57ac27e130c63f341e898f 100644 --- a/src/libs/openbsd.zig +++ b/src/libs/openbsd.zig @@ -327,8 +327,10 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye man.hash.add(target.abi); man.hash.add(target_version); - const full_abilists_path = try comp.dirs.zig_lib.join(arena, &.{abilists_path}); - const abilists_index = try man.addFile(full_abilists_path, abilists_max_size); + const abilists_index = try man.addFilePath(.{ + .root_dir = comp.dirs.zig_lib, + .sub_path = abilists_path, + }, abilists_max_size); if (try man.hit(prog_node)) { const digest = man.final(); diff --git a/src/link.zig b/src/link.zig index 836621f3fea4a25a1f37d5d313d942f8229fcfad..eeab7e4f56f441070fc8817c7d8969c0558a4ee0 100644 --- a/src/link.zig +++ b/src/link.zig @@ -461,8 +461,8 @@ pub const File = struct { allow_undefined_version: bool, enable_new_dtags: ?bool, subsystem: ?std.zig.Subsystem, - linker_script: ?[]const u8, - version_script: ?[]const u8, + linker_script: ?Path, + version_script: ?Path, soname: ?[]const u8, print_gc_sections: bool, print_icf_sections: bool, @@ -493,7 +493,7 @@ pub const File = struct { /// Install name for the dylib install_name: ?[]const u8, /// Path to entitlements file - entitlements: ?[]const u8, + entitlements: ?Path, /// size of the __PAGEZERO segment pagezero_size: ?u64, /// Set minimum space for future expansion of the load commands diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index c8eef4c8651367edbc1abffcd3cf24d76b847603..a73874ea0259b566444233452028d36ec99479e3 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -4735,7 +4735,7 @@ fn flushWriterError(dwarf: *Dwarf, pt: Zcu.PerThread) (UpdateError || Writer.Err } for (dwarf.mods.keys(), dwarf.mods.values()) |mod, *mod_info| { - const root_dir_path = try mod.root.toAbsolute(zcu.comp.dirs, dwarf.gpa); + const root_dir_path = try mod.root.toAbsolute(&zcu.comp.dirs, dwarf.gpa); defer dwarf.gpa.free(root_dir_path); mod_info.root_dir_path = try dwarf.debug_line_str.addString(dwarf, root_dir_path); } diff --git a/src/link/Lld.zig b/src/link/Lld.zig index b1ac4a2834bf7ba5992d658304e40e0ccf2a9a18..90bf4e3966a0dc6400df2c3d56db63d287f19aa3 100644 --- a/src/link/Lld.zig +++ b/src/link/Lld.zig @@ -75,8 +75,8 @@ pub const Elf = struct { entry_name: ?[]const u8, hash_style: HashStyle, image_base: u64, - linker_script: ?[]const u8, - version_script: ?[]const u8, + linker_script: ?Cache.Path, + version_script: ?Cache.Path, sort_section: ?SortSection, print_icf_sections: bool, print_map: bool, @@ -930,7 +930,7 @@ fn elfLink(lld: *Lld, arena: Allocator) !void { if (elf.linker_script) |linker_script| { try argv.append("-T"); - try argv.append(linker_script); + try argv.append(try linker_script.toString(arena)); } if (elf.sort_section) |how| { @@ -1086,7 +1086,7 @@ fn elfLink(lld: *Lld, arena: Allocator) !void { } if (elf.version_script) |version_script| { try argv.append("-version-script"); - try argv.append(version_script); + try argv.append(try version_script.toString(arena)); } if (elf.allow_undefined_version) { try argv.append("--undefined-version"); diff --git a/src/link/MachO.zig b/src/link/MachO.zig index c03d4eac74b73b293e66bf08258a69fea466b721..0a2c0c9c50c14065f77e166fac72b68ef6820bb0 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -127,7 +127,7 @@ frameworks: []const Framework, /// TODO: unify with soname install_name: ?[]const u8, /// Path to entitlements file. -entitlements: ?[]const u8, +entitlements: ?Path, compatibility_version: ?std.SemanticVersion, /// Entry name entry_name: ?[]const u8, @@ -580,7 +580,7 @@ pub fn flush( var codesig = CodeSignature.init(self.getPageSize()); codesig.code_directory.ident = fs.path.basename(self.base.emit.sub_path); if (self.entitlements) |path| codesig.addEntitlements(gpa, io, path) catch |err| - return diags.fail("failed to add entitlements from {s}: {t}", .{ path, err }); + return diags.fail("failed to add entitlements from {f}: {t}", .{ path, err }); try self.writeCodeSignaturePadding(&codesig); break :blk codesig; } else null; diff --git a/src/link/MachO/CodeSignature.zig b/src/link/MachO/CodeSignature.zig index 88fae25e73f87e944e4dcf0b9cb522bee6db4936..8cad16f12990538304dfc084515afe8174c18aea 100644 --- a/src/link/MachO/CodeSignature.zig +++ b/src/link/MachO/CodeSignature.zig @@ -246,8 +246,8 @@ pub fn deinit(self: *CodeSignature, allocator: Allocator) void { } } -pub fn addEntitlements(self: *CodeSignature, allocator: Allocator, io: Io, path: []const u8) !void { - const inner = try Io.Dir.cwd().readFileAlloc(io, path, allocator, .limited(std.math.maxInt(u32))); +pub fn addEntitlements(self: *CodeSignature, allocator: Allocator, io: Io, path: std.Build.Cache.Path) !void { + const inner = try path.root_dir.handle.readFileAlloc(io, path.sub_path, allocator, .limited(std.math.maxInt(u32))); self.entitlements = .{ .inner = inner }; } diff --git a/src/main.zig b/src/main.zig index 733620bd34eb552cb1784a2f36bfb70cab1f864c..eb5ae7d15354880032f098a121e8099578ea32c3 100644 --- a/src/main.zig +++ b/src/main.zig @@ -423,17 +423,16 @@ fn mainArgs( .wasi => {}, else => process.executablePathAlloc(io, arena) catch |err| fatal("unable to find zig self exe path: {t}", .{err}), }; - var dirs: std.zig.Directories = .init( - arena, - io, - EnvVar.ZIG_LIB_DIR.get(environ_map), - EnvVar.ZIG_GLOBAL_CACHE_DIR.get(environ_map), - .global, - preopens, - self_exe_path, - environ_map, - try std.zig.getResolvedCwd(io, arena), - ); + var dirs: std.zig.Directories = .init(arena, io, .{ + .override_zig_lib = EnvVar.ZIG_LIB_DIR.get(environ_map), + .override_global_cache = EnvVar.ZIG_GLOBAL_CACHE_DIR.get(environ_map), + .build_root = null, + .local_cache_strat = .global, + .preopens = preopens, + .self_exe_path = self_exe_path, + .environ_map = environ_map, + .cwd = try std.zig.getResolvedCwd(io, arena), + }); defer dirs.deinit(io); const host = std.zig.resolveTargetQueryOrFatal(io, .{}); var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer); @@ -458,17 +457,16 @@ fn mainArgs( .wasi => args[0], else => process.executablePathAlloc(io, arena) catch |err| fatal("unable to find zig self exe path: {t}", .{err}), }; - var dirs: std.zig.Directories = .init( - arena, - io, - EnvVar.ZIG_LIB_DIR.get(environ_map), - EnvVar.ZIG_GLOBAL_CACHE_DIR.get(environ_map), - .global, - preopens, - if (native_os != .wasi) self_exe_path, - environ_map, - try std.zig.getResolvedCwd(io, arena), - ); + var dirs: std.zig.Directories = .init(arena, io, .{ + .override_zig_lib = EnvVar.ZIG_LIB_DIR.get(environ_map), + .override_global_cache = EnvVar.ZIG_GLOBAL_CACHE_DIR.get(environ_map), + .build_root = null, + .local_cache_strat = .global, + .preopens = preopens, + .self_exe_path = if (native_os != .wasi) self_exe_path, + .environ_map = environ_map, + .cwd = try std.zig.getResolvedCwd(io, arena), + }); defer dirs.deinit(io); const host = std.zig.resolveTargetQueryOrFatal(io, .{}); var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer); @@ -511,7 +509,7 @@ fn mainArgs( } } -const usage_build_generic = +const compile_usage = \\Usage: zig build-exe [options] [files] \\ zig build-lib [options] [files] \\ zig build-obj [options] [files] @@ -565,16 +563,16 @@ const usage_build_generic = \\ --cache-dir [path] Override the local cache directory \\ --global-cache-dir [path] Override the global cache directory \\ --zig-lib-dir [path] Override path to Zig installation lib directory + \\ --build-root [path] Override path to project source files \\ \\Global Compile Options: \\ --name [name] Compilation unit name (not a file path) - \\ --libc [file] Provide a file which specifies libc paths - \\ -x language Treat subsequent input files as having type - \\ --dep [[import=]name] Add an entry to the next module's import table \\ -M[name][=src] Create a module based on the current per-module settings. \\ The first module is the main module. \\ "std" can be configured by omitting src \\ After a -M argument, per-module settings are reset. + \\ --libc [file] Provide a file which specifies libc paths + \\ -x [language] Treat subsequent input files as having type \\ --error-limit [num] Set the maximum amount of distinct error values \\ -fllvm Force using LLVM as the codegen backend \\ -fno-llvm Prevent using LLVM as the codegen backend @@ -599,6 +597,7 @@ const usage_build_generic = \\ --time-report Send timing diagnostics to '--listen' clients \\ \\Per-Module Compile Options: + \\ --dep [[import=]name] Add an entry to the next module's import table \\ -target [name] -- see the targets command \\ -O [mode] Choose what to optimize for \\ debug (default) Prioritize bug detection, accurate debug info, compilation speed @@ -1054,6 +1053,7 @@ fn buildOutputType( var rc_includes: std.zig.RcIncludes = .any; var manifest_file: ?[]const u8 = null; var linker_export_symbol_names: std.ArrayList([]const u8) = .empty; + var build_root_path: ?[]const u8 = null; // Tracks the position in c_source_files which have already their owner populated. var c_source_files_owner_index: usize = 0; @@ -1167,7 +1167,7 @@ fn buildOutputType( fatal("unable to read response file {q}: {t}", .{ resp_file_path, err }); } else if (mem.startsWith(u8, arg, "-")) { if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) { - try Io.File.stdout().writeStreamingAll(io, usage_build_generic); + try Io.File.stdout().writeStreamingAll(io, compile_usage); return cleanExit(io); } else if (mem.eql(u8, arg, "--")) { if (arg_mode == .run) { @@ -1440,6 +1440,8 @@ fn buildOutputType( override_global_cache_dir = args_iter.nextOrFatal(); } else if (mem.eql(u8, arg, "--zig-lib-dir")) { override_lib_dir = args_iter.nextOrFatal(); + } else if (mem.eql(u8, arg, "--build-root")) { + build_root_path = args_iter.nextOrFatal(); } else if (mem.eql(u8, arg, "--debug-log")) { try addDebugLog(arena, args_iter.nextOrFatal()); } else if (mem.eql(u8, arg, "--listen")) { @@ -3254,23 +3256,22 @@ fn buildOutputType( const cwd_path = try std.zig.getResolvedCwd(io, arena); // This `init` calls `fatal` on error. - var dirs: std.zig.Directories = .init( - arena, - io, - override_lib_dir, - override_global_cache_dir, - s: { + var dirs: std.zig.Directories = .init(arena, io, .{ + .override_zig_lib = override_lib_dir, + .override_global_cache = override_global_cache_dir, + .build_root = build_root_path, + .local_cache_strat = s: { if (override_local_cache_dir) |p| break :s .{ .override = p }; break :s switch (arg_mode) { .run => .global, else => .search, }; }, - preopens, - self_exe_path, - environ_map, - cwd_path, - ); + .preopens = preopens, + .self_exe_path = self_exe_path, + .environ_map = environ_map, + .cwd = cwd_path, + }); defer dirs.deinit(io); if (linker_optimization) |o| warn("ignoring deprecated linker optimization setting {q}", .{o}); @@ -3666,8 +3667,8 @@ fn buildOutputType( .want_compiler_rt = if (zig_cc_explicitly_link_compiler_rt) true else want_compiler_rt, .want_ubsan_rt = want_ubsan_rt, .hash_style = hash_style, - .linker_script = linker_script, - .version_script = version_script, + .linker_script = if (linker_script) |p| .initCwd(p) else null, + .version_script = if (version_script) |p| .initCwd(p) else null, .linker_allow_undefined_version = linker_allow_undefined_version, .linker_enable_new_dtags = linker_enable_new_dtags, .disable_c_depfile = disable_c_depfile, @@ -3740,7 +3741,7 @@ fn buildOutputType( .debug_incremental = debug_incremental, .enable_link_snapshots = enable_link_snapshots, .install_name = install_name, - .entitlements = entitlements, + .entitlements = if (entitlements) |p| .initCwd(p) else null, .pagezero_size = pagezero_size, .headerpad_size = headerpad_size, .headerpad_max_install_names = headerpad_max_install_names, @@ -5020,17 +5021,16 @@ fn jitCmdInner( const cwd_path = try std.zig.getResolvedCwd(io, arena); // This `init` calls `fatal` on error. - var dirs: std.zig.Directories = .init( - arena, - io, - override_lib_dir, - override_global_cache_dir, - .global, - preopens, - self_exe_path, - environ_map, - cwd_path, - ); + var dirs: std.zig.Directories = .init(arena, io, .{ + .override_zig_lib = override_lib_dir, + .override_global_cache = override_global_cache_dir, + .build_root = null, + .local_cache_strat = .global, + .preopens = preopens, + .self_exe_path = self_exe_path, + .environ_map = environ_map, + .cwd = cwd_path, + }); defer dirs.deinit(io); var child_argv: std.ArrayList([]const u8) = .empty; diff --git a/tools/check_mingw.zig b/tools/check_mingw.zig index c67b3f2599efaa9592cc238b866a44d2b3e1bf45..74b2f1d588ad938a5287d67929c5ba05e7f73ce1 100644 --- a/tools/check_mingw.zig +++ b/tools/check_mingw.zig @@ -71,11 +71,11 @@ pub fn main(init: std.process.Init) !void { var pp: Preprocessor = .{ .io = io, .arena = pp_arena, - .include_dir = mingw_include_path, + .include_dir = .initCwd(mingw_include_path), .target = target, }; - pp.preprocess(file_path) catch |err| { + pp.preprocess(.initCwd(file_path)) catch |err| { std.log.err("error preprocessing file {s} for target {t}: {t}", .{ entry.path, target.cpu.arch, err }); fail = true; continue;