aboutsummaryrefslogtreecommitdiff
path: root/src/link
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-12-29 20:49:16 -0700
committerAndrew Kelley <andrew@ziglang.org>2022-01-02 13:16:17 -0700
commite3bed8d81dfd7198dd4c496f19a6791e27e41f26 (patch)
tree51703dcbdd51c21207c282585345c2b081cb57b8 /src/link
parentc710d5eefe3f83226f1651947239730e77af43cb (diff)
downloadzig-e3bed8d81dfd7198dd4c496f19a6791e27e41f26.tar.gz
zig-e3bed8d81dfd7198dd4c496f19a6791e27e41f26.zip
stage2: introduce CacheMode
The two CacheMode values are `whole` and `incremental`. `incremental` is what we had before; `whole` is new. Whole cache mode uses everything as inputs to the cache hash; and when a hit occurs it skips everything including linking. This is ideal for when source files change rarely and for backends that do not have good incremental compilation support, for example compiler-rt or libc compiled with LLVM with optimizations on. This is the main motivation for the additional mode, so that we can have LLVM-optimized compiler-rt/libc builds, without waiting for the LLVM backend every single time Zig is invoked. Incremental cache mode hashes only the input file path and a few target options, intentionally relying on collisions to locate already-existing build artifacts which can then be incrementally updated. The bespoke logic for caching stage1 backend build artifacts is removed since we now have a global caching mechanism for when we want to cache the entire compilation, *including* linking. Previously we had to get "creative" with libs.txt and a special byte in the hash id to communicate flags, so that when the cached artifacts were re-linked, we had this information from stage1 even though we didn't actually run it. Now that `CacheMode.whole` includes linking, this extra information does not need to be preserved for cache hits. So although this changeset introduces complexity, it also removes complexity. The main trickiness here comes from the inherent differences between the two modes: `incremental` wants a directory immediately to operate on, while `whole` doesn't know the output directory until the compilation is complete. This commit deals with this problem mostly inside `update()`, where, on a cache miss, it replaces `zig_cache_artifact_directory` with a temporary directory, and then renames it into place once the compilation is complete. Items remaining before this branch can be merged: * [ ] make sure these things make it into the cache manifest: - @import files - @embedFile files - we already add dep files from c but make sure the main .c files make it in there too, not just the included files * [ ] double check that the emit paths of other things besides the binary are working correctly. * [ ] test `-fno-emit-bin` + `-fstage1` * [ ] test `-femit-bin=foo` + `-fstage1` * [ ] implib emit directory copies bin_file_emit directory in create() and needs to be adjusted to be overridden as well. * [ ] make sure emit-h is handled correctly in the cache hash * [ ] Cache: detect duplicate files added to the manifest Some preliminary performance measurements of wall clock time and peak RSS used: stage1 behavior (1077 tests), llvm backend, release build: * cold global cache: 4.6s, 1.1 GiB * warm global cache: 3.4s, 980 MiB stage2 master branch behavior (575 tests), llvm backend, release build: * cold global cache: 0.62s, 191 MiB * warm global cache: 0.40s, 128 MiB stage2 this branch behavior (575 tests), llvm backend, release build: * cold global cache: 0.62s, 179 MiB * warm global cache: 0.27s, 90 MiB
Diffstat (limited to 'src/link')
-rw-r--r--src/link/Coff.zig2
-rw-r--r--src/link/Elf.zig2
-rw-r--r--src/link/MachO.zig2
-rw-r--r--src/link/Wasm.zig2
4 files changed, 8 insertions, 0 deletions
diff --git a/src/link/Coff.zig b/src/link/Coff.zig
index 2445b11caf..e6788120a0 100644
--- a/src/link/Coff.zig
+++ b/src/link/Coff.zig
@@ -920,6 +920,8 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void {
man = comp.cache_parent.obtain();
self.base.releaseLock();
+ comptime assert(Compilation.link_hash_implementation_version == 1);
+
try man.addListOfFiles(self.base.options.objects);
for (comp.c_object_table.keys()) |key| {
_ = try man.addFile(key.status.success.object_path, null);
diff --git a/src/link/Elf.zig b/src/link/Elf.zig
index 992332be36..5f3771a3cb 100644
--- a/src/link/Elf.zig
+++ b/src/link/Elf.zig
@@ -1357,6 +1357,8 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
// We are about to obtain this lock, so here we give other processes a chance first.
self.base.releaseLock();
+ comptime assert(Compilation.link_hash_implementation_version == 1);
+
try man.addOptionalFile(self.base.options.linker_script);
try man.addOptionalFile(self.base.options.version_script);
try man.addListOfFiles(self.base.options.objects);
diff --git a/src/link/MachO.zig b/src/link/MachO.zig
index 7dc6c52372..f970ffb5f2 100644
--- a/src/link/MachO.zig
+++ b/src/link/MachO.zig
@@ -466,6 +466,8 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
// We are about to obtain this lock, so here we give other processes a chance first.
self.base.releaseLock();
+ comptime assert(Compilation.link_hash_implementation_version == 1);
+
try man.addListOfFiles(self.base.options.objects);
for (comp.c_object_table.keys()) |key| {
_ = try man.addFile(key.status.success.object_path, null);
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig
index 1ae50e8e33..5f8f48d1b1 100644
--- a/src/link/Wasm.zig
+++ b/src/link/Wasm.zig
@@ -1094,6 +1094,8 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
// We are about to obtain this lock, so here we give other processes a chance first.
self.base.releaseLock();
+ comptime assert(Compilation.link_hash_implementation_version == 1);
+
try man.addListOfFiles(self.base.options.objects);
for (comp.c_object_table.keys()) |key| {
_ = try man.addFile(key.status.success.object_path, null);