authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-12-13 23:59:02-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-01-01 17:51:19-07:00
log769dea6e37ffef32f0972a0b958ff2ea38db6854
tree788ad21a34b14b9132851d5bcde33603c2c61abf
parent33cdf33b95676dca9f91216e0f8742f9cf7e84fb

Compilation: redo whole vs incremental logic in create and update


3 files changed, 385 insertions(+), 533 deletions(-)

src/Compilation.zig+385-467
......@@ -48,6 +48,9 @@ arena: std.heap.ArenaAllocator,
4848/// Not every Compilation compiles .zig code! For example you could do `zig build-exe foo.o`.
4949/// TODO: rename to zcu: ?*Zcu
5050module: ?*Module,
51/// Contains different state depending on whether the Compilation uses
52/// incremental or whole cache mode.
53cache_use: CacheUse,
5154/// All compilations have a root module because this is where some important
5255/// settings are stored, such as target and optimization mode. This module
5356/// might not have any .zig code associated with it, however.
......@@ -66,7 +69,6 @@ implib_emit: ?Emit,
6669/// This is non-null when `-femit-docs` is provided.
6770docs_emit: ?Emit,
6871root_name: [:0]const u8,
69cache_mode: CacheMode,
7072include_compiler_rt: bool,
7173objects: []Compilation.LinkObject,
7274/// Needed only for passing -F args to clang.
......@@ -82,9 +84,6 @@ no_builtin: bool,
8284c_object_table: std.AutoArrayHashMapUnmanaged(*CObject, void) = .{},
8385win32_resource_table: if (build_options.only_core_functionality) void else std.AutoArrayHashMapUnmanaged(*Win32Resource, void) =
8486 if (build_options.only_core_functionality) {} else .{},
85/// This is a pointer to a local variable inside `update()`.
86whole_cache_manifest: ?*Cache.Manifest = null,
87whole_cache_manifest_mutex: std.Thread.Mutex = .{},
8887
8988link_error_flags: link.File.ErrorFlags = .{},
9089lld_errors: std.ArrayListUnmanaged(LldError) = .{},
......@@ -154,14 +153,6 @@ rc_source_files: []const RcSourceFile,
154153cache_parent: *Cache,
155154/// Path to own executable for invoking `zig clang`.
156155self_exe_path: ?[]const u8,
157/// null means -fno-emit-bin.
158/// This is mutable memory allocated into the Compilation-lifetime arena (`arena`)
159/// of exactly the correct size for "o/[digest]/[basename]".
160/// The basename is of the outputted binary file in case we don't know the directory yet.
161whole_bin_sub_path: ?[]u8,
162/// Same as `whole_bin_sub_path` but for implibs.
163whole_implib_sub_path: ?[]u8,
164whole_docs_sub_path: ?[]u8,
165156zig_lib_directory: Directory,
166157local_cache_directory: Directory,
167158global_cache_directory: Directory,
......@@ -199,9 +190,6 @@ glibc_so_files: ?glibc.BuiltSharedObjects = null,
199190/// The key is the basename, and the value is the absolute path to the completed build artifact.
200191crt_files: std.StringHashMapUnmanaged(CRTFile) = .{},
201192
202/// Keeping track of this possibly open resource so we can close it later.
203owned_link_dir: ?std.fs.Dir,
204
205193/// This is for stage1 and should be deleted upon completion of self-hosting.
206194/// Don't use this for anything other than stage1 compatibility.
207195color: Color = .auto,
......@@ -869,7 +857,32 @@ pub const ClangPreprocessorMode = enum {
869857
870858pub const Framework = link.File.MachO.Framework;
871859pub const SystemLib = link.SystemLib;
872pub const CacheMode = link.CacheMode;
860
861pub const CacheMode = enum { incremental, whole };
862
863pub const CacheUse = union(CacheMode) {
864 incremental: *Incremental,
865 whole: *Whole,
866
867 pub const Whole = struct {
868 /// This is a pointer to a local variable inside `update()`.
869 cache_manifest: ?*Cache.Manifest = null,
870 cache_manifest_mutex: std.Thread.Mutex = .{},
871 /// null means -fno-emit-bin.
872 /// This is mutable memory allocated into the Compilation-lifetime arena (`arena`)
873 /// of exactly the correct size for "o/[digest]/[basename]".
874 /// The basename is of the outputted binary file in case we don't know the directory yet.
875 bin_sub_path: ?[]u8,
876 /// Same as `whole_bin_sub_path` but for implibs.
877 implib_sub_path: ?[]u8,
878 docs_sub_path: ?[]u8,
879 };
880
881 pub const Incremental = struct {
882 /// Where build artifacts and incremental compilation metadata serialization go.
883 artifact_directory: Compilation.Directory,
884 };
885};
873886
874887pub const LinkObject = struct {
875888 path: []const u8,
......@@ -1280,6 +1293,9 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
12801293
12811294 const error_limit = options.error_limit orelse (std.math.maxInt(u16) - 1);
12821295
1296 const each_lib_rpath = options.each_lib_rpath orelse
1297 options.root_mod.resolved_target.is_native_os;
1298
12831299 // We put everything into the cache hash that *cannot be modified
12841300 // during an incremental update*. For example, one cannot change the
12851301 // target between updates, but one can change source files, so the
......@@ -1319,73 +1335,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
13191335 cache.hash.add(options.config.wasi_exec_model);
13201336 // TODO audit this and make sure everything is in it
13211337
1322 const zcu: ?*Module = if (have_zcu) blk: {
1323 // Options that are specific to zig source files, that cannot be
1324 // modified between incremental updates.
1325 var hash = cache.hash;
1326
1327 switch (cache_mode) {
1328 .incremental => {
1329 // Here we put the root source file path name, but *not* with addFile.
1330 // We want the hash to be the same regardless of the contents of the
1331 // source file, because incremental compilation will handle it, but we
1332 // do want to namespace different source file names because they are
1333 // likely different compilations and therefore this would be likely to
1334 // cause cache hits.
1335 try addModuleTableToCacheHash(gpa, arena, &hash, options.root_mod, .path_bytes);
1336 },
1337 .whole => {
1338 // In this case, we postpone adding the input source file until
1339 // we create the cache manifest, in update(), because we want to
1340 // track it and packages as files.
1341 },
1342 }
1343
1344 // Synchronize with other matching comments: ZigOnlyHashStuff
1345 hash.add(use_llvm);
1346 hash.add(options.config.use_lib_llvm);
1347 hash.add(dll_export_fns);
1348 hash.add(options.config.is_test);
1349 hash.add(options.config.test_evented_io);
1350 hash.addOptionalBytes(options.test_filter);
1351 hash.addOptionalBytes(options.test_name_prefix);
1352 hash.add(options.skip_linker_dependencies);
1353 hash.add(formatted_panics);
1354 hash.add(options.emit_h != null);
1355 hash.add(error_limit);
1356
1357 // In the case of incremental cache mode, this `zig_cache_artifact_directory`
1358 // is computed based on a hash of non-linker inputs, and it is where all
1359 // build artifacts are stored (even while in-progress).
1360 //
1361 // For whole cache mode, it is still used for builtin.zig so that the file
1362 // path to builtin.zig can remain consistent during a debugging session at
1363 // runtime. However, we don't know where to put outputs from the linker
1364 // until the final cache hash, which is available after the
1365 // compilation is complete.
1366 //
1367 // Therefore, in whole cache mode, we additionally create a temporary cache
1368 // directory for these two kinds of build artifacts, and then rename it
1369 // into place after the final hash is known. However, we don't want
1370 // to create the temporary directory here, because in the case of a cache hit,
1371 // this would have been wasted syscalls to make the directory and then not
1372 // use it (or delete it).
1373 //
1374 // In summary, for whole cache mode, we simulate `-fno-emit-bin` in this
1375 // function, and `zig_cache_artifact_directory` is *wrong* except for builtin.zig,
1376 // and then at the beginning of `update()` when we find out whether we need
1377 // a temporary directory, we patch up all the places that the incorrect
1378 // `zig_cache_artifact_directory` was passed to various components of the compiler.
1379
1380 const digest = hash.final();
1381 const artifact_sub_dir = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest });
1382 var artifact_dir = try options.local_cache_directory.handle.makeOpenPath(artifact_sub_dir, .{});
1383 errdefer artifact_dir.close();
1384 const zig_cache_artifact_directory: Directory = .{
1385 .handle = artifact_dir,
1386 .path = try options.local_cache_directory.join(arena, &[_][]const u8{artifact_sub_dir}),
1387 };
1388
1338 const opt_zcu: ?*Module = if (have_zcu) blk: {
13891339 // Pre-open the directory handles for cached ZIR code so that it does not need
13901340 // to redundantly happen for each AstGen operation.
13911341 const zir_sub_dir = "z";
......@@ -1404,27 +1354,18 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
14041354 };
14051355
14061356 const emit_h: ?*Module.GlobalEmitH = if (options.emit_h) |loc| eh: {
1407 const eh = try gpa.create(Module.GlobalEmitH);
1357 const eh = try arena.create(Module.GlobalEmitH);
14081358 eh.* = .{ .loc = loc };
14091359 break :eh eh;
14101360 } else null;
1411 errdefer if (emit_h) |eh| gpa.destroy(eh);
1412
1413 // TODO when we implement serialization and deserialization of incremental
1414 // compilation metadata, this is where we would load it. We have open a handle
1415 // to the directory where the output either already is, or will be.
1416 // However we currently do not have serialization of such metadata, so for now
1417 // we set up an empty Module that does the entire compilation fresh.
14181361
14191362 const zcu = try arena.create(Module);
1420 errdefer zcu.deinit();
14211363 zcu.* = .{
14221364 .gpa = gpa,
14231365 .comp = comp,
14241366 .main_mod = options.main_mod orelse options.root_mod,
14251367 .root_mod = options.root_mod,
14261368 .std_mod = options.std_mod,
1427 .zig_cache_artifact_directory = zig_cache_artifact_directory,
14281369 .global_zir_cache = global_zir_cache,
14291370 .local_zir_cache = local_zir_cache,
14301371 .emit_h = emit_h,
......@@ -1432,155 +1373,33 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
14321373 .error_limit = error_limit,
14331374 };
14341375 try zcu.init();
1435
14361376 break :blk zcu;
14371377 } else blk: {
14381378 if (options.emit_h != null) return error.NoZigModuleForCHeader;
14391379 break :blk null;
14401380 };
1441 errdefer if (zcu) |u| u.deinit();
1442
1443 // For resource management purposes.
1444 var owned_link_dir: ?std.fs.Dir = null;
1445 errdefer if (owned_link_dir) |*dir| dir.close();
1446
1447 const bin_file_emit: ?Emit = blk: {
1448 const emit_bin = options.emit_bin orelse break :blk null;
1449
1450 if (emit_bin.directory) |directory| {
1451 break :blk Emit{
1452 .directory = directory,
1453 .sub_path = emit_bin.basename,
1454 };
1455 }
1456
1457 // In case of whole cache mode, `whole_bin_sub_path` is used to distinguish
1458 // between -femit-bin and -fno-emit-bin.
1459 switch (cache_mode) {
1460 .whole => break :blk null,
1461 .incremental => {},
1462 }
1463
1464 if (zcu) |u| {
1465 break :blk Emit{
1466 .directory = u.zig_cache_artifact_directory,
1467 .sub_path = emit_bin.basename,
1468 };
1469 }
1470
1471 // We could use the cache hash as is no problem, however, we increase
1472 // the likelihood of cache hits by adding the first C source file
1473 // path name (not contents) to the hash. This way if the user is compiling
1474 // foo.c and bar.c as separate compilations, they get different cache
1475 // directories.
1476 var hash = cache.hash;
1477 if (options.c_source_files.len >= 1) {
1478 hash.addBytes(options.c_source_files[0].src_path);
1479 } else if (options.link_objects.len >= 1) {
1480 hash.addBytes(options.link_objects[0].path);
1481 }
1482
1483 const digest = hash.final();
1484 const artifact_sub_dir = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest });
1485 const artifact_dir = try options.local_cache_directory.handle.makeOpenPath(artifact_sub_dir, .{});
1486 owned_link_dir = artifact_dir;
1487 const link_artifact_directory: Directory = .{
1488 .handle = artifact_dir,
1489 .path = try options.local_cache_directory.join(arena, &[_][]const u8{artifact_sub_dir}),
1490 };
1491 break :blk Emit{
1492 .directory = link_artifact_directory,
1493 .sub_path = emit_bin.basename,
1494 };
1495 };
1496
1497 const implib_emit: ?Emit = blk: {
1498 const emit_implib = options.emit_implib orelse break :blk null;
1499
1500 if (emit_implib.directory) |directory| {
1501 break :blk Emit{
1502 .directory = directory,
1503 .sub_path = emit_implib.basename,
1504 };
1505 }
1506
1507 // This is here for the same reason as in `bin_file_emit` above.
1508 switch (cache_mode) {
1509 .whole => break :blk null,
1510 .incremental => {},
1511 }
1512
1513 // Use the same directory as the bin. The CLI already emits an
1514 // error if -fno-emit-bin is combined with -femit-implib.
1515 break :blk Emit{
1516 .directory = bin_file_emit.?.directory,
1517 .sub_path = emit_implib.basename,
1518 };
1519 };
1381 errdefer if (opt_zcu) |zcu| zcu.deinit();
15201382
1521 const docs_emit: ?Emit = blk: {
1522 const emit_docs = options.emit_docs orelse break :blk null;
1523
1524 if (emit_docs.directory) |directory| {
1525 break :blk .{
1526 .directory = directory,
1527 .sub_path = emit_docs.basename,
1528 };
1529 }
1530
1531 // This is here for the same reason as in `bin_file_emit` above.
1532 switch (cache_mode) {
1533 .whole => break :blk null,
1534 .incremental => {},
1535 }
1536
1537 // Use the same directory as the bin, if possible.
1538 if (bin_file_emit) |x| break :blk .{
1539 .directory = x.directory,
1540 .sub_path = emit_docs.basename,
1541 };
1542
1543 break :blk .{
1544 .directory = zcu.?.zig_cache_artifact_directory,
1545 .sub_path = emit_docs.basename,
1546 };
1547 };
1548
1549 // This is so that when doing `CacheMode.whole`, the mechanism in update()
1550 // can use it for communicating the result directory via `bin_file.emit`.
1551 // This is used to distinguish between -fno-emit-bin and -femit-bin
1552 // for `CacheMode.whole`.
1553 // This memory will be overwritten with the real digest in update() but
1554 // the basename will be preserved.
1555 const whole_bin_sub_path: ?[]u8 = try prepareWholeEmitSubPath(arena, options.emit_bin);
1556 // Same thing but for implibs.
1557 const whole_implib_sub_path: ?[]u8 = try prepareWholeEmitSubPath(arena, options.emit_implib);
1558 const whole_docs_sub_path: ?[]u8 = try prepareWholeEmitSubPath(arena, options.emit_docs);
1559
1560 var system_libs: std.StringArrayHashMapUnmanaged(SystemLib) = .{};
1383 const system_libs = try std.StringArrayHashMapUnmanaged(SystemLib).init(
1384 gpa,
1385 options.system_lib_names,
1386 options.system_lib_infos,
1387 );
15611388 errdefer system_libs.deinit(gpa);
1562 try system_libs.ensureTotalCapacity(gpa, options.system_lib_names.len);
1563 for (options.system_lib_names, 0..) |lib_name, i| {
1564 system_libs.putAssumeCapacity(lib_name, options.system_lib_infos[i]);
1565 }
1566
1567 const each_lib_rpath = options.each_lib_rpath orelse
1568 options.root_mod.resolved_target.is_native_os;
15691389
15701390 comp.* = .{
15711391 .gpa = gpa,
15721392 .arena = arena_allocator,
1573 .module = zcu,
1393 .module = opt_zcu,
1394 .cache_use = undefined, // populated below
1395 .bin_file = null, // populated below
1396 .implib_emit = null, // handled below
1397 .docs_emit = null, // handled below
15741398 .root_mod = options.root_mod,
15751399 .config = options.config,
1576 .bin_file = null,
1577 .cache_mode = cache_mode,
15781400 .zig_lib_directory = options.zig_lib_directory,
15791401 .local_cache_directory = options.local_cache_directory,
15801402 .global_cache_directory = options.global_cache_directory,
1581 .whole_bin_sub_path = whole_bin_sub_path,
1582 .whole_implib_sub_path = whole_implib_sub_path,
1583 .whole_docs_sub_path = whole_docs_sub_path,
15841403 .emit_asm = options.emit_asm,
15851404 .emit_llvm_ir = options.emit_llvm_ir,
15861405 .emit_llvm_bc = options.emit_llvm_bc,
......@@ -1611,7 +1430,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
16111430 .verbose_llvm_cpu_features = options.verbose_llvm_cpu_features,
16121431 .verbose_link = options.verbose_link,
16131432 .disable_c_depfile = options.disable_c_depfile,
1614 .owned_link_dir = owned_link_dir,
16151433 .color = options.color,
16161434 .reference_trace = options.reference_trace,
16171435 .formatted_panics = formatted_panics,
......@@ -1622,8 +1440,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
16221440 .debug_compiler_runtime_libs = options.debug_compiler_runtime_libs,
16231441 .debug_compile_errors = options.debug_compile_errors,
16241442 .libcxx_abi_version = options.libcxx_abi_version,
1625 .implib_emit = implib_emit,
1626 .docs_emit = docs_emit,
16271443 .root_name = root_name,
16281444 .sysroot = sysroot,
16291445 .system_libs = system_libs,
......@@ -1637,76 +1453,166 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
16371453 .no_builtin = options.no_builtin,
16381454 };
16391455
1640 if (bin_file_emit) |emit| {
1641 comp.bin_file = try link.File.open(arena, .{
1642 .comp = comp,
1643 .emit = emit,
1644 .linker_script = options.linker_script,
1645 .z_nodelete = options.linker_z_nodelete,
1646 .z_notext = options.linker_z_notext,
1647 .z_defs = options.linker_z_defs,
1648 .z_origin = options.linker_z_origin,
1649 .z_nocopyreloc = options.linker_z_nocopyreloc,
1650 .z_now = options.linker_z_now,
1651 .z_relro = options.linker_z_relro,
1652 .z_common_page_size = options.linker_z_common_page_size,
1653 .z_max_page_size = options.linker_z_max_page_size,
1654 .darwin_sdk_layout = libc_dirs.darwin_sdk_layout,
1655 .frameworks = options.frameworks,
1656 .wasi_emulated_libs = options.wasi_emulated_libs,
1657 .lib_dirs = options.lib_dirs,
1658 .rpath_list = options.rpath_list,
1659 .symbol_wrap_set = options.symbol_wrap_set,
1660 .function_sections = options.function_sections,
1661 .data_sections = options.data_sections,
1662 .allow_shlib_undefined = options.linker_allow_shlib_undefined,
1663 .bind_global_refs_locally = options.linker_bind_global_refs_locally orelse false,
1664 .compress_debug_sections = options.linker_compress_debug_sections orelse .none,
1665 .module_definition_file = options.linker_module_definition_file,
1666 .sort_section = options.linker_sort_section,
1667 .import_symbols = options.linker_import_symbols,
1668 .import_table = options.linker_import_table,
1669 .export_table = options.linker_export_table,
1670 .initial_memory = options.linker_initial_memory,
1671 .max_memory = options.linker_max_memory,
1672 .global_base = options.linker_global_base,
1673 .export_symbol_names = options.linker_export_symbol_names,
1674 .print_gc_sections = options.linker_print_gc_sections,
1675 .print_icf_sections = options.linker_print_icf_sections,
1676 .print_map = options.linker_print_map,
1677 .tsaware = options.linker_tsaware,
1678 .nxcompat = options.linker_nxcompat,
1679 .dynamicbase = options.linker_dynamicbase,
1680 .major_subsystem_version = options.major_subsystem_version,
1681 .minor_subsystem_version = options.minor_subsystem_version,
1682 .stack_size = options.stack_size,
1683 .image_base = options.image_base,
1684 .version_script = options.version_script,
1685 .gc_sections = options.linker_gc_sections,
1686 .eh_frame_hdr = link_eh_frame_hdr,
1687 .emit_relocs = options.link_emit_relocs,
1688 .rdynamic = options.rdynamic,
1689 .soname = options.soname,
1690 .compatibility_version = options.compatibility_version,
1691 .dll_export_fns = dll_export_fns,
1692 .each_lib_rpath = each_lib_rpath,
1693 .build_id = build_id,
1694 .disable_lld_caching = options.disable_lld_caching or cache_mode == .whole,
1695 .subsystem = options.subsystem,
1696 .debug_format = options.debug_format,
1697 .hash_style = options.hash_style,
1698 .enable_link_snapshots = options.enable_link_snapshots,
1699 .install_name = options.install_name,
1700 .entitlements = options.entitlements,
1701 .pagezero_size = options.pagezero_size,
1702 .headerpad_size = options.headerpad_size,
1703 .headerpad_max_install_names = options.headerpad_max_install_names,
1704 .dead_strip_dylibs = options.dead_strip_dylibs,
1705 .force_undefined_symbols = options.force_undefined_symbols,
1706 .pdb_source_path = options.pdb_source_path,
1707 .pdb_out_path = options.pdb_out_path,
1708 .entry_addr = null, // CLI does not expose this option (yet?)
1709 });
1456 const lf_open_opts: link.File.OpenOptions = .{
1457 .comp = comp,
1458 .linker_script = options.linker_script,
1459 .z_nodelete = options.linker_z_nodelete,
1460 .z_notext = options.linker_z_notext,
1461 .z_defs = options.linker_z_defs,
1462 .z_origin = options.linker_z_origin,
1463 .z_nocopyreloc = options.linker_z_nocopyreloc,
1464 .z_now = options.linker_z_now,
1465 .z_relro = options.linker_z_relro,
1466 .z_common_page_size = options.linker_z_common_page_size,
1467 .z_max_page_size = options.linker_z_max_page_size,
1468 .darwin_sdk_layout = libc_dirs.darwin_sdk_layout,
1469 .frameworks = options.frameworks,
1470 .wasi_emulated_libs = options.wasi_emulated_libs,
1471 .lib_dirs = options.lib_dirs,
1472 .rpath_list = options.rpath_list,
1473 .symbol_wrap_set = options.symbol_wrap_set,
1474 .function_sections = options.function_sections,
1475 .data_sections = options.data_sections,
1476 .allow_shlib_undefined = options.linker_allow_shlib_undefined,
1477 .bind_global_refs_locally = options.linker_bind_global_refs_locally orelse false,
1478 .compress_debug_sections = options.linker_compress_debug_sections orelse .none,
1479 .module_definition_file = options.linker_module_definition_file,
1480 .sort_section = options.linker_sort_section,
1481 .import_symbols = options.linker_import_symbols,
1482 .import_table = options.linker_import_table,
1483 .export_table = options.linker_export_table,
1484 .initial_memory = options.linker_initial_memory,
1485 .max_memory = options.linker_max_memory,
1486 .global_base = options.linker_global_base,
1487 .export_symbol_names = options.linker_export_symbol_names,
1488 .print_gc_sections = options.linker_print_gc_sections,
1489 .print_icf_sections = options.linker_print_icf_sections,
1490 .print_map = options.linker_print_map,
1491 .tsaware = options.linker_tsaware,
1492 .nxcompat = options.linker_nxcompat,
1493 .dynamicbase = options.linker_dynamicbase,
1494 .major_subsystem_version = options.major_subsystem_version,
1495 .minor_subsystem_version = options.minor_subsystem_version,
1496 .stack_size = options.stack_size,
1497 .image_base = options.image_base,
1498 .version_script = options.version_script,
1499 .gc_sections = options.linker_gc_sections,
1500 .eh_frame_hdr = link_eh_frame_hdr,
1501 .emit_relocs = options.link_emit_relocs,
1502 .rdynamic = options.rdynamic,
1503 .soname = options.soname,
1504 .compatibility_version = options.compatibility_version,
1505 .dll_export_fns = dll_export_fns,
1506 .each_lib_rpath = each_lib_rpath,
1507 .build_id = build_id,
1508 .disable_lld_caching = options.disable_lld_caching or cache_mode == .whole,
1509 .subsystem = options.subsystem,
1510 .debug_format = options.debug_format,
1511 .hash_style = options.hash_style,
1512 .enable_link_snapshots = options.enable_link_snapshots,
1513 .install_name = options.install_name,
1514 .entitlements = options.entitlements,
1515 .pagezero_size = options.pagezero_size,
1516 .headerpad_size = options.headerpad_size,
1517 .headerpad_max_install_names = options.headerpad_max_install_names,
1518 .dead_strip_dylibs = options.dead_strip_dylibs,
1519 .force_undefined_symbols = options.force_undefined_symbols,
1520 .pdb_source_path = options.pdb_source_path,
1521 .pdb_out_path = options.pdb_out_path,
1522 .entry_addr = null, // CLI does not expose this option (yet?)
1523 };
1524
1525 switch (cache_mode) {
1526 .incremental => {
1527 // Options that are specific to zig source files, that cannot be
1528 // modified between incremental updates.
1529 var hash = cache.hash;
1530
1531 // Synchronize with other matching comments: ZigOnlyHashStuff
1532 hash.add(use_llvm);
1533 hash.add(options.config.use_lib_llvm);
1534 hash.add(dll_export_fns);
1535 hash.add(options.config.is_test);
1536 hash.add(options.config.test_evented_io);
1537 hash.addOptionalBytes(options.test_filter);
1538 hash.addOptionalBytes(options.test_name_prefix);
1539 hash.add(options.skip_linker_dependencies);
1540 hash.add(formatted_panics);
1541 hash.add(options.emit_h != null);
1542 hash.add(error_limit);
1543
1544 // Here we put the root source file path name, but *not* with addFile.
1545 // We want the hash to be the same regardless of the contents of the
1546 // source file, because incremental compilation will handle it, but we
1547 // do want to namespace different source file names because they are
1548 // likely different compilations and therefore this would be likely to
1549 // cause cache hits.
1550 try addModuleTableToCacheHash(gpa, arena, &hash, options.root_mod, .path_bytes);
1551
1552 // In the case of incremental cache mode, this `artifact_directory`
1553 // is computed based on a hash of non-linker inputs, and it is where all
1554 // build artifacts are stored (even while in-progress).
1555 const digest = hash.final();
1556 const artifact_sub_dir = "o" ++ std.fs.path.sep_str ++ digest;
1557 var artifact_dir = try options.local_cache_directory.handle.makeOpenPath(artifact_sub_dir, .{});
1558 errdefer artifact_dir.close();
1559 const artifact_directory: Directory = .{
1560 .handle = artifact_dir,
1561 .path = try options.local_cache_directory.join(arena, &[_][]const u8{artifact_sub_dir}),
1562 };
1563
1564 const incremental = try arena.create(CacheUse.Incremental);
1565 incremental.* = .{
1566 .artifact_directory = artifact_directory,
1567 };
1568 comp.cache_use = .{ .incremental = incremental };
1569
1570 if (options.emit_bin) |emit_bin| {
1571 const emit: Emit = .{
1572 .directory = emit_bin.directory orelse artifact_directory,
1573 .sub_path = emit_bin.basename,
1574 };
1575 comp.bin_file = try link.File.open(arena, emit, lf_open_opts);
1576 }
1577
1578 if (options.implib_emit) |emit_implib| {
1579 comp.implib_emit = .{
1580 .directory = emit_implib.directory orelse artifact_directory,
1581 .sub_path = emit_implib.basename,
1582 };
1583 }
1584
1585 if (options.docs_emit) |emit_docs| {
1586 comp.docs_emit = .{
1587 .directory = emit_docs.directory orelse artifact_directory,
1588 .sub_path = emit_docs.basename,
1589 };
1590 }
1591 },
1592 .whole => {
1593 // For whole cache mode, we don't know where to put outputs from
1594 // the linker until the final cache hash, which is available after
1595 // the compilation is complete.
1596 //
1597 // Therefore, bin_file is left null until the beginning of update(),
1598 // where it may find a cache hit, or use a temporary directory to
1599 // hold output artifacts.
1600 const whole = try arena.create(CacheUse.Whole);
1601 whole.* = .{
1602 // This is kept here so that link.File.open can be called later.
1603 .lf_open_opts = lf_open_opts,
1604 // This is so that when doing `CacheMode.whole`, the mechanism in update()
1605 // can use it for communicating the result directory via `bin_file.emit`.
1606 // This is used to distinguish between -fno-emit-bin and -femit-bin
1607 // for `CacheMode.whole`.
1608 // This memory will be overwritten with the real digest in update() but
1609 // the basename will be preserved.
1610 .bin_sub_path = try prepareWholeEmitSubPath(arena, options.emit_bin),
1611 .implib_sub_path = try prepareWholeEmitSubPath(arena, options.emit_implib),
1612 .docs_sub_path = try prepareWholeEmitSubPath(arena, options.emit_docs),
1613 };
1614 comp.cache_use = .{ .whole = whole };
1615 },
17101616 }
17111617
17121618 break :comp comp;
......@@ -1981,7 +1887,6 @@ pub fn destroy(self: *Compilation) void {
19811887 self.clearMiscFailures();
19821888
19831889 self.cache_parent.manifest_dir.close();
1984 if (self.owned_link_dir) |*dir| dir.close();
19851890
19861891 // This destroys `self`.
19871892 var arena_instance = self.arena;
......@@ -2001,30 +1906,6 @@ pub fn getTarget(self: Compilation) Target {
20011906 return self.root_mod.resolved_target.result;
20021907}
20031908
2004fn restorePrevZigCacheArtifactDirectory(comp: *Compilation, directory: *Directory) void {
2005 if (directory.path) |p| comp.gpa.free(p);
2006
2007 // Restore the Module's previous zig_cache_artifact_directory
2008 // This is only for cleanup purposes; Module.deinit calls close
2009 // on the handle of zig_cache_artifact_directory.
2010 if (comp.module) |module| {
2011 const builtin_mod = module.main_mod.deps.get("builtin").?;
2012 module.zig_cache_artifact_directory = builtin_mod.root.root_dir;
2013 }
2014}
2015
2016fn cleanupTmpArtifactDirectory(
2017 comp: *Compilation,
2018 tmp_artifact_directory: *?Directory,
2019 tmp_dir_sub_path: []const u8,
2020) void {
2021 comp.gpa.free(tmp_dir_sub_path);
2022 if (tmp_artifact_directory.*) |*directory| {
2023 directory.handle.close();
2024 restorePrevZigCacheArtifactDirectory(comp, directory);
2025 }
2026}
2027
20281909pub fn hotCodeSwap(comp: *Compilation, prog_node: *std.Progress.Node, pid: std.ChildProcess.Id) !void {
20291910 comp.bin_file.child_pid = pid;
20301911 try comp.makeBinFileWritable();
......@@ -2032,6 +1913,27 @@ pub fn hotCodeSwap(comp: *Compilation, prog_node: *std.Progress.Node, pid: std.C
20321913 try comp.makeBinFileExecutable();
20331914}
20341915
1916fn cleanupAfterUpdate(comp: *Compilation) void {
1917 switch (comp) {
1918 .incremental => return,
1919 .whole => |whole| {
1920 if (whole.cache_manifest) |man| {
1921 man.deinit();
1922 whole.cache_manifest = null;
1923 }
1924 if (comp.bin_file) |lf| {
1925 lf.destroy();
1926 comp.bin_file = null;
1927 }
1928 if (whole.tmp_artifact_directory) |directory| {
1929 directory.handle.close();
1930 if (directory.path) |p| comp.gpa.free(p);
1931 whole.tmp_artifact_directory = null;
1932 }
1933 },
1934 }
1935}
1936
20351937/// Detect changes to source files, perform semantic analysis, and update the output files.
20361938pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void {
20371939 const tracy_trace = trace(@src());
......@@ -2041,92 +1943,91 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void
20411943 comp.last_update_was_cache_hit = false;
20421944
20431945 var man: Cache.Manifest = undefined;
2044 defer if (comp.whole_cache_manifest != null) man.deinit();
1946 defer cleanupAfterUpdate(comp);
20451947
2046 var tmp_dir_sub_path: []const u8 = &.{};
2047 var tmp_artifact_directory: ?Directory = null;
2048 defer cleanupTmpArtifactDirectory(comp, &tmp_artifact_directory, tmp_dir_sub_path);
1948 var tmp_dir_rand_int: u64 = undefined;
20491949
20501950 // If using the whole caching strategy, we check for *everything* up front, including
20511951 // C source files.
2052 if (comp.cache_mode == .whole) {
2053 // We are about to obtain this lock, so here we give other processes a chance first.
2054 if (comp.bin_file) |lf| lf.releaseLock();
2055
2056 man = comp.cache_parent.obtain();
2057 comp.whole_cache_manifest = &man;
2058 try comp.addNonIncrementalStuffToCacheManifest(&man);
2059
2060 const is_hit = man.hit() catch |err| {
2061 // TODO properly bubble these up instead of emitting a warning
2062 const i = man.failed_file_index orelse return err;
2063 const pp = man.files.items[i].prefixed_path orelse return err;
2064 const prefix = man.cache.prefixes()[pp.prefix].path orelse "";
2065 std.log.warn("{s}: {s}{s}", .{ @errorName(err), prefix, pp.sub_path });
2066 return err;
2067 };
2068 if (is_hit) {
2069 comp.last_update_was_cache_hit = true;
2070 log.debug("CacheMode.whole cache hit for {s}", .{comp.root_name});
2071 const digest = man.final();
2072
2073 comp.wholeCacheModeSetBinFilePath(&digest);
1952 switch (comp.cache_use) {
1953 .whole => |whole| {
1954 // We are about to obtain this lock, so here we give other processes a chance first.
1955 assert(comp.bin_file == null);
1956
1957 man = comp.cache_parent.obtain();
1958 whole.cache_manifest = &man;
1959 try comp.addNonIncrementalStuffToCacheManifest(&man);
1960
1961 const is_hit = man.hit() catch |err| {
1962 // TODO properly bubble these up instead of emitting a warning
1963 const i = man.failed_file_index orelse return err;
1964 const pp = man.files.items[i].prefixed_path orelse return err;
1965 const prefix = man.cache.prefixes()[pp.prefix].path orelse "";
1966 std.log.warn("{s}: {s}{s}", .{ @errorName(err), prefix, pp.sub_path });
1967 return err;
1968 };
1969 if (is_hit) {
1970 comp.last_update_was_cache_hit = true;
1971 log.debug("CacheMode.whole cache hit for {s}", .{comp.root_name});
1972 const digest = man.final();
20741973
2075 assert(comp.bin_file.lock == null);
2076 comp.bin_file.lock = man.toOwnedLock();
2077 return;
2078 }
2079 log.debug("CacheMode.whole cache miss for {s}", .{comp.root_name});
1974 comp.wholeCacheModeSetBinFilePath(&digest);
20801975
2081 // Initialize `bin_file.emit` with a temporary Directory so that compilation can
2082 // continue on the same path as incremental, using the temporary Directory.
2083 tmp_artifact_directory = d: {
2084 const s = std.fs.path.sep_str;
2085 const rand_int = std.crypto.random.int(u64);
1976 assert(comp.bin_file.lock == null);
1977 comp.bin_file.lock = man.toOwnedLock();
1978 return;
1979 }
1980 log.debug("CacheMode.whole cache miss for {s}", .{comp.root_name});
20861981
2087 tmp_dir_sub_path = try std.fmt.allocPrint(comp.gpa, "tmp" ++ s ++ "{x}", .{rand_int});
1982 // Compile the artifacts to a temporary directory.
1983 const tmp_artifact_directory = d: {
1984 const s = std.fs.path.sep_str;
1985 tmp_dir_rand_int = std.crypto.random.int(u64);
1986 const tmp_dir_sub_path = "tmp" ++ s ++ Package.Manifest.hex64(tmp_dir_rand_int);
20881987
2089 const path = try comp.local_cache_directory.join(comp.gpa, &.{tmp_dir_sub_path});
2090 errdefer comp.gpa.free(path);
1988 const path = try comp.local_cache_directory.join(comp.gpa, &.{tmp_dir_sub_path});
1989 errdefer comp.gpa.free(path);
20911990
2092 const handle = try comp.local_cache_directory.handle.makeOpenPath(tmp_dir_sub_path, .{});
2093 errdefer handle.close();
1991 const handle = try comp.local_cache_directory.handle.makeOpenPath(tmp_dir_sub_path, .{});
1992 errdefer handle.close();
20941993
2095 break :d .{
2096 .path = path,
2097 .handle = handle,
1994 break :d .{
1995 .path = path,
1996 .handle = handle,
1997 };
20981998 };
2099 };
1999 whole.tmp_artifact_directory = tmp_artifact_directory;
21002000
2101 // This updates the output directory for linker outputs.
2102 if (comp.module) |module| {
2103 module.zig_cache_artifact_directory = tmp_artifact_directory.?;
2104 }
2001 // Now that the directory is known, it is time to create the Emit
2002 // objects and call link.File.open.
21052003
2106 // This resets the link.File to operate as if we called openPath() in create()
2107 // instead of simulating -fno-emit-bin.
2108 var options = comp.bin_file.options.move();
2109 if (comp.whole_bin_sub_path) |sub_path| {
2110 options.emit = .{
2111 .directory = tmp_artifact_directory.?,
2112 .sub_path = std.fs.path.basename(sub_path),
2113 };
2114 }
2115 if (comp.whole_implib_sub_path) |sub_path| {
2116 options.implib_emit = .{
2117 .directory = tmp_artifact_directory.?,
2118 .sub_path = std.fs.path.basename(sub_path),
2119 };
2120 }
2121 if (comp.whole_docs_sub_path) |sub_path| {
2122 options.docs_emit = .{
2123 .directory = tmp_artifact_directory.?,
2124 .sub_path = std.fs.path.basename(sub_path),
2125 };
2126 }
2127 var old_bin_file = comp.bin_file;
2128 comp.bin_file = try link.File.openPath(comp.gpa, options);
2129 old_bin_file.destroy();
2004 if (comp.whole_implib_sub_path) |sub_path| {
2005 comp.implib_emit = .{
2006 .directory = tmp_artifact_directory,
2007 .sub_path = std.fs.path.basename(sub_path),
2008 };
2009 }
2010
2011 if (comp.whole_docs_sub_path) |sub_path| {
2012 comp.docs_emit = .{
2013 .directory = tmp_artifact_directory,
2014 .sub_path = std.fs.path.basename(sub_path),
2015 };
2016 }
2017
2018 if (comp.whole_bin_sub_path) |sub_path| {
2019 const emit: Emit = .{
2020 .directory = tmp_artifact_directory,
2021 .sub_path = std.fs.path.basename(sub_path),
2022 };
2023 // It's a bit strange to use the Compilation arena allocator here
2024 // but in practice it won't leak much and usually whole cache mode
2025 // will be combined with exactly one call to update().
2026 const arena = comp.arena.allocator();
2027 comp.bin_file = try link.File.open(arena, emit, whole.lf_open_opts);
2028 }
2029 },
2030 .incremental => {},
21302031 }
21312032
21322033 // For compiling C objects, we rely on the cache hash system to avoid duplicating work.
......@@ -2231,80 +2132,43 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void
22312132 // Flush takes care of -femit-bin, but we still have -femit-llvm-ir, -femit-llvm-bc, and
22322133 // -femit-asm to handle, in the case of C objects.
22332134 comp.emitOthers();
2135 try comp.flush(main_progress_node);
2136 if (comp.totalErrorCount() != 0) return;
2137 try maybeGenerateAutodocs(comp, main_progress_node);
22342138
2235 if (comp.whole_cache_manifest != null) {
2236 const digest = man.final();
2237
2238 // Rename the temporary directory into place.
2239 var directory = tmp_artifact_directory.?;
2240 tmp_artifact_directory = null;
2241
2242 directory.handle.close();
2243 defer restorePrevZigCacheArtifactDirectory(comp, &directory);
2244
2245 const o_sub_path = try std.fs.path.join(comp.gpa, &[_][]const u8{ "o", &digest });
2246 defer comp.gpa.free(o_sub_path);
2247
2248 // Work around windows `AccessDenied` if any files within this directory are open
2249 // by closing and reopening the file handles.
2250 const need_writable_dance = builtin.os.tag == .windows and comp.bin_file.file != null;
2251 if (need_writable_dance) {
2252 // We cannot just call `makeExecutable` as it makes a false assumption that we have a
2253 // file handle open only when linking an executable file. This used to be true when
2254 // our linkers were incapable of emitting relocatables and static archive. Now that
2255 // they are capable, we need to unconditionally close the file handle and re-open it
2256 // in the follow up call to `makeWritable`.
2257 comp.bin_file.file.?.close();
2258 comp.bin_file.file = null;
2259 }
2260
2261 try comp.bin_file.renameTmpIntoCache(comp.local_cache_directory, tmp_dir_sub_path, o_sub_path);
2262 comp.wholeCacheModeSetBinFilePath(&digest);
2139 switch (comp.cache_use) {
2140 .whole => |whole| {
2141 const digest = man.final();
22632142
2264 // Has to be after the `wholeCacheModeSetBinFilePath` above.
2265 if (need_writable_dance) {
2266 try comp.bin_file.makeWritable();
2267 }
2143 // Rename the temporary directory into place.
2144 // Close tmp dir and link.File to avoid open handle during rename.
2145 if (whole.tmp_artifact_directory) |tmp_directory| {
2146 tmp_directory.handle.close();
2147 if (tmp_directory.path) |p| comp.gpa.free(p);
2148 whole.tmp_artifact_directory = null;
2149 } else unreachable;
2150
2151 if (comp.bin_file) |lf| {
2152 lf.destroy();
2153 comp.bin_file = null;
2154 }
22682155
2269 // This is intentionally sandwiched between renameTmpIntoCache() and writeManifest().
2270 if (comp.module) |module| {
2271 // We need to set the zig_cache_artifact_directory for -femit-asm, -femit-llvm-ir,
2272 // etc to know where to output to.
2273 var artifact_dir = try comp.local_cache_directory.handle.openDir(o_sub_path, .{});
2274 defer artifact_dir.close();
2156 const s = std.fs.path.sep_str;
2157 const tmp_dir_sub_path = "tmp" ++ s ++ Package.Manifest.hex64(tmp_dir_rand_int);
2158 const o_sub_path = "o" ++ s ++ digest;
22752159
2276 const dir_path = try comp.local_cache_directory.join(comp.gpa, &.{o_sub_path});
2277 defer comp.gpa.free(dir_path);
2160 try renameTmpIntoCache(comp.local_cache_directory, tmp_dir_sub_path, o_sub_path);
2161 comp.wholeCacheModeSetBinFilePath(&digest);
22782162
2279 module.zig_cache_artifact_directory = .{
2280 .handle = artifact_dir,
2281 .path = dir_path,
2163 // Failure here only means an unnecessary cache miss.
2164 man.writeManifest() catch |err| {
2165 log.warn("failed to write cache manifest: {s}", .{@errorName(err)});
22822166 };
22832167
2284 try comp.flush(main_progress_node);
2285 if (comp.totalErrorCount() != 0) return;
2286
2287 // Note the placement of this logic is relying on the call to
2288 // `wholeCacheModeSetBinFilePath` above.
2289 try maybeGenerateAutodocs(comp, main_progress_node);
2290 } else {
2291 try comp.flush(main_progress_node);
2292 if (comp.totalErrorCount() != 0) return;
2293 }
2294
2295 // Failure here only means an unnecessary cache miss.
2296 man.writeManifest() catch |err| {
2297 log.warn("failed to write cache manifest: {s}", .{@errorName(err)});
2298 };
2299
2300 assert(comp.bin_file.lock == null);
2301 comp.bin_file.lock = man.toOwnedLock();
2302 } else {
2303 try comp.flush(main_progress_node);
2304
2305 if (comp.totalErrorCount() == 0) {
2306 try maybeGenerateAutodocs(comp, main_progress_node);
2307 }
2168 assert(comp.bin_file.lock == null);
2169 comp.bin_file.lock = man.toOwnedLock();
2170 },
2171 .incremental => {},
23082172 }
23092173
23102174 // Unload all source files to save memory.
......@@ -2321,6 +2185,60 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void
23212185 }
23222186}
23232187
2188/// This function is called by the frontend before flush(). It communicates that
2189/// `options.bin_file.emit` directory needs to be renamed from
2190/// `[zig-cache]/tmp/[random]` to `[zig-cache]/o/[digest]`.
2191/// The frontend would like to simply perform a file system rename, however,
2192/// some linker backends care about the file paths of the objects they are linking.
2193/// So this function call tells linker backends to rename the paths of object files
2194/// to observe the new directory path.
2195/// Linker backends which do not have this requirement can fall back to the simple
2196/// implementation at the bottom of this function.
2197/// This function is only called when CacheMode is `whole`.
2198fn renameTmpIntoCache(
2199 cache_directory: Compilation.Directory,
2200 tmp_dir_sub_path: []const u8,
2201 o_sub_path: []const u8,
2202) !void {
2203 while (true) {
2204 if (builtin.os.tag == .windows) {
2205 // Work around windows `renameW` can't fail with `PathAlreadyExists`
2206 // See https://github.com/ziglang/zig/issues/8362
2207 if (cache_directory.handle.access(o_sub_path, .{})) |_| {
2208 try cache_directory.handle.deleteTree(o_sub_path);
2209 continue;
2210 } else |err| switch (err) {
2211 error.FileNotFound => {},
2212 else => |e| return e,
2213 }
2214 std.fs.rename(
2215 cache_directory.handle,
2216 tmp_dir_sub_path,
2217 cache_directory.handle,
2218 o_sub_path,
2219 ) catch |err| {
2220 log.err("unable to rename cache dir {s} to {s}: {s}", .{ tmp_dir_sub_path, o_sub_path, @errorName(err) });
2221 return err;
2222 };
2223 break;
2224 } else {
2225 std.fs.rename(
2226 cache_directory.handle,
2227 tmp_dir_sub_path,
2228 cache_directory.handle,
2229 o_sub_path,
2230 ) catch |err| switch (err) {
2231 error.PathAlreadyExists => {
2232 try cache_directory.handle.deleteTree(o_sub_path);
2233 continue;
2234 },
2235 else => |e| return e,
2236 };
2237 break;
2238 }
2239 }
2240}
2241
23242242fn maybeGenerateAutodocs(comp: *Compilation, prog_node: *std.Progress.Node) !void {
23252243 const mod = comp.module orelse return;
23262244 // TODO: do this in a separate job during performAllTheWork(). The
......@@ -2362,7 +2280,7 @@ fn wholeCacheModeSetBinFilePath(comp: *Compilation, digest: *const [Cache.hex_di
23622280 if (comp.whole_bin_sub_path) |sub_path| {
23632281 @memcpy(sub_path[digest_start..][0..digest.len], digest);
23642282
2365 comp.bin_file.options.emit = .{
2283 comp.bin_file.?.emit = .{
23662284 .directory = comp.local_cache_directory,
23672285 .sub_path = sub_path,
23682286 };
......@@ -2371,7 +2289,7 @@ fn wholeCacheModeSetBinFilePath(comp: *Compilation, digest: *const [Cache.hex_di
23712289 if (comp.whole_implib_sub_path) |sub_path| {
23722290 @memcpy(sub_path[digest_start..][0..digest.len], digest);
23732291
2374 comp.bin_file.options.implib_emit = .{
2292 comp.implib_emit = .{
23752293 .directory = comp.local_cache_directory,
23762294 .sub_path = sub_path,
23772295 };
......@@ -2380,7 +2298,7 @@ fn wholeCacheModeSetBinFilePath(comp: *Compilation, digest: *const [Cache.hex_di
23802298 if (comp.whole_docs_sub_path) |sub_path| {
23812299 @memcpy(sub_path[digest_start..][0..digest.len], digest);
23822300
2383 comp.bin_file.options.docs_emit = .{
2301 comp.docs_emit = .{
23842302 .directory = comp.local_cache_directory,
23852303 .sub_path = sub_path,
23862304 };
src/Module.zig-3
......@@ -52,8 +52,6 @@ comptime {
5252gpa: Allocator,
5353comp: *Compilation,
5454
55/// Where build artifacts and incremental compilation metadata serialization go.
56zig_cache_artifact_directory: Compilation.Directory,
5755/// Pointer to externally managed resource.
5856root_mod: *Package.Module,
5957/// Normally, `main_mod` and `root_mod` are the same. The exception is `zig test`, in which
......@@ -2508,7 +2506,6 @@ pub fn deinit(mod: *Module) void {
25082506 emit_h.failed_decls.deinit(gpa);
25092507 emit_h.decl_table.deinit(gpa);
25102508 emit_h.allocated_emit_h.deinit(gpa);
2511 gpa.destroy(emit_h);
25122509 }
25132510
25142511 for (mod.failed_files.values()) |value| {
src/link.zig-63
......@@ -32,8 +32,6 @@ pub const SystemLib = struct {
3232 path: ?[]const u8,
3333};
3434
35pub const CacheMode = enum { incremental, whole };
36
3735pub fn hashAddSystemLibs(
3836 man: *Cache.Manifest,
3937 hm: std.StringArrayHashMapUnmanaged(SystemLib),
......@@ -776,67 +774,6 @@ pub const File = struct {
776774 }
777775 }
778776
779 /// This function is called by the frontend before flush(). It communicates that
780 /// `options.bin_file.emit` directory needs to be renamed from
781 /// `[zig-cache]/tmp/[random]` to `[zig-cache]/o/[digest]`.
782 /// The frontend would like to simply perform a file system rename, however,
783 /// some linker backends care about the file paths of the objects they are linking.
784 /// So this function call tells linker backends to rename the paths of object files
785 /// to observe the new directory path.
786 /// Linker backends which do not have this requirement can fall back to the simple
787 /// implementation at the bottom of this function.
788 /// This function is only called when CacheMode is `whole`.
789 pub fn renameTmpIntoCache(
790 base: *File,
791 cache_directory: Compilation.Directory,
792 tmp_dir_sub_path: []const u8,
793 o_sub_path: []const u8,
794 ) !void {
795 // So far, none of the linker backends need to respond to this event, however,
796 // it makes sense that they might want to. So we leave this mechanism here
797 // for now. Once the linker backends get more mature, if it turns out this
798 // is not needed we can refactor this into having the frontend do the rename
799 // directly, and remove this function from link.zig.
800 _ = base;
801 while (true) {
802 if (builtin.os.tag == .windows) {
803 // Work around windows `renameW` can't fail with `PathAlreadyExists`
804 // See https://github.com/ziglang/zig/issues/8362
805 if (cache_directory.handle.access(o_sub_path, .{})) |_| {
806 try cache_directory.handle.deleteTree(o_sub_path);
807 continue;
808 } else |err| switch (err) {
809 error.FileNotFound => {},
810 else => |e| return e,
811 }
812 std.fs.rename(
813 cache_directory.handle,
814 tmp_dir_sub_path,
815 cache_directory.handle,
816 o_sub_path,
817 ) catch |err| {
818 log.err("unable to rename cache dir {s} to {s}: {s}", .{ tmp_dir_sub_path, o_sub_path, @errorName(err) });
819 return err;
820 };
821 break;
822 } else {
823 std.fs.rename(
824 cache_directory.handle,
825 tmp_dir_sub_path,
826 cache_directory.handle,
827 o_sub_path,
828 ) catch |err| switch (err) {
829 error.PathAlreadyExists => {
830 try cache_directory.handle.deleteTree(o_sub_path);
831 continue;
832 },
833 else => |e| return e,
834 };
835 break;
836 }
837 }
838 }
839
840777 pub fn linkAsArchive(base: *File, comp: *Compilation, prog_node: *std.Progress.Node) FlushError!void {
841778 const tracy = trace(@src());
842779 defer tracy.end();