Commit 67e31807df

Andrew Kelley <andrew@ziglang.org>
2021-12-30 23:32:50
stage2: CacheMode.whole fixes
* Logic to check whether a bin file is not emitted is more complicated in between `Compilation.create` and `Compilation.update`. Fixed the logic that decides whether to build compiler-rt and other support artifacts. * Basically, one cannot inspect the value of `comp.bin_file.emit` until after update() is called - fixed another instance of this happening in the CLI. * In the CLI, `runOrTest` is updated to properly use the result value of `comp.bin_file.options.emit` rather than guessing whether the output binary is. * Don't assume that the emit output has no directory components in sub_path. In other words, don't assume that the emit directory is the final directory; there may be sub-directories.
1 parent e3bed8d
Changed files (2)
src/Compilation.zig
@@ -1662,7 +1662,9 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
         comp.c_object_table.putAssumeCapacityNoClobber(c_object, {});
     }
 
-    if (comp.bin_file.options.emit != null and !comp.bin_file.options.skip_linker_dependencies) {
+    const have_bin_emit = comp.bin_file.options.emit != null or comp.whole_bin_basename != null;
+
+    if (have_bin_emit and !comp.bin_file.options.skip_linker_dependencies) {
         // If we need to build glibc for the target, add work items for it.
         // We go through the work queue so that building can be done in parallel.
         if (comp.wantBuildGLibCFromSource()) {
@@ -1767,8 +1769,10 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
 
         if (comp.bin_file.options.include_compiler_rt and capable_of_building_compiler_rt) {
             if (is_exe_or_dyn_lib) {
+                log.debug("queuing a job to build compiler_rt_lib", .{});
                 try comp.work_queue.writeItem(.{ .compiler_rt_lib = {} });
             } else if (options.output_mode != .Obj) {
+                log.debug("queuing a job to build compiler_rt_obj", .{});
                 // If build-obj with -fcompiler-rt is requested, that is handled specially
                 // elsewhere. In this case we are making a static library, so we ask
                 // for a compiler-rt object to put in it.
@@ -1930,6 +1934,7 @@ pub fn update(comp: *Compilation) !void {
             return err;
         };
         if (is_hit) {
+            log.debug("CacheMode.whole cache hit for {s}", .{comp.bin_file.options.root_name});
             const digest = man.final();
 
             // Communicate the output binary location to parent Compilations.
@@ -1952,6 +1957,8 @@ pub fn update(comp: *Compilation) !void {
             comp.bin_file.lock = man.toOwnedLock();
             return;
         }
+        log.debug("CacheMode.whole cache miss for {s}", .{comp.bin_file.options.root_name});
+
         comp.whole_cache_manifest = &man;
 
         // Initialize `bin_file.emit` with a temporary Directory so that compilation can
@@ -2187,6 +2194,8 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes
 
             try addPackageTableToCacheHash(&man.hash, &arena_allocator, mod.main_pkg.table, &seen_table, .{ .files = man });
         }
+
+        man.hash.add(mod.emit_h != null);
     }
 
     try man.addOptionalFile(comp.bin_file.options.linker_script);
src/main.zig
@@ -2564,9 +2564,7 @@ fn buildOutputType(
 
         switch (emit_bin) {
             .no => break :blk .none,
-            .yes_default_path => break :blk .{
-                .print = comp.bin_file.options.emit.?.directory.path orelse ".",
-            },
+            .yes_default_path => break :blk .print_emit_bin_dir_path,
             .yes => |full_path| break :blk .{ .update = full_path },
             .yes_a_out => break :blk .{ .update = a_out_basename },
         }
@@ -2598,7 +2596,6 @@ fn buildOutputType(
             comp,
             gpa,
             arena,
-            emit_bin_loc,
             test_exec_args.items,
             self_exe_path,
             arg_mode,
@@ -2671,7 +2668,6 @@ fn buildOutputType(
                         comp,
                         gpa,
                         arena,
-                        emit_bin_loc,
                         test_exec_args.items,
                         self_exe_path,
                         arg_mode,
@@ -2697,7 +2693,6 @@ fn buildOutputType(
                         comp,
                         gpa,
                         arena,
-                        emit_bin_loc,
                         test_exec_args.items,
                         self_exe_path,
                         arg_mode,
@@ -2762,7 +2757,6 @@ fn runOrTest(
     comp: *Compilation,
     gpa: Allocator,
     arena: Allocator,
-    emit_bin_loc: ?Compilation.EmitLoc,
     test_exec_args: []const ?[]const u8,
     self_exe_path: []const u8,
     arg_mode: ArgMode,
@@ -2773,10 +2767,11 @@ fn runOrTest(
     runtime_args_start: ?usize,
     link_libc: bool,
 ) !void {
-    const exe_loc = emit_bin_loc orelse return;
-    const exe_directory = exe_loc.directory orelse comp.bin_file.options.emit.?.directory;
+    const exe_emit = comp.bin_file.options.emit orelse return;
+    // A naive `directory.join` here will indeed get the correct path to the binary,
+    // however, in the case of cwd, we actually want `./foo` so that the path can be executed.
     const exe_path = try fs.path.join(arena, &[_][]const u8{
-        exe_directory.path orelse ".", exe_loc.basename,
+        exe_emit.directory.path orelse ".", exe_emit.sub_path,
     });
 
     var argv = std.ArrayList([]const u8).init(gpa);
@@ -2880,7 +2875,7 @@ fn runOrTest(
 
 const AfterUpdateHook = union(enum) {
     none,
-    print: []const u8,
+    print_emit_bin_dir_path,
     update: []const u8,
 };
 
@@ -2906,7 +2901,13 @@ fn updateModule(gpa: Allocator, comp: *Compilation, hook: AfterUpdateHook) !void
         return error.SemanticAnalyzeFail;
     } else switch (hook) {
         .none => {},
-        .print => |bin_path| try io.getStdOut().writer().print("{s}\n", .{bin_path}),
+        .print_emit_bin_dir_path => {
+            const emit = comp.bin_file.options.emit.?;
+            const full_path = try emit.directory.join(gpa, &.{emit.sub_path});
+            defer gpa.free(full_path);
+            const dir_path = fs.path.dirname(full_path).?;
+            try io.getStdOut().writer().print("{s}\n", .{dir_path});
+        },
         .update => |full_path| {
             const bin_sub_path = comp.bin_file.options.emit.?.sub_path;
             const cwd = fs.cwd();
@@ -3469,9 +3470,10 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
         };
         try comp.makeBinFileExecutable();
 
-        child_argv.items[argv_index_exe] = try comp.bin_file.options.emit.?.directory.join(
+        const emit = comp.bin_file.options.emit.?;
+        child_argv.items[argv_index_exe] = try emit.directory.join(
             arena,
-            &[_][]const u8{exe_basename},
+            &[_][]const u8{emit.sub_path},
         );
 
         break :argv child_argv.items;