authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-25 18:01:35-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-25 18:01:35-07:00
log70d7d7e919d7f297e63ca421f6be5925259136e2
tree1635b864f21a78a8d273fa9a946191a8b9796e8b
parent670e7d456c24a8597af6b3809bf1e9ea68746ade

stage2: disable lld caching when output dir is owned by user

Normally when using LLD to link, Zig uses a file named "lld.id" in the same directory as the output binary which contains the hash of the link operation, allowing Zig to skip linking when the hash would be unchanged. In the case that the output binary is being emitted into a directory which is externally modified - essentially anything other than zig-cache - then this flag would be set to disable this machinery to avoid false positives. * Better defaults when using -fno-LLVM * Fix compiler_rt and libc static libraries were getting a .zig extension instead of .a extension. * when using the stage1 backend, put the object file next to the stage1.id file in the cache directory. this prevents an object file from polluting the cwd when using zig from the CLI.

5 files changed, 149 insertions(+), 120 deletions(-)

BRANCH_TODO+5-6
...@@ -1,7 +1,6 @@...@@ -1,7 +1,6 @@
1 * make sure that `zig cc -o hello hello.c -target native-native-musl` and `zig build-exe hello.zig -lc -target native-native-musl` will share the same libc build.
2 * zig cc as a preprocessor (-E)
1 * tests passing with -Dskip-non-native3 * tests passing with -Dskip-non-native
2 * make sure zig cc works
3 - using it as a preprocessor (-E)
4 - try building some software
5 * `-ftime-report`4 * `-ftime-report`
6 * -fstack-report print stack size diagnostics\n"5 * -fstack-report print stack size diagnostics\n"
7 * -fdump-analysis write analysis.json file with type information\n"6 * -fdump-analysis write analysis.json file with type information\n"
...@@ -15,14 +14,12 @@...@@ -15,14 +14,12 @@
15 * MachO LLD linking14 * MachO LLD linking
16 * COFF LLD linking15 * COFF LLD linking
17 * WASM LLD linking16 * WASM LLD linking
18 * skip LLD caching when bin directory is not in the cache (so we don't put `id.txt` into the cwd)
19 (maybe make it an explicit option and have main.zig disable it)
20 - make sure that `zig cc -o hello hello.c -target native-native-musl` and `zig build-exe hello.zig -lc -target native-native-musl` will share the same libc build.
21 * audit the CLI options for stage217 * audit the CLI options for stage2
22 * audit the base cache hash18 * audit the base cache hash
23 * On operating systems that support it, do an execve for `zig test` and `zig run` rather than child process.19 * On operating systems that support it, do an execve for `zig test` and `zig run` rather than child process.
24 * restore error messages for stage2_add_link_lib20 * restore error messages for stage2_add_link_lib
25 * windows CUSTOMBUILD : error : unable to build compiler_rt: FileNotFound [D:\a\1\s\build\zig_install_lib_files.vcxproj]21 * windows CUSTOMBUILD : error : unable to build compiler_rt: FileNotFound [D:\a\1\s\build\zig_install_lib_files.vcxproj]
22 * try building some software with zig cc
2623
27 * implement proper parsing of clang stderr/stdout and exposing compile errors with the Compilation API24 * implement proper parsing of clang stderr/stdout and exposing compile errors with the Compilation API
28 * implement proper parsing of LLD stderr/stdout and exposing compile errors with the Compilation API25 * implement proper parsing of LLD stderr/stdout and exposing compile errors with the Compilation API
...@@ -59,3 +56,5 @@...@@ -59,3 +56,5 @@
59 * close the --pkg-begin --pkg-end Package directory handles56 * close the --pkg-begin --pkg-end Package directory handles
60 * make std.Progress support multithreaded57 * make std.Progress support multithreaded
61 * update musl.zig static data to use native path separator in static data rather than replacing '/' at runtime58 * update musl.zig static data to use native path separator in static data rather than replacing '/' at runtime
59 * linking hello world with LLD, lld is silently calling exit(1) instead of reporting ok=false. when run standalone the error message is: ld.lld: error: section [index 3] has a sh_offset (0x57000) + sh_size (0x68) that is greater than the file size (0x57060)
60
src/Compilation.zig+51-33
...@@ -3,10 +3,11 @@ const Compilation = @This();...@@ -3,10 +3,11 @@ const Compilation = @This();
3const std = @import("std");3const std = @import("std");
4const mem = std.mem;4const mem = std.mem;
5const Allocator = std.mem.Allocator;5const Allocator = std.mem.Allocator;
6const Value = @import("value.zig").Value;
7const assert = std.debug.assert;6const assert = std.debug.assert;
8const log = std.log.scoped(.compilation);7const log = std.log.scoped(.compilation);
9const Target = std.Target;8const Target = std.Target;
9
10const Value = @import("value.zig").Value;
10const target_util = @import("target.zig");11const target_util = @import("target.zig");
11const Package = @import("Package.zig");12const Package = @import("Package.zig");
12const link = @import("link.zig");13const link = @import("link.zig");
...@@ -286,6 +287,13 @@ pub const InitOptions = struct {...@@ -286,6 +287,13 @@ pub const InitOptions = struct {
286 emit_h: ?EmitLoc = null,287 emit_h: ?EmitLoc = null,
287 link_mode: ?std.builtin.LinkMode = null,288 link_mode: ?std.builtin.LinkMode = null,
288 dll_export_fns: ?bool = false,289 dll_export_fns: ?bool = false,
290 /// Normally when using LLD to link, Zig uses a file named "lld.id" in the
291 /// same directory as the output binary which contains the hash of the link
292 /// operation, allowing Zig to skip linking when the hash would be unchanged.
293 /// In the case that the output binary is being emitted into a directory which
294 /// is externally modified - essentially anything other than zig-cache - then
295 /// this flag would be set to disable this machinery to avoid false positives.
296 disable_lld_caching: bool = false,
289 object_format: ?std.builtin.ObjectFormat = null,297 object_format: ?std.builtin.ObjectFormat = null,
290 optimize_mode: std.builtin.Mode = .Debug,298 optimize_mode: std.builtin.Mode = .Debug,
291 keep_source_files_loaded: bool = false,299 keep_source_files_loaded: bool = false,
...@@ -371,6 +379,26 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -371,6 +379,26 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
371379
372 const ofmt = options.object_format orelse options.target.getObjectFormat();380 const ofmt = options.object_format orelse options.target.getObjectFormat();
373381
382 // Make a decision on whether to use LLVM or our own backend.
383 const use_llvm = if (options.use_llvm) |explicit| explicit else blk: {
384 // If we have no zig code to compile, no need for LLVM.
385 if (options.root_pkg == null)
386 break :blk false;
387
388 // If we are the stage1 compiler, we depend on the stage1 c++ llvm backend
389 // to compile zig code.
390 if (build_options.is_stage1)
391 break :blk true;
392
393 // We would want to prefer LLVM for release builds when it is available, however
394 // we don't have an LLVM backend yet :)
395 // We would also want to prefer LLVM for architectures that we don't have self-hosted support for too.
396 break :blk false;
397 };
398 if (!use_llvm and options.machine_code_model != .default) {
399 return error.MachineCodeModelNotSupported;
400 }
401
374 // Make a decision on whether to use LLD or our own linker.402 // Make a decision on whether to use LLD or our own linker.
375 const use_lld = if (options.use_lld) |explicit| explicit else blk: {403 const use_lld = if (options.use_lld) |explicit| explicit else blk: {
376 if (!build_options.have_llvm)404 if (!build_options.have_llvm)
...@@ -393,7 +421,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -393,7 +421,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
393 break :blk true;421 break :blk true;
394 }422 }
395423
396 if (build_options.is_stage1) {424 if (use_llvm) {
397 // If stage1 generates an object file, self-hosted linker is not425 // If stage1 generates an object file, self-hosted linker is not
398 // yet sophisticated enough to handle that.426 // yet sophisticated enough to handle that.
399 break :blk options.root_pkg != null;427 break :blk options.root_pkg != null;
...@@ -402,25 +430,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -402,25 +430,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
402 break :blk false;430 break :blk false;
403 };431 };
404432
405 // Make a decision on whether to use LLVM or our own backend.
406 const use_llvm = if (options.use_llvm) |explicit| explicit else blk: {
407 // If we have no zig code to compile, no need for LLVM.
408 if (options.root_pkg == null)
409 break :blk false;
410
411 // If we are the stage1 compiler, we depend on the stage1 c++ llvm backend
412 // to compile zig code.
413 if (build_options.is_stage1)
414 break :blk true;
415
416 // We would want to prefer LLVM for release builds when it is available, however
417 // we don't have an LLVM backend yet :)
418 // We would also want to prefer LLVM for architectures that we don't have self-hosted support for too.
419 break :blk false;
420 };
421 if (!use_llvm and options.machine_code_model != .default) {
422 return error.MachineCodeModelNotSupported;
423 }
424433
425 const link_libc = options.link_libc or434 const link_libc = options.link_libc or
426 (is_exe_or_dyn_lib and target_util.osRequiresLibC(options.target));435 (is_exe_or_dyn_lib and target_util.osRequiresLibC(options.target));
...@@ -720,6 +729,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -720,6 +729,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
720 .llvm_cpu_features = llvm_cpu_features,729 .llvm_cpu_features = llvm_cpu_features,
721 .is_compiler_rt_or_libc = options.is_compiler_rt_or_libc,730 .is_compiler_rt_or_libc = options.is_compiler_rt_or_libc,
722 .each_lib_rpath = options.each_lib_rpath orelse false,731 .each_lib_rpath = options.each_lib_rpath orelse false,
732 .disable_lld_caching = options.disable_lld_caching,
723 });733 });
724 errdefer bin_file.destroy();734 errdefer bin_file.destroy();
725 comp.* = .{735 comp.* = .{
...@@ -2288,7 +2298,7 @@ pub fn updateSubCompilation(sub_compilation: *Compilation) !void {...@@ -2288,7 +2298,7 @@ pub fn updateSubCompilation(sub_compilation: *Compilation) !void {
2288 }2298 }
2289}2299}
22902300
2291fn buildStaticLibFromZig(comp: *Compilation, basename: []const u8, out: *?CRTFile) !void {2301fn buildStaticLibFromZig(comp: *Compilation, src_basename: []const u8, out: *?CRTFile) !void {
2292 const tracy = trace(@src());2302 const tracy = trace(@src());
2293 defer tracy.end();2303 defer tracy.end();
22942304
...@@ -2304,12 +2314,20 @@ fn buildStaticLibFromZig(comp: *Compilation, basename: []const u8, out: *?CRTFil...@@ -2304,12 +2314,20 @@ fn buildStaticLibFromZig(comp: *Compilation, basename: []const u8, out: *?CRTFil
2304 .path = special_path,2314 .path = special_path,
2305 .handle = special_dir,2315 .handle = special_dir,
2306 },2316 },
2307 .root_src_path = basename,2317 .root_src_path = src_basename,
2308 };2318 };
2319 const root_name = mem.split(src_basename, ".").next().?;
2320 const target = comp.getTarget();
2321 const bin_basename = try std.zig.binNameAlloc(comp.gpa, .{
2322 .root_name = root_name,
2323 .target = target,
2324 .output_mode = .Lib,
2325 });
2326 defer comp.gpa.free(bin_basename);
23092327
2310 const emit_bin = Compilation.EmitLoc{2328 const emit_bin = Compilation.EmitLoc{
2311 .directory = null, // Put it in the cache directory.2329 .directory = null, // Put it in the cache directory.
2312 .basename = basename,2330 .basename = bin_basename,
2313 };2331 };
2314 const optimize_mode: std.builtin.Mode = blk: {2332 const optimize_mode: std.builtin.Mode = blk: {
2315 if (comp.is_test)2333 if (comp.is_test)
...@@ -2323,8 +2341,8 @@ fn buildStaticLibFromZig(comp: *Compilation, basename: []const u8, out: *?CRTFil...@@ -2323,8 +2341,8 @@ fn buildStaticLibFromZig(comp: *Compilation, basename: []const u8, out: *?CRTFil
2323 .global_cache_directory = comp.global_cache_directory,2341 .global_cache_directory = comp.global_cache_directory,
2324 .local_cache_directory = comp.global_cache_directory,2342 .local_cache_directory = comp.global_cache_directory,
2325 .zig_lib_directory = comp.zig_lib_directory,2343 .zig_lib_directory = comp.zig_lib_directory,
2326 .target = comp.getTarget(),2344 .target = target,
2327 .root_name = mem.split(basename, ".").next().?,2345 .root_name = root_name,
2328 .root_pkg = &root_pkg,2346 .root_pkg = &root_pkg,
2329 .output_mode = .Lib,2347 .output_mode = .Lib,
2330 .rand = comp.rand,2348 .rand = comp.rand,
...@@ -2358,7 +2376,9 @@ fn buildStaticLibFromZig(comp: *Compilation, basename: []const u8, out: *?CRTFil...@@ -2358,7 +2376,9 @@ fn buildStaticLibFromZig(comp: *Compilation, basename: []const u8, out: *?CRTFil
23582376
2359 assert(out.* == null);2377 assert(out.* == null);
2360 out.* = Compilation.CRTFile{2378 out.* = Compilation.CRTFile{
2361 .full_object_path = try sub_compilation.bin_file.options.directory.join(comp.gpa, &[_][]const u8{basename}),2379 .full_object_path = try sub_compilation.bin_file.options.directory.join(comp.gpa, &[_][]const u8{
2380 sub_compilation.bin_file.options.sub_path,
2381 }),
2362 .lock = sub_compilation.bin_file.toOwnedLock(),2382 .lock = sub_compilation.bin_file.toOwnedLock(),
2363 };2383 };
2364}2384}
...@@ -2461,7 +2481,7 @@ fn updateStage1Module(comp: *Compilation) !void {...@@ -2461,7 +2481,7 @@ fn updateStage1Module(comp: *Compilation) !void {
2461 ) orelse return error.OutOfMemory;2481 ) orelse return error.OutOfMemory;
24622482
2463 const stage1_pkg = try createStage1Pkg(arena, "root", mod.root_pkg, null);2483 const stage1_pkg = try createStage1Pkg(arena, "root", mod.root_pkg, null);
2464 const output_dir = comp.bin_file.options.directory.path orelse ".";2484 const output_dir = directory.path orelse ".";
2465 const test_filter = comp.test_filter orelse ""[0..0];2485 const test_filter = comp.test_filter orelse ""[0..0];
2466 const test_name_prefix = comp.test_name_prefix orelse ""[0..0];2486 const test_name_prefix = comp.test_name_prefix orelse ""[0..0];
2467 stage1_module.* = .{2487 stage1_module.* = .{
...@@ -2617,13 +2637,11 @@ pub fn build_crt_file(...@@ -2617,13 +2637,11 @@ pub fn build_crt_file(
2617 try sub_compilation.updateSubCompilation();2637 try sub_compilation.updateSubCompilation();
26182638
2619 try comp.crt_files.ensureCapacity(comp.gpa, comp.crt_files.count() + 1);2639 try comp.crt_files.ensureCapacity(comp.gpa, comp.crt_files.count() + 1);
2620 const artifact_path = if (sub_compilation.bin_file.options.directory.path) |p|
2621 try std.fs.path.join(comp.gpa, &[_][]const u8{ p, basename })
2622 else
2623 try comp.gpa.dupe(u8, basename);
26242640
2625 comp.crt_files.putAssumeCapacityNoClobber(basename, .{2641 comp.crt_files.putAssumeCapacityNoClobber(basename, .{
2626 .full_object_path = artifact_path,2642 .full_object_path = try sub_compilation.bin_file.options.directory.join(comp.gpa, &[_][]const u8{
2643 sub_compilation.bin_file.options.sub_path,
2644 }),
2627 .lock = sub_compilation.bin_file.toOwnedLock(),2645 .lock = sub_compilation.bin_file.toOwnedLock(),
2628 });2646 });
2629}2647}
src/link.zig+1
...@@ -66,6 +66,7 @@ pub const Options = struct {...@@ -66,6 +66,7 @@ pub const Options = struct {
66 error_return_tracing: bool,66 error_return_tracing: bool,
67 is_compiler_rt_or_libc: bool,67 is_compiler_rt_or_libc: bool,
68 each_lib_rpath: bool,68 each_lib_rpath: bool,
69 disable_lld_caching: bool,
69 gc_sections: ?bool = null,70 gc_sections: ?bool = null,
70 allow_shlib_undefined: ?bool = null,71 allow_shlib_undefined: ?bool = null,
71 linker_script: ?[]const u8 = null,72 linker_script: ?[]const u8 = null,
src/link/Elf.zig+91-81
...@@ -23,6 +23,7 @@ const File = link.File;...@@ -23,6 +23,7 @@ const File = link.File;
23const build_options = @import("build_options");23const build_options = @import("build_options");
24const target_util = @import("../target.zig");24const target_util = @import("../target.zig");
25const glibc = @import("../glibc.zig");25const glibc = @import("../glibc.zig");
26const Cache = @import("../Cache.zig");
2627
27const default_entry_addr = 0x8000000;28const default_entry_addr = 0x8000000;
2829
...@@ -1225,7 +1226,8 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {...@@ -1225,7 +1226,8 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
1225 const use_stage1 = build_options.is_stage1 and self.base.options.use_llvm;1226 const use_stage1 = build_options.is_stage1 and self.base.options.use_llvm;
1226 if (use_stage1) {1227 if (use_stage1) {
1227 const obj_basename = try std.fmt.allocPrint(arena, "{}.o", .{self.base.options.root_name});1228 const obj_basename = try std.fmt.allocPrint(arena, "{}.o", .{self.base.options.root_name});
1228 const full_obj_path = try directory.join(arena, &[_][]const u8{obj_basename});1229 const o_directory = self.base.options.module.?.zig_cache_artifact_directory;
1230 const full_obj_path = try o_directory.join(arena, &[_][]const u8{obj_basename});
1229 break :blk full_obj_path;1231 break :blk full_obj_path;
1230 }1232 }
12311233
...@@ -1235,6 +1237,12 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {...@@ -1235,6 +1237,12 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
1235 break :blk full_obj_path;1237 break :blk full_obj_path;
1236 } else null;1238 } else null;
12371239
1240 const is_lib = self.base.options.output_mode == .Lib;
1241 const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib;
1242 const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe;
1243 const have_dynamic_linker = self.base.options.link_libc and
1244 self.base.options.link_mode == .Dynamic and is_exe_or_dyn_lib;
1245
1238 // Here we want to determine whether we can save time by not invoking LLD when the1246 // Here we want to determine whether we can save time by not invoking LLD when the
1239 // output is unchanged. None of the linker options or the object files that are being1247 // output is unchanged. None of the linker options or the object files that are being
1240 // linked are in the hash that namespaces the directory we are outputting to. Therefore,1248 // linked are in the hash that namespaces the directory we are outputting to. Therefore,
...@@ -1245,78 +1253,78 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {...@@ -1245,78 +1253,78 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
1245 // our digest. If so, we can skip linking. Otherwise, we proceed with invoking LLD.1253 // our digest. If so, we can skip linking. Otherwise, we proceed with invoking LLD.
1246 const id_symlink_basename = "lld.id";1254 const id_symlink_basename = "lld.id";
12471255
1248 // We are about to obtain this lock, so here we give other processes a chance first.1256 var man: Cache.Manifest = undefined;
1249 self.base.releaseLock();1257 defer if (!self.base.options.disable_lld_caching) man.deinit();
12501258
1251 var ch = comp.cache_parent.obtain();1259 var digest: [Cache.hex_digest_len]u8 = undefined;
1252 defer ch.deinit();1260
1261 if (!self.base.options.disable_lld_caching) {
1262 man = comp.cache_parent.obtain();
1263
1264 // We are about to obtain this lock, so here we give other processes a chance first.
1265 self.base.releaseLock();
1266
1267 try man.addOptionalFile(self.base.options.linker_script);
1268 try man.addOptionalFile(self.base.options.version_script);
1269 try man.addListOfFiles(self.base.options.objects);
1270 for (comp.c_object_table.items()) |entry| {
1271 _ = try man.addFile(entry.key.status.success.object_path, null);
1272 }
1273 try man.addOptionalFile(module_obj_path);
1274 // We can skip hashing libc and libc++ components that we are in charge of building from Zig
1275 // installation sources because they are always a product of the compiler version + target information.
1276 man.hash.addOptional(self.base.options.stack_size_override);
1277 man.hash.addOptional(self.base.options.gc_sections);
1278 man.hash.add(self.base.options.eh_frame_hdr);
1279 man.hash.add(self.base.options.rdynamic);
1280 man.hash.addListOfBytes(self.base.options.extra_lld_args);
1281 man.hash.addListOfBytes(self.base.options.lib_dirs);
1282 man.hash.addListOfBytes(self.base.options.rpath_list);
1283 man.hash.add(self.base.options.each_lib_rpath);
1284 man.hash.add(self.base.options.is_compiler_rt_or_libc);
1285 man.hash.add(self.base.options.z_nodelete);
1286 man.hash.add(self.base.options.z_defs);
1287 if (self.base.options.link_libc) {
1288 man.hash.add(self.base.options.libc_installation != null);
1289 if (self.base.options.libc_installation) |libc_installation| {
1290 man.hash.addBytes(libc_installation.crt_dir.?);
1291 }
1292 if (have_dynamic_linker) {
1293 man.hash.addOptionalBytes(self.base.options.dynamic_linker);
1294 }
1295 }
1296 if (is_dyn_lib) {
1297 man.hash.addOptionalBytes(self.base.options.override_soname);
1298 man.hash.addOptional(self.base.options.version);
1299 }
1300 man.hash.addListOfBytes(self.base.options.system_libs);
1301 man.hash.addOptional(self.base.options.allow_shlib_undefined);
1302 man.hash.add(self.base.options.bind_global_refs_locally);
12531303
1254 const is_lib = self.base.options.output_mode == .Lib;1304 // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.
1255 const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib;1305 _ = try man.hit();
1256 const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe;1306 digest = man.final();
1257 const have_dynamic_linker = self.base.options.link_libc and
1258 self.base.options.link_mode == .Dynamic and is_exe_or_dyn_lib;
12591307
1260 try ch.addOptionalFile(self.base.options.linker_script);1308 var prev_digest_buf: [digest.len]u8 = undefined;
1261 try ch.addOptionalFile(self.base.options.version_script);1309 const prev_digest: []u8 = directory.handle.readLink(id_symlink_basename, &prev_digest_buf) catch |err| blk: {
1262 try ch.addListOfFiles(self.base.options.objects);1310 log.debug("ELF LLD new_digest={} readlink error: {}", .{digest, @errorName(err)});
1263 for (comp.c_object_table.items()) |entry| {1311 // Handle this as a cache miss.
1264 _ = try ch.addFile(entry.key.status.success.object_path, null);1312 break :blk prev_digest_buf[0..0];
1265 }1313 };
1266 try ch.addOptionalFile(module_obj_path);1314 if (mem.eql(u8, prev_digest, &digest)) {
1267 // We can skip hashing libc and libc++ components that we are in charge of building from Zig1315 log.debug("ELF LLD digest={} match - skipping invocation", .{digest});
1268 // installation sources because they are always a product of the compiler version + target information.1316 // Hot diggity dog! The output binary is already there.
1269 ch.hash.addOptional(self.base.options.stack_size_override);1317 self.base.lock = man.toOwnedLock();
1270 ch.hash.addOptional(self.base.options.gc_sections);1318 return;
1271 ch.hash.add(self.base.options.eh_frame_hdr);
1272 ch.hash.add(self.base.options.rdynamic);
1273 ch.hash.addListOfBytes(self.base.options.extra_lld_args);
1274 ch.hash.addListOfBytes(self.base.options.lib_dirs);
1275 ch.hash.addListOfBytes(self.base.options.rpath_list);
1276 ch.hash.add(self.base.options.each_lib_rpath);
1277 ch.hash.add(self.base.options.is_compiler_rt_or_libc);
1278 ch.hash.add(self.base.options.z_nodelete);
1279 ch.hash.add(self.base.options.z_defs);
1280 if (self.base.options.link_libc) {
1281 ch.hash.add(self.base.options.libc_installation != null);
1282 if (self.base.options.libc_installation) |libc_installation| {
1283 ch.hash.addBytes(libc_installation.crt_dir.?);
1284 }
1285 if (have_dynamic_linker) {
1286 ch.hash.addOptionalBytes(self.base.options.dynamic_linker);
1287 }1319 }
1320 log.debug("ELF LLD prev_digest={} new_digest={}", .{prev_digest, digest});
1321
1322 // We are about to change the output file to be different, so we invalidate the build hash now.
1323 directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) {
1324 error.FileNotFound => {},
1325 else => |e| return e,
1326 };
1288 }1327 }
1289 if (is_dyn_lib) {
1290 ch.hash.addOptionalBytes(self.base.options.override_soname);
1291 ch.hash.addOptional(self.base.options.version);
1292 }
1293 ch.hash.addListOfBytes(self.base.options.system_libs);
1294 ch.hash.addOptional(self.base.options.allow_shlib_undefined);
1295 ch.hash.add(self.base.options.bind_global_refs_locally);
1296
1297 // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.
1298 _ = try ch.hit();
1299 const digest = ch.final();
1300
1301 var prev_digest_buf: [digest.len]u8 = undefined;
1302 const prev_digest: []u8 = directory.handle.readLink(id_symlink_basename, &prev_digest_buf) catch |err| blk: {
1303 log.debug("ELF LLD new_digest={} readlink error: {}", .{digest, @errorName(err)});
1304 // Handle this as a cache miss.
1305 break :blk prev_digest_buf[0..0];
1306 };
1307 if (mem.eql(u8, prev_digest, &digest)) {
1308 log.debug("ELF LLD digest={} match - skipping invocation", .{digest});
1309 // Hot diggity dog! The output binary is already there.
1310 self.base.lock = ch.toOwnedLock();
1311 return;
1312 }
1313 log.debug("ELF LLD prev_digest={} new_digest={}", .{prev_digest, digest});
1314
1315 // We are about to change the output file to be different, so we invalidate the build hash now.
1316 directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) {
1317 error.FileNotFound => {},
1318 else => |e| return e,
1319 };
13201328
1321 const target = self.base.options.target;1329 const target = self.base.options.target;
1322 const is_obj = self.base.options.output_mode == .Obj;1330 const is_obj = self.base.options.output_mode == .Obj;
...@@ -1620,18 +1628,20 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {...@@ -1620,18 +1628,20 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
1620 std.log.warn("unexpected LLD stderr: {}", .{stderr_context.data.items});1628 std.log.warn("unexpected LLD stderr: {}", .{stderr_context.data.items});
1621 }1629 }
16221630
1623 // Update the dangling symlink with the digest. If it fails we can continue; it only1631 if (!self.base.options.disable_lld_caching) {
1624 // means that the next invocation will have an unnecessary cache miss.1632 // Update the dangling symlink with the digest. If it fails we can continue; it only
1625 directory.handle.symLink(&digest, id_symlink_basename, .{}) catch |err| {1633 // means that the next invocation will have an unnecessary cache miss.
1626 std.log.warn("failed to save linking hash digest symlink: {}", .{@errorName(err)});1634 directory.handle.symLink(&digest, id_symlink_basename, .{}) catch |err| {
1627 };1635 std.log.warn("failed to save linking hash digest symlink: {}", .{@errorName(err)});
1628 // Again failure here only means an unnecessary cache miss.1636 };
1629 ch.writeManifest() catch |err| {1637 // Again failure here only means an unnecessary cache miss.
1630 std.log.warn("failed to write cache manifest when linking: {}", .{ @errorName(err) });1638 man.writeManifest() catch |err| {
1631 };1639 std.log.warn("failed to write cache manifest when linking: {}", .{ @errorName(err) });
1632 // We hang on to this lock so that the output file path can be used without1640 };
1633 // other processes clobbering it.1641 // We hang on to this lock so that the output file path can be used without
1634 self.base.lock = ch.toOwnedLock();1642 // other processes clobbering it.
1643 self.base.lock = man.toOwnedLock();
1644 }
1635}1645}
16361646
1637const LLDContext = struct {1647const LLDContext = struct {
src/main.zig+1
...@@ -1425,6 +1425,7 @@ pub fn buildOutputType(...@@ -1425,6 +1425,7 @@ pub fn buildOutputType(
1425 .test_evented_io = test_evented_io,1425 .test_evented_io = test_evented_io,
1426 .test_filter = test_filter,1426 .test_filter = test_filter,
1427 .test_name_prefix = test_name_prefix,1427 .test_name_prefix = test_name_prefix,
1428 .disable_lld_caching = !have_enable_cache,
1428 }) catch |err| {1429 }) catch |err| {
1429 fatal("unable to create compilation: {}", .{@errorName(err)});1430 fatal("unable to create compilation: {}", .{@errorName(err)});
1430 };1431 };