| ... | ... | @@ -41,8 +41,8 @@ gpa: Allocator, |
| 41 | 41 | arena_state: std.heap.ArenaAllocator.State, |
| 42 | 42 | bin_file: *link.File, |
| 43 | 43 | c_object_table: std.AutoArrayHashMapUnmanaged(*CObject, void) = .{}, |
| 44 | | stage1_lock: ?Cache.Lock = null, |
| 45 | | stage1_cache_manifest: *Cache.Manifest = undefined, |
| 44 | /// This is a pointer to a local variable inside `update()`. |
| 45 | whole_cache_manifest: ?*Cache.Manifest = null, |
| 46 | 46 | |
| 47 | 47 | link_error_flags: link.File.ErrorFlags = .{}, |
| 48 | 48 | |
| ... | ... | @@ -98,6 +98,9 @@ clang_argv: []const []const u8, |
| 98 | 98 | cache_parent: *Cache, |
| 99 | 99 | /// Path to own executable for invoking `zig clang`. |
| 100 | 100 | self_exe_path: ?[]const u8, |
| 101 | /// null means -fno-emit-bin. Contains the basename of the |
| 102 | /// outputted binary file in case we don't know the directory yet. |
| 103 | whole_bin_basename: ?[]const u8, |
| 101 | 104 | zig_lib_directory: Directory, |
| 102 | 105 | local_cache_directory: Directory, |
| 103 | 106 | global_cache_directory: Directory, |
| ... | ... | @@ -612,6 +615,15 @@ pub const Directory = struct { |
| 612 | 615 | return std.fs.path.joinZ(allocator, paths); |
| 613 | 616 | } |
| 614 | 617 | } |
| 618 | |
| 619 | /// Whether or not the handle should be closed, or the path should be freed |
| 620 | /// is determined by usage, however this function is provided for convenience |
| 621 | /// if it happens to be what the caller needs. |
| 622 | pub fn closeAndFree(self: *Directory, gpa: Allocator) void { |
| 623 | self.handle.close(); |
| 624 | if (self.path) |p| gpa.free(p); |
| 625 | self.* = undefined; |
| 626 | } |
| 615 | 627 | }; |
| 616 | 628 | |
| 617 | 629 | pub const EmitLoc = struct { |
| ... | ... | @@ -631,6 +643,7 @@ pub const ClangPreprocessorMode = enum { |
| 631 | 643 | }; |
| 632 | 644 | |
| 633 | 645 | pub const SystemLib = link.SystemLib; |
| 646 | pub const CacheMode = link.CacheMode; |
| 634 | 647 | |
| 635 | 648 | pub const InitOptions = struct { |
| 636 | 649 | zig_lib_directory: Directory, |
| ... | ... | @@ -668,6 +681,7 @@ pub const InitOptions = struct { |
| 668 | 681 | /// is externally modified - essentially anything other than zig-cache - then |
| 669 | 682 | /// this flag would be set to disable this machinery to avoid false positives. |
| 670 | 683 | disable_lld_caching: bool = false, |
| 684 | cache_mode: CacheMode = .incremental, |
| 671 | 685 | object_format: ?std.Target.ObjectFormat = null, |
| 672 | 686 | optimize_mode: std.builtin.Mode = .Debug, |
| 673 | 687 | keep_source_files_loaded: bool = false, |
| ... | ... | @@ -885,6 +899,8 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 885 | 899 | break :blk build_options.is_stage1; |
| 886 | 900 | }; |
| 887 | 901 | |
| 902 | const cache_mode = if (use_stage1) CacheMode.whole else options.cache_mode; |
| 903 | |
| 888 | 904 | // Make a decision on whether to use LLVM or our own backend. |
| 889 | 905 | const use_llvm = build_options.have_llvm and blk: { |
| 890 | 906 | if (options.use_llvm) |explicit| |
| ... | ... | @@ -1219,18 +1235,26 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1219 | 1235 | // modified between incremental updates. |
| 1220 | 1236 | var hash = cache.hash; |
| 1221 | 1237 | |
| 1222 | | // Here we put the root source file path name, but *not* with addFile. We want the |
| 1223 | | // hash to be the same regardless of the contents of the source file, because |
| 1224 | | // incremental compilation will handle it, but we do want to namespace different |
| 1225 | | // source file names because they are likely different compilations and therefore this |
| 1226 | | // would be likely to cause cache hits. |
| 1227 | | hash.addBytes(main_pkg.root_src_path); |
| 1228 | | hash.addOptionalBytes(main_pkg.root_src_directory.path); |
| 1229 | | { |
| 1230 | | var local_arena = std.heap.ArenaAllocator.init(gpa); |
| 1231 | | defer local_arena.deinit(); |
| 1232 | | var seen_table = std.AutoHashMap(*Package, void).init(local_arena.allocator()); |
| 1233 | | try addPackageTableToCacheHash(&hash, &local_arena, main_pkg.table, &seen_table, .path_bytes); |
| 1238 | switch (cache_mode) { |
| 1239 | .incremental => { |
| 1240 | // Here we put the root source file path name, but *not* with addFile. |
| 1241 | // We want the hash to be the same regardless of the contents of the |
| 1242 | // source file, because incremental compilation will handle it, but we |
| 1243 | // do want to namespace different source file names because they are |
| 1244 | // likely different compilations and therefore this would be likely to |
| 1245 | // cause cache hits. |
| 1246 | hash.addBytes(main_pkg.root_src_path); |
| 1247 | hash.addOptionalBytes(main_pkg.root_src_directory.path); |
| 1248 | { |
| 1249 | var seen_table = std.AutoHashMap(*Package, void).init(arena); |
| 1250 | try addPackageTableToCacheHash(&hash, &arena_allocator, main_pkg.table, &seen_table, .path_bytes); |
| 1251 | } |
| 1252 | }, |
| 1253 | .whole => { |
| 1254 | // In this case, we postpone adding the input source file until |
| 1255 | // we create the cache manifest, in update(), because we want to |
| 1256 | // track it and packages as files. |
| 1257 | }, |
| 1234 | 1258 | } |
| 1235 | 1259 | hash.add(valgrind); |
| 1236 | 1260 | hash.add(single_threaded); |
| ... | ... | @@ -1238,9 +1262,35 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1238 | 1262 | hash.add(use_llvm); |
| 1239 | 1263 | hash.add(dll_export_fns); |
| 1240 | 1264 | hash.add(options.is_test); |
| 1265 | hash.add(options.test_evented_io); |
| 1266 | hash.addOptionalBytes(options.test_filter); |
| 1267 | hash.addOptionalBytes(options.test_name_prefix); |
| 1241 | 1268 | hash.add(options.skip_linker_dependencies); |
| 1242 | 1269 | hash.add(options.parent_compilation_link_libc); |
| 1243 | 1270 | |
| 1271 | // In the case of incremental cache mode, this `zig_cache_artifact_directory` |
| 1272 | // is computed based on a hash of non-linker inputs, and it is where all |
| 1273 | // build artifacts are stored (even while in-progress). |
| 1274 | // |
| 1275 | // For whole cache mode, it is still used for builtin.zig so that the file |
| 1276 | // path to builtin.zig can remain consistent during a debugging session at |
| 1277 | // runtime. However, we don't know where to put outputs from the linker |
| 1278 | // or stage1 backend object files until the final cache hash, which is available |
| 1279 | // after the compilation is complete. |
| 1280 | // |
| 1281 | // Therefore, in whole cache mode, we additionally create a temporary cache |
| 1282 | // directory for these two kinds of build artifacts, and then rename it |
| 1283 | // into place after the final hash is known. However, we don't want |
| 1284 | // to create the temporary directory here, because in the case of a cache hit, |
| 1285 | // this would have been wasted syscalls to make the directory and then not |
| 1286 | // use it (or delete it). |
| 1287 | // |
| 1288 | // In summary, for whole cache mode, we simulate `-fno-emit-bin` in this |
| 1289 | // function, and `zig_cache_artifact_directory` is *wrong* except for builtin.zig, |
| 1290 | // and then at the beginning of `update()` when we find out whether we need |
| 1291 | // a temporary directory, we patch up all the places that the incorrect |
| 1292 | // `zig_cache_artifact_directory` was passed to various components of the compiler. |
| 1293 | |
| 1244 | 1294 | const digest = hash.final(); |
| 1245 | 1295 | const artifact_sub_dir = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest }); |
| 1246 | 1296 | var artifact_dir = try options.local_cache_directory.handle.makeOpenPath(artifact_sub_dir, .{}); |
| ... | ... | @@ -1374,6 +1424,11 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1374 | 1424 | }; |
| 1375 | 1425 | } |
| 1376 | 1426 | |
| 1427 | switch (cache_mode) { |
| 1428 | .whole => break :blk null, |
| 1429 | .incremental => {}, |
| 1430 | } |
| 1431 | |
| 1377 | 1432 | if (module) |zm| { |
| 1378 | 1433 | break :blk link.Emit{ |
| 1379 | 1434 | .directory = zm.zig_cache_artifact_directory, |
| ... | ... | @@ -1425,6 +1480,18 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1425 | 1480 | }; |
| 1426 | 1481 | }; |
| 1427 | 1482 | |
| 1483 | // This is so that when doing `CacheMode.whole`, the mechanism in update() |
| 1484 | // can use it for communicating the result directory via `bin_file.emit`. |
| 1485 | // This is used to distinguish between -fno-emit-bin and -femit-bin |
| 1486 | // for `CacheMode.whole`. |
| 1487 | const whole_bin_basename: ?[]const u8 = if (options.emit_bin) |x| |
| 1488 | if (x.directory == null) |
| 1489 | x.basename |
| 1490 | else |
| 1491 | null |
| 1492 | else |
| 1493 | null; |
| 1494 | |
| 1428 | 1495 | var system_libs: std.StringArrayHashMapUnmanaged(SystemLib) = .{}; |
| 1429 | 1496 | errdefer system_libs.deinit(gpa); |
| 1430 | 1497 | try system_libs.ensureTotalCapacity(gpa, options.system_lib_names.len); |
| ... | ... | @@ -1512,7 +1579,8 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1512 | 1579 | .skip_linker_dependencies = options.skip_linker_dependencies, |
| 1513 | 1580 | .parent_compilation_link_libc = options.parent_compilation_link_libc, |
| 1514 | 1581 | .each_lib_rpath = options.each_lib_rpath orelse options.is_native_os, |
| 1515 | | .disable_lld_caching = options.disable_lld_caching, |
| 1582 | .cache_mode = cache_mode, |
| 1583 | .disable_lld_caching = options.disable_lld_caching or cache_mode == .whole, |
| 1516 | 1584 | .subsystem = options.subsystem, |
| 1517 | 1585 | .is_test = options.is_test, |
| 1518 | 1586 | .wasi_exec_model = wasi_exec_model, |
| ... | ... | @@ -1529,6 +1597,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1529 | 1597 | .local_cache_directory = options.local_cache_directory, |
| 1530 | 1598 | .global_cache_directory = options.global_cache_directory, |
| 1531 | 1599 | .bin_file = bin_file, |
| 1600 | .whole_bin_basename = whole_bin_basename, |
| 1532 | 1601 | .emit_asm = options.emit_asm, |
| 1533 | 1602 | .emit_llvm_ir = options.emit_llvm_ir, |
| 1534 | 1603 | .emit_llvm_bc = options.emit_llvm_bc, |
| ... | ... | @@ -1725,20 +1794,11 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1725 | 1794 | return comp; |
| 1726 | 1795 | } |
| 1727 | 1796 | |
| 1728 | | fn releaseStage1Lock(comp: *Compilation) void { |
| 1729 | | if (comp.stage1_lock) |*lock| { |
| 1730 | | lock.release(); |
| 1731 | | comp.stage1_lock = null; |
| 1732 | | } |
| 1733 | | } |
| 1734 | | |
| 1735 | 1797 | pub fn destroy(self: *Compilation) void { |
| 1736 | 1798 | const optional_module = self.bin_file.options.module; |
| 1737 | 1799 | self.bin_file.destroy(); |
| 1738 | 1800 | if (optional_module) |module| module.deinit(); |
| 1739 | 1801 | |
| 1740 | | self.releaseStage1Lock(); |
| 1741 | | |
| 1742 | 1802 | const gpa = self.gpa; |
| 1743 | 1803 | self.work_queue.deinit(); |
| 1744 | 1804 | self.anon_work_queue.deinit(); |
| ... | ... | @@ -1815,22 +1875,135 @@ pub fn getTarget(self: Compilation) Target { |
| 1815 | 1875 | return self.bin_file.options.target; |
| 1816 | 1876 | } |
| 1817 | 1877 | |
| 1878 | fn restorePrevZigCacheArtifactDirectory(comp: *Compilation, directory: *Directory) void { |
| 1879 | if (directory.path) |p| comp.gpa.free(p); |
| 1880 | |
| 1881 | // Restore the Module's previous zig_cache_artifact_directory |
| 1882 | // This is only for cleanup purposes; Module.deinit calls close |
| 1883 | // on the handle of zig_cache_artifact_directory. |
| 1884 | if (comp.bin_file.options.module) |module| { |
| 1885 | const builtin_pkg = module.main_pkg.table.get("builtin").?; |
| 1886 | module.zig_cache_artifact_directory = builtin_pkg.root_src_directory; |
| 1887 | } |
| 1888 | } |
| 1889 | |
| 1890 | fn cleanupTmpArtifactDirectory( |
| 1891 | comp: *Compilation, |
| 1892 | tmp_artifact_directory: *?Directory, |
| 1893 | tmp_dir_sub_path: []const u8, |
| 1894 | ) void { |
| 1895 | comp.gpa.free(tmp_dir_sub_path); |
| 1896 | if (tmp_artifact_directory.*) |*directory| { |
| 1897 | directory.handle.close(); |
| 1898 | restorePrevZigCacheArtifactDirectory(comp, directory); |
| 1899 | } |
| 1900 | } |
| 1901 | |
| 1818 | 1902 | /// Detect changes to source files, perform semantic analysis, and update the output files. |
| 1819 | | pub fn update(self: *Compilation) !void { |
| 1903 | pub fn update(comp: *Compilation) !void { |
| 1820 | 1904 | const tracy_trace = trace(@src()); |
| 1821 | 1905 | defer tracy_trace.end(); |
| 1822 | 1906 | |
| 1823 | | self.clearMiscFailures(); |
| 1907 | comp.clearMiscFailures(); |
| 1908 | |
| 1909 | var man: Cache.Manifest = undefined; |
| 1910 | defer if (comp.whole_cache_manifest != null) man.deinit(); |
| 1911 | |
| 1912 | var tmp_dir_sub_path: []const u8 = &.{}; |
| 1913 | var tmp_artifact_directory: ?Directory = null; |
| 1914 | defer cleanupTmpArtifactDirectory(comp, &tmp_artifact_directory, tmp_dir_sub_path); |
| 1915 | |
| 1916 | // If using the whole caching strategy, we check for *everything* up front, including |
| 1917 | // C source files. |
| 1918 | if (comp.bin_file.options.cache_mode == .whole) { |
| 1919 | // We are about to obtain this lock, so here we give other processes a chance first. |
| 1920 | comp.bin_file.releaseLock(); |
| 1921 | |
| 1922 | man = comp.cache_parent.obtain(); |
| 1923 | try comp.addNonIncrementalStuffToCacheManifest(&man); |
| 1924 | |
| 1925 | const is_hit = man.hit() catch |err| { |
| 1926 | // TODO properly bubble these up instead of emitting a warning |
| 1927 | const i = man.failed_file_index orelse return err; |
| 1928 | const file_path = man.files.items[i].path orelse return err; |
| 1929 | std.log.warn("{s}: {s}", .{ @errorName(err), file_path }); |
| 1930 | return err; |
| 1931 | }; |
| 1932 | if (is_hit) { |
| 1933 | const digest = man.final(); |
| 1934 | |
| 1935 | // Communicate the output binary location to parent Compilations. |
| 1936 | if (comp.whole_bin_basename) |basename| { |
| 1937 | const new_sub_path = try std.fs.path.join(comp.gpa, &.{ |
| 1938 | "o", &digest, basename, |
| 1939 | }); |
| 1940 | if (comp.bin_file.options.emit) |emit| { |
| 1941 | comp.gpa.free(emit.sub_path); |
| 1942 | } |
| 1943 | comp.bin_file.options.emit = .{ |
| 1944 | .directory = comp.local_cache_directory, |
| 1945 | .sub_path = new_sub_path, |
| 1946 | }; |
| 1947 | } |
| 1948 | |
| 1949 | comp.emitOthers(); |
| 1950 | |
| 1951 | assert(comp.bin_file.lock == null); |
| 1952 | comp.bin_file.lock = man.toOwnedLock(); |
| 1953 | return; |
| 1954 | } |
| 1955 | comp.whole_cache_manifest = &man; |
| 1956 | |
| 1957 | // Initialize `bin_file.emit` with a temporary Directory so that compilation can |
| 1958 | // continue on the same path as incremental, using the temporary Directory. |
| 1959 | tmp_artifact_directory = d: { |
| 1960 | const s = std.fs.path.sep_str; |
| 1961 | const rand_int = std.crypto.random.int(u64); |
| 1962 | |
| 1963 | tmp_dir_sub_path = try std.fmt.allocPrint(comp.gpa, "tmp" ++ s ++ "{x}", .{rand_int}); |
| 1964 | |
| 1965 | const path = try comp.local_cache_directory.join(comp.gpa, &.{tmp_dir_sub_path}); |
| 1966 | errdefer comp.gpa.free(path); |
| 1967 | |
| 1968 | const handle = try comp.local_cache_directory.handle.makeOpenPath(tmp_dir_sub_path, .{}); |
| 1969 | errdefer handle.close(); |
| 1970 | |
| 1971 | break :d .{ |
| 1972 | .path = path, |
| 1973 | .handle = handle, |
| 1974 | }; |
| 1975 | }; |
| 1976 | |
| 1977 | // This updates the output directory for stage1 backend and linker outputs. |
| 1978 | if (comp.bin_file.options.module) |module| { |
| 1979 | module.zig_cache_artifact_directory = tmp_artifact_directory.?; |
| 1980 | } |
| 1981 | |
| 1982 | // This resets the link.File to operate as if we called openPath() in create() |
| 1983 | // instead of simulating -fno-emit-bin. |
| 1984 | var options = comp.bin_file.options; |
| 1985 | if (comp.whole_bin_basename) |basename| { |
| 1986 | if (options.emit) |emit| { |
| 1987 | comp.gpa.free(emit.sub_path); |
| 1988 | } |
| 1989 | options.emit = .{ |
| 1990 | .directory = tmp_artifact_directory.?, |
| 1991 | .sub_path = basename, |
| 1992 | }; |
| 1993 | } |
| 1994 | comp.bin_file.destroy(); |
| 1995 | comp.bin_file = try link.File.openPath(comp.gpa, options); |
| 1996 | } |
| 1824 | 1997 | |
| 1825 | 1998 | // For compiling C objects, we rely on the cache hash system to avoid duplicating work. |
| 1826 | 1999 | // Add a Job for each C object. |
| 1827 | | try self.c_object_work_queue.ensureUnusedCapacity(self.c_object_table.count()); |
| 1828 | | for (self.c_object_table.keys()) |key| { |
| 1829 | | self.c_object_work_queue.writeItemAssumeCapacity(key); |
| 2000 | try comp.c_object_work_queue.ensureUnusedCapacity(comp.c_object_table.count()); |
| 2001 | for (comp.c_object_table.keys()) |key| { |
| 2002 | comp.c_object_work_queue.writeItemAssumeCapacity(key); |
| 1830 | 2003 | } |
| 1831 | 2004 | |
| 1832 | | const use_stage1 = build_options.is_stage1 and self.bin_file.options.use_stage1; |
| 1833 | | if (self.bin_file.options.module) |module| { |
| 2005 | const use_stage1 = build_options.is_stage1 and comp.bin_file.options.use_stage1; |
| 2006 | if (comp.bin_file.options.module) |module| { |
| 1834 | 2007 | module.compile_log_text.shrinkAndFree(module.gpa, 0); |
| 1835 | 2008 | module.generation += 1; |
| 1836 | 2009 | |
| ... | ... | @@ -1845,7 +2018,7 @@ pub fn update(self: *Compilation) !void { |
| 1845 | 2018 | // import_table here. |
| 1846 | 2019 | // Likewise, in the case of `zig test`, the test runner is the root source file, |
| 1847 | 2020 | // and so there is nothing to import the main file. |
| 1848 | | if (use_stage1 or self.bin_file.options.is_test) { |
| 2021 | if (use_stage1 or comp.bin_file.options.is_test) { |
| 1849 | 2022 | _ = try module.importPkg(module.main_pkg); |
| 1850 | 2023 | } |
| 1851 | 2024 | |
| ... | ... | @@ -1854,34 +2027,34 @@ pub fn update(self: *Compilation) !void { |
| 1854 | 2027 | // to update it. |
| 1855 | 2028 | // We still want AstGen work items for stage1 so that we expose compile errors |
| 1856 | 2029 | // that are implemented in stage2 but not stage1. |
| 1857 | | try self.astgen_work_queue.ensureUnusedCapacity(module.import_table.count()); |
| 2030 | try comp.astgen_work_queue.ensureUnusedCapacity(module.import_table.count()); |
| 1858 | 2031 | for (module.import_table.values()) |value| { |
| 1859 | | self.astgen_work_queue.writeItemAssumeCapacity(value); |
| 2032 | comp.astgen_work_queue.writeItemAssumeCapacity(value); |
| 1860 | 2033 | } |
| 1861 | 2034 | |
| 1862 | 2035 | if (!use_stage1) { |
| 1863 | 2036 | // Put a work item in for checking if any files used with `@embedFile` changed. |
| 1864 | 2037 | { |
| 1865 | | try self.embed_file_work_queue.ensureUnusedCapacity(module.embed_table.count()); |
| 2038 | try comp.embed_file_work_queue.ensureUnusedCapacity(module.embed_table.count()); |
| 1866 | 2039 | var it = module.embed_table.iterator(); |
| 1867 | 2040 | while (it.next()) |entry| { |
| 1868 | 2041 | const embed_file = entry.value_ptr.*; |
| 1869 | | self.embed_file_work_queue.writeItemAssumeCapacity(embed_file); |
| 2042 | comp.embed_file_work_queue.writeItemAssumeCapacity(embed_file); |
| 1870 | 2043 | } |
| 1871 | 2044 | } |
| 1872 | 2045 | |
| 1873 | | try self.work_queue.writeItem(.{ .analyze_pkg = std_pkg }); |
| 1874 | | if (self.bin_file.options.is_test) { |
| 1875 | | try self.work_queue.writeItem(.{ .analyze_pkg = module.main_pkg }); |
| 2046 | try comp.work_queue.writeItem(.{ .analyze_pkg = std_pkg }); |
| 2047 | if (comp.bin_file.options.is_test) { |
| 2048 | try comp.work_queue.writeItem(.{ .analyze_pkg = module.main_pkg }); |
| 1876 | 2049 | } |
| 1877 | 2050 | } |
| 1878 | 2051 | } |
| 1879 | 2052 | |
| 1880 | | try self.performAllTheWork(); |
| 2053 | try comp.performAllTheWork(); |
| 1881 | 2054 | |
| 1882 | 2055 | if (!use_stage1) { |
| 1883 | | if (self.bin_file.options.module) |module| { |
| 1884 | | if (self.bin_file.options.is_test and self.totalErrorCount() == 0) { |
| 2056 | if (comp.bin_file.options.module) |module| { |
| 2057 | if (comp.bin_file.options.is_test and comp.totalErrorCount() == 0) { |
| 1885 | 2058 | // The `test_functions` decl has been intentionally postponed until now, |
| 1886 | 2059 | // at which point we must populate it with the list of test functions that |
| 1887 | 2060 | // have been discovered and not filtered out. |
| ... | ... | @@ -1910,39 +2083,184 @@ pub fn update(self: *Compilation) !void { |
| 1910 | 2083 | } |
| 1911 | 2084 | } |
| 1912 | 2085 | |
| 1913 | | if (self.totalErrorCount() != 0) { |
| 2086 | if (comp.totalErrorCount() != 0) { |
| 1914 | 2087 | // Skip flushing. |
| 1915 | | self.link_error_flags = .{}; |
| 2088 | comp.link_error_flags = .{}; |
| 1916 | 2089 | return; |
| 1917 | 2090 | } |
| 1918 | 2091 | |
| 1919 | 2092 | // This is needed before reading the error flags. |
| 1920 | | try self.bin_file.flush(self); |
| 1921 | | self.link_error_flags = self.bin_file.errorFlags(); |
| 2093 | try comp.bin_file.flush(comp); |
| 2094 | comp.link_error_flags = comp.bin_file.errorFlags(); |
| 1922 | 2095 | |
| 1923 | 2096 | if (!use_stage1) { |
| 1924 | | if (self.bin_file.options.module) |module| { |
| 2097 | if (comp.bin_file.options.module) |module| { |
| 1925 | 2098 | try link.File.C.flushEmitH(module); |
| 1926 | 2099 | } |
| 1927 | 2100 | } |
| 1928 | 2101 | |
| 1929 | 2102 | // Flush takes care of -femit-bin, but we still have -femit-llvm-ir, -femit-llvm-bc, and |
| 1930 | 2103 | // -femit-asm to handle, in the case of C objects. |
| 1931 | | self.emitOthers(); |
| 2104 | comp.emitOthers(); |
| 1932 | 2105 | |
| 1933 | 2106 | // If there are any errors, we anticipate the source files being loaded |
| 1934 | 2107 | // to report error messages. Otherwise we unload all source files to save memory. |
| 1935 | 2108 | // The ZIR needs to stay loaded in memory because (1) Decl objects contain references |
| 1936 | 2109 | // to it, and (2) generic instantiations, comptime calls, inline calls will need |
| 1937 | 2110 | // to reference the ZIR. |
| 1938 | | if (self.totalErrorCount() == 0 and !self.keep_source_files_loaded) { |
| 1939 | | if (self.bin_file.options.module) |module| { |
| 2111 | if (!comp.keep_source_files_loaded) { |
| 2112 | if (comp.bin_file.options.module) |module| { |
| 1940 | 2113 | for (module.import_table.values()) |file| { |
| 1941 | | file.unloadTree(self.gpa); |
| 1942 | | file.unloadSource(self.gpa); |
| 2114 | file.unloadTree(comp.gpa); |
| 2115 | file.unloadSource(comp.gpa); |
| 2116 | } |
| 2117 | } |
| 2118 | } |
| 2119 | |
| 2120 | if (comp.whole_cache_manifest != null) { |
| 2121 | const digest = man.final(); |
| 2122 | |
| 2123 | // Rename the temporary directory into place. |
| 2124 | var directory = tmp_artifact_directory.?; |
| 2125 | tmp_artifact_directory = null; |
| 2126 | |
| 2127 | directory.handle.close(); |
| 2128 | defer restorePrevZigCacheArtifactDirectory(comp, &directory); |
| 2129 | |
| 2130 | const o_sub_path = try std.fs.path.join(comp.gpa, &[_][]const u8{ "o", &digest }); |
| 2131 | defer comp.gpa.free(o_sub_path); |
| 2132 | |
| 2133 | try std.fs.rename( |
| 2134 | comp.local_cache_directory.handle, |
| 2135 | tmp_dir_sub_path, |
| 2136 | comp.local_cache_directory.handle, |
| 2137 | o_sub_path, |
| 2138 | ); |
| 2139 | |
| 2140 | // Failure here only means an unnecessary cache miss. |
| 2141 | man.writeManifest() catch |err| { |
| 2142 | log.warn("failed to write cache manifest: {s}", .{@errorName(err)}); |
| 2143 | }; |
| 2144 | |
| 2145 | // Communicate the output binary location to parent Compilations. |
| 2146 | if (comp.whole_bin_basename) |basename| { |
| 2147 | comp.bin_file.options.emit = .{ |
| 2148 | .directory = comp.local_cache_directory, |
| 2149 | .sub_path = try std.fs.path.join(comp.gpa, &.{ "o", &digest, basename }), |
| 2150 | }; |
| 2151 | } |
| 2152 | |
| 2153 | assert(comp.bin_file.lock == null); |
| 2154 | comp.bin_file.lock = man.toOwnedLock(); |
| 2155 | return; |
| 2156 | } |
| 2157 | } |
| 2158 | |
| 2159 | /// This is only observed at compile-time and used to emit a compile error |
| 2160 | /// to remind the programmer to update multiple related pieces of code that |
| 2161 | /// are in different locations. Bump this number when adding or deleting |
| 2162 | /// anything from the link cache manifest. |
| 2163 | pub const link_hash_implementation_version = 1; |
| 2164 | |
| 2165 | fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifest) !void { |
| 2166 | const gpa = comp.gpa; |
| 2167 | const target = comp.getTarget(); |
| 2168 | |
| 2169 | var arena_allocator = std.heap.ArenaAllocator.init(gpa); |
| 2170 | errdefer arena_allocator.deinit(); |
| 2171 | const arena = arena_allocator.allocator(); |
| 2172 | |
| 2173 | comptime assert(link_hash_implementation_version == 1); |
| 2174 | |
| 2175 | if (comp.bin_file.options.module) |mod| { |
| 2176 | const main_zig_file = try mod.main_pkg.root_src_directory.join(arena, &[_][]const u8{ |
| 2177 | mod.main_pkg.root_src_path, |
| 2178 | }); |
| 2179 | _ = try man.addFile(main_zig_file, null); |
| 2180 | { |
| 2181 | var seen_table = std.AutoHashMap(*Package, void).init(arena); |
| 2182 | |
| 2183 | // Skip builtin.zig; it is useless as an input, and we don't want to have to |
| 2184 | // write it before checking for a cache hit. |
| 2185 | const builtin_pkg = mod.main_pkg.table.get("builtin").?; |
| 2186 | try seen_table.put(builtin_pkg, {}); |
| 2187 | |
| 2188 | try addPackageTableToCacheHash(&man.hash, &arena_allocator, mod.main_pkg.table, &seen_table, .{ .files = man }); |
| 2189 | } |
| 2190 | } |
| 2191 | |
| 2192 | try man.addOptionalFile(comp.bin_file.options.linker_script); |
| 2193 | try man.addOptionalFile(comp.bin_file.options.version_script); |
| 2194 | try man.addListOfFiles(comp.bin_file.options.objects); |
| 2195 | |
| 2196 | for (comp.c_object_table.keys()) |key| { |
| 2197 | _ = try man.addFile(key.src.src_path, null); |
| 2198 | man.hash.addListOfBytes(key.src.extra_flags); |
| 2199 | } |
| 2200 | |
| 2201 | man.hash.addOptionalEmitLoc(comp.emit_asm); |
| 2202 | man.hash.addOptionalEmitLoc(comp.emit_llvm_ir); |
| 2203 | man.hash.addOptionalEmitLoc(comp.emit_llvm_bc); |
| 2204 | man.hash.addOptionalEmitLoc(comp.emit_analysis); |
| 2205 | man.hash.addOptionalEmitLoc(comp.emit_docs); |
| 2206 | |
| 2207 | man.hash.addListOfBytes(comp.clang_argv); |
| 2208 | |
| 2209 | man.hash.addOptional(comp.bin_file.options.stack_size_override); |
| 2210 | man.hash.addOptional(comp.bin_file.options.image_base_override); |
| 2211 | man.hash.addOptional(comp.bin_file.options.gc_sections); |
| 2212 | man.hash.add(comp.bin_file.options.eh_frame_hdr); |
| 2213 | man.hash.add(comp.bin_file.options.emit_relocs); |
| 2214 | man.hash.add(comp.bin_file.options.rdynamic); |
| 2215 | man.hash.addListOfBytes(comp.bin_file.options.lib_dirs); |
| 2216 | man.hash.addListOfBytes(comp.bin_file.options.rpath_list); |
| 2217 | man.hash.add(comp.bin_file.options.each_lib_rpath); |
| 2218 | man.hash.add(comp.bin_file.options.skip_linker_dependencies); |
| 2219 | man.hash.add(comp.bin_file.options.z_nodelete); |
| 2220 | man.hash.add(comp.bin_file.options.z_notext); |
| 2221 | man.hash.add(comp.bin_file.options.z_defs); |
| 2222 | man.hash.add(comp.bin_file.options.z_origin); |
| 2223 | man.hash.add(comp.bin_file.options.z_noexecstack); |
| 2224 | man.hash.add(comp.bin_file.options.z_now); |
| 2225 | man.hash.add(comp.bin_file.options.z_relro); |
| 2226 | man.hash.add(comp.bin_file.options.include_compiler_rt); |
| 2227 | if (comp.bin_file.options.link_libc) { |
| 2228 | man.hash.add(comp.bin_file.options.libc_installation != null); |
| 2229 | if (comp.bin_file.options.libc_installation) |libc_installation| { |
| 2230 | man.hash.addBytes(libc_installation.crt_dir.?); |
| 2231 | if (target.abi == .msvc) { |
| 2232 | man.hash.addBytes(libc_installation.msvc_lib_dir.?); |
| 2233 | man.hash.addBytes(libc_installation.kernel32_lib_dir.?); |
| 1943 | 2234 | } |
| 1944 | 2235 | } |
| 2236 | man.hash.addOptionalBytes(comp.bin_file.options.dynamic_linker); |
| 1945 | 2237 | } |
| 2238 | man.hash.addOptionalBytes(comp.bin_file.options.soname); |
| 2239 | man.hash.addOptional(comp.bin_file.options.version); |
| 2240 | link.hashAddSystemLibs(&man.hash, comp.bin_file.options.system_libs); |
| 2241 | man.hash.addOptional(comp.bin_file.options.allow_shlib_undefined); |
| 2242 | man.hash.add(comp.bin_file.options.bind_global_refs_locally); |
| 2243 | man.hash.add(comp.bin_file.options.tsan); |
| 2244 | man.hash.addOptionalBytes(comp.bin_file.options.sysroot); |
| 2245 | man.hash.add(comp.bin_file.options.linker_optimization); |
| 2246 | |
| 2247 | // WASM specific stuff |
| 2248 | man.hash.add(comp.bin_file.options.import_memory); |
| 2249 | man.hash.addOptional(comp.bin_file.options.initial_memory); |
| 2250 | man.hash.addOptional(comp.bin_file.options.max_memory); |
| 2251 | man.hash.addOptional(comp.bin_file.options.global_base); |
| 2252 | |
| 2253 | // Mach-O specific stuff |
| 2254 | man.hash.addListOfBytes(comp.bin_file.options.framework_dirs); |
| 2255 | man.hash.addListOfBytes(comp.bin_file.options.frameworks); |
| 2256 | |
| 2257 | // COFF specific stuff |
| 2258 | man.hash.addOptional(comp.bin_file.options.subsystem); |
| 2259 | man.hash.add(comp.bin_file.options.tsaware); |
| 2260 | man.hash.add(comp.bin_file.options.nxcompat); |
| 2261 | man.hash.add(comp.bin_file.options.dynamicbase); |
| 2262 | man.hash.addOptional(comp.bin_file.options.major_subsystem_version); |
| 2263 | man.hash.addOptional(comp.bin_file.options.minor_subsystem_version); |
| 1946 | 2264 | } |
| 1947 | 2265 | |
| 1948 | 2266 | fn emitOthers(comp: *Compilation) void { |
| ... | ... | @@ -2988,7 +3306,9 @@ pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult { |
| 2988 | 3306 | |
| 2989 | 3307 | const dep_basename = std.fs.path.basename(out_dep_path); |
| 2990 | 3308 | try man.addDepFilePost(zig_cache_tmp_dir, dep_basename); |
| 2991 | | if (build_options.is_stage1 and comp.bin_file.options.use_stage1) try comp.stage1_cache_manifest.addDepFilePost(zig_cache_tmp_dir, dep_basename); |
| 3309 | if (comp.whole_cache_manifest) |whole_cache_manifest| { |
| 3310 | try whole_cache_manifest.addDepFilePost(zig_cache_tmp_dir, dep_basename); |
| 3311 | } |
| 2992 | 3312 | |
| 2993 | 3313 | const digest = man.final(); |
| 2994 | 3314 | const o_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest }); |
| ... | ... | @@ -3351,13 +3671,13 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P |
| 3351 | 3671 | }; |
| 3352 | 3672 | } |
| 3353 | 3673 | |
| 3354 | | pub fn tmpFilePath(comp: *Compilation, arena: Allocator, suffix: []const u8) error{OutOfMemory}![]const u8 { |
| 3674 | pub fn tmpFilePath(comp: *Compilation, ally: Allocator, suffix: []const u8) error{OutOfMemory}![]const u8 { |
| 3355 | 3675 | const s = std.fs.path.sep_str; |
| 3356 | 3676 | const rand_int = std.crypto.random.int(u64); |
| 3357 | 3677 | if (comp.local_cache_directory.path) |p| { |
| 3358 | | return std.fmt.allocPrint(arena, "{s}" ++ s ++ "tmp" ++ s ++ "{x}-{s}", .{ p, rand_int, suffix }); |
| 3678 | return std.fmt.allocPrint(ally, "{s}" ++ s ++ "tmp" ++ s ++ "{x}-{s}", .{ p, rand_int, suffix }); |
| 3359 | 3679 | } else { |
| 3360 | | return std.fmt.allocPrint(arena, "tmp" ++ s ++ "{x}-{s}", .{ rand_int, suffix }); |
| 3680 | return std.fmt.allocPrint(ally, "tmp" ++ s ++ "{x}-{s}", .{ rand_int, suffix }); |
| 3361 | 3681 | } |
| 3362 | 3682 | } |
| 3363 | 3683 | |
| ... | ... | @@ -4424,6 +4744,7 @@ fn buildOutputFromZig( |
| 4424 | 4744 | .global_cache_directory = comp.global_cache_directory, |
| 4425 | 4745 | .local_cache_directory = comp.global_cache_directory, |
| 4426 | 4746 | .zig_lib_directory = comp.zig_lib_directory, |
| 4747 | .cache_mode = .whole, |
| 4427 | 4748 | .target = target, |
| 4428 | 4749 | .root_name = root_name, |
| 4429 | 4750 | .main_pkg = &main_pkg, |
| ... | ... | @@ -4501,10 +4822,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node |
| 4501 | 4822 | mod.main_pkg.root_src_path, |
| 4502 | 4823 | }); |
| 4503 | 4824 | const zig_lib_dir = comp.zig_lib_directory.path.?; |
| 4504 | | const builtin_zig_path = try directory.join(arena, &[_][]const u8{"builtin.zig"}); |
| 4505 | 4825 | const target = comp.getTarget(); |
| 4506 | | const id_symlink_basename = "stage1.id"; |
| 4507 | | const libs_txt_basename = "libs.txt"; |
| 4508 | 4826 | |
| 4509 | 4827 | // The include_compiler_rt stored in the bin file options here means that we need |
| 4510 | 4828 | // compiler-rt symbols *somehow*. However, in the context of using the stage1 backend |
| ... | ... | @@ -4516,115 +4834,6 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node |
| 4516 | 4834 | const include_compiler_rt = comp.bin_file.options.output_mode == .Obj and |
| 4517 | 4835 | comp.bin_file.options.include_compiler_rt; |
| 4518 | 4836 | |
| 4519 | | // We are about to obtain this lock, so here we give other processes a chance first. |
| 4520 | | comp.releaseStage1Lock(); |
| 4521 | | |
| 4522 | | // Unlike with the self-hosted Zig module, stage1 does not support incremental compilation, |
| 4523 | | // so we input all the zig source files into the cache hash system. We're going to keep |
| 4524 | | // the artifact directory the same, however, so we take the same strategy as linking |
| 4525 | | // does where we have a file which specifies the hash of the output directory so that we can |
| 4526 | | // skip the expensive compilation step if the hash matches. |
| 4527 | | var man = comp.cache_parent.obtain(); |
| 4528 | | defer man.deinit(); |
| 4529 | | |
| 4530 | | _ = try man.addFile(main_zig_file, null); |
| 4531 | | { |
| 4532 | | var seen_table = std.AutoHashMap(*Package, void).init(arena_allocator.allocator()); |
| 4533 | | try addPackageTableToCacheHash(&man.hash, &arena_allocator, mod.main_pkg.table, &seen_table, .{ .files = &man }); |
| 4534 | | } |
| 4535 | | man.hash.add(comp.bin_file.options.valgrind); |
| 4536 | | man.hash.add(comp.bin_file.options.single_threaded); |
| 4537 | | man.hash.add(target.os.getVersionRange()); |
| 4538 | | man.hash.add(comp.bin_file.options.dll_export_fns); |
| 4539 | | man.hash.add(comp.bin_file.options.function_sections); |
| 4540 | | man.hash.add(include_compiler_rt); |
| 4541 | | man.hash.add(comp.bin_file.options.is_test); |
| 4542 | | man.hash.add(comp.bin_file.options.emit != null); |
| 4543 | | man.hash.add(mod.emit_h != null); |
| 4544 | | if (mod.emit_h) |emit_h| { |
| 4545 | | man.hash.addEmitLoc(emit_h.loc); |
| 4546 | | } |
| 4547 | | man.hash.addOptionalEmitLoc(comp.emit_asm); |
| 4548 | | man.hash.addOptionalEmitLoc(comp.emit_llvm_ir); |
| 4549 | | man.hash.addOptionalEmitLoc(comp.emit_llvm_bc); |
| 4550 | | man.hash.addOptionalEmitLoc(comp.emit_analysis); |
| 4551 | | man.hash.addOptionalEmitLoc(comp.emit_docs); |
| 4552 | | man.hash.add(comp.test_evented_io); |
| 4553 | | man.hash.addOptionalBytes(comp.test_filter); |
| 4554 | | man.hash.addOptionalBytes(comp.test_name_prefix); |
| 4555 | | man.hash.addListOfBytes(comp.clang_argv); |
| 4556 | | |
| 4557 | | // Capture the state in case we come back from this branch where the hash doesn't match. |
| 4558 | | const prev_hash_state = man.hash.peekBin(); |
| 4559 | | const input_file_count = man.files.items.len; |
| 4560 | | |
| 4561 | | const hit = man.hit() catch |err| { |
| 4562 | | const i = man.failed_file_index orelse return err; |
| 4563 | | const file_path = man.files.items[i].path orelse return err; |
| 4564 | | fatal("unable to build stage1 zig object: {s}: {s}", .{ @errorName(err), file_path }); |
| 4565 | | }; |
| 4566 | | if (hit) { |
| 4567 | | const digest = man.final(); |
| 4568 | | |
| 4569 | | // We use an extra hex-encoded byte here to store some flags. |
| 4570 | | var prev_digest_buf: [digest.len + 2]u8 = undefined; |
| 4571 | | const prev_digest: []u8 = Cache.readSmallFile( |
| 4572 | | directory.handle, |
| 4573 | | id_symlink_basename, |
| 4574 | | &prev_digest_buf, |
| 4575 | | ) catch |err| blk: { |
| 4576 | | log.debug("stage1 {s} new_digest={s} error: {s}", .{ |
| 4577 | | mod.main_pkg.root_src_path, |
| 4578 | | std.fmt.fmtSliceHexLower(&digest), |
| 4579 | | @errorName(err), |
| 4580 | | }); |
| 4581 | | // Handle this as a cache miss. |
| 4582 | | break :blk prev_digest_buf[0..0]; |
| 4583 | | }; |
| 4584 | | if (prev_digest.len >= digest.len + 2) hit: { |
| 4585 | | if (!mem.eql(u8, prev_digest[0..digest.len], &digest)) |
| 4586 | | break :hit; |
| 4587 | | |
| 4588 | | log.debug("stage1 {s} digest={s} match - skipping invocation", .{ |
| 4589 | | mod.main_pkg.root_src_path, |
| 4590 | | std.fmt.fmtSliceHexLower(&digest), |
| 4591 | | }); |
| 4592 | | var flags_bytes: [1]u8 = undefined; |
| 4593 | | _ = std.fmt.hexToBytes(&flags_bytes, prev_digest[digest.len..]) catch { |
| 4594 | | log.warn("bad cache stage1 digest: '{s}'", .{std.fmt.fmtSliceHexLower(prev_digest)}); |
| 4595 | | break :hit; |
| 4596 | | }; |
| 4597 | | |
| 4598 | | if (directory.handle.readFileAlloc(comp.gpa, libs_txt_basename, 10 * 1024 * 1024)) |libs_txt| { |
| 4599 | | var it = mem.tokenize(u8, libs_txt, "\n"); |
| 4600 | | while (it.next()) |lib_name| { |
| 4601 | | try comp.stage1AddLinkLib(lib_name); |
| 4602 | | } |
| 4603 | | } else |err| switch (err) { |
| 4604 | | error.FileNotFound => {}, // That's OK, it just means 0 libs. |
| 4605 | | else => { |
| 4606 | | log.warn("unable to read cached list of link libs: {s}", .{@errorName(err)}); |
| 4607 | | break :hit; |
| 4608 | | }, |
| 4609 | | } |
| 4610 | | comp.stage1_lock = man.toOwnedLock(); |
| 4611 | | mod.stage1_flags = @bitCast(@TypeOf(mod.stage1_flags), flags_bytes[0]); |
| 4612 | | return; |
| 4613 | | } |
| 4614 | | log.debug("stage1 {s} prev_digest={s} new_digest={s}", .{ |
| 4615 | | mod.main_pkg.root_src_path, |
| 4616 | | std.fmt.fmtSliceHexLower(prev_digest), |
| 4617 | | std.fmt.fmtSliceHexLower(&digest), |
| 4618 | | }); |
| 4619 | | man.unhit(prev_hash_state, input_file_count); |
| 4620 | | } |
| 4621 | | |
| 4622 | | // We are about to change the output file to be different, so we invalidate the build hash now. |
| 4623 | | directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) { |
| 4624 | | error.FileNotFound => {}, |
| 4625 | | else => |e| return e, |
| 4626 | | }; |
| 4627 | | |
| 4628 | 4837 | const stage2_target = try arena.create(stage1.Stage2Target); |
| 4629 | 4838 | stage2_target.* = .{ |
| 4630 | 4839 | .arch = @enumToInt(target.cpu.arch) + 1, // skip over ZigLLVM_UnknownArch |
| ... | ... | @@ -4637,9 +4846,9 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node |
| 4637 | 4846 | .llvm_target_abi = if (target_util.llvmMachineAbi(target)) |s| s.ptr else null, |
| 4638 | 4847 | }; |
| 4639 | 4848 | |
| 4640 | | comp.stage1_cache_manifest = &man; |
| 4641 | | |
| 4642 | 4849 | const main_pkg_path = mod.main_pkg.root_src_directory.path orelse ""; |
| 4850 | const builtin_pkg = mod.main_pkg.table.get("builtin").?; |
| 4851 | const builtin_zig_path = try builtin_pkg.root_src_directory.join(arena, &.{builtin_pkg.root_src_path}); |
| 4643 | 4852 | |
| 4644 | 4853 | const stage1_module = stage1.create( |
| 4645 | 4854 | @enumToInt(comp.bin_file.options.optimize_mode), |
| ... | ... | @@ -4740,19 +4949,8 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node |
| 4740 | 4949 | .have_dllmain_crt_startup = false, |
| 4741 | 4950 | }; |
| 4742 | 4951 | |
| 4743 | | const inferred_lib_start_index = comp.bin_file.options.system_libs.count(); |
| 4744 | 4952 | stage1_module.build_object(); |
| 4745 | 4953 | |
| 4746 | | if (comp.bin_file.options.system_libs.count() > inferred_lib_start_index) { |
| 4747 | | // We need to save the inferred link libs to the cache, otherwise if we get a cache hit |
| 4748 | | // next time we will be missing these libs. |
| 4749 | | var libs_txt = std.ArrayList(u8).init(arena); |
| 4750 | | for (comp.bin_file.options.system_libs.keys()[inferred_lib_start_index..]) |key| { |
| 4751 | | try libs_txt.writer().print("{s}\n", .{key}); |
| 4752 | | } |
| 4753 | | try directory.handle.writeFile(libs_txt_basename, libs_txt.items); |
| 4754 | | } |
| 4755 | | |
| 4756 | 4954 | mod.stage1_flags = .{ |
| 4757 | 4955 | .have_c_main = stage1_module.have_c_main, |
| 4758 | 4956 | .have_winmain = stage1_module.have_winmain, |
| ... | ... | @@ -4763,34 +4961,6 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node |
| 4763 | 4961 | }; |
| 4764 | 4962 | |
| 4765 | 4963 | stage1_module.destroy(); |
| 4766 | | |
| 4767 | | const digest = man.final(); |
| 4768 | | |
| 4769 | | // Update the small file with the digest. If it fails we can continue; it only |
| 4770 | | // means that the next invocation will have an unnecessary cache miss. |
| 4771 | | const stage1_flags_byte = @bitCast(u8, mod.stage1_flags); |
| 4772 | | log.debug("stage1 {s} final digest={s} flags={x}", .{ |
| 4773 | | mod.main_pkg.root_src_path, std.fmt.fmtSliceHexLower(&digest), stage1_flags_byte, |
| 4774 | | }); |
| 4775 | | var digest_plus_flags: [digest.len + 2]u8 = undefined; |
| 4776 | | digest_plus_flags[0..digest.len].* = digest; |
| 4777 | | assert(std.fmt.formatIntBuf(digest_plus_flags[digest.len..], stage1_flags_byte, 16, .lower, .{ |
| 4778 | | .width = 2, |
| 4779 | | .fill = '0', |
| 4780 | | }) == 2); |
| 4781 | | log.debug("saved digest + flags: '{s}' (byte = {}) have_winmain_crt_startup={}", .{ |
| 4782 | | digest_plus_flags, stage1_flags_byte, mod.stage1_flags.have_winmain_crt_startup, |
| 4783 | | }); |
| 4784 | | Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest_plus_flags) catch |err| { |
| 4785 | | log.warn("failed to save stage1 hash digest file: {s}", .{@errorName(err)}); |
| 4786 | | }; |
| 4787 | | // Failure here only means an unnecessary cache miss. |
| 4788 | | man.writeManifest() catch |err| { |
| 4789 | | log.warn("failed to write cache manifest when linking: {s}", .{@errorName(err)}); |
| 4790 | | }; |
| 4791 | | // We hang on to this lock so that the output file path can be used without |
| 4792 | | // other processes clobbering it. |
| 4793 | | comp.stage1_lock = man.toOwnedLock(); |
| 4794 | 4964 | } |
| 4795 | 4965 | |
| 4796 | 4966 | fn stage1LocPath(arena: Allocator, opt_loc: ?EmitLoc, cache_directory: Directory) ![]const u8 { |
| ... | ... | @@ -4862,6 +5032,7 @@ pub fn build_crt_file( |
| 4862 | 5032 | .local_cache_directory = comp.global_cache_directory, |
| 4863 | 5033 | .global_cache_directory = comp.global_cache_directory, |
| 4864 | 5034 | .zig_lib_directory = comp.zig_lib_directory, |
| 5035 | .cache_mode = .whole, |
| 4865 | 5036 | .target = target, |
| 4866 | 5037 | .root_name = root_name, |
| 4867 | 5038 | .main_pkg = null, |