authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-08-19 21:49:29-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-08-19 21:49:29-07:00
logdffc8c44f9a01aa05ea364ffdc71509d15bc2601
treeb9b610ac10bb537b8b0dfba500f6599c5e4b2e15
parent7071d1b3c2ed908bb8f1170673b50568ed56da7b
parent80999391d9b0db0303f59942cb52542a6e4da331
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #21115 from Snektron/build-system-asm

compilation and build system fixes

33 files changed, 363 insertions(+), 345 deletions(-)

lib/compiler/objcopy.zig+4-3
...@@ -201,9 +201,10 @@ fn cmdObjCopy(...@@ -201,9 +201,10 @@ fn cmdObjCopy(
201 if (seen_update) fatal("zig objcopy only supports 1 update for now", .{});201 if (seen_update) fatal("zig objcopy only supports 1 update for now", .{});
202 seen_update = true;202 seen_update = true;
203203
204 try server.serveEmitBinPath(output, .{204 // The build system already knows what the output is at this point, we
205 .flags = .{ .cache_hit = false },205 // only need to communicate that the process has finished.
206 });206 // Use the empty error bundle to indicate that the update is done.
207 try server.serveErrorBundle(std.zig.ErrorBundle.empty);
207 },208 },
208 else => fatal("unsupported message: {s}", .{@tagName(hdr.tag)}),209 else => fatal("unsupported message: {s}", .{@tagName(hdr.tag)}),
209 }210 }
lib/std/Build.zig+1-1
...@@ -2373,7 +2373,7 @@ pub const LazyPath = union(enum) {...@@ -2373,7 +2373,7 @@ pub const LazyPath = union(enum) {
2373 // basis for not traversing up too many directories.2373 // basis for not traversing up too many directories.
23742374
2375 var file_path: Cache.Path = .{2375 var file_path: Cache.Path = .{
2376 .root_dir = gen.file.step.owner.build_root,2376 .root_dir = Cache.Directory.cwd(),
2377 .sub_path = gen.file.path orelse {2377 .sub_path = gen.file.path orelse {
2378 std.debug.lockStdErr();2378 std.debug.lockStdErr();
2379 const stderr = std.io.getStdErr();2379 const stderr = std.io.getStdErr();
lib/std/Build/Cache.zig+7-2
...@@ -896,8 +896,8 @@ pub const Manifest = struct {...@@ -896,8 +896,8 @@ pub const Manifest = struct {
896 }896 }
897 }897 }
898898
899 /// Returns a hex encoded hash of the inputs.899 /// Returns a binary hash of the inputs.
900 pub fn final(self: *Manifest) HexDigest {900 pub fn finalBin(self: *Manifest) BinDigest {
901 assert(self.manifest_file != null);901 assert(self.manifest_file != null);
902902
903 // We don't close the manifest file yet, because we want to903 // We don't close the manifest file yet, because we want to
...@@ -908,7 +908,12 @@ pub const Manifest = struct {...@@ -908,7 +908,12 @@ pub const Manifest = struct {
908908
909 var bin_digest: BinDigest = undefined;909 var bin_digest: BinDigest = undefined;
910 self.hash.hasher.final(&bin_digest);910 self.hash.hasher.final(&bin_digest);
911 return bin_digest;
912 }
911913
914 /// Returns a hex encoded hash of the inputs.
915 pub fn final(self: *Manifest) HexDigest {
916 const bin_digest = self.finalBin();
912 return binToHex(bin_digest);917 return binToHex(bin_digest);
913 }918 }
914919
lib/std/Build/Fuzz.zig+11-7
...@@ -100,6 +100,15 @@ pub fn start(...@@ -100,6 +100,15 @@ pub fn start(
100}100}
101101
102fn rebuildTestsWorkerRun(run: *Step.Run, ttyconf: std.io.tty.Config, parent_prog_node: std.Progress.Node) void {102fn rebuildTestsWorkerRun(run: *Step.Run, ttyconf: std.io.tty.Config, parent_prog_node: std.Progress.Node) void {
103 rebuildTestsWorkerRunFallible(run, ttyconf, parent_prog_node) catch |err| {
104 const compile = run.producer.?;
105 log.err("step '{s}': failed to rebuild in fuzz mode: {s}", .{
106 compile.step.name, @errorName(err),
107 });
108 };
109}
110
111fn rebuildTestsWorkerRunFallible(run: *Step.Run, ttyconf: std.io.tty.Config, parent_prog_node: std.Progress.Node) !void {
103 const gpa = run.step.owner.allocator;112 const gpa = run.step.owner.allocator;
104 const stderr = std.io.getStdErr();113 const stderr = std.io.getStdErr();
105114
...@@ -121,14 +130,9 @@ fn rebuildTestsWorkerRun(run: *Step.Run, ttyconf: std.io.tty.Config, parent_prog...@@ -121,14 +130,9 @@ fn rebuildTestsWorkerRun(run: *Step.Run, ttyconf: std.io.tty.Config, parent_prog
121130
122 const rebuilt_bin_path = result catch |err| switch (err) {131 const rebuilt_bin_path = result catch |err| switch (err) {
123 error.MakeFailed => return,132 error.MakeFailed => return,
124 else => {133 else => |other| return other,
125 log.err("step '{s}': failed to rebuild in fuzz mode: {s}", .{
126 compile.step.name, @errorName(err),
127 });
128 return;
129 },
130 };134 };
131 run.rebuilt_executable = rebuilt_bin_path;135 run.rebuilt_executable = try rebuilt_bin_path.join(gpa, compile.out_filename);
132}136}
133137
134fn fuzzWorkerRun(138fn fuzzWorkerRun(
lib/std/Build/Fuzz/WebServer.zig+30-14
...@@ -8,6 +8,8 @@ const Coverage = std.debug.Coverage;...@@ -8,6 +8,8 @@ const Coverage = std.debug.Coverage;
8const abi = std.Build.Fuzz.abi;8const abi = std.Build.Fuzz.abi;
9const log = std.log;9const log = std.log;
10const assert = std.debug.assert;10const assert = std.debug.assert;
11const Cache = std.Build.Cache;
12const Path = Cache.Path;
1113
12const WebServer = @This();14const WebServer = @This();
1315
...@@ -31,6 +33,10 @@ coverage_mutex: std.Thread.Mutex,...@@ -31,6 +33,10 @@ coverage_mutex: std.Thread.Mutex,
31/// Signaled when `coverage_files` changes.33/// Signaled when `coverage_files` changes.
32coverage_condition: std.Thread.Condition,34coverage_condition: std.Thread.Condition,
3335
36const fuzzer_bin_name = "fuzzer";
37const fuzzer_arch_os_abi = "wasm32-freestanding";
38const fuzzer_cpu_features = "baseline+atomics+bulk_memory+multivalue+mutable_globals+nontrapping_fptoint+reference_types+sign_ext";
39
34const CoverageMap = struct {40const CoverageMap = struct {
35 mapped_memory: []align(std.mem.page_size) const u8,41 mapped_memory: []align(std.mem.page_size) const u8,
36 coverage: Coverage,42 coverage: Coverage,
...@@ -181,9 +187,18 @@ fn serveWasm(...@@ -181,9 +187,18 @@ fn serveWasm(
181187
182 // Do the compilation every request, so that the user can edit the files188 // Do the compilation every request, so that the user can edit the files
183 // and see the changes without restarting the server.189 // and see the changes without restarting the server.
184 const wasm_binary_path = try buildWasmBinary(ws, arena, optimize_mode);190 const wasm_base_path = try buildWasmBinary(ws, arena, optimize_mode);
191 const bin_name = try std.zig.binNameAlloc(arena, .{
192 .root_name = fuzzer_bin_name,
193 .target = std.zig.system.resolveTargetQuery(std.Build.parseTargetQuery(.{
194 .arch_os_abi = fuzzer_arch_os_abi,
195 .cpu_features = fuzzer_cpu_features,
196 }) catch unreachable) catch unreachable,
197 .output_mode = .Exe,
198 });
185 // std.http.Server does not have a sendfile API yet.199 // std.http.Server does not have a sendfile API yet.
186 const file_contents = try std.fs.cwd().readFileAlloc(gpa, wasm_binary_path, 10 * 1024 * 1024);200 const bin_path = try wasm_base_path.join(arena, bin_name);
201 const file_contents = try bin_path.root_dir.handle.readFileAlloc(gpa, bin_path.sub_path, 10 * 1024 * 1024);
187 defer gpa.free(file_contents);202 defer gpa.free(file_contents);
188 try request.respond(file_contents, .{203 try request.respond(file_contents, .{
189 .extra_headers = &.{204 .extra_headers = &.{
...@@ -197,7 +212,7 @@ fn buildWasmBinary(...@@ -197,7 +212,7 @@ fn buildWasmBinary(
197 ws: *WebServer,212 ws: *WebServer,
198 arena: Allocator,213 arena: Allocator,
199 optimize_mode: std.builtin.OptimizeMode,214 optimize_mode: std.builtin.OptimizeMode,
200) ![]const u8 {215) !Path {
201 const gpa = ws.gpa;216 const gpa = ws.gpa;
202217
203 const main_src_path: Build.Cache.Path = .{218 const main_src_path: Build.Cache.Path = .{
...@@ -219,11 +234,11 @@ fn buildWasmBinary(...@@ -219,11 +234,11 @@ fn buildWasmBinary(
219 ws.zig_exe_path, "build-exe", //234 ws.zig_exe_path, "build-exe", //
220 "-fno-entry", //235 "-fno-entry", //
221 "-O", @tagName(optimize_mode), //236 "-O", @tagName(optimize_mode), //
222 "-target", "wasm32-freestanding", //237 "-target", fuzzer_arch_os_abi, //
223 "-mcpu", "baseline+atomics+bulk_memory+multivalue+mutable_globals+nontrapping_fptoint+reference_types+sign_ext", //238 "-mcpu", fuzzer_cpu_features, //
224 "--cache-dir", ws.global_cache_directory.path orelse ".", //239 "--cache-dir", ws.global_cache_directory.path orelse ".", //
225 "--global-cache-dir", ws.global_cache_directory.path orelse ".", //240 "--global-cache-dir", ws.global_cache_directory.path orelse ".", //
226 "--name", "fuzzer", //241 "--name", fuzzer_bin_name, //
227 "-rdynamic", //242 "-rdynamic", //
228 "-fsingle-threaded", //243 "-fsingle-threaded", //
229 "--dep", "Walk", //244 "--dep", "Walk", //
...@@ -251,7 +266,7 @@ fn buildWasmBinary(...@@ -251,7 +266,7 @@ fn buildWasmBinary(
251 try sendMessage(child.stdin.?, .exit);266 try sendMessage(child.stdin.?, .exit);
252267
253 const Header = std.zig.Server.Message.Header;268 const Header = std.zig.Server.Message.Header;
254 var result: ?[]const u8 = null;269 var result: ?Path = null;
255 var result_error_bundle = std.zig.ErrorBundle.empty;270 var result_error_bundle = std.zig.ErrorBundle.empty;
256271
257 const stdout = poller.fifo(.stdout);272 const stdout = poller.fifo(.stdout);
...@@ -288,13 +303,17 @@ fn buildWasmBinary(...@@ -288,13 +303,17 @@ fn buildWasmBinary(
288 .extra = extra_array,303 .extra = extra_array,
289 };304 };
290 },305 },
291 .emit_bin_path => {306 .emit_digest => {
292 const EbpHdr = std.zig.Server.Message.EmitBinPath;307 const EbpHdr = std.zig.Server.Message.EmitDigest;
293 const ebp_hdr = @as(*align(1) const EbpHdr, @ptrCast(body));308 const ebp_hdr = @as(*align(1) const EbpHdr, @ptrCast(body));
294 if (!ebp_hdr.flags.cache_hit) {309 if (!ebp_hdr.flags.cache_hit) {
295 log.info("source changes detected; rebuilt wasm component", .{});310 log.info("source changes detected; rebuilt wasm component", .{});
296 }311 }
297 result = try arena.dupe(u8, body[@sizeOf(EbpHdr)..]);312 const digest = body[@sizeOf(EbpHdr)..][0..Cache.bin_digest_len];
313 result = Path{
314 .root_dir = ws.global_cache_directory,
315 .sub_path = try arena.dupe(u8, "o" ++ std.fs.path.sep_str ++ Cache.binToHex(digest.*)),
316 };
298 },317 },
299 else => {}, // ignore other messages318 else => {}, // ignore other messages
300 }319 }
...@@ -568,10 +587,7 @@ fn prepareTables(...@@ -568,10 +587,7 @@ fn prepareTables(
568 };587 };
569 errdefer gop.value_ptr.coverage.deinit(gpa);588 errdefer gop.value_ptr.coverage.deinit(gpa);
570589
571 const rebuilt_exe_path: Build.Cache.Path = .{590 const rebuilt_exe_path = run_step.rebuilt_executable.?;
572 .root_dir = Build.Cache.Directory.cwd(),
573 .sub_path = run_step.rebuilt_executable.?,
574 };
575 var debug_info = std.debug.Info.load(gpa, rebuilt_exe_path, &gop.value_ptr.coverage) catch |err| {591 var debug_info = std.debug.Info.load(gpa, rebuilt_exe_path, &gop.value_ptr.coverage) catch |err| {
576 log.err("step '{s}': failed to load debug information for '{}': {s}", .{592 log.err("step '{s}': failed to load debug information for '{}': {s}", .{
577 run_step.step.name, rebuilt_exe_path, @errorName(err),593 run_step.step.name, rebuilt_exe_path, @errorName(err),
lib/std/Build/Step.zig+12-11
...@@ -317,6 +317,8 @@ const Build = std.Build;...@@ -317,6 +317,8 @@ const Build = std.Build;
317const Allocator = std.mem.Allocator;317const Allocator = std.mem.Allocator;
318const assert = std.debug.assert;318const assert = std.debug.assert;
319const builtin = @import("builtin");319const builtin = @import("builtin");
320const Cache = Build.Cache;
321const Path = Cache.Path;
320322
321pub fn evalChildProcess(s: *Step, argv: []const []const u8) ![]u8 {323pub fn evalChildProcess(s: *Step, argv: []const []const u8) ![]u8 {
322 const run_result = try captureChildProcess(s, std.Progress.Node.none, argv);324 const run_result = try captureChildProcess(s, std.Progress.Node.none, argv);
...@@ -373,7 +375,7 @@ pub fn evalZigProcess(...@@ -373,7 +375,7 @@ pub fn evalZigProcess(
373 argv: []const []const u8,375 argv: []const []const u8,
374 prog_node: std.Progress.Node,376 prog_node: std.Progress.Node,
375 watch: bool,377 watch: bool,
376) !?[]const u8 {378) !?Path {
377 if (s.getZigProcess()) |zp| update: {379 if (s.getZigProcess()) |zp| update: {
378 assert(watch);380 assert(watch);
379 if (std.Progress.have_ipc) if (zp.progress_ipc_fd) |fd| prog_node.setIpcFd(fd);381 if (std.Progress.have_ipc) if (zp.progress_ipc_fd) |fd| prog_node.setIpcFd(fd);
...@@ -477,7 +479,7 @@ pub fn evalZigProcess(...@@ -477,7 +479,7 @@ pub fn evalZigProcess(
477 return result;479 return result;
478}480}
479481
480fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool) !?[]const u8 {482fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool) !?Path {
481 const b = s.owner;483 const b = s.owner;
482 const arena = b.allocator;484 const arena = b.allocator;
483485
...@@ -487,7 +489,7 @@ fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool) !?[]const u8 {...@@ -487,7 +489,7 @@ fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool) !?[]const u8 {
487 if (!watch) try sendMessage(zp.child.stdin.?, .exit);489 if (!watch) try sendMessage(zp.child.stdin.?, .exit);
488490
489 const Header = std.zig.Server.Message.Header;491 const Header = std.zig.Server.Message.Header;
490 var result: ?[]const u8 = null;492 var result: ?Path = null;
491493
492 const stdout = zp.poller.fifo(.stdout);494 const stdout = zp.poller.fifo(.stdout);
493495
...@@ -531,16 +533,15 @@ fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool) !?[]const u8 {...@@ -531,16 +533,15 @@ fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool) !?[]const u8 {
531 break;533 break;
532 }534 }
533 },535 },
534 .emit_bin_path => {536 .emit_digest => {
535 const EbpHdr = std.zig.Server.Message.EmitBinPath;537 const EbpHdr = std.zig.Server.Message.EmitDigest;
536 const ebp_hdr = @as(*align(1) const EbpHdr, @ptrCast(body));538 const ebp_hdr = @as(*align(1) const EbpHdr, @ptrCast(body));
537 s.result_cached = ebp_hdr.flags.cache_hit;539 s.result_cached = ebp_hdr.flags.cache_hit;
538 result = try arena.dupe(u8, body[@sizeOf(EbpHdr)..]);540 const digest = body[@sizeOf(EbpHdr)..][0..Cache.bin_digest_len];
539 if (watch) {541 result = Path{
540 // This message indicates the end of the update.542 .root_dir = b.cache_root,
541 stdout.discard(body.len);543 .sub_path = try arena.dupe(u8, "o" ++ std.fs.path.sep_str ++ Cache.binToHex(digest.*)),
542 break;544 };
543 }
544 },545 },
545 .file_system_inputs => {546 .file_system_inputs => {
546 s.clearWatchInputs();547 s.clearWatchInputs();
lib/std/Build/Step/Compile.zig+14-15
...@@ -17,6 +17,7 @@ const Module = std.Build.Module;...@@ -17,6 +17,7 @@ const Module = std.Build.Module;
17const InstallDir = std.Build.InstallDir;17const InstallDir = std.Build.InstallDir;
18const GeneratedFile = std.Build.GeneratedFile;18const GeneratedFile = std.Build.GeneratedFile;
19const Compile = @This();19const Compile = @This();
20const Path = std.Build.Cache.Path;
2021
21pub const base_id: Step.Id = .compile;22pub const base_id: Step.Id = .compile;
2223
...@@ -1765,7 +1766,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {...@@ -1765,7 +1766,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
17651766
1766 const zig_args = try getZigArgs(compile, false);1767 const zig_args = try getZigArgs(compile, false);
17671768
1768 const maybe_output_bin_path = step.evalZigProcess(1769 const maybe_output_dir = step.evalZigProcess(
1769 zig_args,1770 zig_args,
1770 options.progress_node,1771 options.progress_node,
1771 (b.graph.incremental == true) and options.watch,1772 (b.graph.incremental == true) and options.watch,
...@@ -1779,53 +1780,51 @@ fn make(step: *Step, options: Step.MakeOptions) !void {...@@ -1779,53 +1780,51 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
1779 };1780 };
17801781
1781 // Update generated files1782 // Update generated files
1782 if (maybe_output_bin_path) |output_bin_path| {1783 if (maybe_output_dir) |output_dir| {
1783 const output_dir = fs.path.dirname(output_bin_path).?;
1784
1785 if (compile.emit_directory) |lp| {1784 if (compile.emit_directory) |lp| {
1786 lp.path = output_dir;1785 lp.path = b.fmt("{}", .{output_dir});
1787 }1786 }
17881787
1789 // -femit-bin[=path] (default) Output machine code1788 // -femit-bin[=path] (default) Output machine code
1790 if (compile.generated_bin) |bin| {1789 if (compile.generated_bin) |bin| {
1791 bin.path = b.pathJoin(&.{ output_dir, compile.out_filename });1790 bin.path = output_dir.joinString(b.allocator, compile.out_filename) catch @panic("OOM");
1792 }1791 }
17931792
1794 const sep = std.fs.path.sep;1793 const sep = std.fs.path.sep_str;
17951794
1796 // output PDB if someone requested it1795 // output PDB if someone requested it
1797 if (compile.generated_pdb) |pdb| {1796 if (compile.generated_pdb) |pdb| {
1798 pdb.path = b.fmt("{s}{c}{s}.pdb", .{ output_dir, sep, compile.name });1797 pdb.path = b.fmt("{}" ++ sep ++ "{s}.pdb", .{ output_dir, compile.name });
1799 }1798 }
18001799
1801 // -femit-implib[=path] (default) Produce an import .lib when building a Windows DLL1800 // -femit-implib[=path] (default) Produce an import .lib when building a Windows DLL
1802 if (compile.generated_implib) |implib| {1801 if (compile.generated_implib) |implib| {
1803 implib.path = b.fmt("{s}{c}{s}.lib", .{ output_dir, sep, compile.name });1802 implib.path = b.fmt("{}" ++ sep ++ "{s}.lib", .{ output_dir, compile.name });
1804 }1803 }
18051804
1806 // -femit-h[=path] Generate a C header file (.h)1805 // -femit-h[=path] Generate a C header file (.h)
1807 if (compile.generated_h) |lp| {1806 if (compile.generated_h) |lp| {
1808 lp.path = b.fmt("{s}{c}{s}.h", .{ output_dir, sep, compile.name });1807 lp.path = b.fmt("{}" ++ sep ++ "{s}.h", .{ output_dir, compile.name });
1809 }1808 }
18101809
1811 // -femit-docs[=path] Create a docs/ dir with html documentation1810 // -femit-docs[=path] Create a docs/ dir with html documentation
1812 if (compile.generated_docs) |generated_docs| {1811 if (compile.generated_docs) |generated_docs| {
1813 generated_docs.path = b.pathJoin(&.{ output_dir, "docs" });1812 generated_docs.path = output_dir.joinString(b.allocator, "docs") catch @panic("OOM");
1814 }1813 }
18151814
1816 // -femit-asm[=path] Output .s (assembly code)1815 // -femit-asm[=path] Output .s (assembly code)
1817 if (compile.generated_asm) |lp| {1816 if (compile.generated_asm) |lp| {
1818 lp.path = b.fmt("{s}{c}{s}.s", .{ output_dir, sep, compile.name });1817 lp.path = b.fmt("{}" ++ sep ++ "{s}.s", .{ output_dir, compile.name });
1819 }1818 }
18201819
1821 // -femit-llvm-ir[=path] Produce a .ll file with optimized LLVM IR (requires LLVM extensions)1820 // -femit-llvm-ir[=path] Produce a .ll file with optimized LLVM IR (requires LLVM extensions)
1822 if (compile.generated_llvm_ir) |lp| {1821 if (compile.generated_llvm_ir) |lp| {
1823 lp.path = b.fmt("{s}{c}{s}.ll", .{ output_dir, sep, compile.name });1822 lp.path = b.fmt("{}" ++ sep ++ "{s}.ll", .{ output_dir, compile.name });
1824 }1823 }
18251824
1826 // -femit-llvm-bc[=path] Produce an optimized LLVM module as a .bc file (requires LLVM extensions)1825 // -femit-llvm-bc[=path] Produce an optimized LLVM module as a .bc file (requires LLVM extensions)
1827 if (compile.generated_llvm_bc) |lp| {1826 if (compile.generated_llvm_bc) |lp| {
1828 lp.path = b.fmt("{s}{c}{s}.bc", .{ output_dir, sep, compile.name });1827 lp.path = b.fmt("{}" ++ sep ++ "{s}.bc", .{ output_dir, compile.name });
1829 }1828 }
1830 }1829 }
18311830
...@@ -1841,7 +1840,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {...@@ -1841,7 +1840,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
1841 }1840 }
1842}1841}
18431842
1844pub fn rebuildInFuzzMode(c: *Compile, progress_node: std.Progress.Node) ![]const u8 {1843pub fn rebuildInFuzzMode(c: *Compile, progress_node: std.Progress.Node) !Path {
1845 const gpa = c.step.owner.allocator;1844 const gpa = c.step.owner.allocator;
18461845
1847 c.step.result_error_msgs.clearRetainingCapacity();1846 c.step.result_error_msgs.clearRetainingCapacity();
lib/std/Build/Step/InstallArtifact.zig+25-24
...@@ -125,10 +125,10 @@ fn make(step: *Step, options: Step.MakeOptions) !void {...@@ -125,10 +125,10 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
125125
126 if (install_artifact.dest_dir) |dest_dir| {126 if (install_artifact.dest_dir) |dest_dir| {
127 const full_dest_path = b.getInstallPath(dest_dir, install_artifact.dest_sub_path);127 const full_dest_path = b.getInstallPath(dest_dir, install_artifact.dest_sub_path);
128 const full_src_path = install_artifact.emitted_bin.?.getPath2(b, step);128 const src_path = install_artifact.emitted_bin.?.getPath3(b, step);
129 const p = fs.Dir.updateFile(cwd, full_src_path, cwd, full_dest_path, .{}) catch |err| {129 const p = fs.Dir.updateFile(src_path.root_dir.handle, src_path.sub_path, cwd, full_dest_path, .{}) catch |err| {
130 return step.fail("unable to update file from '{s}' to '{s}': {s}", .{130 return step.fail("unable to update file from '{s}' to '{s}': {s}", .{
131 full_src_path, full_dest_path, @errorName(err),131 src_path.sub_path, full_dest_path, @errorName(err),
132 });132 });
133 };133 };
134 all_cached = all_cached and p == .fresh;134 all_cached = all_cached and p == .fresh;
...@@ -141,22 +141,22 @@ fn make(step: *Step, options: Step.MakeOptions) !void {...@@ -141,22 +141,22 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
141 }141 }
142142
143 if (install_artifact.implib_dir) |implib_dir| {143 if (install_artifact.implib_dir) |implib_dir| {
144 const full_src_path = install_artifact.emitted_implib.?.getPath2(b, step);144 const src_path = install_artifact.emitted_implib.?.getPath3(b, step);
145 const full_implib_path = b.getInstallPath(implib_dir, fs.path.basename(full_src_path));145 const full_implib_path = b.getInstallPath(implib_dir, fs.path.basename(src_path.sub_path));
146 const p = fs.Dir.updateFile(cwd, full_src_path, cwd, full_implib_path, .{}) catch |err| {146 const p = fs.Dir.updateFile(src_path.root_dir.handle, src_path.sub_path, cwd, full_implib_path, .{}) catch |err| {
147 return step.fail("unable to update file from '{s}' to '{s}': {s}", .{147 return step.fail("unable to update file from '{s}' to '{s}': {s}", .{
148 full_src_path, full_implib_path, @errorName(err),148 src_path.sub_path, full_implib_path, @errorName(err),
149 });149 });
150 };150 };
151 all_cached = all_cached and p == .fresh;151 all_cached = all_cached and p == .fresh;
152 }152 }
153153
154 if (install_artifact.pdb_dir) |pdb_dir| {154 if (install_artifact.pdb_dir) |pdb_dir| {
155 const full_src_path = install_artifact.emitted_pdb.?.getPath2(b, step);155 const src_path = install_artifact.emitted_pdb.?.getPath3(b, step);
156 const full_pdb_path = b.getInstallPath(pdb_dir, fs.path.basename(full_src_path));156 const full_pdb_path = b.getInstallPath(pdb_dir, fs.path.basename(src_path.sub_path));
157 const p = fs.Dir.updateFile(cwd, full_src_path, cwd, full_pdb_path, .{}) catch |err| {157 const p = fs.Dir.updateFile(src_path.root_dir.handle, src_path.sub_path, cwd, full_pdb_path, .{}) catch |err| {
158 return step.fail("unable to update file from '{s}' to '{s}': {s}", .{158 return step.fail("unable to update file from '{s}' to '{s}': {s}", .{
159 full_src_path, full_pdb_path, @errorName(err),159 src_path.sub_path, full_pdb_path, @errorName(err),
160 });160 });
161 };161 };
162 all_cached = all_cached and p == .fresh;162 all_cached = all_cached and p == .fresh;
...@@ -164,11 +164,11 @@ fn make(step: *Step, options: Step.MakeOptions) !void {...@@ -164,11 +164,11 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
164164
165 if (install_artifact.h_dir) |h_dir| {165 if (install_artifact.h_dir) |h_dir| {
166 if (install_artifact.emitted_h) |emitted_h| {166 if (install_artifact.emitted_h) |emitted_h| {
167 const full_src_path = emitted_h.getPath2(b, step);167 const src_path = emitted_h.getPath3(b, step);
168 const full_h_path = b.getInstallPath(h_dir, fs.path.basename(full_src_path));168 const full_h_path = b.getInstallPath(h_dir, fs.path.basename(src_path.sub_path));
169 const p = fs.Dir.updateFile(cwd, full_src_path, cwd, full_h_path, .{}) catch |err| {169 const p = fs.Dir.updateFile(src_path.root_dir.handle, src_path.sub_path, cwd, full_h_path, .{}) catch |err| {
170 return step.fail("unable to update file from '{s}' to '{s}': {s}", .{170 return step.fail("unable to update file from '{s}' to '{s}': {s}", .{
171 full_src_path, full_h_path, @errorName(err),171 src_path.sub_path, full_h_path, @errorName(err),
172 });172 });
173 };173 };
174 all_cached = all_cached and p == .fresh;174 all_cached = all_cached and p == .fresh;
...@@ -176,22 +176,22 @@ fn make(step: *Step, options: Step.MakeOptions) !void {...@@ -176,22 +176,22 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
176176
177 for (install_artifact.artifact.installed_headers.items) |installation| switch (installation) {177 for (install_artifact.artifact.installed_headers.items) |installation| switch (installation) {
178 .file => |file| {178 .file => |file| {
179 const full_src_path = file.source.getPath2(b, step);179 const src_path = file.source.getPath3(b, step);
180 const full_h_path = b.getInstallPath(h_dir, file.dest_rel_path);180 const full_h_path = b.getInstallPath(h_dir, file.dest_rel_path);
181 const p = fs.Dir.updateFile(cwd, full_src_path, cwd, full_h_path, .{}) catch |err| {181 const p = fs.Dir.updateFile(src_path.root_dir.handle, src_path.sub_path, cwd, full_h_path, .{}) catch |err| {
182 return step.fail("unable to update file from '{s}' to '{s}': {s}", .{182 return step.fail("unable to update file from '{s}' to '{s}': {s}", .{
183 full_src_path, full_h_path, @errorName(err),183 src_path.sub_path, full_h_path, @errorName(err),
184 });184 });
185 };185 };
186 all_cached = all_cached and p == .fresh;186 all_cached = all_cached and p == .fresh;
187 },187 },
188 .directory => |dir| {188 .directory => |dir| {
189 const full_src_dir_path = dir.source.getPath2(b, step);189 const src_dir_path = dir.source.getPath3(b, step);
190 const full_h_prefix = b.getInstallPath(h_dir, dir.dest_rel_path);190 const full_h_prefix = b.getInstallPath(h_dir, dir.dest_rel_path);
191191
192 var src_dir = b.build_root.handle.openDir(full_src_dir_path, .{ .iterate = true }) catch |err| {192 var src_dir = src_dir_path.root_dir.handle.openDir(src_dir_path.sub_path, .{ .iterate = true }) catch |err| {
193 return step.fail("unable to open source directory '{s}': {s}", .{193 return step.fail("unable to open source directory '{s}': {s}", .{
194 full_src_dir_path, @errorName(err),194 src_dir_path.sub_path, @errorName(err),
195 });195 });
196 };196 };
197 defer src_dir.close();197 defer src_dir.close();
...@@ -208,14 +208,15 @@ fn make(step: *Step, options: Step.MakeOptions) !void {...@@ -208,14 +208,15 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
208 continue :next_entry;208 continue :next_entry;
209 }209 }
210 }210 }
211 const full_src_entry_path = b.pathJoin(&.{ full_src_dir_path, entry.path });211
212 const src_entry_path = src_dir_path.join(b.allocator, entry.path) catch @panic("OOM");
212 const full_dest_path = b.pathJoin(&.{ full_h_prefix, entry.path });213 const full_dest_path = b.pathJoin(&.{ full_h_prefix, entry.path });
213 switch (entry.kind) {214 switch (entry.kind) {
214 .directory => try cwd.makePath(full_dest_path),215 .directory => try cwd.makePath(full_dest_path),
215 .file => {216 .file => {
216 const p = fs.Dir.updateFile(cwd, full_src_entry_path, cwd, full_dest_path, .{}) catch |err| {217 const p = fs.Dir.updateFile(src_entry_path.root_dir.handle, src_entry_path.sub_path, cwd, full_dest_path, .{}) catch |err| {
217 return step.fail("unable to update file from '{s}' to '{s}': {s}", .{218 return step.fail("unable to update file from '{s}' to '{s}': {s}", .{
218 full_src_entry_path, full_dest_path, @errorName(err),219 src_entry_path.sub_path, full_dest_path, @errorName(err),
219 });220 });
220 };221 };
221 all_cached = all_cached and p == .fresh;222 all_cached = all_cached and p == .fresh;
lib/std/Build/Step/Run.zig+3-2
...@@ -7,6 +7,7 @@ const mem = std.mem;...@@ -7,6 +7,7 @@ const mem = std.mem;
7const process = std.process;7const process = std.process;
8const EnvMap = process.EnvMap;8const EnvMap = process.EnvMap;
9const assert = std.debug.assert;9const assert = std.debug.assert;
10const Path = Build.Cache.Path;
1011
11const Run = @This();12const Run = @This();
1213
...@@ -93,7 +94,7 @@ cached_test_metadata: ?CachedTestMetadata = null,...@@ -93,7 +94,7 @@ cached_test_metadata: ?CachedTestMetadata = null,
9394
94/// Populated during the fuzz phase if this run step corresponds to a unit test95/// Populated during the fuzz phase if this run step corresponds to a unit test
95/// executable that contains fuzz tests.96/// executable that contains fuzz tests.
96rebuilt_executable: ?[]const u8,97rebuilt_executable: ?Path,
9798
98/// If this Run step was produced by a Compile step, it is tracked here.99/// If this Run step was produced by a Compile step, it is tracked here.
99producer: ?*Step.Compile,100producer: ?*Step.Compile,
...@@ -872,7 +873,7 @@ pub fn rerunInFuzzMode(...@@ -872,7 +873,7 @@ pub fn rerunInFuzzMode(
872 .artifact => |pa| {873 .artifact => |pa| {
873 const artifact = pa.artifact;874 const artifact = pa.artifact;
874 const file_path = if (artifact == run.producer.?)875 const file_path = if (artifact == run.producer.?)
875 run.rebuilt_executable.?876 b.fmt("{}", .{run.rebuilt_executable.?})
876 else877 else
877 (artifact.installed_path orelse artifact.generated_bin.?.path.?);878 (artifact.installed_path orelse artifact.generated_bin.?.path.?);
878 try argv_list.append(arena, b.fmt("{s}{s}", .{ pa.prefix, file_path }));879 try argv_list.append(arena, b.fmt("{s}{s}", .{ pa.prefix, file_path }));
lib/std/Build/Step/TranslateC.zig+6-6
...@@ -153,12 +153,12 @@ fn make(step: *Step, options: Step.MakeOptions) !void {...@@ -153,12 +153,12 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
153 try argv_list.append(c_macro);153 try argv_list.append(c_macro);
154 }154 }
155155
156 try argv_list.append(translate_c.source.getPath2(b, step));156 const c_source_path = translate_c.source.getPath2(b, step);
157 try argv_list.append(c_source_path);
157158
158 const output_path = try step.evalZigProcess(argv_list.items, prog_node, false);159 const output_dir = try step.evalZigProcess(argv_list.items, prog_node, false);
159160
160 translate_c.out_basename = fs.path.basename(output_path.?);161 const basename = std.fs.path.stem(std.fs.path.basename(c_source_path));
161 const output_dir = fs.path.dirname(output_path.?).?;162 translate_c.out_basename = b.fmt("{s}.zig", .{basename});
162163 translate_c.output_file.path = output_dir.?.joinString(b.allocator, translate_c.out_basename) catch @panic("OOM");
163 translate_c.output_file.path = b.pathJoin(&.{ output_dir, translate_c.out_basename });
164}164}
lib/std/zig/Server.zig+11-10
...@@ -14,8 +14,8 @@ pub const Message = struct {...@@ -14,8 +14,8 @@ pub const Message = struct {
14 zig_version,14 zig_version,
15 /// Body is an ErrorBundle.15 /// Body is an ErrorBundle.
16 error_bundle,16 error_bundle,
17 /// Body is a EmitBinPath.17 /// Body is a EmitDigest.
18 emit_bin_path,18 emit_digest,
19 /// Body is a TestMetadata19 /// Body is a TestMetadata
20 test_metadata,20 test_metadata,
21 /// Body is a TestResults21 /// Body is a TestResults
...@@ -82,8 +82,8 @@ pub const Message = struct {...@@ -82,8 +82,8 @@ pub const Message = struct {
82 };82 };
8383
84 /// Trailing:84 /// Trailing:
85 /// * file system path where the emitted binary can be found85 /// * the hex digest of the cache directory within the /o/ subdirectory.
86 pub const EmitBinPath = extern struct {86 pub const EmitDigest = extern struct {
87 flags: Flags,87 flags: Flags,
8888
89 pub const Flags = packed struct(u8) {89 pub const Flags = packed struct(u8) {
...@@ -196,17 +196,17 @@ pub fn serveU64Message(s: *Server, tag: OutMessage.Tag, int: u64) !void {...@@ -196,17 +196,17 @@ pub fn serveU64Message(s: *Server, tag: OutMessage.Tag, int: u64) !void {
196 }, &.{std.mem.asBytes(&msg_le)});196 }, &.{std.mem.asBytes(&msg_le)});
197}197}
198198
199pub fn serveEmitBinPath(199pub fn serveEmitDigest(
200 s: *Server,200 s: *Server,
201 fs_path: []const u8,201 digest: *const [Cache.bin_digest_len]u8,
202 header: OutMessage.EmitBinPath,202 header: OutMessage.EmitDigest,
203) !void {203) !void {
204 try s.serveMessage(.{204 try s.serveMessage(.{
205 .tag = .emit_bin_path,205 .tag = .emit_digest,
206 .bytes_len = @intCast(fs_path.len + @sizeOf(OutMessage.EmitBinPath)),206 .bytes_len = @intCast(digest.len + @sizeOf(OutMessage.EmitDigest)),
207 }, &.{207 }, &.{
208 std.mem.asBytes(&header),208 std.mem.asBytes(&header),
209 fs_path,209 digest,
210 });210 });
211}211}
212212
...@@ -328,3 +328,4 @@ const Allocator = std.mem.Allocator;...@@ -328,3 +328,4 @@ const Allocator = std.mem.Allocator;
328const assert = std.debug.assert;328const assert = std.debug.assert;
329const native_endian = builtin.target.cpu.arch.endian();329const native_endian = builtin.target.cpu.arch.endian();
330const need_bswap = native_endian != .little;330const need_bswap = native_endian != .little;
331const Cache = std.Build.Cache;
src/Compilation.zig+68-88
...@@ -39,6 +39,8 @@ const Air = @import("Air.zig");...@@ -39,6 +39,8 @@ const Air = @import("Air.zig");
39const Builtin = @import("Builtin.zig");39const Builtin = @import("Builtin.zig");
40const LlvmObject = @import("codegen/llvm.zig").Object;40const LlvmObject = @import("codegen/llvm.zig").Object;
41const dev = @import("dev.zig");41const dev = @import("dev.zig");
42pub const Directory = Cache.Directory;
43const Path = Cache.Path;
4244
43pub const Config = @import("Compilation/Config.zig");45pub const Config = @import("Compilation/Config.zig");
4446
...@@ -70,9 +72,9 @@ bin_file: ?*link.File,...@@ -70,9 +72,9 @@ bin_file: ?*link.File,
70/// The root path for the dynamic linker and system libraries (as well as frameworks on Darwin)72/// The root path for the dynamic linker and system libraries (as well as frameworks on Darwin)
71sysroot: ?[]const u8,73sysroot: ?[]const u8,
72/// This is `null` when not building a Windows DLL, or when `-fno-emit-implib` is used.74/// This is `null` when not building a Windows DLL, or when `-fno-emit-implib` is used.
73implib_emit: ?Emit,75implib_emit: ?Path,
74/// This is non-null when `-femit-docs` is provided.76/// This is non-null when `-femit-docs` is provided.
75docs_emit: ?Emit,77docs_emit: ?Path,
76root_name: [:0]const u8,78root_name: [:0]const u8,
77include_compiler_rt: bool,79include_compiler_rt: bool,
78objects: []Compilation.LinkObject,80objects: []Compilation.LinkObject,
...@@ -269,27 +271,9 @@ llvm_opt_bisect_limit: c_int,...@@ -269,27 +271,9 @@ llvm_opt_bisect_limit: c_int,
269271
270file_system_inputs: ?*std.ArrayListUnmanaged(u8),272file_system_inputs: ?*std.ArrayListUnmanaged(u8),
271273
272pub const Emit = struct {274/// This is the digest of the cache for the current compilation.
273 /// Where the output will go.275/// This digest will be known after update() is called.
274 directory: Directory,276digest: ?[Cache.bin_digest_len]u8 = null,
275 /// Path to the output file, relative to `directory`.
276 sub_path: []const u8,
277
278 /// Returns the full path to `basename` if it were in the same directory as the
279 /// `Emit` sub_path.
280 pub fn basenamePath(emit: Emit, arena: Allocator, basename: []const u8) ![:0]const u8 {
281 const full_path = if (emit.directory.path) |p|
282 try std.fs.path.join(arena, &[_][]const u8{ p, emit.sub_path })
283 else
284 emit.sub_path;
285
286 if (std.fs.path.dirname(full_path)) |dirname| {
287 return try std.fs.path.joinZ(arena, &.{ dirname, basename });
288 } else {
289 return try arena.dupeZ(u8, basename);
290 }
291 }
292};
293277
294pub const default_stack_protector_buffer_size = target_util.default_stack_protector_buffer_size;278pub const default_stack_protector_buffer_size = target_util.default_stack_protector_buffer_size;
295pub const SemaError = Zcu.SemaError;279pub const SemaError = Zcu.SemaError;
...@@ -868,8 +852,6 @@ pub const LldError = struct {...@@ -868,8 +852,6 @@ pub const LldError = struct {
868 }852 }
869};853};
870854
871pub const Directory = Cache.Directory;
872
873pub const EmitLoc = struct {855pub const EmitLoc = struct {
874 /// If this is `null` it means the file will be output to the cache directory.856 /// If this is `null` it means the file will be output to the cache directory.
875 /// When provided, both the open file handle and the path name must outlive the `Compilation`.857 /// When provided, both the open file handle and the path name must outlive the `Compilation`.
...@@ -1672,7 +1654,9 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -1672,7 +1654,9 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
1672 // In the case of incremental cache mode, this `artifact_directory`1654 // In the case of incremental cache mode, this `artifact_directory`
1673 // is computed based on a hash of non-linker inputs, and it is where all1655 // is computed based on a hash of non-linker inputs, and it is where all
1674 // build artifacts are stored (even while in-progress).1656 // build artifacts are stored (even while in-progress).
1657 comp.digest = hash.peekBin();
1675 const digest = hash.final();1658 const digest = hash.final();
1659
1676 const artifact_sub_dir = "o" ++ std.fs.path.sep_str ++ digest;1660 const artifact_sub_dir = "o" ++ std.fs.path.sep_str ++ digest;
1677 var artifact_dir = try options.local_cache_directory.handle.makeOpenPath(artifact_sub_dir, .{});1661 var artifact_dir = try options.local_cache_directory.handle.makeOpenPath(artifact_sub_dir, .{});
1678 errdefer artifact_dir.close();1662 errdefer artifact_dir.close();
...@@ -1688,8 +1672,8 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -1688,8 +1672,8 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
1688 comp.cache_use = .{ .incremental = incremental };1672 comp.cache_use = .{ .incremental = incremental };
16891673
1690 if (options.emit_bin) |emit_bin| {1674 if (options.emit_bin) |emit_bin| {
1691 const emit: Emit = .{1675 const emit: Path = .{
1692 .directory = emit_bin.directory orelse artifact_directory,1676 .root_dir = emit_bin.directory orelse artifact_directory,
1693 .sub_path = emit_bin.basename,1677 .sub_path = emit_bin.basename,
1694 };1678 };
1695 comp.bin_file = try link.File.open(arena, comp, emit, lf_open_opts);1679 comp.bin_file = try link.File.open(arena, comp, emit, lf_open_opts);
...@@ -1697,14 +1681,14 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -1697,14 +1681,14 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
16971681
1698 if (options.emit_implib) |emit_implib| {1682 if (options.emit_implib) |emit_implib| {
1699 comp.implib_emit = .{1683 comp.implib_emit = .{
1700 .directory = emit_implib.directory orelse artifact_directory,1684 .root_dir = emit_implib.directory orelse artifact_directory,
1701 .sub_path = emit_implib.basename,1685 .sub_path = emit_implib.basename,
1702 };1686 };
1703 }1687 }
17041688
1705 if (options.emit_docs) |emit_docs| {1689 if (options.emit_docs) |emit_docs| {
1706 comp.docs_emit = .{1690 comp.docs_emit = .{
1707 .directory = emit_docs.directory orelse artifact_directory,1691 .root_dir = emit_docs.directory orelse artifact_directory,
1708 .sub_path = emit_docs.basename,1692 .sub_path = emit_docs.basename,
1709 };1693 };
1710 }1694 }
...@@ -2121,9 +2105,11 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {...@@ -2121,9 +2105,11 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
21212105
2122 comp.last_update_was_cache_hit = true;2106 comp.last_update_was_cache_hit = true;
2123 log.debug("CacheMode.whole cache hit for {s}", .{comp.root_name});2107 log.debug("CacheMode.whole cache hit for {s}", .{comp.root_name});
2124 const digest = man.final();2108 const bin_digest = man.finalBin();
2109 const hex_digest = Cache.binToHex(bin_digest);
21252110
2126 comp.wholeCacheModeSetBinFilePath(whole, &digest);2111 comp.digest = bin_digest;
2112 comp.wholeCacheModeSetBinFilePath(whole, &hex_digest);
21272113
2128 assert(whole.lock == null);2114 assert(whole.lock == null);
2129 whole.lock = man.toOwnedLock();2115 whole.lock = man.toOwnedLock();
...@@ -2155,21 +2141,21 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {...@@ -2155,21 +2141,21 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
21552141
2156 if (whole.implib_sub_path) |sub_path| {2142 if (whole.implib_sub_path) |sub_path| {
2157 comp.implib_emit = .{2143 comp.implib_emit = .{
2158 .directory = tmp_artifact_directory,2144 .root_dir = tmp_artifact_directory,
2159 .sub_path = std.fs.path.basename(sub_path),2145 .sub_path = std.fs.path.basename(sub_path),
2160 };2146 };
2161 }2147 }
21622148
2163 if (whole.docs_sub_path) |sub_path| {2149 if (whole.docs_sub_path) |sub_path| {
2164 comp.docs_emit = .{2150 comp.docs_emit = .{
2165 .directory = tmp_artifact_directory,2151 .root_dir = tmp_artifact_directory,
2166 .sub_path = std.fs.path.basename(sub_path),2152 .sub_path = std.fs.path.basename(sub_path),
2167 };2153 };
2168 }2154 }
21692155
2170 if (whole.bin_sub_path) |sub_path| {2156 if (whole.bin_sub_path) |sub_path| {
2171 const emit: Emit = .{2157 const emit: Path = .{
2172 .directory = tmp_artifact_directory,2158 .root_dir = tmp_artifact_directory,
2173 .sub_path = std.fs.path.basename(sub_path),2159 .sub_path = std.fs.path.basename(sub_path),
2174 };2160 };
2175 comp.bin_file = try link.File.createEmpty(arena, comp, emit, whole.lf_open_opts);2161 comp.bin_file = try link.File.createEmpty(arena, comp, emit, whole.lf_open_opts);
...@@ -2329,7 +2315,8 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {...@@ -2329,7 +2315,8 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
2329 try man.populateOtherManifest(pwc.manifest, pwc.prefix_map);2315 try man.populateOtherManifest(pwc.manifest, pwc.prefix_map);
2330 }2316 }
23312317
2332 const digest = man.final();2318 const bin_digest = man.finalBin();
2319 const hex_digest = Cache.binToHex(bin_digest);
23332320
2334 // Rename the temporary directory into place.2321 // Rename the temporary directory into place.
2335 // Close tmp dir and link.File to avoid open handle during rename.2322 // Close tmp dir and link.File to avoid open handle during rename.
...@@ -2341,7 +2328,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {...@@ -2341,7 +2328,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
23412328
2342 const s = std.fs.path.sep_str;2329 const s = std.fs.path.sep_str;
2343 const tmp_dir_sub_path = "tmp" ++ s ++ std.fmt.hex(tmp_dir_rand_int);2330 const tmp_dir_sub_path = "tmp" ++ s ++ std.fmt.hex(tmp_dir_rand_int);
2344 const o_sub_path = "o" ++ s ++ digest;2331 const o_sub_path = "o" ++ s ++ hex_digest;
23452332
2346 // Work around windows `AccessDenied` if any files within this2333 // Work around windows `AccessDenied` if any files within this
2347 // directory are open by closing and reopening the file handles.2334 // directory are open by closing and reopening the file handles.
...@@ -2376,14 +2363,15 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {...@@ -2376,14 +2363,15 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
2376 },2363 },
2377 );2364 );
2378 };2365 };
2379 comp.wholeCacheModeSetBinFilePath(whole, &digest);2366 comp.digest = bin_digest;
2367 comp.wholeCacheModeSetBinFilePath(whole, &hex_digest);
23802368
2381 // The linker flush functions need to know the final output path2369 // The linker flush functions need to know the final output path
2382 // for debug info purposes because executable debug info contains2370 // for debug info purposes because executable debug info contains
2383 // references object file paths.2371 // references object file paths.
2384 if (comp.bin_file) |lf| {2372 if (comp.bin_file) |lf| {
2385 lf.emit = .{2373 lf.emit = .{
2386 .directory = comp.local_cache_directory,2374 .root_dir = comp.local_cache_directory,
2387 .sub_path = whole.bin_sub_path.?,2375 .sub_path = whole.bin_sub_path.?,
2388 };2376 };
23892377
...@@ -2393,9 +2381,10 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {...@@ -2393,9 +2381,10 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
2393 }2381 }
2394 }2382 }
23952383
2396 try flush(comp, arena, .main, main_progress_node);2384 try flush(comp, arena, .{
23972385 .root_dir = comp.local_cache_directory,
2398 if (try comp.totalErrorCount() != 0) return;2386 .sub_path = o_sub_path,
2387 }, .main, main_progress_node);
23992388
2400 // Failure here only means an unnecessary cache miss.2389 // Failure here only means an unnecessary cache miss.
2401 man.writeManifest() catch |err| {2390 man.writeManifest() catch |err| {
...@@ -2410,8 +2399,10 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {...@@ -2410,8 +2399,10 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
2410 assert(whole.lock == null);2399 assert(whole.lock == null);
2411 whole.lock = man.toOwnedLock();2400 whole.lock = man.toOwnedLock();
2412 },2401 },
2413 .incremental => {2402 .incremental => |incremental| {
2414 try flush(comp, arena, .main, main_progress_node);2403 try flush(comp, arena, .{
2404 .root_dir = incremental.artifact_directory,
2405 }, .main, main_progress_node);
2415 },2406 },
2416 }2407 }
2417}2408}
...@@ -2440,7 +2431,13 @@ pub fn appendFileSystemInput(...@@ -2440,7 +2431,13 @@ pub fn appendFileSystemInput(
2440 std.debug.panic("missing prefix directory: {}, {s}", .{ root, sub_file_path });2431 std.debug.panic("missing prefix directory: {}, {s}", .{ root, sub_file_path });
2441}2432}
24422433
2443fn flush(comp: *Compilation, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) !void {2434fn flush(
2435 comp: *Compilation,
2436 arena: Allocator,
2437 default_artifact_directory: Path,
2438 tid: Zcu.PerThread.Id,
2439 prog_node: std.Progress.Node,
2440) !void {
2444 if (comp.bin_file) |lf| {2441 if (comp.bin_file) |lf| {
2445 // This is needed before reading the error flags.2442 // This is needed before reading the error flags.
2446 lf.flush(arena, tid, prog_node) catch |err| switch (err) {2443 lf.flush(arena, tid, prog_node) catch |err| switch (err) {
...@@ -2454,17 +2451,7 @@ fn flush(comp: *Compilation, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:...@@ -2454,17 +2451,7 @@ fn flush(comp: *Compilation, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
2454 try link.File.C.flushEmitH(zcu);2451 try link.File.C.flushEmitH(zcu);
24552452
2456 if (zcu.llvm_object) |llvm_object| {2453 if (zcu.llvm_object) |llvm_object| {
2457 const default_emit = switch (comp.cache_use) {2454 try emitLlvmObject(comp, arena, default_artifact_directory, null, llvm_object, prog_node);
2458 .whole => |whole| .{
2459 .directory = whole.tmp_artifact_directory.?,
2460 .sub_path = "dummy",
2461 },
2462 .incremental => |incremental| .{
2463 .directory = incremental.artifact_directory,
2464 .sub_path = "dummy",
2465 },
2466 };
2467 try emitLlvmObject(comp, arena, default_emit, null, llvm_object, prog_node);
2468 }2455 }
2469 }2456 }
2470}2457}
...@@ -2533,7 +2520,7 @@ fn wholeCacheModeSetBinFilePath(...@@ -2533,7 +2520,7 @@ fn wholeCacheModeSetBinFilePath(
2533 @memcpy(sub_path[digest_start..][0..digest.len], digest);2520 @memcpy(sub_path[digest_start..][0..digest.len], digest);
25342521
2535 comp.implib_emit = .{2522 comp.implib_emit = .{
2536 .directory = comp.local_cache_directory,2523 .root_dir = comp.local_cache_directory,
2537 .sub_path = sub_path,2524 .sub_path = sub_path,
2538 };2525 };
2539 }2526 }
...@@ -2542,7 +2529,7 @@ fn wholeCacheModeSetBinFilePath(...@@ -2542,7 +2529,7 @@ fn wholeCacheModeSetBinFilePath(
2542 @memcpy(sub_path[digest_start..][0..digest.len], digest);2529 @memcpy(sub_path[digest_start..][0..digest.len], digest);
25432530
2544 comp.docs_emit = .{2531 comp.docs_emit = .{
2545 .directory = comp.local_cache_directory,2532 .root_dir = comp.local_cache_directory,
2546 .sub_path = sub_path,2533 .sub_path = sub_path,
2547 };2534 };
2548 }2535 }
...@@ -2745,7 +2732,7 @@ fn emitOthers(comp: *Compilation) void {...@@ -2745,7 +2732,7 @@ fn emitOthers(comp: *Compilation) void {
2745pub fn emitLlvmObject(2732pub fn emitLlvmObject(
2746 comp: *Compilation,2733 comp: *Compilation,
2747 arena: Allocator,2734 arena: Allocator,
2748 default_emit: Emit,2735 default_artifact_directory: Path,
2749 bin_emit_loc: ?EmitLoc,2736 bin_emit_loc: ?EmitLoc,
2750 llvm_object: LlvmObject.Ptr,2737 llvm_object: LlvmObject.Ptr,
2751 prog_node: std.Progress.Node,2738 prog_node: std.Progress.Node,
...@@ -2756,10 +2743,10 @@ pub fn emitLlvmObject(...@@ -2756,10 +2743,10 @@ pub fn emitLlvmObject(
2756 try llvm_object.emit(.{2743 try llvm_object.emit(.{
2757 .pre_ir_path = comp.verbose_llvm_ir,2744 .pre_ir_path = comp.verbose_llvm_ir,
2758 .pre_bc_path = comp.verbose_llvm_bc,2745 .pre_bc_path = comp.verbose_llvm_bc,
2759 .bin_path = try resolveEmitLoc(arena, default_emit, bin_emit_loc),2746 .bin_path = try resolveEmitLoc(arena, default_artifact_directory, bin_emit_loc),
2760 .asm_path = try resolveEmitLoc(arena, default_emit, comp.emit_asm),2747 .asm_path = try resolveEmitLoc(arena, default_artifact_directory, comp.emit_asm),
2761 .post_ir_path = try resolveEmitLoc(arena, default_emit, comp.emit_llvm_ir),2748 .post_ir_path = try resolveEmitLoc(arena, default_artifact_directory, comp.emit_llvm_ir),
2762 .post_bc_path = try resolveEmitLoc(arena, default_emit, comp.emit_llvm_bc),2749 .post_bc_path = try resolveEmitLoc(arena, default_artifact_directory, comp.emit_llvm_bc),
27632750
2764 .is_debug = comp.root_mod.optimize_mode == .Debug,2751 .is_debug = comp.root_mod.optimize_mode == .Debug,
2765 .is_small = comp.root_mod.optimize_mode == .ReleaseSmall,2752 .is_small = comp.root_mod.optimize_mode == .ReleaseSmall,
...@@ -2772,14 +2759,14 @@ pub fn emitLlvmObject(...@@ -2772,14 +2759,14 @@ pub fn emitLlvmObject(
27722759
2773fn resolveEmitLoc(2760fn resolveEmitLoc(
2774 arena: Allocator,2761 arena: Allocator,
2775 default_emit: Emit,2762 default_artifact_directory: Path,
2776 opt_loc: ?EmitLoc,2763 opt_loc: ?EmitLoc,
2777) Allocator.Error!?[*:0]const u8 {2764) Allocator.Error!?[*:0]const u8 {
2778 const loc = opt_loc orelse return null;2765 const loc = opt_loc orelse return null;
2779 const slice = if (loc.directory) |directory|2766 const slice = if (loc.directory) |directory|
2780 try directory.joinZ(arena, &.{loc.basename})2767 try directory.joinZ(arena, &.{loc.basename})
2781 else2768 else
2782 try default_emit.basenamePath(arena, loc.basename);2769 try default_artifact_directory.joinStringZ(arena, loc.basename);
2783 return slice.ptr;2770 return slice.ptr;
2784}2771}
27852772
...@@ -3035,7 +3022,7 @@ pub fn saveState(comp: *Compilation) !void {...@@ -3035,7 +3022,7 @@ pub fn saveState(comp: *Compilation) !void {
30353022
3036 // Using an atomic file prevents a crash or power failure from corrupting3023 // Using an atomic file prevents a crash or power failure from corrupting
3037 // the previous incremental compilation state.3024 // the previous incremental compilation state.
3038 var af = try lf.emit.directory.handle.atomicFile(basename, .{});3025 var af = try lf.emit.root_dir.handle.atomicFile(basename, .{});
3039 defer af.deinit();3026 defer af.deinit();
3040 try af.file.pwritevAll(bufs.items, 0);3027 try af.file.pwritevAll(bufs.items, 0);
3041 try af.finish();3028 try af.finish();
...@@ -4000,11 +3987,11 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void {...@@ -4000,11 +3987,11 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void {
4000 return comp.lockAndSetMiscFailure(.docs_copy, "no Zig code to document", .{});3987 return comp.lockAndSetMiscFailure(.docs_copy, "no Zig code to document", .{});
40013988
4002 const emit = comp.docs_emit.?;3989 const emit = comp.docs_emit.?;
4003 var out_dir = emit.directory.handle.makeOpenPath(emit.sub_path, .{}) catch |err| {3990 var out_dir = emit.root_dir.handle.makeOpenPath(emit.sub_path, .{}) catch |err| {
4004 return comp.lockAndSetMiscFailure(3991 return comp.lockAndSetMiscFailure(
4005 .docs_copy,3992 .docs_copy,
4006 "unable to create output directory '{}{s}': {s}",3993 "unable to create output directory '{}{s}': {s}",
4007 .{ emit.directory, emit.sub_path, @errorName(err) },3994 .{ emit.root_dir, emit.sub_path, @errorName(err) },
4008 );3995 );
4009 };3996 };
4010 defer out_dir.close();3997 defer out_dir.close();
...@@ -4024,7 +4011,7 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void {...@@ -4024,7 +4011,7 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void {
4024 return comp.lockAndSetMiscFailure(4011 return comp.lockAndSetMiscFailure(
4025 .docs_copy,4012 .docs_copy,
4026 "unable to create '{}{s}/sources.tar': {s}",4013 "unable to create '{}{s}/sources.tar': {s}",
4027 .{ emit.directory, emit.sub_path, @errorName(err) },4014 .{ emit.root_dir, emit.sub_path, @errorName(err) },
4028 );4015 );
4029 };4016 };
4030 defer tar_file.close();4017 defer tar_file.close();
...@@ -4223,11 +4210,11 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -4223,11 +4210,11 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) anye
4223 try comp.updateSubCompilation(sub_compilation, .docs_wasm, prog_node);4210 try comp.updateSubCompilation(sub_compilation, .docs_wasm, prog_node);
42244211
4225 const emit = comp.docs_emit.?;4212 const emit = comp.docs_emit.?;
4226 var out_dir = emit.directory.handle.makeOpenPath(emit.sub_path, .{}) catch |err| {4213 var out_dir = emit.root_dir.handle.makeOpenPath(emit.sub_path, .{}) catch |err| {
4227 return comp.lockAndSetMiscFailure(4214 return comp.lockAndSetMiscFailure(
4228 .docs_copy,4215 .docs_copy,
4229 "unable to create output directory '{}{s}': {s}",4216 "unable to create output directory '{}{s}': {s}",
4230 .{ emit.directory, emit.sub_path, @errorName(err) },4217 .{ emit.root_dir, emit.sub_path, @errorName(err) },
4231 );4218 );
4232 };4219 };
4233 defer out_dir.close();4220 defer out_dir.close();
...@@ -4241,7 +4228,7 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -4241,7 +4228,7 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) anye
4241 return comp.lockAndSetMiscFailure(.docs_copy, "unable to copy '{}{s}' to '{}{s}': {s}", .{4228 return comp.lockAndSetMiscFailure(.docs_copy, "unable to copy '{}{s}' to '{}{s}': {s}", .{
4242 sub_compilation.local_cache_directory,4229 sub_compilation.local_cache_directory,
4243 sub_compilation.cache_use.whole.bin_sub_path.?,4230 sub_compilation.cache_use.whole.bin_sub_path.?,
4244 emit.directory,4231 emit.root_dir,
4245 emit.sub_path,4232 emit.sub_path,
4246 @errorName(err),4233 @errorName(err),
4247 });4234 });
...@@ -4403,7 +4390,7 @@ pub fn obtainWin32ResourceCacheManifest(comp: *const Compilation) Cache.Manifest...@@ -4403,7 +4390,7 @@ pub fn obtainWin32ResourceCacheManifest(comp: *const Compilation) Cache.Manifest
4403}4390}
44044391
4405pub const CImportResult = struct {4392pub const CImportResult = struct {
4406 out_zig_path: []u8,4393 digest: [Cache.bin_digest_len]u8,
4407 cache_hit: bool,4394 cache_hit: bool,
4408 errors: std.zig.ErrorBundle,4395 errors: std.zig.ErrorBundle,
44094396
...@@ -4413,8 +4400,6 @@ pub const CImportResult = struct {...@@ -4413,8 +4400,6 @@ pub const CImportResult = struct {
4413};4400};
44144401
4415/// Caller owns returned memory.4402/// Caller owns returned memory.
4416/// This API is currently coupled pretty tightly to stage1's needs; it will need to be reworked
4417/// a bit when we want to start using it from self-hosted.
4418pub fn cImport(comp: *Compilation, c_src: []const u8, owner_mod: *Package.Module) !CImportResult {4403pub fn cImport(comp: *Compilation, c_src: []const u8, owner_mod: *Package.Module) !CImportResult {
4419 dev.check(.translate_c_command);4404 dev.check(.translate_c_command);
44204405
...@@ -4503,7 +4488,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8, owner_mod: *Package.Module...@@ -4503,7 +4488,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8, owner_mod: *Package.Module
4503 error.OutOfMemory => return error.OutOfMemory,4488 error.OutOfMemory => return error.OutOfMemory,
4504 error.SemanticAnalyzeFail => {4489 error.SemanticAnalyzeFail => {
4505 return CImportResult{4490 return CImportResult{
4506 .out_zig_path = "",4491 .digest = undefined,
4507 .cache_hit = actual_hit,4492 .cache_hit = actual_hit,
4508 .errors = errors,4493 .errors = errors,
4509 };4494 };
...@@ -4528,8 +4513,9 @@ pub fn cImport(comp: *Compilation, c_src: []const u8, owner_mod: *Package.Module...@@ -4528,8 +4513,9 @@ pub fn cImport(comp: *Compilation, c_src: []const u8, owner_mod: *Package.Module
4528 .incremental => {},4513 .incremental => {},
4529 }4514 }
45304515
4531 const digest = man.final();4516 const bin_digest = man.finalBin();
4532 const o_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest });4517 const hex_digest = Cache.binToHex(bin_digest);
4518 const o_sub_path = "o" ++ std.fs.path.sep_str ++ hex_digest;
4533 var o_dir = try comp.local_cache_directory.handle.makeOpenPath(o_sub_path, .{});4519 var o_dir = try comp.local_cache_directory.handle.makeOpenPath(o_sub_path, .{});
4534 defer o_dir.close();4520 defer o_dir.close();
45354521
...@@ -4541,8 +4527,8 @@ pub fn cImport(comp: *Compilation, c_src: []const u8, owner_mod: *Package.Module...@@ -4541,8 +4527,8 @@ pub fn cImport(comp: *Compilation, c_src: []const u8, owner_mod: *Package.Module
45414527
4542 try out_zig_file.writeAll(formatted);4528 try out_zig_file.writeAll(formatted);
45434529
4544 break :digest digest;4530 break :digest bin_digest;
4545 } else man.final();4531 } else man.finalBin();
45464532
4547 if (man.have_exclusive_lock) {4533 if (man.have_exclusive_lock) {
4548 // Write the updated manifest. This is a no-op if the manifest is not dirty. Note that it is4534 // Write the updated manifest. This is a no-op if the manifest is not dirty. Note that it is
...@@ -4554,14 +4540,8 @@ pub fn cImport(comp: *Compilation, c_src: []const u8, owner_mod: *Package.Module...@@ -4554,14 +4540,8 @@ pub fn cImport(comp: *Compilation, c_src: []const u8, owner_mod: *Package.Module
4554 };4540 };
4555 }4541 }
45564542
4557 const out_zig_path = try comp.local_cache_directory.join(comp.arena, &.{
4558 "o", &digest, cimport_zig_basename,
4559 });
4560 if (comp.verbose_cimport) {
4561 log.info("C import output: {s}", .{out_zig_path});
4562 }
4563 return CImportResult{4543 return CImportResult{
4564 .out_zig_path = out_zig_path,4544 .digest = digest,
4565 .cache_hit = actual_hit,4545 .cache_hit = actual_hit,
4566 .errors = std.zig.ErrorBundle.empty,4546 .errors = std.zig.ErrorBundle.empty,
4567 };4547 };
...@@ -4800,7 +4780,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr...@@ -4800,7 +4780,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
4800 try argv.appendSlice(c_object.src.cache_exempt_flags);4780 try argv.appendSlice(c_object.src.cache_exempt_flags);
48014781
4802 const out_obj_path = if (comp.bin_file) |lf|4782 const out_obj_path = if (comp.bin_file) |lf|
4803 try lf.emit.directory.join(arena, &.{lf.emit.sub_path})4783 try lf.emit.root_dir.join(arena, &.{lf.emit.sub_path})
4804 else4784 else
4805 "/dev/null";4785 "/dev/null";
48064786
src/Sema.zig+7-4
...@@ -183,6 +183,7 @@ const InternPool = @import("InternPool.zig");...@@ -183,6 +183,7 @@ const InternPool = @import("InternPool.zig");
183const Alignment = InternPool.Alignment;183const Alignment = InternPool.Alignment;
184const AnalUnit = InternPool.AnalUnit;184const AnalUnit = InternPool.AnalUnit;
185const ComptimeAllocIndex = InternPool.ComptimeAllocIndex;185const ComptimeAllocIndex = InternPool.ComptimeAllocIndex;
186const Cache = std.Build.Cache;
186187
187pub const default_branch_quota = 1000;188pub const default_branch_quota = 1000;
188pub const default_reference_trace_len = 2;189pub const default_reference_trace_len = 2;
...@@ -5871,16 +5872,18 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -5871,16 +5872,18 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
5871 return sema.failWithOwnedErrorMsg(&child_block, msg);5872 return sema.failWithOwnedErrorMsg(&child_block, msg);
5872 }5873 }
5873 const parent_mod = parent_block.ownerModule();5874 const parent_mod = parent_block.ownerModule();
5875 const digest = Cache.binToHex(c_import_res.digest);
5876 const c_import_zig_path = try comp.arena.dupe(u8, "o" ++ std.fs.path.sep_str ++ digest);
5874 const c_import_mod = Package.Module.create(comp.arena, .{5877 const c_import_mod = Package.Module.create(comp.arena, .{
5875 .global_cache_directory = comp.global_cache_directory,5878 .global_cache_directory = comp.global_cache_directory,
5876 .paths = .{5879 .paths = .{
5877 .root = .{5880 .root = .{
5878 .root_dir = Compilation.Directory.cwd(),5881 .root_dir = comp.local_cache_directory,
5879 .sub_path = std.fs.path.dirname(c_import_res.out_zig_path) orelse "",5882 .sub_path = c_import_zig_path,
5880 },5883 },
5881 .root_src_path = std.fs.path.basename(c_import_res.out_zig_path),5884 .root_src_path = "cimport.zig",
5882 },5885 },
5883 .fully_qualified_name = c_import_res.out_zig_path,5886 .fully_qualified_name = c_import_zig_path,
5884 .cc_argv = parent_mod.cc_argv,5887 .cc_argv = parent_mod.cc_argv,
5885 .inherited = .{},5888 .inherited = .{},
5886 .global = comp.config,5889 .global = comp.config,
src/link.zig+13-9
...@@ -11,6 +11,7 @@ const wasi_libc = @import("wasi_libc.zig");...@@ -11,6 +11,7 @@ const wasi_libc = @import("wasi_libc.zig");
11const Air = @import("Air.zig");11const Air = @import("Air.zig");
12const Allocator = std.mem.Allocator;12const Allocator = std.mem.Allocator;
13const Cache = std.Build.Cache;13const Cache = std.Build.Cache;
14const Path = Cache.Path;
14const Compilation = @import("Compilation.zig");15const Compilation = @import("Compilation.zig");
15const LibCInstallation = std.zig.LibCInstallation;16const LibCInstallation = std.zig.LibCInstallation;
16const Liveness = @import("Liveness.zig");17const Liveness = @import("Liveness.zig");
...@@ -56,7 +57,7 @@ pub const File = struct {...@@ -56,7 +57,7 @@ pub const File = struct {
5657
57 /// The owner of this output File.58 /// The owner of this output File.
58 comp: *Compilation,59 comp: *Compilation,
59 emit: Compilation.Emit,60 emit: Path,
6061
61 file: ?fs.File,62 file: ?fs.File,
62 /// When linking with LLD, this linker code will output an object file only at63 /// When linking with LLD, this linker code will output an object file only at
...@@ -189,7 +190,7 @@ pub const File = struct {...@@ -189,7 +190,7 @@ pub const File = struct {
189 pub fn open(190 pub fn open(
190 arena: Allocator,191 arena: Allocator,
191 comp: *Compilation,192 comp: *Compilation,
192 emit: Compilation.Emit,193 emit: Path,
193 options: OpenOptions,194 options: OpenOptions,
194 ) !*File {195 ) !*File {
195 switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt)) {196 switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt)) {
...@@ -204,7 +205,7 @@ pub const File = struct {...@@ -204,7 +205,7 @@ pub const File = struct {
204 pub fn createEmpty(205 pub fn createEmpty(
205 arena: Allocator,206 arena: Allocator,
206 comp: *Compilation,207 comp: *Compilation,
207 emit: Compilation.Emit,208 emit: Path,
208 options: OpenOptions,209 options: OpenOptions,
209 ) !*File {210 ) !*File {
210 switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt)) {211 switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt)) {
...@@ -243,8 +244,8 @@ pub const File = struct {...@@ -243,8 +244,8 @@ pub const File = struct {
243 emit.sub_path, std.crypto.random.int(u32),244 emit.sub_path, std.crypto.random.int(u32),
244 });245 });
245 defer gpa.free(tmp_sub_path);246 defer gpa.free(tmp_sub_path);
246 try emit.directory.handle.copyFile(emit.sub_path, emit.directory.handle, tmp_sub_path, .{});247 try emit.root_dir.handle.copyFile(emit.sub_path, emit.root_dir.handle, tmp_sub_path, .{});
247 try emit.directory.handle.rename(tmp_sub_path, emit.sub_path);248 try emit.root_dir.handle.rename(tmp_sub_path, emit.sub_path);
248 switch (builtin.os.tag) {249 switch (builtin.os.tag) {
249 .linux => std.posix.ptrace(std.os.linux.PTRACE.ATTACH, pid, 0, 0) catch |err| {250 .linux => std.posix.ptrace(std.os.linux.PTRACE.ATTACH, pid, 0, 0) catch |err| {
250 log.warn("ptrace failure: {s}", .{@errorName(err)});251 log.warn("ptrace failure: {s}", .{@errorName(err)});
...@@ -260,7 +261,7 @@ pub const File = struct {...@@ -260,7 +261,7 @@ pub const File = struct {
260 const use_lld = build_options.have_llvm and comp.config.use_lld;261 const use_lld = build_options.have_llvm and comp.config.use_lld;
261 const output_mode = comp.config.output_mode;262 const output_mode = comp.config.output_mode;
262 const link_mode = comp.config.link_mode;263 const link_mode = comp.config.link_mode;
263 base.file = try emit.directory.handle.createFile(emit.sub_path, .{264 base.file = try emit.root_dir.handle.createFile(emit.sub_path, .{
264 .truncate = false,265 .truncate = false,
265 .read = true,266 .read = true,
266 .mode = determineMode(use_lld, output_mode, link_mode),267 .mode = determineMode(use_lld, output_mode, link_mode),
...@@ -603,7 +604,7 @@ pub const File = struct {...@@ -603,7 +604,7 @@ pub const File = struct {
603 // Until then, we do `lld -r -o output.o input.o` even though the output is the same604 // Until then, we do `lld -r -o output.o input.o` even though the output is the same
604 // as the input. For the preprocessing case (`zig cc -E -o foo`) we copy the file605 // as the input. For the preprocessing case (`zig cc -E -o foo`) we copy the file
605 // to the final location. See also the corresponding TODO in Coff linking.606 // to the final location. See also the corresponding TODO in Coff linking.
606 const full_out_path = try emit.directory.join(gpa, &[_][]const u8{emit.sub_path});607 const full_out_path = try emit.root_dir.join(gpa, &[_][]const u8{emit.sub_path});
607 defer gpa.free(full_out_path);608 defer gpa.free(full_out_path);
608 assert(comp.c_object_table.count() == 1);609 assert(comp.c_object_table.count() == 1);
609 const the_key = comp.c_object_table.keys()[0];610 const the_key = comp.c_object_table.keys()[0];
...@@ -751,7 +752,7 @@ pub const File = struct {...@@ -751,7 +752,7 @@ pub const File = struct {
751 const comp = base.comp;752 const comp = base.comp;
752 const gpa = comp.gpa;753 const gpa = comp.gpa;
753754
754 const directory = base.emit.directory; // Just an alias to make it shorter to type.755 const directory = base.emit.root_dir; // Just an alias to make it shorter to type.
755 const full_out_path = try directory.join(arena, &[_][]const u8{base.emit.sub_path});756 const full_out_path = try directory.join(arena, &[_][]const u8{base.emit.sub_path});
756 const full_out_path_z = try arena.dupeZ(u8, full_out_path);757 const full_out_path_z = try arena.dupeZ(u8, full_out_path);
757 const opt_zcu = comp.module;758 const opt_zcu = comp.module;
...@@ -1029,7 +1030,10 @@ pub const File = struct {...@@ -1029,7 +1030,10 @@ pub const File = struct {
1029 llvm_object: LlvmObject.Ptr,1030 llvm_object: LlvmObject.Ptr,
1030 prog_node: std.Progress.Node,1031 prog_node: std.Progress.Node,
1031 ) !void {1032 ) !void {
1032 return base.comp.emitLlvmObject(arena, base.emit, .{1033 return base.comp.emitLlvmObject(arena, .{
1034 .root_dir = base.emit.root_dir,
1035 .sub_path = std.fs.path.dirname(base.emit.sub_path) orelse "",
1036 }, .{
1033 .directory = null,1037 .directory = null,
1034 .basename = base.zcu_object_sub_path.?,1038 .basename = base.zcu_object_sub_path.?,
1035 }, llvm_object, prog_node);1039 }, llvm_object, prog_node);
src/link/C.zig+4-3
...@@ -3,6 +3,7 @@ const mem = std.mem;...@@ -3,6 +3,7 @@ const mem = std.mem;
3const assert = std.debug.assert;3const assert = std.debug.assert;
4const Allocator = std.mem.Allocator;4const Allocator = std.mem.Allocator;
5const fs = std.fs;5const fs = std.fs;
6const Path = std.Build.Cache.Path;
67
7const C = @This();8const C = @This();
8const build_options = @import("build_options");9const build_options = @import("build_options");
...@@ -104,7 +105,7 @@ pub fn addString(this: *C, s: []const u8) Allocator.Error!String {...@@ -104,7 +105,7 @@ pub fn addString(this: *C, s: []const u8) Allocator.Error!String {
104pub fn open(105pub fn open(
105 arena: Allocator,106 arena: Allocator,
106 comp: *Compilation,107 comp: *Compilation,
107 emit: Compilation.Emit,108 emit: Path,
108 options: link.File.OpenOptions,109 options: link.File.OpenOptions,
109) !*C {110) !*C {
110 return createEmpty(arena, comp, emit, options);111 return createEmpty(arena, comp, emit, options);
...@@ -113,7 +114,7 @@ pub fn open(...@@ -113,7 +114,7 @@ pub fn open(
113pub fn createEmpty(114pub fn createEmpty(
114 arena: Allocator,115 arena: Allocator,
115 comp: *Compilation,116 comp: *Compilation,
116 emit: Compilation.Emit,117 emit: Path,
117 options: link.File.OpenOptions,118 options: link.File.OpenOptions,
118) !*C {119) !*C {
119 const target = comp.root_mod.resolved_target.result;120 const target = comp.root_mod.resolved_target.result;
...@@ -127,7 +128,7 @@ pub fn createEmpty(...@@ -127,7 +128,7 @@ pub fn createEmpty(
127 assert(!use_lld);128 assert(!use_lld);
128 assert(!use_llvm);129 assert(!use_llvm);
129130
130 const file = try emit.directory.handle.createFile(emit.sub_path, .{131 const file = try emit.root_dir.handle.createFile(emit.sub_path, .{
131 // Truncation is done on `flush`.132 // Truncation is done on `flush`.
132 .truncate = false,133 .truncate = false,
133 });134 });
src/link/Coff.zig+4-3
...@@ -219,7 +219,7 @@ pub const min_text_capacity = padToIdeal(minimum_text_block_size);...@@ -219,7 +219,7 @@ pub const min_text_capacity = padToIdeal(minimum_text_block_size);
219pub fn createEmpty(219pub fn createEmpty(
220 arena: Allocator,220 arena: Allocator,
221 comp: *Compilation,221 comp: *Compilation,
222 emit: Compilation.Emit,222 emit: Path,
223 options: link.File.OpenOptions,223 options: link.File.OpenOptions,
224) !*Coff {224) !*Coff {
225 const target = comp.root_mod.resolved_target.result;225 const target = comp.root_mod.resolved_target.result;
...@@ -315,7 +315,7 @@ pub fn createEmpty(...@@ -315,7 +315,7 @@ pub fn createEmpty(
315 // If using LLD to link, this code should produce an object file so that it315 // If using LLD to link, this code should produce an object file so that it
316 // can be passed to LLD.316 // can be passed to LLD.
317 const sub_path = if (use_lld) zcu_object_sub_path.? else emit.sub_path;317 const sub_path = if (use_lld) zcu_object_sub_path.? else emit.sub_path;
318 self.base.file = try emit.directory.handle.createFile(sub_path, .{318 self.base.file = try emit.root_dir.handle.createFile(sub_path, .{
319 .truncate = true,319 .truncate = true,
320 .read = true,320 .read = true,
321 .mode = link.File.determineMode(use_lld, output_mode, link_mode),321 .mode = link.File.determineMode(use_lld, output_mode, link_mode),
...@@ -416,7 +416,7 @@ pub fn createEmpty(...@@ -416,7 +416,7 @@ pub fn createEmpty(
416pub fn open(416pub fn open(
417 arena: Allocator,417 arena: Allocator,
418 comp: *Compilation,418 comp: *Compilation,
419 emit: Compilation.Emit,419 emit: Path,
420 options: link.File.OpenOptions,420 options: link.File.OpenOptions,
421) !*Coff {421) !*Coff {
422 // TODO: restore saved linker state, don't truncate the file, and422 // TODO: restore saved linker state, don't truncate the file, and
...@@ -2714,6 +2714,7 @@ const math = std.math;...@@ -2714,6 +2714,7 @@ const math = std.math;
2714const mem = std.mem;2714const mem = std.mem;
27152715
2716const Allocator = std.mem.Allocator;2716const Allocator = std.mem.Allocator;
2717const Path = std.Build.Cache.Path;
27172718
2718const codegen = @import("../codegen.zig");2719const codegen = @import("../codegen.zig");
2719const link = @import("../link.zig");2720const link = @import("../link.zig");
src/link/Coff/lld.zig+2-2
...@@ -27,7 +27,7 @@ pub fn linkWithLLD(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no...@@ -27,7 +27,7 @@ pub fn linkWithLLD(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
27 const comp = self.base.comp;27 const comp = self.base.comp;
28 const gpa = comp.gpa;28 const gpa = comp.gpa;
2929
30 const directory = self.base.emit.directory; // Just an alias to make it shorter to type.30 const directory = self.base.emit.root_dir; // Just an alias to make it shorter to type.
31 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});31 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
3232
33 // If there is no Zig code to compile, then we should skip flushing the output file because it33 // If there is no Zig code to compile, then we should skip flushing the output file because it
...@@ -248,7 +248,7 @@ pub fn linkWithLLD(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no...@@ -248,7 +248,7 @@ pub fn linkWithLLD(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
248 try argv.append(try allocPrint(arena, "-OUT:{s}", .{full_out_path}));248 try argv.append(try allocPrint(arena, "-OUT:{s}", .{full_out_path}));
249249
250 if (comp.implib_emit) |emit| {250 if (comp.implib_emit) |emit| {
251 const implib_out_path = try emit.directory.join(arena, &[_][]const u8{emit.sub_path});251 const implib_out_path = try emit.root_dir.join(arena, &[_][]const u8{emit.sub_path});
252 try argv.append(try allocPrint(arena, "-IMPLIB:{s}", .{implib_out_path}));252 try argv.append(try allocPrint(arena, "-IMPLIB:{s}", .{implib_out_path}));
253 }253 }
254254
src/link/Elf.zig+7-6
...@@ -204,7 +204,7 @@ pub const SortSection = enum { name, alignment };...@@ -204,7 +204,7 @@ pub const SortSection = enum { name, alignment };
204pub fn createEmpty(204pub fn createEmpty(
205 arena: Allocator,205 arena: Allocator,
206 comp: *Compilation,206 comp: *Compilation,
207 emit: Compilation.Emit,207 emit: Path,
208 options: link.File.OpenOptions,208 options: link.File.OpenOptions,
209) !*Elf {209) !*Elf {
210 const target = comp.root_mod.resolved_target.result;210 const target = comp.root_mod.resolved_target.result;
...@@ -321,7 +321,7 @@ pub fn createEmpty(...@@ -321,7 +321,7 @@ pub fn createEmpty(
321 // If using LLD to link, this code should produce an object file so that it321 // If using LLD to link, this code should produce an object file so that it
322 // can be passed to LLD.322 // can be passed to LLD.
323 const sub_path = if (use_lld) zcu_object_sub_path.? else emit.sub_path;323 const sub_path = if (use_lld) zcu_object_sub_path.? else emit.sub_path;
324 self.base.file = try emit.directory.handle.createFile(sub_path, .{324 self.base.file = try emit.root_dir.handle.createFile(sub_path, .{
325 .truncate = true,325 .truncate = true,
326 .read = true,326 .read = true,
327 .mode = link.File.determineMode(use_lld, output_mode, link_mode),327 .mode = link.File.determineMode(use_lld, output_mode, link_mode),
...@@ -401,7 +401,7 @@ pub fn createEmpty(...@@ -401,7 +401,7 @@ pub fn createEmpty(
401pub fn open(401pub fn open(
402 arena: Allocator,402 arena: Allocator,
403 comp: *Compilation,403 comp: *Compilation,
404 emit: Compilation.Emit,404 emit: Path,
405 options: link.File.OpenOptions,405 options: link.File.OpenOptions,
406) !*Elf {406) !*Elf {
407 // TODO: restore saved linker state, don't truncate the file, and407 // TODO: restore saved linker state, don't truncate the file, and
...@@ -999,7 +999,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -999,7 +999,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
999999
1000 const target = comp.root_mod.resolved_target.result;1000 const target = comp.root_mod.resolved_target.result;
1001 const link_mode = comp.config.link_mode;1001 const link_mode = comp.config.link_mode;
1002 const directory = self.base.emit.directory; // Just an alias to make it shorter to type.1002 const directory = self.base.emit.root_dir; // Just an alias to make it shorter to type.
1003 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});1003 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
1004 const module_obj_path: ?[]const u8 = if (self.base.zcu_object_sub_path) |path| blk: {1004 const module_obj_path: ?[]const u8 = if (self.base.zcu_object_sub_path) |path| blk: {
1005 if (fs.path.dirname(full_out_path)) |dirname| {1005 if (fs.path.dirname(full_out_path)) |dirname| {
...@@ -1356,7 +1356,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {...@@ -1356,7 +1356,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
13561356
1357 const target = self.base.comp.root_mod.resolved_target.result;1357 const target = self.base.comp.root_mod.resolved_target.result;
1358 const link_mode = self.base.comp.config.link_mode;1358 const link_mode = self.base.comp.config.link_mode;
1359 const directory = self.base.emit.directory; // Just an alias to make it shorter to type.1359 const directory = self.base.emit.root_dir; // Just an alias to make it shorter to type.
1360 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});1360 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
1361 const module_obj_path: ?[]const u8 = if (self.base.zcu_object_sub_path) |path| blk: {1361 const module_obj_path: ?[]const u8 = if (self.base.zcu_object_sub_path) |path| blk: {
1362 if (fs.path.dirname(full_out_path)) |dirname| {1362 if (fs.path.dirname(full_out_path)) |dirname| {
...@@ -2054,7 +2054,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s...@@ -2054,7 +2054,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
2054 const comp = self.base.comp;2054 const comp = self.base.comp;
2055 const gpa = comp.gpa;2055 const gpa = comp.gpa;
20562056
2057 const directory = self.base.emit.directory; // Just an alias to make it shorter to type.2057 const directory = self.base.emit.root_dir; // Just an alias to make it shorter to type.
2058 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});2058 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
20592059
2060 // If there is no Zig code to compile, then we should skip flushing the output file because it2060 // If there is no Zig code to compile, then we should skip flushing the output file because it
...@@ -6016,6 +6016,7 @@ const Allocator = std.mem.Allocator;...@@ -6016,6 +6016,7 @@ const Allocator = std.mem.Allocator;
6016const Archive = @import("Elf/Archive.zig");6016const Archive = @import("Elf/Archive.zig");
6017pub const Atom = @import("Elf/Atom.zig");6017pub const Atom = @import("Elf/Atom.zig");
6018const Cache = std.Build.Cache;6018const Cache = std.Build.Cache;
6019const Path = Cache.Path;
6019const Compilation = @import("../Compilation.zig");6020const Compilation = @import("../Compilation.zig");
6020const ComdatGroupSection = synthetic_sections.ComdatGroupSection;6021const ComdatGroupSection = synthetic_sections.ComdatGroupSection;
6021const CopyRelSection = synthetic_sections.CopyRelSection;6022const CopyRelSection = synthetic_sections.CopyRelSection;
src/link/MachO.zig+9-8
...@@ -156,7 +156,7 @@ pub fn hashAddFrameworks(man: *Cache.Manifest, hm: []const Framework) !void {...@@ -156,7 +156,7 @@ pub fn hashAddFrameworks(man: *Cache.Manifest, hm: []const Framework) !void {
156pub fn createEmpty(156pub fn createEmpty(
157 arena: Allocator,157 arena: Allocator,
158 comp: *Compilation,158 comp: *Compilation,
159 emit: Compilation.Emit,159 emit: Path,
160 options: link.File.OpenOptions,160 options: link.File.OpenOptions,
161) !*MachO {161) !*MachO {
162 const target = comp.root_mod.resolved_target.result;162 const target = comp.root_mod.resolved_target.result;
...@@ -221,7 +221,7 @@ pub fn createEmpty(...@@ -221,7 +221,7 @@ pub fn createEmpty(
221 }221 }
222 errdefer self.base.destroy();222 errdefer self.base.destroy();
223223
224 self.base.file = try emit.directory.handle.createFile(emit.sub_path, .{224 self.base.file = try emit.root_dir.handle.createFile(emit.sub_path, .{
225 .truncate = true,225 .truncate = true,
226 .read = true,226 .read = true,
227 .mode = link.File.determineMode(false, output_mode, link_mode),227 .mode = link.File.determineMode(false, output_mode, link_mode),
...@@ -260,7 +260,7 @@ pub fn createEmpty(...@@ -260,7 +260,7 @@ pub fn createEmpty(
260pub fn open(260pub fn open(
261 arena: Allocator,261 arena: Allocator,
262 comp: *Compilation,262 comp: *Compilation,
263 emit: Compilation.Emit,263 emit: Path,
264 options: link.File.OpenOptions,264 options: link.File.OpenOptions,
265) !*MachO {265) !*MachO {
266 // TODO: restore saved linker state, don't truncate the file, and266 // TODO: restore saved linker state, don't truncate the file, and
...@@ -353,7 +353,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n...@@ -353,7 +353,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
353 const sub_prog_node = prog_node.start("MachO Flush", 0);353 const sub_prog_node = prog_node.start("MachO Flush", 0);
354 defer sub_prog_node.end();354 defer sub_prog_node.end();
355355
356 const directory = self.base.emit.directory;356 const directory = self.base.emit.root_dir;
357 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});357 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
358 const module_obj_path: ?[]const u8 = if (self.base.zcu_object_sub_path) |path| blk: {358 const module_obj_path: ?[]const u8 = if (self.base.zcu_object_sub_path) |path| blk: {
359 if (fs.path.dirname(full_out_path)) |dirname| {359 if (fs.path.dirname(full_out_path)) |dirname| {
...@@ -586,7 +586,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n...@@ -586,7 +586,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
586 if (codesig) |*csig| {586 if (codesig) |*csig| {
587 try self.writeCodeSignature(csig); // code signing always comes last587 try self.writeCodeSignature(csig); // code signing always comes last
588 const emit = self.base.emit;588 const emit = self.base.emit;
589 try invalidateKernelCache(emit.directory.handle, emit.sub_path);589 try invalidateKernelCache(emit.root_dir.handle, emit.sub_path);
590 }590 }
591}591}
592592
...@@ -597,7 +597,7 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {...@@ -597,7 +597,7 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
597 defer arena_allocator.deinit();597 defer arena_allocator.deinit();
598 const arena = arena_allocator.allocator();598 const arena = arena_allocator.allocator();
599599
600 const directory = self.base.emit.directory;600 const directory = self.base.emit.root_dir;
601 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});601 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
602 const module_obj_path: ?[]const u8 = if (self.base.zcu_object_sub_path) |path| blk: {602 const module_obj_path: ?[]const u8 = if (self.base.zcu_object_sub_path) |path| blk: {
603 if (fs.path.dirname(full_out_path)) |dirname| {603 if (fs.path.dirname(full_out_path)) |dirname| {
...@@ -3199,7 +3199,7 @@ fn copyRangeAllZeroOut(self: *MachO, old_offset: u64, new_offset: u64, size: u64...@@ -3199,7 +3199,7 @@ fn copyRangeAllZeroOut(self: *MachO, old_offset: u64, new_offset: u64, size: u64
3199}3199}
32003200
3201const InitMetadataOptions = struct {3201const InitMetadataOptions = struct {
3202 emit: Compilation.Emit,3202 emit: Path,
3203 zo: *ZigObject,3203 zo: *ZigObject,
3204 symbol_count_hint: u64,3204 symbol_count_hint: u64,
3205 program_code_size_hint: u64,3205 program_code_size_hint: u64,
...@@ -3271,7 +3271,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {...@@ -3271,7 +3271,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
3271 );3271 );
3272 defer gpa.free(d_sym_path);3272 defer gpa.free(d_sym_path);
32733273
3274 var d_sym_bundle = try options.emit.directory.handle.makeOpenPath(d_sym_path, .{});3274 var d_sym_bundle = try options.emit.root_dir.handle.makeOpenPath(d_sym_path, .{});
3275 defer d_sym_bundle.close();3275 defer d_sym_bundle.close();
32763276
3277 const d_sym_file = try d_sym_bundle.createFile(options.emit.sub_path, .{3277 const d_sym_file = try d_sym_bundle.createFile(options.emit.sub_path, .{
...@@ -4603,6 +4603,7 @@ pub const Atom = @import("MachO/Atom.zig");...@@ -4603,6 +4603,7 @@ pub const Atom = @import("MachO/Atom.zig");
4603const AtomicBool = std.atomic.Value(bool);4603const AtomicBool = std.atomic.Value(bool);
4604const Bind = bind.Bind;4604const Bind = bind.Bind;
4605const Cache = std.Build.Cache;4605const Cache = std.Build.Cache;
4606const Path = Cache.Path;
4606const CodeSignature = @import("MachO/CodeSignature.zig");4607const CodeSignature = @import("MachO/CodeSignature.zig");
4607const Compilation = @import("../Compilation.zig");4608const Compilation = @import("../Compilation.zig");
4608const DataInCode = synthetic.DataInCode;4609const DataInCode = synthetic.DataInCode;
src/link/MachO/load_commands.zig+2-2
...@@ -53,7 +53,7 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32...@@ -53,7 +53,7 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32
53 if (macho_file.base.isDynLib()) {53 if (macho_file.base.isDynLib()) {
54 const emit = macho_file.base.emit;54 const emit = macho_file.base.emit;
55 const install_name = macho_file.install_name orelse55 const install_name = macho_file.install_name orelse
56 try emit.directory.join(gpa, &.{emit.sub_path});56 try emit.root_dir.join(gpa, &.{emit.sub_path});
57 defer if (macho_file.install_name == null) gpa.free(install_name);57 defer if (macho_file.install_name == null) gpa.free(install_name);
58 sizeofcmds += calcInstallNameLen(58 sizeofcmds += calcInstallNameLen(
59 @sizeOf(macho.dylib_command),59 @sizeOf(macho.dylib_command),
...@@ -237,7 +237,7 @@ pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void {...@@ -237,7 +237,7 @@ pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void {
237 assert(comp.config.output_mode == .Lib and comp.config.link_mode == .dynamic);237 assert(comp.config.output_mode == .Lib and comp.config.link_mode == .dynamic);
238 const emit = macho_file.base.emit;238 const emit = macho_file.base.emit;
239 const install_name = macho_file.install_name orelse239 const install_name = macho_file.install_name orelse
240 try emit.directory.join(gpa, &.{emit.sub_path});240 try emit.root_dir.join(gpa, &.{emit.sub_path});
241 defer if (macho_file.install_name == null) gpa.free(install_name);241 defer if (macho_file.install_name == null) gpa.free(install_name);
242 const curr = comp.version orelse std.SemanticVersion{242 const curr = comp.version orelse std.SemanticVersion{
243 .major = 1,243 .major = 1,
src/link/NvPtx.zig+3-2
...@@ -11,6 +11,7 @@ const builtin = @import("builtin");...@@ -11,6 +11,7 @@ const builtin = @import("builtin");
11const Allocator = std.mem.Allocator;11const Allocator = std.mem.Allocator;
12const assert = std.debug.assert;12const assert = std.debug.assert;
13const log = std.log.scoped(.link);13const log = std.log.scoped(.link);
14const Path = std.Build.Cache.Path;
1415
15const Zcu = @import("../Zcu.zig");16const Zcu = @import("../Zcu.zig");
16const InternPool = @import("../InternPool.zig");17const InternPool = @import("../InternPool.zig");
...@@ -28,7 +29,7 @@ llvm_object: LlvmObject.Ptr,...@@ -28,7 +29,7 @@ llvm_object: LlvmObject.Ptr,
28pub fn createEmpty(29pub fn createEmpty(
29 arena: Allocator,30 arena: Allocator,
30 comp: *Compilation,31 comp: *Compilation,
31 emit: Compilation.Emit,32 emit: Path,
32 options: link.File.OpenOptions,33 options: link.File.OpenOptions,
33) !*NvPtx {34) !*NvPtx {
34 const target = comp.root_mod.resolved_target.result;35 const target = comp.root_mod.resolved_target.result;
...@@ -70,7 +71,7 @@ pub fn createEmpty(...@@ -70,7 +71,7 @@ pub fn createEmpty(
70pub fn open(71pub fn open(
71 arena: Allocator,72 arena: Allocator,
72 comp: *Compilation,73 comp: *Compilation,
73 emit: Compilation.Emit,74 emit: Path,
74 options: link.File.OpenOptions,75 options: link.File.OpenOptions,
75) !*NvPtx {76) !*NvPtx {
76 const target = comp.root_mod.resolved_target.result;77 const target = comp.root_mod.resolved_target.result;
src/link/Plan9.zig+4-3
...@@ -23,6 +23,7 @@ const mem = std.mem;...@@ -23,6 +23,7 @@ const mem = std.mem;
23const Allocator = std.mem.Allocator;23const Allocator = std.mem.Allocator;
24const log = std.log.scoped(.link);24const log = std.log.scoped(.link);
25const assert = std.debug.assert;25const assert = std.debug.assert;
26const Path = std.Build.Cache.Path;
2627
27base: link.File,28base: link.File,
28sixtyfour_bit: bool,29sixtyfour_bit: bool,
...@@ -275,7 +276,7 @@ pub fn defaultBaseAddrs(arch: std.Target.Cpu.Arch) Bases {...@@ -275,7 +276,7 @@ pub fn defaultBaseAddrs(arch: std.Target.Cpu.Arch) Bases {
275pub fn createEmpty(276pub fn createEmpty(
276 arena: Allocator,277 arena: Allocator,
277 comp: *Compilation,278 comp: *Compilation,
278 emit: Compilation.Emit,279 emit: Path,
279 options: link.File.OpenOptions,280 options: link.File.OpenOptions,
280) !*Plan9 {281) !*Plan9 {
281 const target = comp.root_mod.resolved_target.result;282 const target = comp.root_mod.resolved_target.result;
...@@ -1199,7 +1200,7 @@ pub fn deinit(self: *Plan9) void {...@@ -1199,7 +1200,7 @@ pub fn deinit(self: *Plan9) void {
1199pub fn open(1200pub fn open(
1200 arena: Allocator,1201 arena: Allocator,
1201 comp: *Compilation,1202 comp: *Compilation,
1202 emit: Compilation.Emit,1203 emit: Path,
1203 options: link.File.OpenOptions,1204 options: link.File.OpenOptions,
1204) !*Plan9 {1205) !*Plan9 {
1205 const target = comp.root_mod.resolved_target.result;1206 const target = comp.root_mod.resolved_target.result;
...@@ -1213,7 +1214,7 @@ pub fn open(...@@ -1213,7 +1214,7 @@ pub fn open(
1213 const self = try createEmpty(arena, comp, emit, options);1214 const self = try createEmpty(arena, comp, emit, options);
1214 errdefer self.base.destroy();1215 errdefer self.base.destroy();
12151216
1216 const file = try emit.directory.handle.createFile(emit.sub_path, .{1217 const file = try emit.root_dir.handle.createFile(emit.sub_path, .{
1217 .read = true,1218 .read = true,
1218 .mode = link.File.determineMode(1219 .mode = link.File.determineMode(
1219 use_lld,1220 use_lld,
src/link/SpirV.zig+4-3
...@@ -26,6 +26,7 @@ const std = @import("std");...@@ -26,6 +26,7 @@ const std = @import("std");
26const Allocator = std.mem.Allocator;26const Allocator = std.mem.Allocator;
27const assert = std.debug.assert;27const assert = std.debug.assert;
28const log = std.log.scoped(.link);28const log = std.log.scoped(.link);
29const Path = std.Build.Cache.Path;
2930
30const Zcu = @import("../Zcu.zig");31const Zcu = @import("../Zcu.zig");
31const InternPool = @import("../InternPool.zig");32const InternPool = @import("../InternPool.zig");
...@@ -54,7 +55,7 @@ object: codegen.Object,...@@ -54,7 +55,7 @@ object: codegen.Object,
54pub fn createEmpty(55pub fn createEmpty(
55 arena: Allocator,56 arena: Allocator,
56 comp: *Compilation,57 comp: *Compilation,
57 emit: Compilation.Emit,58 emit: Path,
58 options: link.File.OpenOptions,59 options: link.File.OpenOptions,
59) !*SpirV {60) !*SpirV {
60 const gpa = comp.gpa;61 const gpa = comp.gpa;
...@@ -95,7 +96,7 @@ pub fn createEmpty(...@@ -95,7 +96,7 @@ pub fn createEmpty(
95pub fn open(96pub fn open(
96 arena: Allocator,97 arena: Allocator,
97 comp: *Compilation,98 comp: *Compilation,
98 emit: Compilation.Emit,99 emit: Path,
99 options: link.File.OpenOptions,100 options: link.File.OpenOptions,
100) !*SpirV {101) !*SpirV {
101 const target = comp.root_mod.resolved_target.result;102 const target = comp.root_mod.resolved_target.result;
...@@ -110,7 +111,7 @@ pub fn open(...@@ -110,7 +111,7 @@ pub fn open(
110 errdefer spirv.base.destroy();111 errdefer spirv.base.destroy();
111112
112 // TODO: read the file and keep valid parts instead of truncating113 // TODO: read the file and keep valid parts instead of truncating
113 const file = try emit.directory.handle.createFile(emit.sub_path, .{114 const file = try emit.root_dir.handle.createFile(emit.sub_path, .{
114 .truncate = true,115 .truncate = true,
115 .read = true,116 .read = true,
116 });117 });
src/link/Wasm.zig+6-5
...@@ -22,6 +22,7 @@ const Air = @import("../Air.zig");...@@ -22,6 +22,7 @@ const Air = @import("../Air.zig");
22const Allocator = std.mem.Allocator;22const Allocator = std.mem.Allocator;
23const Archive = @import("Wasm/Archive.zig");23const Archive = @import("Wasm/Archive.zig");
24const Cache = std.Build.Cache;24const Cache = std.Build.Cache;
25const Path = Cache.Path;
25const CodeGen = @import("../arch/wasm/CodeGen.zig");26const CodeGen = @import("../arch/wasm/CodeGen.zig");
26const Compilation = @import("../Compilation.zig");27const Compilation = @import("../Compilation.zig");
27const Dwarf = @import("Dwarf.zig");28const Dwarf = @import("Dwarf.zig");
...@@ -346,7 +347,7 @@ pub const StringTable = struct {...@@ -346,7 +347,7 @@ pub const StringTable = struct {
346pub fn open(347pub fn open(
347 arena: Allocator,348 arena: Allocator,
348 comp: *Compilation,349 comp: *Compilation,
349 emit: Compilation.Emit,350 emit: Path,
350 options: link.File.OpenOptions,351 options: link.File.OpenOptions,
351) !*Wasm {352) !*Wasm {
352 // TODO: restore saved linker state, don't truncate the file, and353 // TODO: restore saved linker state, don't truncate the file, and
...@@ -357,7 +358,7 @@ pub fn open(...@@ -357,7 +358,7 @@ pub fn open(
357pub fn createEmpty(358pub fn createEmpty(
358 arena: Allocator,359 arena: Allocator,
359 comp: *Compilation,360 comp: *Compilation,
360 emit: Compilation.Emit,361 emit: Path,
361 options: link.File.OpenOptions,362 options: link.File.OpenOptions,
362) !*Wasm {363) !*Wasm {
363 const gpa = comp.gpa;364 const gpa = comp.gpa;
...@@ -430,7 +431,7 @@ pub fn createEmpty(...@@ -430,7 +431,7 @@ pub fn createEmpty(
430 // can be passed to LLD.431 // can be passed to LLD.
431 const sub_path = if (use_lld) zcu_object_sub_path.? else emit.sub_path;432 const sub_path = if (use_lld) zcu_object_sub_path.? else emit.sub_path;
432433
433 wasm.base.file = try emit.directory.handle.createFile(sub_path, .{434 wasm.base.file = try emit.root_dir.handle.createFile(sub_path, .{
434 .truncate = true,435 .truncate = true,
435 .read = true,436 .read = true,
436 .mode = if (fs.has_executable_bit)437 .mode = if (fs.has_executable_bit)
...@@ -2496,7 +2497,7 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no...@@ -2496,7 +2497,7 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
2496 const sub_prog_node = prog_node.start("Wasm Flush", 0);2497 const sub_prog_node = prog_node.start("Wasm Flush", 0);
2497 defer sub_prog_node.end();2498 defer sub_prog_node.end();
24982499
2499 const directory = wasm.base.emit.directory; // Just an alias to make it shorter to type.2500 const directory = wasm.base.emit.root_dir; // Just an alias to make it shorter to type.
2500 const full_out_path = try directory.join(arena, &[_][]const u8{wasm.base.emit.sub_path});2501 const full_out_path = try directory.join(arena, &[_][]const u8{wasm.base.emit.sub_path});
2501 const module_obj_path: ?[]const u8 = if (wasm.base.zcu_object_sub_path) |path| blk: {2502 const module_obj_path: ?[]const u8 = if (wasm.base.zcu_object_sub_path) |path| blk: {
2502 if (fs.path.dirname(full_out_path)) |dirname| {2503 if (fs.path.dirname(full_out_path)) |dirname| {
...@@ -3346,7 +3347,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:...@@ -3346,7 +3347,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
33463347
3347 const gpa = comp.gpa;3348 const gpa = comp.gpa;
33483349
3349 const directory = wasm.base.emit.directory; // Just an alias to make it shorter to type.3350 const directory = wasm.base.emit.root_dir; // Just an alias to make it shorter to type.
3350 const full_out_path = try directory.join(arena, &[_][]const u8{wasm.base.emit.sub_path});3351 const full_out_path = try directory.join(arena, &[_][]const u8{wasm.base.emit.sub_path});
33513352
3352 // If there is no Zig code to compile, then we should skip flushing the output file because it3353 // If there is no Zig code to compile, then we should skip flushing the output file because it
src/main.zig+18-68
...@@ -3519,7 +3519,7 @@ fn buildOutputType(...@@ -3519,7 +3519,7 @@ fn buildOutputType(
3519 if (test_exec_args.items.len == 0 and target.ofmt == .c) default_exec_args: {3519 if (test_exec_args.items.len == 0 and target.ofmt == .c) default_exec_args: {
3520 // Default to using `zig run` to execute the produced .c code from `zig test`.3520 // Default to using `zig run` to execute the produced .c code from `zig test`.
3521 const c_code_loc = emit_bin_loc orelse break :default_exec_args;3521 const c_code_loc = emit_bin_loc orelse break :default_exec_args;
3522 const c_code_directory = c_code_loc.directory orelse comp.bin_file.?.emit.directory;3522 const c_code_directory = c_code_loc.directory orelse comp.bin_file.?.emit.root_dir;
3523 const c_code_path = try fs.path.join(arena, &[_][]const u8{3523 const c_code_path = try fs.path.join(arena, &[_][]const u8{
3524 c_code_directory.path orelse ".", c_code_loc.basename,3524 c_code_directory.path orelse ".", c_code_loc.basename,
3525 });3525 });
...@@ -4142,7 +4142,7 @@ fn serve(...@@ -4142,7 +4142,7 @@ fn serve(
4142 if (output.errors.errorMessageCount() != 0) {4142 if (output.errors.errorMessageCount() != 0) {
4143 try server.serveErrorBundle(output.errors);4143 try server.serveErrorBundle(output.errors);
4144 } else {4144 } else {
4145 try server.serveEmitBinPath(output.out_zig_path, .{4145 try server.serveEmitDigest(&output.digest, .{
4146 .flags = .{ .cache_hit = output.cache_hit },4146 .flags = .{ .cache_hit = output.cache_hit },
4147 });4147 });
4148 }4148 }
...@@ -4229,62 +4229,10 @@ fn serveUpdateResults(s: *Server, comp: *Compilation) !void {...@@ -4229,62 +4229,10 @@ fn serveUpdateResults(s: *Server, comp: *Compilation) !void {
4229 return;4229 return;
4230 }4230 }
42314231
4232 // This logic is counter-intuitive because the protocol accounts for each4232 if (comp.digest) |digest| {
4233 // emitted artifact possibly being in a different location, which correctly4233 try s.serveEmitDigest(&digest, .{
4234 // matches the behavior of the compiler, however, the build system
4235 // currently always passes flags that makes all build artifacts output to
4236 // the same local cache directory, and relies on them all being in the same
4237 // directory.
4238 //
4239 // So, until the build system and protocol are changed to reflect this,
4240 // this logic must ensure that emit_bin_path is emitted for at least one
4241 // thing, if there are any artifacts.
4242
4243 switch (comp.cache_use) {
4244 .incremental => if (comp.bin_file) |lf| {
4245 const full_path = try lf.emit.directory.join(gpa, &.{lf.emit.sub_path});
4246 defer gpa.free(full_path);
4247 try s.serveEmitBinPath(full_path, .{
4248 .flags = .{ .cache_hit = comp.last_update_was_cache_hit },
4249 });
4250 return;
4251 },
4252 .whole => |whole| if (whole.bin_sub_path) |sub_path| {
4253 const full_path = try comp.local_cache_directory.join(gpa, &.{sub_path});
4254 defer gpa.free(full_path);
4255 try s.serveEmitBinPath(full_path, .{
4256 .flags = .{ .cache_hit = comp.last_update_was_cache_hit },
4257 });
4258 return;
4259 },
4260 }
4261
4262 for ([_]?Compilation.Emit{
4263 comp.docs_emit,
4264 comp.implib_emit,
4265 }) |opt_emit| {
4266 const emit = opt_emit orelse continue;
4267 const full_path = try emit.directory.join(gpa, &.{emit.sub_path});
4268 defer gpa.free(full_path);
4269 try s.serveEmitBinPath(full_path, .{
4270 .flags = .{ .cache_hit = comp.last_update_was_cache_hit },4234 .flags = .{ .cache_hit = comp.last_update_was_cache_hit },
4271 });4235 });
4272 return;
4273 }
4274
4275 for ([_]?Compilation.EmitLoc{
4276 comp.emit_asm,
4277 comp.emit_llvm_ir,
4278 comp.emit_llvm_bc,
4279 }) |opt_emit_loc| {
4280 const emit_loc = opt_emit_loc orelse continue;
4281 const directory = emit_loc.directory orelse continue;
4282 const full_path = try directory.join(gpa, &.{emit_loc.basename});
4283 defer gpa.free(full_path);
4284 try s.serveEmitBinPath(full_path, .{
4285 .flags = .{ .cache_hit = comp.last_update_was_cache_hit },
4286 });
4287 return;
4288 }4236 }
42894237
4290 // Serve empty error bundle to indicate the update is done.4238 // Serve empty error bundle to indicate the update is done.
...@@ -4308,7 +4256,7 @@ fn runOrTest(...@@ -4308,7 +4256,7 @@ fn runOrTest(
4308 // A naive `directory.join` here will indeed get the correct path to the binary,4256 // A naive `directory.join` here will indeed get the correct path to the binary,
4309 // however, in the case of cwd, we actually want `./foo` so that the path can be executed.4257 // however, in the case of cwd, we actually want `./foo` so that the path can be executed.
4310 const exe_path = try fs.path.join(arena, &[_][]const u8{4258 const exe_path = try fs.path.join(arena, &[_][]const u8{
4311 lf.emit.directory.path orelse ".", lf.emit.sub_path,4259 lf.emit.root_dir.path orelse ".", lf.emit.sub_path,
4312 });4260 });
43134261
4314 var argv = std.ArrayList([]const u8).init(gpa);4262 var argv = std.ArrayList([]const u8).init(gpa);
...@@ -4420,7 +4368,7 @@ fn runOrTestHotSwap(...@@ -4420,7 +4368,7 @@ fn runOrTestHotSwap(
4420 // tmp zig-cache and use it to spawn the child process. This way we are free to update4368 // tmp zig-cache and use it to spawn the child process. This way we are free to update
4421 // the binary with each requested hot update.4369 // the binary with each requested hot update.
4422 .windows => blk: {4370 .windows => blk: {
4423 try lf.emit.directory.handle.copyFile(lf.emit.sub_path, comp.local_cache_directory.handle, lf.emit.sub_path, .{});4371 try lf.emit.root_dir.handle.copyFile(lf.emit.sub_path, comp.local_cache_directory.handle, lf.emit.sub_path, .{});
4424 break :blk try fs.path.join(gpa, &[_][]const u8{4372 break :blk try fs.path.join(gpa, &[_][]const u8{
4425 comp.local_cache_directory.path orelse ".", lf.emit.sub_path,4373 comp.local_cache_directory.path orelse ".", lf.emit.sub_path,
4426 });4374 });
...@@ -4429,7 +4377,7 @@ fn runOrTestHotSwap(...@@ -4429,7 +4377,7 @@ fn runOrTestHotSwap(
4429 // A naive `directory.join` here will indeed get the correct path to the binary,4377 // A naive `directory.join` here will indeed get the correct path to the binary,
4430 // however, in the case of cwd, we actually want `./foo` so that the path can be executed.4378 // however, in the case of cwd, we actually want `./foo` so that the path can be executed.
4431 else => try fs.path.join(gpa, &[_][]const u8{4379 else => try fs.path.join(gpa, &[_][]const u8{
4432 lf.emit.directory.path orelse ".", lf.emit.sub_path,4380 lf.emit.root_dir.path orelse ".", lf.emit.sub_path,
4433 }),4381 }),
4434 };4382 };
4435 defer gpa.free(exe_path);4383 defer gpa.free(exe_path);
...@@ -4539,9 +4487,11 @@ fn cmdTranslateC(...@@ -4539,9 +4487,11 @@ fn cmdTranslateC(
4539 };4487 };
45404488
4541 if (fancy_output) |p| p.cache_hit = true;4489 if (fancy_output) |p| p.cache_hit = true;
4542 const digest = if (try man.hit()) digest: {4490 const bin_digest, const hex_digest = if (try man.hit()) digest: {
4543 if (file_system_inputs) |buf| try man.populateFileSystemInputs(buf);4491 if (file_system_inputs) |buf| try man.populateFileSystemInputs(buf);
4544 break :digest man.final();4492 const bin_digest = man.finalBin();
4493 const hex_digest = Cache.binToHex(bin_digest);
4494 break :digest .{ bin_digest, hex_digest };
4545 } else digest: {4495 } else digest: {
4546 if (fancy_output) |p| p.cache_hit = false;4496 if (fancy_output) |p| p.cache_hit = false;
4547 var argv = std.ArrayList([]const u8).init(arena);4497 var argv = std.ArrayList([]const u8).init(arena);
...@@ -4639,8 +4589,10 @@ fn cmdTranslateC(...@@ -4639,8 +4589,10 @@ fn cmdTranslateC(
4639 };4589 };
4640 }4590 }
46414591
4642 const digest = man.final();4592 const bin_digest = man.finalBin();
4643 const o_sub_path = try fs.path.join(arena, &[_][]const u8{ "o", &digest });4593 const hex_digest = Cache.binToHex(bin_digest);
4594
4595 const o_sub_path = try fs.path.join(arena, &[_][]const u8{ "o", &hex_digest });
46444596
4645 var o_dir = try comp.local_cache_directory.handle.makeOpenPath(o_sub_path, .{});4597 var o_dir = try comp.local_cache_directory.handle.makeOpenPath(o_sub_path, .{});
4646 defer o_dir.close();4598 defer o_dir.close();
...@@ -4656,16 +4608,14 @@ fn cmdTranslateC(...@@ -4656,16 +4608,14 @@ fn cmdTranslateC(
46564608
4657 if (file_system_inputs) |buf| try man.populateFileSystemInputs(buf);4609 if (file_system_inputs) |buf| try man.populateFileSystemInputs(buf);
46584610
4659 break :digest digest;4611 break :digest .{ bin_digest, hex_digest };
4660 };4612 };
46614613
4662 if (fancy_output) |p| {4614 if (fancy_output) |p| {
4663 p.out_zig_path = try comp.local_cache_directory.join(comp.gpa, &[_][]const u8{4615 p.digest = bin_digest;
4664 "o", &digest, translated_zig_basename,
4665 });
4666 p.errors = std.zig.ErrorBundle.empty;4616 p.errors = std.zig.ErrorBundle.empty;
4667 } else {4617 } else {
4668 const out_zig_path = try fs.path.join(arena, &[_][]const u8{ "o", &digest, translated_zig_basename });4618 const out_zig_path = try fs.path.join(arena, &[_][]const u8{ "o", &hex_digest, translated_zig_basename });
4669 const zig_file = comp.local_cache_directory.handle.openFile(out_zig_path, .{}) catch |err| {4619 const zig_file = comp.local_cache_directory.handle.openFile(out_zig_path, .{}) catch |err| {
4670 const path = comp.local_cache_directory.path orelse ".";4620 const path = comp.local_cache_directory.path orelse ".";
4671 fatal("unable to open cached translated zig file '{s}{s}{s}': {s}", .{ path, fs.path.sep_str, out_zig_path, @errorName(err) });4621 fatal("unable to open cached translated zig file '{s}{s}{s}': {s}", .{ path, fs.path.sep_str, out_zig_path, @errorName(err) });
test/standalone/build.zig.zon+9-8
...@@ -51,14 +51,15 @@...@@ -51,14 +51,15 @@
51 .install_raw_hex = .{51 .install_raw_hex = .{
52 .path = "install_raw_hex",52 .path = "install_raw_hex",
53 },53 },
54 // https://github.com/ziglang/zig/issues/1748454 .emit_asm_and_bin = .{
55 //.emit_asm_and_bin = .{55 .path = "emit_asm_and_bin",
56 // .path = "emit_asm_and_bin",56 },
57 //},57 .emit_llvm_no_bin = .{
58 // https://github.com/ziglang/zig/issues/1748458 .path = "emit_llvm_no_bin",
59 //.issue_12588 = .{59 },
60 // .path = "issue_12588",60 .emit_asm_no_bin = .{
61 //},61 .path = "emit_asm_no_bin",
62 },
62 .child_process = .{63 .child_process = .{
63 .path = "child_process",64 .path = "child_process",
64 },65 },
test/standalone/emit_asm_no_bin/build.zig created+19
...@@ -0,0 +1,19 @@
1const std = @import("std");
2
3pub fn build(b: *std.Build) void {
4 const test_step = b.step("test", "Test it");
5 b.default_step = test_step;
6
7 const optimize: std.builtin.OptimizeMode = .Debug;
8
9 const obj = b.addObject(.{
10 .name = "main",
11 .root_source_file = b.path("main.zig"),
12 .optimize = optimize,
13 .target = b.graph.host,
14 });
15 _ = obj.getEmittedAsm();
16 b.default_step.dependOn(&obj.step);
17
18 test_step.dependOn(&obj.step);
19}
test/standalone/emit_asm_no_bin/main.zig created+1
...@@ -0,0 +1 @@
1pub fn main() void {}
test/standalone/emit_llvm_no_bin/build.zig created+20
...@@ -0,0 +1,20 @@
1const std = @import("std");
2
3pub fn build(b: *std.Build) void {
4 const test_step = b.step("test", "Test it");
5 b.default_step = test_step;
6
7 const optimize: std.builtin.OptimizeMode = .Debug;
8
9 const obj = b.addObject(.{
10 .name = "main",
11 .root_source_file = b.path("main.zig"),
12 .optimize = optimize,
13 .target = b.graph.host,
14 });
15 _ = obj.getEmittedLlvmIr();
16 _ = obj.getEmittedLlvmBc();
17 b.default_step.dependOn(&obj.step);
18
19 test_step.dependOn(&obj.step);
20}
test/standalone/emit_llvm_no_bin/main.zig created+6
...@@ -0,0 +1,6 @@
1const std = @import("std");
2
3export fn strFromFloatHelp(float: f64) void {
4 var buf: [400]u8 = undefined;
5 _ = std.fmt.bufPrint(&buf, "{d}", .{float}) catch unreachable;
6}
test/standalone/issue_12588/build.zig deleted-20
...@@ -1,20 +0,0 @@
1const std = @import("std");
2
3pub fn build(b: *std.Build) void {
4 const test_step = b.step("test", "Test it");
5 b.default_step = test_step;
6
7 const optimize: std.builtin.OptimizeMode = .Debug;
8
9 const obj = b.addObject(.{
10 .name = "main",
11 .root_source_file = b.path("main.zig"),
12 .optimize = optimize,
13 .target = b.graph.host,
14 });
15 _ = obj.getEmittedLlvmIr();
16 _ = obj.getEmittedLlvmBc();
17 b.default_step.dependOn(&obj.step);
18
19 test_step.dependOn(&obj.step);
20}
test/standalone/issue_12588/main.zig deleted-6
...@@ -1,6 +0,0 @@
1const std = @import("std");
2
3export fn strFromFloatHelp(float: f64) void {
4 var buf: [400]u8 = undefined;
5 _ = std.fmt.bufPrint(&buf, "{d}", .{float}) catch unreachable;
6}
tools/incr-check.zig+33-10
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1const std = @import("std");1const std = @import("std");
2const fatal = std.process.fatal;2const fatal = std.process.fatal;
3const Allocator = std.mem.Allocator;3const Allocator = std.mem.Allocator;
4const Cache = std.Build.Cache;
45
5const usage = "usage: incr-check <zig binary path> <input file> [--zig-lib-dir lib] [--debug-zcu] [--emit none|bin|c] [--zig-cc-binary /path/to/zig]";6const usage = "usage: incr-check <zig binary path> <input file> [--zig-lib-dir lib] [--debug-zcu] [--emit none|bin|c] [--zig-cc-binary /path/to/zig]";
67
...@@ -233,30 +234,52 @@ const Eval = struct {...@@ -233,30 +234,52 @@ const Eval = struct {
233 fatal("error_bundle included unexpected stderr:\n{s}", .{stderr_data});234 fatal("error_bundle included unexpected stderr:\n{s}", .{stderr_data});
234 }235 }
235 }236 }
236 if (result_error_bundle.errorMessageCount() == 0) {237 if (result_error_bundle.errorMessageCount() != 0) {
237 // Empty bundle indicates successful update in a `-fno-emit-bin` build.
238 try eval.checkSuccessOutcome(update, null, prog_node);
239 } else {
240 try eval.checkErrorOutcome(update, result_error_bundle);238 try eval.checkErrorOutcome(update, result_error_bundle);
241 }239 }
242 // This message indicates the end of the update.240 // This message indicates the end of the update.
243 stdout.discard(body.len);241 stdout.discard(body.len);
244 return;242 return;
245 },243 },
246 .emit_bin_path => {244 .emit_digest => {
247 const EbpHdr = std.zig.Server.Message.EmitBinPath;245 const EbpHdr = std.zig.Server.Message.EmitDigest;
248 const ebp_hdr = @as(*align(1) const EbpHdr, @ptrCast(body));246 const ebp_hdr = @as(*align(1) const EbpHdr, @ptrCast(body));
249 _ = ebp_hdr;247 _ = ebp_hdr;
250 const result_binary = try arena.dupe(u8, body[@sizeOf(EbpHdr)..]);
251 if (stderr.readableLength() > 0) {248 if (stderr.readableLength() > 0) {
252 const stderr_data = try stderr.toOwnedSlice();249 const stderr_data = try stderr.toOwnedSlice();
253 if (eval.allow_stderr) {250 if (eval.allow_stderr) {
254 std.log.info("emit_bin_path included stderr:\n{s}", .{stderr_data});251 std.log.info("emit_digest included stderr:\n{s}", .{stderr_data});
255 } else {252 } else {
256 fatal("emit_bin_path included unexpected stderr:\n{s}", .{stderr_data});253 fatal("emit_digest included unexpected stderr:\n{s}", .{stderr_data});
257 }254 }
258 }255 }
259 try eval.checkSuccessOutcome(update, result_binary, prog_node);256
257 if (eval.emit == .none) {
258 try eval.checkSuccessOutcome(update, null, prog_node);
259 // This message indicates the end of the update.
260 stdout.discard(body.len);
261 return;
262 }
263
264 const digest = body[@sizeOf(EbpHdr)..][0..Cache.bin_digest_len];
265 const result_dir = ".local-cache" ++ std.fs.path.sep_str ++ "o" ++ std.fs.path.sep_str ++ Cache.binToHex(digest.*);
266
267 const name = std.fs.path.stem(std.fs.path.basename(eval.case.root_source_file));
268 const bin_name = try std.zig.binNameAlloc(arena, .{
269 .root_name = name,
270 .target = try std.zig.system.resolveTargetQuery(try std.Build.parseTargetQuery(.{
271 .arch_os_abi = eval.case.target_query,
272 .object_format = switch (eval.emit) {
273 .none => unreachable,
274 .bin => null,
275 .c => "c",
276 },
277 })),
278 .output_mode = .Exe,
279 });
280 const bin_path = try std.fs.path.join(arena, &.{ result_dir, bin_name });
281
282 try eval.checkSuccessOutcome(update, bin_path, prog_node);
260 // This message indicates the end of the update.283 // This message indicates the end of the update.
261 stdout.discard(body.len);284 stdout.discard(body.len);
262 return;285 return;