| author | |
| committer | |
| log | 22c141605b532eb7d62bfecb020868e580476b93 |
| tree | b9d0f06006f4c36f05aa9bfe6e6f94add6c9fcd3 |
| parent | 64caa0e324d522915769dd5cc8a11374f919f01f |
9 files changed, 240 insertions(+), 409 deletions(-)
lib/compiler/Maker.zig+1| ... | ... | @@ -1573,6 +1573,7 @@ fn configure(graph: *Graph, options: ConfigureOptions) !ScannedConfig { |
| 1573 | 1573 | const configure_exe_path: Path = if (std.zig.buildExeSubprocess(gpa, io, .{ |
| 1574 | 1574 | .argv = build_configurer_argv.items, |
| 1575 | 1575 | .cache_root = graph.local_cache_root, |
| 1576 | .cache = &graph.cache, | |
| 1576 | 1577 | .root_name = configurer_exe_name, |
| 1577 | 1578 | .environ_map = &graph.environ_map, |
| 1578 | 1579 | .cache_manifest = config_man, |
lib/compiler/Maker/Step.zig+27-62| ... | ... | @@ -659,68 +659,33 @@ fn zigProcessUpdate(step_index: Configuration.Step.Index, maker: *Maker, zp: *Zi |
| 659 | 659 | // This message indicates the end of the update. |
| 660 | 660 | if (watch) break; |
| 661 | 661 | }, |
| 662 | .emit_digest => { | |
| 663 | const emit_digest = body_r.takeStruct(std.zig.Server.Message.EmitDigest, .little) catch unreachable; | |
| 664 | const digest = body_r.takeArray(Cache.bin_digest_len) catch unreachable; | |
| 665 | s.result_cache_status = if (emit_digest.flags.cache_hit) .hit else .incomplete_manifest; | |
| 666 | result = .{ .bin = digest.* }; | |
| 667 | }, | |
| 668 | .file_system_inputs => { | |
| 669 | clearWatchInputs(s, maker); | |
| 670 | const conf = &maker.scanned_config.configuration; | |
| 671 | const conf_step = step_index.ptr(conf); | |
| 672 | var it = std.mem.splitScalar(u8, body, 0); | |
| 673 | while (it.next()) |prefixed_path| { | |
| 674 | const prefix_index: std.zig.Server.Message.PathPrefix = @fromBackingInt(@intCast(prefixed_path[0] - 1)); | |
| 675 | const sub_path = try arena.dupe(u8, prefixed_path[1..]); | |
| 676 | const sub_path_dirname = Dir.path.dirname(sub_path) orelse ""; | |
| 677 | switch (prefix_index) { | |
| 678 | .cwd => { | |
| 679 | const path: Path = .{ | |
| 680 | .root_dir = .cwd(), | |
| 681 | .sub_path = sub_path_dirname, | |
| 682 | }; | |
| 683 | try addWatchInputFromPath(s, maker, path, Dir.path.basename(sub_path)); | |
| 684 | }, | |
| 685 | .zig_lib => zl: { | |
| 686 | switch (conf_step.extended.get(conf.extra)) { | |
| 687 | .compile => |compile| if (compile.zig_lib_dir.value) |zig_lib_dir| { | |
| 688 | const resolved = try maker.resolveLazyPathIndex(arena, zig_lib_dir, step_index); | |
| 689 | const appended = try resolved.join(arena, sub_path); | |
| 690 | try addWatchInputPath(s, maker, appended); | |
| 691 | break :zl; | |
| 692 | }, | |
| 693 | else => {}, | |
| 694 | } | |
| 695 | const path: Path = .{ | |
| 696 | .root_dir = graph.zig_lib_directory, | |
| 697 | .sub_path = sub_path_dirname, | |
| 698 | }; | |
| 699 | try addWatchInputFromPath(s, maker, path, Dir.path.basename(sub_path)); | |
| 700 | }, | |
| 701 | .local_cache => { | |
| 702 | const path: Path = .{ | |
| 703 | .root_dir = graph.local_cache_root, | |
| 704 | .sub_path = sub_path_dirname, | |
| 705 | }; | |
| 706 | try addWatchInputFromPath(s, maker, path, Dir.path.basename(sub_path)); | |
| 707 | }, | |
| 708 | .global_cache => { | |
| 709 | const path: Path = .{ | |
| 710 | .root_dir = graph.global_cache_root, | |
| 711 | .sub_path = sub_path_dirname, | |
| 712 | }; | |
| 713 | try addWatchInputFromPath(s, maker, path, Dir.path.basename(sub_path)); | |
| 714 | }, | |
| 715 | .build_root => { | |
| 716 | const path: Path = .{ | |
| 717 | .root_dir = graph.build_root_directory, | |
| 718 | .sub_path = sub_path_dirname, | |
| 719 | }; | |
| 720 | try addWatchInputFromPath(s, maker, path, Dir.path.basename(sub_path)); | |
| 721 | }, | |
| 722 | } | |
| 723 | } | |
| 662 | .cache_manifest => { | |
| 663 | const cache_manifest = body_r.takeStruct(std.zig.Server.Message.CacheManifest, .little) catch unreachable; | |
| 664 | var diag: Cache.Manifest.CheckDiagnostic = undefined; | |
| 665 | var man = graph.cache.obtain(); | |
| 666 | defer man.deinit(); | |
| 667 | man.openFile(&cache_manifest.input_hash, &diag) catch |err| switch (err) { | |
| 668 | else => |e| return e, | |
| 669 | error.CacheCheckFailed => return s.fail(maker, "opening cache manifest failed: {f}", .{ | |
| 670 | diag.fmt(&man), | |
| 671 | }), | |
| 672 | }; | |
| 673 | ||
| 674 | s.result_cache_status = switch (cache_manifest.cache_status.result) { | |
| 675 | .hit => .hit, | |
| 676 | .incomplete_manifest => .incomplete_manifest, | |
| 677 | .invalid_manifest => .invalid_manifest, | |
| 678 | inline .path_deleted, .directory_status_changed, .metadata_changed, .contents_changed => |tag| b: { | |
| 679 | const off: Cache.Manifest.File.Offset = @fromBackingInt(cache_manifest.cache_status.file_off); | |
| 680 | break :b @unionInit( | |
| 681 | ResultCacheStatus, | |
| 682 | @tagName(tag), | |
| 683 | try gpa.dupeSentinel(u8, off.path(man.contents.items), 0), | |
| 684 | ); | |
| 685 | }, | |
| 686 | }; | |
| 687 | result = .{ .bin = cache_manifest.discovered_hash }; | |
| 688 | try setWatchInputsFromManifest(s, maker, &man); | |
| 724 | 689 | }, |
| 725 | 690 | .time_report => if (maker.web_server) |ws| { |
| 726 | 691 | const tr = body_r.takeStruct(std.zig.Server.Message.TimeReport, .little) catch unreachable; |
lib/compiler/Maker/WebServer.zig+23-1| ... | ... | @@ -650,15 +650,37 @@ fn buildClientWasm(ws: *WebServer, arena: Allocator, optimize: std.builtin.Optim |
| 650 | 650 | const compile_prog_node = ws.root_prog_node.start("Compile WebAssembly Component", 0); |
| 651 | 651 | defer compile_prog_node.end(); |
| 652 | 652 | |
| 653 | var cache: Cache = .{ | |
| 654 | .gpa = gpa, | |
| 655 | .io = io, | |
| 656 | .manifest_dir = try graph.global_cache_root.handle.createDirPathOpen(io, "h", .{}), | |
| 657 | .cwd = graph.cache.cwd, | |
| 658 | }; | |
| 659 | defer cache.manifest_dir.close(io); | |
| 660 | cache.addPrefix(.cwd()); | |
| 661 | cache.addPrefix(graph.zig_lib_directory); | |
| 662 | cache.addPrefix(graph.global_cache_root); | |
| 663 | ||
| 653 | 664 | const result = try std.zig.buildExeSubprocess(gpa, io, .{ |
| 654 | 665 | .argv = argv.items, |
| 655 | 666 | .cache_root = graph.global_cache_root, |
| 667 | .cache = &cache, | |
| 668 | .prefix_map = .{ | |
| 669 | 0, // cwd is the same | |
| 670 | 1, // zig lib dir is the same | |
| 671 | 2, // local cache is mapped to global cache | |
| 672 | 2, // global cache is the same | |
| 673 | 0, // build root is not provided | |
| 674 | }, | |
| 656 | 675 | .root_name = root_name, |
| 657 | 676 | .arch_os_abi = arch_os_abi, |
| 658 | 677 | .cpu_features = cpu_features, |
| 659 | 678 | .progress_node = compile_prog_node, |
| 660 | 679 | }); |
| 661 | if (!result.cache_hit) log.info("source changes detected; rebuilt wasm component", .{}); | |
| 680 | switch (result.cache_result) { | |
| 681 | .hit => {}, | |
| 682 | else => log.info("source changes detected: {t}; rebuilt wasm component", .{result.cache_result}), | |
| 683 | } | |
| 662 | 684 | return result.path; |
| 663 | 685 | } |
| 664 | 686 |
lib/std/Build/Cache.zig+56-70| ... | ... | @@ -286,7 +286,7 @@ pub const Manifest = struct { |
| 286 | 286 | want_refresh_timestamp: bool = true, |
| 287 | 287 | /// Uses `Cache.gpa`. |
| 288 | 288 | files: Files = .empty, |
| 289 | /// Indexes line up with `files`, but only up until `hit` is called. Uses | |
| 289 | /// Indexes line up with `files`, but only up until `check` is called. Uses | |
| 290 | 290 | /// `Cache.gpa`. |
| 291 | 291 | input_paths: std.ArrayList(InputPath) = .empty, |
| 292 | 292 | /// Keeps track of the last time we performed a file system write to observe |
| ... | ... | @@ -693,12 +693,12 @@ pub const Manifest = struct { |
| 693 | 693 | }; |
| 694 | 694 | |
| 695 | 695 | /// Add a file or directory path as a dependency of process being cached. |
| 696 | /// When `hit` is called, the contents will be checked to ensure | |
| 696 | /// When `check` is called, the contents will be checked to ensure | |
| 697 | 697 | /// that it matches the contents from previous times. |
| 698 | 698 | /// |
| 699 | 699 | /// The contents of the input file may be requested and subsequently |
| 700 | 700 | /// obtained via methods of the returned `InputPath.Index` after calling |
| 701 | /// `hit`. | |
| 701 | /// `check`. | |
| 702 | 702 | /// |
| 703 | 703 | /// Contents of a directory are considered to be the sorted list of file |
| 704 | 704 | /// names of direct entries, separated by null byte. Each file name is |
| ... | ... | @@ -910,7 +910,57 @@ pub const Manifest = struct { |
| 910 | 910 | |
| 911 | 911 | var input_digest: BinDigest = undefined; |
| 912 | 912 | man.hash.hasher.final(&input_digest); |
| 913 | const input_hex_digest = binToHex(input_digest); | |
| 913 | ||
| 914 | try openFile(man, &input_digest, diag); | |
| 915 | ||
| 916 | man.want_refresh_timestamp = true; | |
| 917 | ||
| 918 | // We're going to construct a second hash. Its input will begin with the digest we've already computed | |
| 919 | // (`input_digest`), and then it'll have the digests of each input file, including discovered files (see | |
| 920 | // `addDiscoveredPath`). If this is a hit, we learn the set of discovered files from the manifest on disk. If | |
| 921 | // this is a miss, we'll learn those from future calls to `addDiscoveredPath` etc. As such, the state of | |
| 922 | // `man.hash.hasher` after this function depends on whether this is a hit or a miss. | |
| 923 | // | |
| 924 | // If we return `CheckResult.hit`, then `man.hash.hasher` must already include the digests of the discovered | |
| 925 | // files, so the caller can call `final`. Otherwise, on a cache miss, `man.hash.hasher` will include the digests | |
| 926 | // of all non-discovered files -- that is, the ones we've already been told about. The rest will be discovered | |
| 927 | // through calls to `addDiscoveredPath` etc, which will update the hasher. After all files are added, the user | |
| 928 | // can use `final`, and will at some point `finalize` the file list to disk. | |
| 929 | man.hash.hasher = hasher_init; | |
| 930 | man.hash.hasher.update(&input_digest); | |
| 931 | ||
| 932 | hit: { | |
| 933 | const miss_result = miss: { | |
| 934 | const result = try man.checkLocked(diag); | |
| 935 | if (result == .hit) { | |
| 936 | break :hit; | |
| 937 | } else if (!try man.upgradeToExclusiveLock(diag)) { | |
| 938 | break :miss result; | |
| 939 | } | |
| 940 | // Missed with the shared lock, and upgraded to an exclusive lock. However, another process may have | |
| 941 | // modified the cache directory, so we need to check again before deciding to miss. | |
| 942 | man.shrinkFilesToInput(); | |
| 943 | const refreshed_result = try man.checkLocked(diag); | |
| 944 | if (refreshed_result == .hit) break :hit; | |
| 945 | break :miss refreshed_result; | |
| 946 | }; | |
| 947 | ||
| 948 | // Cache miss, but `checkLocked` guarantees that all input files have their digests computed, even on a | |
| 949 | // cache miss, which is needed because they will be used in the manifest digest. | |
| 950 | man.state = .miss; | |
| 951 | return miss_result; | |
| 952 | } | |
| 953 | ||
| 954 | if (man.want_shared_lock) { | |
| 955 | man.downgradeToSharedLock() catch |err| return fail(diag, .{ .manifest_lock = err }); | |
| 956 | } | |
| 957 | ||
| 958 | man.state = .hit; | |
| 959 | return .hit; | |
| 960 | } | |
| 961 | ||
| 962 | pub fn openFile(man: *Manifest, input_digest: *const BinDigest, diag: *CheckDiagnostic) CheckError!void { | |
| 963 | const input_hex_digest = binToHex(input_digest.*); | |
| 914 | 964 | |
| 915 | 965 | const manifest_file_path = &input_hex_digest; |
| 916 | 966 | const io = man.cache.io; |
| ... | ... | @@ -969,51 +1019,6 @@ pub const Manifest = struct { |
| 969 | 1019 | else => |e| return fail(diag, .{ .manifest_create = e }), |
| 970 | 1020 | } |
| 971 | 1021 | } |
| 972 | ||
| 973 | man.want_refresh_timestamp = true; | |
| 974 | ||
| 975 | // We're going to construct a second hash. Its input will begin with the digest we've already computed | |
| 976 | // (`input_digest`), and then it'll have the digests of each input file, including discovered files (see | |
| 977 | // `addDiscoveredPath`). If this is a hit, we learn the set of discovered files from the manifest on disk. If | |
| 978 | // this is a miss, we'll learn those from future calls to `addDiscoveredPath` etc. As such, the state of | |
| 979 | // `man.hash.hasher` after this function depends on whether this is a hit or a miss. | |
| 980 | // | |
| 981 | // If we return `CheckResult.hit`, then `man.hash.hasher` must already include the digests of the discovered | |
| 982 | // files, so the caller can call `final`. Otherwise, on a cache miss, `man.hash.hasher` will include the digests | |
| 983 | // of all non-discovered files -- that is, the ones we've already been told about. The rest will be discovered | |
| 984 | // through calls to `addDiscoveredPath` etc, which will update the hasher. After all files are added, the user | |
| 985 | // can use `final`, and will at some point `finalize` the file list to disk. | |
| 986 | man.hash.hasher = hasher_init; | |
| 987 | man.hash.hasher.update(&input_digest); | |
| 988 | ||
| 989 | hit: { | |
| 990 | const miss_result = miss: { | |
| 991 | const result = try man.checkLocked(diag); | |
| 992 | if (result == .hit) { | |
| 993 | break :hit; | |
| 994 | } else if (!try man.upgradeToExclusiveLock(diag)) { | |
| 995 | break :miss result; | |
| 996 | } | |
| 997 | // Missed with the shared lock, and upgraded to an exclusive lock. However, another process may have | |
| 998 | // modified the cache directory, so we need to check again before deciding to miss. | |
| 999 | man.shrinkFilesToInput(); | |
| 1000 | const refreshed_result = try man.checkLocked(diag); | |
| 1001 | if (refreshed_result == .hit) break :hit; | |
| 1002 | break :miss refreshed_result; | |
| 1003 | }; | |
| 1004 | ||
| 1005 | // Cache miss, but `checkLocked` guarantees that all input files have their digests computed, even on a | |
| 1006 | // cache miss, which is needed because they will be used in the manifest digest. | |
| 1007 | man.state = .miss; | |
| 1008 | return miss_result; | |
| 1009 | } | |
| 1010 | ||
| 1011 | if (man.want_shared_lock) { | |
| 1012 | man.downgradeToSharedLock() catch |err| return fail(diag, .{ .manifest_lock = err }); | |
| 1013 | } | |
| 1014 | ||
| 1015 | man.state = .hit; | |
| 1016 | return .hit; | |
| 1017 | 1022 | } |
| 1018 | 1023 | |
| 1019 | 1024 | fn transitionToMissDiscovered(m: *Manifest) void { |
| ... | ... | @@ -1673,7 +1678,7 @@ pub const Manifest = struct { |
| 1673 | 1678 | if (timestamp.nanoseconds < man.recent_problematic_timestamp.nanoseconds) |
| 1674 | 1679 | return false; |
| 1675 | 1680 | |
| 1676 | // This flag prevents multiple filesystem writes for the same hit() call. | |
| 1681 | // This flag prevents multiple filesystem writes for the same `check` call. | |
| 1677 | 1682 | if (man.want_refresh_timestamp) { |
| 1678 | 1683 | man.want_refresh_timestamp = false; |
| 1679 | 1684 | |
| ... | ... | @@ -2120,7 +2125,7 @@ pub const Manifest = struct { |
| 2120 | 2125 | } |
| 2121 | 2126 | |
| 2122 | 2127 | /// Releases the manifest file and frees any memory the Manifest was using. |
| 2123 | /// `Manifest.hit` must be called first. | |
| 2128 | /// `Manifest.check` must be called first. | |
| 2124 | 2129 | /// |
| 2125 | 2130 | /// Don't forget to call `finalize` before this! |
| 2126 | 2131 | pub fn deinit(m: *Manifest) void { |
| ... | ... | @@ -2142,25 +2147,6 @@ pub const Manifest = struct { |
| 2142 | 2147 | m.* = undefined; |
| 2143 | 2148 | } |
| 2144 | 2149 | |
| 2145 | pub fn populateFileSystemInputs(man: *const Manifest, buf: *std.ArrayList(u8)) Allocator.Error!void { | |
| 2146 | assert(@typeInfo(std.zig.Server.Message.PathPrefix).@"enum".field_names.len == man.cache.prefixes_len); | |
| 2147 | buf.clearRetainingCapacity(); | |
| 2148 | const gpa = man.cache.gpa; | |
| 2149 | const files = man.files.keys(); | |
| 2150 | if (files.len > 0) { | |
| 2151 | const contents = man.contents.items; | |
| 2152 | for (files) |file| { | |
| 2153 | const file_path = file.path(contents); | |
| 2154 | try buf.ensureUnusedCapacity(gpa, file_path.len + 2); | |
| 2155 | buf.appendAssumeCapacity(@as(u8, file.get(contents).flags.prefix) + 1); | |
| 2156 | buf.appendSliceAssumeCapacity(file_path); | |
| 2157 | buf.appendAssumeCapacity(0); | |
| 2158 | } | |
| 2159 | // The null byte is a separator, not a terminator. | |
| 2160 | buf.items.len -= 1; | |
| 2161 | } | |
| 2162 | } | |
| 2163 | ||
| 2164 | 2150 | /// Add the full set of paths from another `Manifest` as a dependency of process being cached, after cache miss |
| 2165 | 2151 | /// occurs. |
| 2166 | 2152 | /// |
lib/std/zig.zig+35-29| ... | ... | @@ -1826,10 +1826,12 @@ pub fn isUpDir(p: []const u8) bool { |
| 1826 | 1826 | pub const BuildExeSubprocessOptions = struct { |
| 1827 | 1827 | argv: []const []const u8, |
| 1828 | 1828 | cache_root: Cache.Directory, |
| 1829 | cache: *Cache, | |
| 1829 | 1830 | root_name: []const u8, |
| 1830 | 1831 | |
| 1831 | 1832 | environ_map: ?*std.process.Environ.Map = null, |
| 1832 | 1833 | cache_manifest: ?*Cache.Manifest = null, |
| 1834 | prefix_map: [5]u8 = .{ 0, 1, 2, 3, 4 }, | |
| 1833 | 1835 | arch_os_abi: ?[]const u8 = null, |
| 1834 | 1836 | cpu_features: ?[]const u8 = null, |
| 1835 | 1837 | progress_node: std.Progress.Node = .none, |
| ... | ... | @@ -1848,7 +1850,7 @@ pub const BuildExeSubprocessError = error{ |
| 1848 | 1850 | |
| 1849 | 1851 | pub const BuildExeSubprocessResult = struct { |
| 1850 | 1852 | received_fs_inputs: bool, |
| 1851 | cache_hit: bool, | |
| 1853 | cache_result: Cache.Manifest.CheckResult, | |
| 1852 | 1854 | path: Cache.Path, |
| 1853 | 1855 | }; |
| 1854 | 1856 | |
| ... | ... | @@ -1911,7 +1913,7 @@ pub fn buildExeSubprocess( |
| 1911 | 1913 | const error_bundle = options.error_bundle orelse &default_error_bundle; |
| 1912 | 1914 | |
| 1913 | 1915 | var received_fs_inputs = false; |
| 1914 | var cache_hit = false; | |
| 1916 | var cache_result: Cache.Manifest.CheckResult = .incomplete_manifest; | |
| 1915 | 1917 | |
| 1916 | 1918 | var eos_err: error{EndOfStream}!void = {}; |
| 1917 | 1919 | |
| ... | ... | @@ -1948,37 +1950,41 @@ pub fn buildExeSubprocess( |
| 1948 | 1950 | else => |e| return e, |
| 1949 | 1951 | }; |
| 1950 | 1952 | }, |
| 1951 | .emit_digest => { | |
| 1952 | const EmitDigest = Server.Message.EmitDigest; | |
| 1953 | const ebp_hdr: *align(1) const EmitDigest = @ptrCast(body); | |
| 1954 | cache_hit = ebp_hdr.flags.cache_hit; | |
| 1955 | const digest = body[@sizeOf(EmitDigest)..][0..Cache.bin_digest_len]; | |
| 1953 | .cache_manifest => { | |
| 1954 | var body_r: std.Io.Reader = .fixed(body); | |
| 1955 | const cache_manifest = body_r.takeStruct(std.zig.Server.Message.CacheManifest, .little) catch unreachable; | |
| 1956 | var diag: Cache.Manifest.CheckDiagnostic = undefined; | |
| 1957 | var man = options.cache.obtain(); | |
| 1958 | defer man.deinit(); | |
| 1959 | man.openFile(&cache_manifest.input_hash, &diag) catch |err| switch (err) { | |
| 1960 | else => |e| return e, | |
| 1961 | error.CacheCheckFailed => { | |
| 1962 | log.err("opening cache manifest failed: {f}", .{diag.fmt(&man)}); | |
| 1963 | return error.AlreadyReported; | |
| 1964 | }, | |
| 1965 | }; | |
| 1966 | ||
| 1967 | cache_result = switch (cache_manifest.cache_status.result) { | |
| 1968 | .hit => .hit, | |
| 1969 | .incomplete_manifest => .incomplete_manifest, | |
| 1970 | .invalid_manifest => .invalid_manifest, | |
| 1971 | .path_deleted => .{ .path_deleted = @fromBackingInt(cache_manifest.cache_status.file_off) }, | |
| 1972 | .directory_status_changed => .{ .directory_status_changed = @fromBackingInt(cache_manifest.cache_status.file_off) }, | |
| 1973 | .metadata_changed => .{ .metadata_changed = @fromBackingInt(cache_manifest.cache_status.file_off) }, | |
| 1974 | .contents_changed => .{ .contents_changed = @fromBackingInt(cache_manifest.cache_status.file_off) }, | |
| 1975 | }; | |
| 1976 | ||
| 1977 | if (options.cache_manifest) |parent_man| { | |
| 1978 | try parent_man.addDiscoveredManifest(&man, options.prefix_map); | |
| 1979 | received_fs_inputs = true; | |
| 1980 | } | |
| 1981 | ||
| 1956 | 1982 | if (result) |r| gpa.free(r.sub_path); |
| 1957 | 1983 | result = .{ |
| 1958 | 1984 | .root_dir = options.cache_root, |
| 1959 | .sub_path = try Dir.path.join(gpa, &.{ "o", &Cache.binToHex(digest.*) }), | |
| 1985 | .sub_path = try Dir.path.join(gpa, &.{ "o", &Cache.binToHex(cache_manifest.discovered_hash) }), | |
| 1960 | 1986 | }; |
| 1961 | 1987 | }, |
| 1962 | .file_system_inputs => if (options.cache_manifest) |man| { | |
| 1963 | received_fs_inputs = true; | |
| 1964 | var it = mem.splitScalar(u8, body, 0); | |
| 1965 | while (it.next()) |prefixed_path| { | |
| 1966 | const prefix: Server.Message.PathPrefix = @fromBackingInt(@intCast(prefixed_path[0] - 1)); | |
| 1967 | const sub_path = prefixed_path[1..]; | |
| 1968 | man.addDiscoveredPath(.{ | |
| 1969 | .discovered_path = .{ .prefixed = .{ | |
| 1970 | .prefix = @intCast(@backingInt(prefix)), | |
| 1971 | .sub_path = sub_path, | |
| 1972 | } }, | |
| 1973 | }) catch |err| switch (err) { | |
| 1974 | error.Canceled, error.OutOfMemory => |e| return e, | |
| 1975 | else => |e| { | |
| 1976 | log.err("adding {t} {s} to cache failed: {t}", .{ prefix, sub_path, e }); | |
| 1977 | return error.AlreadyReported; | |
| 1978 | }, | |
| 1979 | }; | |
| 1980 | } | |
| 1981 | }, | |
| 1982 | 1988 | else => {}, // ignore other messages |
| 1983 | 1989 | } |
| 1984 | 1990 | } |
| ... | ... | @@ -2049,7 +2055,7 @@ pub fn buildExeSubprocess( |
| 2049 | 2055 | defer gpa.free(bin_name); |
| 2050 | 2056 | return .{ |
| 2051 | 2057 | .received_fs_inputs = received_fs_inputs, |
| 2052 | .cache_hit = cache_hit, | |
| 2058 | .cache_result = cache_result, | |
| 2053 | 2059 | .path = try base_path.join(gpa, bin_name), |
| 2054 | 2060 | }; |
| 2055 | 2061 | } |
lib/std/zig/Server.zig+39-29| ... | ... | @@ -33,8 +33,6 @@ pub const Message = struct { |
| 33 | 33 | zig_version, |
| 34 | 34 | /// Body is an ErrorBundle. |
| 35 | 35 | error_bundle, |
| 36 | /// Body is a EmitDigest. | |
| 37 | emit_digest, | |
| 38 | 36 | /// Body is a TestMetadata |
| 39 | 37 | test_metadata, |
| 40 | 38 | /// Body is a TestResults |
| ... | ... | @@ -45,14 +43,9 @@ pub const Message = struct { |
| 45 | 43 | /// runner to enforce unit test time limits is relatively accurate under extreme system load |
| 46 | 44 | /// (where there may be a non-trivial delay before the test process is scheduled). |
| 47 | 45 | test_started, |
| 48 | /// Body is a series of strings, delimited by null bytes. | |
| 49 | /// Each string is a prefixed file path. | |
| 50 | /// The first byte indicates the file prefix path (see prefixes fields | |
| 51 | /// of Cache). This byte is sent over the wire incremented so that null | |
| 52 | /// bytes are not confused with string terminators. | |
| 53 | /// The remaining bytes is the file path relative to that prefix. | |
| 54 | /// The prefixes are hard-coded in Compilation.create (cwd, zig lib dir, local cache dir) | |
| 55 | file_system_inputs, | |
| 46 | /// All the information needed to place a file watch on file system inputs. Same memory layout as | |
| 47 | /// `std.Build.Cache.Manifest.contents`. Body is a `CacheManifest`. | |
| 48 | cache_manifest, | |
| 56 | 49 | /// Body is: |
| 57 | 50 | /// - a u64le that indicates the file path within the cache used |
| 58 | 51 | /// to store coverage information. The integer is a hash of the PCs |
| ... | ... | @@ -208,14 +201,33 @@ pub const Message = struct { |
| 208 | 201 | }; |
| 209 | 202 | }; |
| 210 | 203 | |
| 211 | /// Trailing: | |
| 212 | /// * the hex digest of the cache directory within the /o/ subdirectory. | |
| 213 | pub const EmitDigest = extern struct { | |
| 214 | flags: Flags, | |
| 215 | ||
| 216 | pub const Flags = packed struct(u8) { | |
| 217 | cache_hit: bool, | |
| 218 | reserved: u7 = 0, | |
| 204 | pub const CacheManifest = extern struct { | |
| 205 | /// Hit or miss, and if miss, what kind of miss, and which file or directory caused it. | |
| 206 | cache_status: CacheStatus, | |
| 207 | /// Binary digest of the cache inputs. Tells where to locate the manifest file. | |
| 208 | input_hash: std.Build.Cache.BinDigest, | |
| 209 | /// Binary digest of hashed input_hash plus each file's hash. Tells where to locate the cached | |
| 210 | /// artifacts. This is technically denormalized data assuming the cache manifest file is intact. | |
| 211 | discovered_hash: std.Build.Cache.BinDigest, | |
| 212 | ||
| 213 | pub const CacheStatus = packed struct(u32) { | |
| 214 | result: Result, | |
| 215 | /// Presence determined by cache_status. | |
| 216 | file_off: u29, | |
| 217 | ||
| 218 | pub const Result = enum(u3) { | |
| 219 | hit, | |
| 220 | incomplete_manifest, | |
| 221 | invalid_manifest, | |
| 222 | /// Has file_off | |
| 223 | path_deleted, | |
| 224 | /// Has file_off | |
| 225 | directory_status_changed, | |
| 226 | /// Has file_off | |
| 227 | metadata_changed, | |
| 228 | /// Has file_off | |
| 229 | contents_changed, | |
| 230 | }; | |
| 219 | 231 | }; |
| 220 | 232 | }; |
| 221 | 233 | |
| ... | ... | @@ -317,30 +329,24 @@ pub fn serveBroadcastFuzzInputMessage(s: *const Server, test_i: u32, bytes: []co |
| 317 | 329 | try s.out.flush(); |
| 318 | 330 | } |
| 319 | 331 | |
| 320 | pub fn serveEmitDigest( | |
| 321 | s: *Server, | |
| 322 | digest: *const [Cache.bin_digest_len]u8, | |
| 323 | header: OutMessage.EmitDigest, | |
| 324 | ) !void { | |
| 332 | pub fn serveCacheManifestUnflushed(s: *Server, header: OutMessage.CacheManifest) !void { | |
| 325 | 333 | try s.serveMessageHeader(.{ |
| 326 | .tag = .emit_digest, | |
| 327 | .bytes_len = @intCast(digest.len + @sizeOf(OutMessage.EmitDigest)), | |
| 334 | .tag = .cache_manifest, | |
| 335 | .bytes_len = @sizeOf(OutMessage.CacheManifest), | |
| 328 | 336 | }); |
| 329 | 337 | try s.out.writeStruct(header, .little); |
| 330 | try s.out.writeAll(digest); | |
| 331 | try s.out.flush(); | |
| 332 | 338 | } |
| 333 | 339 | |
| 334 | 340 | pub fn serveTestResults(s: *Server, msg: OutMessage.TestResults) !void { |
| 335 | 341 | try s.serveMessageHeader(.{ |
| 336 | 342 | .tag = .test_results, |
| 337 | .bytes_len = @intCast(@sizeOf(OutMessage.TestResults)), | |
| 343 | .bytes_len = @sizeOf(OutMessage.TestResults), | |
| 338 | 344 | }); |
| 339 | 345 | try s.out.writeStruct(msg, .little); |
| 340 | 346 | try s.out.flush(); |
| 341 | 347 | } |
| 342 | 348 | |
| 343 | pub fn serveErrorBundle(s: *Server, tag: Message.Tag, error_bundle: std.zig.ErrorBundle) !void { | |
| 349 | pub fn serveErrorBundleUnflushed(s: *Server, tag: Message.Tag, error_bundle: std.zig.ErrorBundle) !void { | |
| 344 | 350 | const eb_hdr: OutMessage.ErrorBundle = .{ |
| 345 | 351 | .extra_len = @intCast(error_bundle.extra.len), |
| 346 | 352 | .string_bytes_len = @intCast(error_bundle.string_bytes.len), |
| ... | ... | @@ -354,6 +360,10 @@ pub fn serveErrorBundle(s: *Server, tag: Message.Tag, error_bundle: std.zig.Erro |
| 354 | 360 | try s.out.writeStruct(eb_hdr, .little); |
| 355 | 361 | try s.out.writeSliceEndian(u32, error_bundle.extra, .little); |
| 356 | 362 | try s.out.writeAll(error_bundle.string_bytes); |
| 363 | } | |
| 364 | ||
| 365 | pub fn serveErrorBundle(s: *Server, tag: Message.Tag, error_bundle: std.zig.ErrorBundle) !void { | |
| 366 | try serveErrorBundleUnflushed(s, tag, error_bundle); | |
| 357 | 367 | try s.out.flush(); |
| 358 | 368 | } |
| 359 | 369 |
src/Compilation.zig+41-157| ... | ... | @@ -176,7 +176,14 @@ debug_compile_errors: bool, |
| 176 | 176 | /// Do not check this field directly. Instead, use the `debugIncremental` wrapper function. |
| 177 | 177 | debug_incremental: bool, |
| 178 | 178 | alloc_failure_occurred: bool = false, |
| 179 | last_update_was_cache_hit: bool = false, | |
| 179 | ||
| 180 | last_update_cache_status: Cache.Manifest.CheckResult, | |
| 181 | /// Corresponds to .zig-cache/h/* filenames. | |
| 182 | /// Remains stable across updates. | |
| 183 | input_digest: [Cache.bin_digest_len]u8, | |
| 184 | /// Corresponds to .zig-cache/o/* filenames. | |
| 185 | /// May change across updates. | |
| 186 | discovered_digest: [Cache.bin_digest_len]u8, | |
| 180 | 187 | |
| 181 | 188 | c_source_files: []const CSourceFile, |
| 182 | 189 | rc_source_files: []const RcSourceFile, |
| ... | ... | @@ -251,12 +258,6 @@ llvm_opt_bisect_limit: c_int, |
| 251 | 258 | |
| 252 | 259 | time_report: ?TimeReport, |
| 253 | 260 | |
| 254 | file_system_inputs: ?*std.ArrayList(u8), | |
| 255 | ||
| 256 | /// This is the digest of the cache for the current compilation. | |
| 257 | /// This digest will be known after update() is called. | |
| 258 | digest: ?[Cache.bin_digest_len]u8 = null, | |
| 259 | ||
| 260 | 261 | /// Non-`null` iff we are emitting a binary. |
| 261 | 262 | /// Does not change for the lifetime of this `Compilation`. |
| 262 | 263 | /// Cwd-relative if `cache_use == .none`. Otherwise, relative to our subdirectory in the cache. |
| ... | ... | @@ -1600,9 +1601,6 @@ pub const CreateOptions = struct { |
| 1600 | 1601 | error_limit: ?Zcu.ErrorInt = null, |
| 1601 | 1602 | global_cc_argv: []const []const u8 = &.{}, |
| 1602 | 1603 | |
| 1603 | /// Tracks all files that can cause the Compilation to be invalidated and need a rebuild. | |
| 1604 | file_system_inputs: ?*std.ArrayList(u8) = null, | |
| 1605 | ||
| 1606 | 1604 | parent_whole_cache: ?ParentWholeCache = null, |
| 1607 | 1605 | |
| 1608 | 1606 | environ_map: *const std.process.Environ.Map, |
| ... | ... | @@ -2147,7 +2145,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, |
| 2147 | 2145 | .force_undefined_symbols = options.force_undefined_symbols, |
| 2148 | 2146 | .link_eh_frame_hdr = link_eh_frame_hdr, |
| 2149 | 2147 | .global_cc_argv = options.global_cc_argv, |
| 2150 | .file_system_inputs = options.file_system_inputs, | |
| 2151 | 2148 | .parent_whole_cache = options.parent_whole_cache, |
| 2152 | 2149 | .link_diags = .init(gpa, io), |
| 2153 | 2150 | .oneshot_prelink_tasks = .empty, |
| ... | ... | @@ -2158,6 +2155,11 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, |
| 2158 | 2155 | .emit_llvm_bc = try options.emit_llvm_bc.resolve(arena, &options, .llvm_bc), |
| 2159 | 2156 | .emit_docs = try options.emit_docs.resolve(arena, &options, .docs), |
| 2160 | 2157 | .environ_map = options.environ_map, |
| 2158 | ||
| 2159 | // These are populated during `update`. | |
| 2160 | .last_update_cache_status = undefined, | |
| 2161 | .input_digest = undefined, | |
| 2162 | .discovered_digest = undefined, | |
| 2161 | 2163 | }; |
| 2162 | 2164 | |
| 2163 | 2165 | errdefer { |
| ... | ... | @@ -2300,7 +2302,8 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, |
| 2300 | 2302 | // In the case of incremental cache mode, this `artifact_directory` |
| 2301 | 2303 | // is computed based on a hash of non-linker inputs, and it is where all |
| 2302 | 2304 | // build artifacts are stored (even while in-progress). |
| 2303 | comp.digest = hash.peekBin(); | |
| 2305 | comp.input_digest = hash.peekBin(); | |
| 2306 | comp.computed_digest = comp.input_digest; | |
| 2304 | 2307 | const digest = hash.final(); |
| 2305 | 2308 | |
| 2306 | 2309 | const artifact_sub_dir = "o" ++ fs.path.sep_str ++ digest; |
| ... | ... | @@ -2817,7 +2820,6 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE |
| 2817 | 2820 | log.debug("{s} whole cache {f} ignore_hit={}", .{ comp.root_name, status.fmt(&man), ignore_hit }); |
| 2818 | 2821 | if (status == .hit and !ignore_hit) { |
| 2819 | 2822 | // In this case the cache hit contains the full set of file system inputs. Nice! |
| 2820 | if (comp.file_system_inputs) |buf| try man.populateFileSystemInputs(buf); | |
| 2821 | 2823 | if (comp.parent_whole_cache) |pwc| { |
| 2822 | 2824 | try pwc.mutex.lock(io); |
| 2823 | 2825 | defer pwc.mutex.unlock(io); |
| ... | ... | @@ -2881,29 +2883,14 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE |
| 2881 | 2883 | try comp.c_object_work_queue.ensureUnusedCapacity(gpa, comp.c_objects.items.len); |
| 2882 | 2884 | for (comp.c_objects.items) |c_object| { |
| 2883 | 2885 | comp.c_object_work_queue.pushBackAssumeCapacity(c_object); |
| 2884 | try comp.appendFileSystemInput(try .fromUnresolved(arena, comp.dirs, &.{c_object.src.src_path})); | |
| 2885 | 2886 | } |
| 2886 | 2887 | } |
| 2887 | 2888 | |
| 2888 | for (comp.link_inputs) |input| { | |
| 2889 | const path = input.path(); | |
| 2890 | try comp.appendFileSystemInput(try .fromUnresolved(arena, comp.dirs, &.{ | |
| 2891 | path.root_dir.path orelse ".", | |
| 2892 | path.sub_path, | |
| 2893 | })); | |
| 2894 | } | |
| 2895 | ||
| 2896 | 2889 | // For compiling Win32 resources, we rely on the cache hash system to avoid duplicating work. |
| 2897 | 2890 | // Add a Job for each Win32 resource file. |
| 2898 | 2891 | try comp.win32_resource_work_queue.ensureUnusedCapacity(gpa, comp.win32_resources.items.len); |
| 2899 | 2892 | for (comp.win32_resources.items) |win32_resource| { |
| 2900 | 2893 | comp.win32_resource_work_queue.pushBackAssumeCapacity(win32_resource); |
| 2901 | switch (win32_resource.src) { | |
| 2902 | .rc => |f| { | |
| 2903 | try comp.appendFileSystemInput(try .fromUnresolved(arena, comp.dirs, &.{f.src_path})); | |
| 2904 | }, | |
| 2905 | .manifest => {}, | |
| 2906 | } | |
| 2907 | 2894 | } |
| 2908 | 2895 | |
| 2909 | 2896 | if (comp.zcu) |zcu| { |
| ... | ... | @@ -2911,11 +2898,6 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE |
| 2911 | 2898 | |
| 2912 | 2899 | zcu.skip_analysis_this_update = false; |
| 2913 | 2900 | |
| 2914 | // TODO: doing this in `resolveReferences` later could avoid adding inputs for dead embedfiles. Investigate! | |
| 2915 | for (zcu.embed_table.keys()) |embed_file| { | |
| 2916 | try comp.appendFileSystemInput(embed_file.path); | |
| 2917 | } | |
| 2918 | ||
| 2919 | 2901 | zcu.analysis_roots_len = 0; |
| 2920 | 2902 | |
| 2921 | 2903 | zcu.analysis_roots_buffer[zcu.analysis_roots_len] = zcu.std_mod; |
| ... | ... | @@ -3003,7 +2985,6 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE |
| 3003 | 2985 | } |
| 3004 | 2986 | |
| 3005 | 2987 | if (comp.link_depfile) |depfile_path| if (comp.bin_file) |lf| { |
| 3006 | assert(comp.file_system_inputs != null); | |
| 3007 | 2988 | comp.createDepFile(depfile_path, lf.emit) catch |err| |
| 3008 | 2989 | comp.setMiscFailure(.link_depfile, "writing linker dependency file failed: {t}", .{err}); |
| 3009 | 2990 | }; |
| ... | ... | @@ -3024,7 +3005,6 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE |
| 3024 | 3005 | switch (comp.cache_use) { |
| 3025 | 3006 | .none, .incremental => try flush(comp, arena), |
| 3026 | 3007 | .whole => |whole| { |
| 3027 | if (comp.file_system_inputs) |buf| try man.populateFileSystemInputs(buf); | |
| 3028 | 3008 | if (comp.parent_whole_cache) |pwc| { |
| 3029 | 3009 | try pwc.mutex.lock(io); |
| 3030 | 3010 | defer pwc.mutex.unlock(io); |
| ... | ... | @@ -3129,39 +3109,6 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE |
| 3129 | 3109 | } |
| 3130 | 3110 | } |
| 3131 | 3111 | |
| 3132 | /// Thread-safe. Assumes that `comp.mutex` is *not* already held by the caller. | |
| 3133 | pub fn appendFileSystemInput(comp: *Compilation, path: Compilation.Path) Allocator.Error!void { | |
| 3134 | const gpa = comp.gpa; | |
| 3135 | const io = comp.io; | |
| 3136 | const fsi = comp.file_system_inputs orelse return; | |
| 3137 | const prefixes = comp.cache_parent.prefixes(); | |
| 3138 | ||
| 3139 | const want_prefix_dir: Cache.Directory = switch (path.root) { | |
| 3140 | .zig_lib => comp.dirs.zig_lib, | |
| 3141 | .global_cache => comp.dirs.global_cache, | |
| 3142 | .local_cache => comp.dirs.local_cache, | |
| 3143 | .build_root => comp.dirs.build_root, | |
| 3144 | .none => .cwd(), | |
| 3145 | }; | |
| 3146 | const prefix: u8 = for (prefixes, 1..) |prefix_dir, i| { | |
| 3147 | if (prefix_dir.eql(want_prefix_dir)) { | |
| 3148 | break @intCast(i); | |
| 3149 | } | |
| 3150 | } else std.debug.panic( | |
| 3151 | "missing prefix directory {t} ('{f}') for {q}", | |
| 3152 | .{ path.root, want_prefix_dir, path.sub_path }, | |
| 3153 | ); | |
| 3154 | ||
| 3155 | // There may be concurrent calls to this function from C object workers and/or the main thread. | |
| 3156 | comp.mutex.lockUncancelable(io); | |
| 3157 | defer comp.mutex.unlock(io); | |
| 3158 | ||
| 3159 | try fsi.ensureUnusedCapacity(gpa, path.sub_path.len + 3); | |
| 3160 | if (fsi.items.len > 0) fsi.appendAssumeCapacity(0); | |
| 3161 | fsi.appendAssumeCapacity(prefix); | |
| 3162 | fsi.appendSliceAssumeCapacity(path.sub_path); | |
| 3163 | } | |
| 3164 | ||
| 3165 | 3112 | fn resolveEmitPath(comp: *Compilation, path: []const u8) Cache.Path { |
| 3166 | 3113 | return .{ |
| 3167 | 3114 | .root_dir = switch (comp.cache_use) { |
| ... | ... | @@ -4649,6 +4596,7 @@ fn writeDepFile( |
| 4649 | 4596 | w: *std.Io.Writer, |
| 4650 | 4597 | ) std.Io.Writer.Error!void { |
| 4651 | 4598 | const prefixes = comp.cache_parent.prefixes(); |
| 4599 | if (true) @panic("TODO reimplement this based on Cache.Manifest data"); | |
| 4652 | 4600 | const fsi = comp.file_system_inputs.?.items; |
| 4653 | 4601 | |
| 4654 | 4602 | try w.print("{f}:", .{bin_file}); |
| ... | ... | @@ -4667,11 +4615,8 @@ fn writeDepFile( |
| 4667 | 4615 | } |
| 4668 | 4616 | |
| 4669 | 4617 | fn workerDocsCopy(comp: *Compilation) void { |
| 4670 | docsCopyFallible(comp) catch |err| return comp.lockAndSetMiscFailure( | |
| 4671 | .docs_copy, | |
| 4672 | "unable to copy autodocs artifacts: {s}", | |
| 4673 | .{@errorName(err)}, | |
| 4674 | ); | |
| 4618 | docsCopyFallible(comp) catch |err| | |
| 4619 | return comp.lockAndSetMiscFailure(.docs_copy, "unable to copy autodocs artifacts: {t}", .{err}); | |
| 4675 | 4620 | } |
| 4676 | 4621 | |
| 4677 | 4622 | fn docsCopyFallible(comp: *Compilation) anyerror!void { |
| ... | ... | @@ -4680,11 +4625,9 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void { |
| 4680 | 4625 | |
| 4681 | 4626 | const docs_path = comp.resolveEmitPath(comp.emit_docs.?); |
| 4682 | 4627 | var out_dir = docs_path.root_dir.handle.createDirPathOpen(io, docs_path.sub_path, .{}) catch |err| { |
| 4683 | return comp.lockAndSetMiscFailure( | |
| 4684 | .docs_copy, | |
| 4685 | "unable to create output directory '{f}': {s}", | |
| 4686 | .{ docs_path, @errorName(err) }, | |
| 4687 | ); | |
| 4628 | return comp.lockAndSetMiscFailure(.docs_copy, "unable to create output directory {qf}: {t}", .{ | |
| 4629 | docs_path, err, | |
| 4630 | }); | |
| 4688 | 4631 | }; |
| 4689 | 4632 | defer out_dir.close(io); |
| 4690 | 4633 | |
| ... | ... | @@ -4695,11 +4638,7 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void { |
| 4695 | 4638 | } |
| 4696 | 4639 | |
| 4697 | 4640 | var tar_file = out_dir.createFile(io, "sources.tar", .{}) catch |err| { |
| 4698 | return comp.lockAndSetMiscFailure( | |
| 4699 | .docs_copy, | |
| 4700 | "unable to create '{f}/sources.tar': {s}", | |
| 4701 | .{ docs_path, @errorName(err) }, | |
| 4702 | ); | |
| 4641 | return comp.lockAndSetMiscFailure(.docs_copy, "unable to create '{f}/sources.tar': {t}", .{ docs_path, err }); | |
| 4703 | 4642 | }; |
| 4704 | 4643 | defer tar_file.close(io); |
| 4705 | 4644 | |
| ... | ... | @@ -5719,64 +5658,17 @@ fn updateCObject( |
| 5719 | 5658 | .sub_path = fs.path.basename(raw_dep_file_path), |
| 5720 | 5659 | }; |
| 5721 | 5660 | |
| 5722 | if (comp.file_system_inputs != null) { | |
| 5723 | // TODO instead of this rely on passing the manifest contents directly | |
| 5724 | ||
| 5725 | // Use the same file size limit as the cache code does for dependency files. | |
| 5726 | const dep_file_contents = dep_file_path.root_dir.handle.readFileAlloc(io, dep_file_path.sub_path, gpa, .unlimited) catch |err| switch (err) { | |
| 5727 | error.OutOfMemory, error.Canceled => |e| return e, | |
| 5728 | else => |e| return comp.failCObjRetryable( | |
| 5729 | c_object, | |
| 5730 | "failed to read '{f}': {t}", | |
| 5731 | .{ dep_file_path, e }, | |
| 5732 | ), | |
| 5733 | }; | |
| 5734 | defer gpa.free(dep_file_contents); | |
| 5735 | ||
| 5736 | var str_buf: std.ArrayList(u8) = .empty; | |
| 5737 | defer str_buf.deinit(gpa); | |
| 5738 | ||
| 5739 | var it: std.Build.Cache.DepTokenizer = .{ .bytes = dep_file_contents }; | |
| 5740 | while (it.next()) |token| { | |
| 5741 | const input_path: Compilation.Path = switch (token) { | |
| 5742 | .target, .target_must_resolve => continue, | |
| 5743 | .prereq => |file_path| try .fromUnresolved(arena, comp.dirs, &.{file_path}), | |
| 5744 | .prereq_must_resolve => p: { | |
| 5745 | try token.resolve(gpa, &str_buf); | |
| 5746 | break :p try .fromUnresolved(arena, comp.dirs, &.{str_buf.items}); | |
| 5747 | }, | |
| 5748 | else => |err_token| return comp.failCObjRetryable( | |
| 5749 | c_object, | |
| 5750 | "failed parsing '{f}': {f}", | |
| 5751 | .{ dep_file_path, err_token }, | |
| 5752 | ), | |
| 5753 | }; | |
| 5754 | try comp.appendFileSystemInput(input_path); | |
| 5755 | } | |
| 5756 | } | |
| 5757 | ||
| 5758 | 5661 | // Add the files depended on to the cache system. |
| 5759 | 5662 | var diags: Cache.Manifest.AddDiscoveredDepFileDiagnostic = undefined; |
| 5760 | 5663 | man.addDiscoveredDepFile(dep_file_path, &diags) catch |err| switch (err) { |
| 5761 | error.OutOfMemory, | |
| 5762 | error.Canceled, | |
| 5763 | => |e| return e, | |
| 5764 | ||
| 5765 | error.InvalidDepFile => return comp.failCObjRetryable( | |
| 5766 | c_object, | |
| 5767 | "failed to parse '{f}': {f}", | |
| 5768 | .{ dep_file_path, diags.dep_tokenizer }, | |
| 5769 | ), | |
| 5770 | error.FileSystemFailure => return comp.failCObjRetryable( | |
| 5771 | c_object, | |
| 5772 | "failed to parse '{f}': {f}", | |
| 5773 | .{ dep_file_path, diags.add_discovered_path }, | |
| 5774 | ), | |
| 5775 | else => |e| return comp.failCObjRetryable( | |
| 5776 | c_object, | |
| 5777 | "failed to read '{f}': {t}", | |
| 5778 | .{ dep_file_path, e }, | |
| 5779 | ), | |
| 5664 | error.OutOfMemory, error.Canceled => |e| return e, | |
| 5665 | error.InvalidDepFile => return comp.failCObjRetryable(c_object, "failed to parse {qf}: {f}", .{ | |
| 5666 | dep_file_path, diags.dep_tokenizer, | |
| 5667 | }), | |
| 5668 | error.FileSystemFailure => return comp.failCObjRetryable(c_object, "failed to parse {qf}: {f}", .{ | |
| 5669 | dep_file_path, diags.add_discovered_path, | |
| 5670 | }), | |
| 5671 | else => |e| return comp.failCObjRetryable(c_object, "failed to read {qf}: {t}", .{ dep_file_path, e }), | |
| 5780 | 5672 | }; |
| 5781 | 5673 | switch (comp.cache_use) { |
| 5782 | 5674 | .whole => |whole| { |
| ... | ... | @@ -5784,25 +5676,17 @@ fn updateCObject( |
| 5784 | 5676 | try whole.cache_manifest_mutex.lock(io); |
| 5785 | 5677 | defer whole.cache_manifest_mutex.unlock(io); |
| 5786 | 5678 | whole_cache_manifest.addDiscoveredDepFile(dep_file_path, &diags) catch |err| switch (err) { |
| 5787 | error.OutOfMemory, | |
| 5788 | error.Canceled, | |
| 5789 | => |e| return e, | |
| 5790 | ||
| 5791 | error.InvalidDepFile => return comp.failCObjRetryable( | |
| 5792 | c_object, | |
| 5793 | "failed to parse '{f}': {f}", | |
| 5794 | .{ dep_file_path, diags.dep_tokenizer }, | |
| 5795 | ), | |
| 5796 | error.FileSystemFailure => return comp.failCObjRetryable( | |
| 5797 | c_object, | |
| 5798 | "failed to parse '{f}': {f}", | |
| 5799 | .{ dep_file_path, diags.add_discovered_path }, | |
| 5800 | ), | |
| 5801 | else => |e| return comp.failCObjRetryable( | |
| 5802 | c_object, | |
| 5803 | "failed to read '{f}': {t}", | |
| 5804 | .{ dep_file_path, e }, | |
| 5805 | ), | |
| 5679 | error.OutOfMemory, error.Canceled => |e| return e, | |
| 5680 | ||
| 5681 | error.InvalidDepFile => return comp.failCObjRetryable(c_object, "failed to parse {qf}: {f}", .{ | |
| 5682 | dep_file_path, diags.dep_tokenizer, | |
| 5683 | }), | |
| 5684 | error.FileSystemFailure => return comp.failCObjRetryable(c_object, "failed to parse {qf}: {f}", .{ | |
| 5685 | dep_file_path, diags.add_discovered_path, | |
| 5686 | }), | |
| 5687 | else => |e| return comp.failCObjRetryable(c_object, "failed to read {qf}: {t}", .{ | |
| 5688 | dep_file_path, e, | |
| 5689 | }), | |
| 5806 | 5690 | }; |
| 5807 | 5691 | } |
| 5808 | 5692 | }, |
src/Zcu/PerThread.zig-4| ... | ... | @@ -2643,8 +2643,6 @@ fn computeAliveFiles(pt: Zcu.PerThread) Allocator.Error!bool { |
| 2643 | 2643 | .success => {}, |
| 2644 | 2644 | } |
| 2645 | 2645 | |
| 2646 | try comp.appendFileSystemInput(file.path); | |
| 2647 | ||
| 2648 | 2646 | switch (file.getMode()) { |
| 2649 | 2647 | .zig => {}, // continue to logic below |
| 2650 | 2648 | .zon => continue, // ZON can't import anything |
| ... | ... | @@ -3020,8 +3018,6 @@ fn newEmbedFile(pt: Zcu.PerThread, path: Compilation.Path) EmbedFileError!*Zcu.E |
| 3020 | 3018 | var opt_ip_str: ?InternPool.String = null; |
| 3021 | 3019 | try pt.updateEmbedFile(new_file, &opt_ip_str); |
| 3022 | 3020 | |
| 3023 | try comp.appendFileSystemInput(path); | |
| 3024 | ||
| 3025 | 3021 | // Add the file contents to the `whole` cache manifest if necessary. |
| 3026 | 3022 | cache: { |
| 3027 | 3023 | const whole = switch (zcu.comp.cache_use) { |
src/main.zig+18-57| ... | ... | @@ -3627,9 +3627,6 @@ fn buildOutputType( |
| 3627 | 3627 | break :b .whole; |
| 3628 | 3628 | }; |
| 3629 | 3629 | |
| 3630 | var file_system_inputs: std.ArrayList(u8) = .empty; | |
| 3631 | defer file_system_inputs.deinit(gpa); | |
| 3632 | ||
| 3633 | 3630 | // Deduplicate rpath entries |
| 3634 | 3631 | var rpath_dedup = std.array_hash_map.String(void){}; |
| 3635 | 3632 | for (create_module.rpath_list.items) |rpath| { |
| ... | ... | @@ -3762,7 +3759,6 @@ fn buildOutputType( |
| 3762 | 3759 | // than to any particular module. This feature can greatly reduce CLI |
| 3763 | 3760 | // noise when --search-prefix and -M are combined. |
| 3764 | 3761 | .global_cc_argv = try cc_argv.toOwnedSlice(arena), |
| 3765 | .file_system_inputs = &file_system_inputs, | |
| 3766 | 3762 | .debug_compiler_runtime_libs = debug_compiler_runtime_libs, |
| 3767 | 3763 | .environ_map = environ_map, |
| 3768 | 3764 | }) catch |err| switch (err) { |
| ... | ... | @@ -3818,7 +3814,6 @@ fn buildOutputType( |
| 3818 | 3814 | arg_mode, |
| 3819 | 3815 | all_args, |
| 3820 | 3816 | runtime_args_start, |
| 3821 | environ_map, | |
| 3822 | 3817 | ); |
| 3823 | 3818 | return cleanExit(io); |
| 3824 | 3819 | }, |
| ... | ... | @@ -3845,7 +3840,6 @@ fn buildOutputType( |
| 3845 | 3840 | arg_mode, |
| 3846 | 3841 | all_args, |
| 3847 | 3842 | runtime_args_start, |
| 3848 | environ_map, | |
| 3849 | 3843 | ); |
| 3850 | 3844 | return cleanExit(io); |
| 3851 | 3845 | }, |
| ... | ... | @@ -3858,7 +3852,7 @@ fn buildOutputType( |
| 3858 | 3852 | defer root_prog_node.end(); |
| 3859 | 3853 | |
| 3860 | 3854 | if (arg_mode == .translate_c) { |
| 3861 | return cmdTranslateC(comp, arena, null, null, root_prog_node, environ_map); | |
| 3855 | return cmdTranslateC(comp, arena, null, root_prog_node, environ_map); | |
| 3862 | 3856 | } |
| 3863 | 3857 | |
| 3864 | 3858 | updateModule(comp, color, root_prog_node) catch |err| switch (err) { |
| ... | ... | @@ -4400,7 +4394,6 @@ fn serve( |
| 4400 | 4394 | arg_mode: ArgMode, |
| 4401 | 4395 | all_args: []const []const u8, |
| 4402 | 4396 | runtime_args_start: ?usize, |
| 4403 | environ_map: *process.Environ.Map, | |
| 4404 | 4397 | ) !void { |
| 4405 | 4398 | const gpa = comp.gpa; |
| 4406 | 4399 | const io = comp.io; |
| ... | ... | @@ -4422,8 +4415,6 @@ fn serve( |
| 4422 | 4415 | const main_progress_node = std.Progress.start(io, .{}); |
| 4423 | 4416 | defer main_progress_node.end(); |
| 4424 | 4417 | |
| 4425 | const file_system_inputs = comp.file_system_inputs.?; | |
| 4426 | ||
| 4427 | 4418 | const IncrementalDebugServer = if (build_options.enable_debug_extensions and !builtin.single_threaded) |
| 4428 | 4419 | @import("IncrementalDebugServer.zig") |
| 4429 | 4420 | else |
| ... | ... | @@ -4446,29 +4437,8 @@ fn serve( |
| 4446 | 4437 | switch (hdr.tag) { |
| 4447 | 4438 | .exit => return cleanExit(io), |
| 4448 | 4439 | .update => { |
| 4449 | file_system_inputs.clearRetainingCapacity(); | |
| 4450 | ||
| 4451 | 4440 | if (arg_mode == .translate_c) { |
| 4452 | var arena_instance = std.heap.ArenaAllocator.init(gpa); | |
| 4453 | defer arena_instance.deinit(); | |
| 4454 | const arena = arena_instance.allocator(); | |
| 4455 | var output: Compilation.TranslateCResult = undefined; | |
| 4456 | try cmdTranslateC(comp, arena, &output, file_system_inputs, main_progress_node, environ_map); | |
| 4457 | defer output.deinit(gpa); | |
| 4458 | ||
| 4459 | if (file_system_inputs.items.len != 0) { | |
| 4460 | try server.serveStringMessage(.file_system_inputs, file_system_inputs.items); | |
| 4461 | } | |
| 4462 | ||
| 4463 | if (output.errors.errorMessageCount() != 0) { | |
| 4464 | try server.serveErrorBundle(.error_bundle, output.errors); | |
| 4465 | } else { | |
| 4466 | try server.serveEmitDigest(&output.digest, .{ | |
| 4467 | .flags = .{ .cache_hit = output.cache_hit }, | |
| 4468 | }); | |
| 4469 | } | |
| 4470 | ||
| 4471 | continue; | |
| 4441 | @panic("TODO delete translate-c"); | |
| 4472 | 4442 | } |
| 4473 | 4443 | |
| 4474 | 4444 | try comp.makeBinFileWritable(); |
| ... | ... | @@ -4496,7 +4466,6 @@ fn serve( |
| 4496 | 4466 | //); |
| 4497 | 4467 | }, |
| 4498 | 4468 | .hot_update => { |
| 4499 | file_system_inputs.clearRetainingCapacity(); | |
| 4500 | 4469 | if (child_pid) |pid| { |
| 4501 | 4470 | try comp.hotCodeSwap(main_progress_node, pid); |
| 4502 | 4471 | try serveUpdateResults(&server, comp); |
| ... | ... | @@ -4530,14 +4499,6 @@ fn serveUpdateResults(s: *Server, comp: *Compilation) !void { |
| 4530 | 4499 | var error_bundle = try comp.getAllErrorsAlloc(); |
| 4531 | 4500 | defer error_bundle.deinit(gpa); |
| 4532 | 4501 | |
| 4533 | if (comp.file_system_inputs) |file_system_inputs| { | |
| 4534 | if (file_system_inputs.items.len == 0) { | |
| 4535 | assert(error_bundle.errorMessageCount() > 0); | |
| 4536 | } else { | |
| 4537 | try s.serveStringMessage(.file_system_inputs, file_system_inputs.items); | |
| 4538 | } | |
| 4539 | } | |
| 4540 | ||
| 4541 | 4502 | if (comp.time_report) |*tr| { |
| 4542 | 4503 | var decls_len: u32 = 0; |
| 4543 | 4504 | |
| ... | ... | @@ -4613,22 +4574,25 @@ fn serveUpdateResults(s: *Server, comp: *Compilation) !void { |
| 4613 | 4574 | }, |
| 4614 | 4575 | }); |
| 4615 | 4576 | try s.out.writeVecAll(&slices); |
| 4616 | try s.out.flush(); | |
| 4617 | 4577 | } |
| 4618 | 4578 | |
| 4619 | if (error_bundle.errorMessageCount() > 0) { | |
| 4620 | try s.serveErrorBundle(.error_bundle, error_bundle); | |
| 4621 | return; | |
| 4622 | } | |
| 4623 | ||
| 4624 | if (comp.digest) |digest| { | |
| 4625 | try s.serveEmitDigest(&digest, .{ | |
| 4626 | .flags = .{ .cache_hit = comp.last_update_was_cache_hit }, | |
| 4627 | }); | |
| 4628 | } | |
| 4579 | try s.serveCacheManifestUnflushed(.{ | |
| 4580 | .cache_status = switch (comp.last_update_cache_status) { | |
| 4581 | .hit => .{ .result = .hit, .file_off = 0 }, | |
| 4582 | .incomplete_manifest => .{ .result = .incomplete_manifest, .file_off = 0 }, | |
| 4583 | .invalid_manifest => .{ .result = .invalid_manifest, .file_off = 0 }, | |
| 4584 | .path_deleted => |off| .{ .result = .path_deleted, .file_off = off }, | |
| 4585 | .directory_status_changed => |off| .{ .result = .directory_status_changed, .file_off = off }, | |
| 4586 | .metadata_changed => |off| .{ .result = .metadata_changed, .file_off = off }, | |
| 4587 | .contents_changed => |off| .{ .result = .contents_changed, .file_off = off }, | |
| 4588 | }, | |
| 4589 | .input_hash = comp.input_hash, | |
| 4590 | .discovered_hash = comp.discovered_hash, | |
| 4591 | }); | |
| 4629 | 4592 | |
| 4630 | // Serve empty error bundle to indicate the update is done. | |
| 4631 | try s.serveErrorBundle(.error_bundle, std.zig.ErrorBundle.empty); | |
| 4593 | // Even if error bundle is empty, serve it to indicate the update is done. | |
| 4594 | try s.serveErrorBundleUnflushed(.error_bundle, error_bundle); | |
| 4595 | try s.out.flush(); | |
| 4632 | 4596 | } |
| 4633 | 4597 | |
| 4634 | 4598 | fn runOrTest( |
| ... | ... | @@ -4889,7 +4853,6 @@ fn cmdTranslateC( |
| 4889 | 4853 | comp: *Compilation, |
| 4890 | 4854 | arena: Allocator, |
| 4891 | 4855 | fancy_output: ?*Compilation.TranslateCResult, |
| 4892 | file_system_inputs: ?*std.ArrayList(u8), | |
| 4893 | 4856 | prog_node: std.Progress.Node, |
| 4894 | 4857 | environ_map: *process.Environ.Map, |
| 4895 | 4858 | ) !void { |
| ... | ... | @@ -4934,7 +4897,6 @@ fn cmdTranslateC( |
| 4934 | 4897 | |
| 4935 | 4898 | if (result.errors.errorMessageCount() != 0) { |
| 4936 | 4899 | if (fancy_output) |p| { |
| 4937 | if (file_system_inputs) |buf| try man.populateFileSystemInputs(buf); | |
| 4938 | 4900 | p.* = result; |
| 4939 | 4901 | return; |
| 4940 | 4902 | } else { |
| ... | ... | @@ -4948,7 +4910,6 @@ fn cmdTranslateC( |
| 4948 | 4910 | break :result result; |
| 4949 | 4911 | }; |
| 4950 | 4912 | |
| 4951 | if (file_system_inputs) |buf| try man.populateFileSystemInputs(buf); | |
| 4952 | 4913 | if (fancy_output) |p| { |
| 4953 | 4914 | p.* = result; |
| 4954 | 4915 | } else { |