authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-28 20:55:52-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-28 20:55:52-07:00
log5fed42d70a9ce23581bc8e1651a417161f269663
treef5e39475e122e1ff29e50513c1b70a0a249f2855
parentada19c498d6cb52dd8f0de71d42baf845cfadc21

the stage1 backend cache stores inferred link libs

So that we properly learn about extern "foo" functions called even when we get a stage1 cache hit.

3 files changed, 69 insertions(+), 24 deletions(-)

BRANCH_TODO-4
......@@ -1,7 +1,3 @@
1 * the have_foo flags that we get from stage1 have to be stored in the cache otherwise we get
2 a different result for subsystem when we have a cached stage1 execution result.
3 same deal with extern "foo" libraries used
4 * add jobs to build import libs for windows DLLs for extern "foo" functions used
51 * MachO LLD linking
62 * WASM LLD linking
73 * audit the CLI options for stage2
src/Compilation.zig+49-10
......@@ -2498,6 +2498,7 @@ fn updateStage1Module(comp: *Compilation) !void {
24982498 const builtin_zig_path = try directory.join(arena, &[_][]const u8{"builtin.zig"});
24992499 const target = comp.getTarget();
25002500 const id_symlink_basename = "stage1.id";
2501 const libs_txt_basename = "libs.txt";
25012502
25022503 // We are about to obtain this lock, so here we give other processes a chance first.
25032504 comp.releaseStage1Lock();
......@@ -2538,18 +2539,32 @@ fn updateStage1Module(comp: *Compilation) !void {
25382539 // Handle this as a cache miss.
25392540 break :blk prev_digest_buf[0..0];
25402541 };
2541 if (prev_digest.len >= digest.len + 2) {
2542 if (mem.eql(u8, prev_digest[0..digest.len], &digest)) {
2543 log.debug("stage1 {} digest={} match - skipping invocation", .{ mod.root_pkg.root_src_path, digest });
2544 var flags_bytes: [1]u8 = undefined;
2545 if (std.fmt.hexToBytes(&flags_bytes, prev_digest[digest.len..])) |_| {
2546 comp.stage1_lock = man.toOwnedLock();
2547 mod.stage1_flags = @bitCast(@TypeOf(mod.stage1_flags), flags_bytes[0]);
2548 return;
2549 } else |err| {
2550 log.warn("bad cache stage1 digest: '{s}'", .{prev_digest});
2542 if (prev_digest.len >= digest.len + 2) hit: {
2543 if (!mem.eql(u8, prev_digest[0..digest.len], &digest))
2544 break :hit;
2545
2546 log.debug("stage1 {} digest={} match - skipping invocation", .{ mod.root_pkg.root_src_path, digest });
2547 var flags_bytes: [1]u8 = undefined;
2548 _ = std.fmt.hexToBytes(&flags_bytes, prev_digest[digest.len..]) catch {
2549 log.warn("bad cache stage1 digest: '{s}'", .{prev_digest});
2550 break :hit;
2551 };
2552
2553 if (directory.handle.readFileAlloc(comp.gpa, libs_txt_basename, 10 * 1024 * 1024)) |libs_txt| {
2554 var it = mem.tokenize(libs_txt, "\n");
2555 while (it.next()) |lib_name| {
2556 try comp.stage1AddLinkLib(lib_name);
25512557 }
2558 } else |err| switch (err) {
2559 error.FileNotFound => {}, // That's OK, it just means 0 libs.
2560 else => {
2561 log.warn("unable to read cached list of link libs: {s}", .{@errorName(err)});
2562 break :hit;
2563 },
25522564 }
2565 comp.stage1_lock = man.toOwnedLock();
2566 mod.stage1_flags = @bitCast(@TypeOf(mod.stage1_flags), flags_bytes[0]);
2567 return;
25532568 }
25542569 log.debug("stage1 {} prev_digest={} new_digest={}", .{ mod.root_pkg.root_src_path, prev_digest, digest });
25552570 man.unhit(prev_hash_state, input_file_count);
......@@ -2668,8 +2683,20 @@ fn updateStage1Module(comp: *Compilation) !void {
26682683 .have_wwinmain_crt_startup = false,
26692684 .have_dllmain_crt_startup = false,
26702685 };
2686
2687 const inferred_lib_start_index = comp.bin_file.options.system_libs.count();
26712688 stage1_module.build_object();
26722689
2690 if (comp.bin_file.options.system_libs.count() > inferred_lib_start_index) {
2691 // We need to save the inferred link libs to the cache, otherwise if we get a cache hit
2692 // next time we will be missing these libs.
2693 var libs_txt = std.ArrayList(u8).init(arena);
2694 for (comp.bin_file.options.system_libs.items()[inferred_lib_start_index..]) |entry| {
2695 try libs_txt.writer().print("{s}\n", .{entry.key});
2696 }
2697 try directory.handle.writeFile(libs_txt_basename, libs_txt.items);
2698 }
2699
26732700 mod.stage1_flags = .{
26742701 .have_c_main = stage1_module.have_c_main,
26752702 .have_winmain = stage1_module.have_winmain,
......@@ -2814,3 +2841,15 @@ pub fn build_crt_file(
28142841 .lock = sub_compilation.bin_file.toOwnedLock(),
28152842 });
28162843}
2844
2845pub fn stage1AddLinkLib(comp: *Compilation, lib_name: []const u8) !void {
2846 // This happens when an `extern "foo"` function is referenced by the stage1 backend.
2847 // If we haven't seen this library yet and we're targeting Windows, we need to queue up
2848 // a work item to produce the DLL import library for this.
2849 const gop = try comp.bin_file.options.system_libs.getOrPut(comp.gpa, lib_name);
2850 if (!gop.found_existing and comp.getTarget().os.tag == .windows) {
2851 try comp.work_queue.writeItem(.{
2852 .windows_import_lib = comp.bin_file.options.system_libs.count() - 1,
2853 });
2854 }
2855}
src/stage1.zig+20-10
......@@ -381,23 +381,33 @@ export fn stage2_add_link_lib(
381381 symbol_name_len: usize,
382382) ?[*:0]const u8 {
383383 const comp = @intToPtr(*Compilation, stage1.userdata);
384 const lib_name = lib_name_ptr[0..lib_name_len];
385 const symbol_name = symbol_name_ptr[0..symbol_name_len];
384 const lib_name = std.ascii.allocLowerString(comp.gpa, lib_name_ptr[0..lib_name_len]) catch return "out of memory";
386385 const target = comp.getTarget();
387386 const is_libc = target_util.is_libc_lib_name(target, lib_name);
388 if (is_libc and !comp.bin_file.options.link_libc) {
389 return "dependency on libc must be explicitly specified in the build command";
387 if (is_libc) {
388 if (!comp.bin_file.options.link_libc) {
389 return "dependency on libc must be explicitly specified in the build command";
390 }
391 return null;
390392 }
391
392 if (!is_libc and !target.isWasm() and !comp.bin_file.options.pic) {
393 const msg = std.fmt.allocPrint0(
393 if (target_util.is_libcpp_lib_name(target, lib_name)) {
394 if (!comp.bin_file.options.link_libcpp) {
395 return "dependency on libc++ must be explicitly specified in the build command";
396 }
397 return null;
398 }
399 if (!target.isWasm() and !comp.bin_file.options.pic) {
400 return std.fmt.allocPrint0(
394401 comp.gpa,
395402 "dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by `-l{s}` or `-fPIC`.",
396403 .{ lib_name, lib_name },
397 ) catch return "out of memory";
398 return msg.ptr;
404 ) catch "out of memory";
399405 }
400
406 comp.stage1AddLinkLib(lib_name) catch |err| {
407 return std.fmt.allocPrint0(comp.gpa, "unable to add link lib '{s}': {s}", .{
408 lib_name, @errorName(err),
409 }) catch "out of memory";
410 };
401411 return null;
402412}
403413