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

compilation and build system fixes
This commit is contained in:
Andrew Kelley 2024-08-19 21:49:29 -07:00 committed by GitHub
commit dffc8c44f9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
31 changed files with 337 additions and 319 deletions

View File

@ -201,9 +201,10 @@ fn cmdObjCopy(
if (seen_update) fatal("zig objcopy only supports 1 update for now", .{}); if (seen_update) fatal("zig objcopy only supports 1 update for now", .{});
seen_update = true; seen_update = true;
try server.serveEmitBinPath(output, .{ // The build system already knows what the output is at this point, we
.flags = .{ .cache_hit = false }, // only need to communicate that the process has finished.
}); // Use the empty error bundle to indicate that the update is done.
try server.serveErrorBundle(std.zig.ErrorBundle.empty);
}, },
else => fatal("unsupported message: {s}", .{@tagName(hdr.tag)}), else => fatal("unsupported message: {s}", .{@tagName(hdr.tag)}),
} }

View File

@ -2373,7 +2373,7 @@ pub const LazyPath = union(enum) {
// basis for not traversing up too many directories. // basis for not traversing up too many directories.
var file_path: Cache.Path = .{ var file_path: Cache.Path = .{
.root_dir = gen.file.step.owner.build_root, .root_dir = Cache.Directory.cwd(),
.sub_path = gen.file.path orelse { .sub_path = gen.file.path orelse {
std.debug.lockStdErr(); std.debug.lockStdErr();
const stderr = std.io.getStdErr(); const stderr = std.io.getStdErr();

View File

@ -896,8 +896,8 @@ pub const Manifest = struct {
} }
} }
/// Returns a hex encoded hash of the inputs. /// Returns a binary hash of the inputs.
pub fn final(self: *Manifest) HexDigest { pub fn finalBin(self: *Manifest) BinDigest {
assert(self.manifest_file != null); assert(self.manifest_file != null);
// We don't close the manifest file yet, because we want to // We don't close the manifest file yet, because we want to
@ -908,7 +908,12 @@ pub const Manifest = struct {
var bin_digest: BinDigest = undefined; var bin_digest: BinDigest = undefined;
self.hash.hasher.final(&bin_digest); self.hash.hasher.final(&bin_digest);
return bin_digest;
}
/// Returns a hex encoded hash of the inputs.
pub fn final(self: *Manifest) HexDigest {
const bin_digest = self.finalBin();
return binToHex(bin_digest); return binToHex(bin_digest);
} }

View File

@ -100,6 +100,15 @@ pub fn start(
} }
fn rebuildTestsWorkerRun(run: *Step.Run, ttyconf: std.io.tty.Config, parent_prog_node: std.Progress.Node) void { fn rebuildTestsWorkerRun(run: *Step.Run, ttyconf: std.io.tty.Config, parent_prog_node: std.Progress.Node) void {
rebuildTestsWorkerRunFallible(run, ttyconf, parent_prog_node) catch |err| {
const compile = run.producer.?;
log.err("step '{s}': failed to rebuild in fuzz mode: {s}", .{
compile.step.name, @errorName(err),
});
};
}
fn rebuildTestsWorkerRunFallible(run: *Step.Run, ttyconf: std.io.tty.Config, parent_prog_node: std.Progress.Node) !void {
const gpa = run.step.owner.allocator; const gpa = run.step.owner.allocator;
const stderr = std.io.getStdErr(); const stderr = std.io.getStdErr();
@ -121,14 +130,9 @@ fn rebuildTestsWorkerRun(run: *Step.Run, ttyconf: std.io.tty.Config, parent_prog
const rebuilt_bin_path = result catch |err| switch (err) { const rebuilt_bin_path = result catch |err| switch (err) {
error.MakeFailed => return, error.MakeFailed => return,
else => { else => |other| return other,
log.err("step '{s}': failed to rebuild in fuzz mode: {s}", .{
compile.step.name, @errorName(err),
});
return;
},
}; };
run.rebuilt_executable = rebuilt_bin_path; run.rebuilt_executable = try rebuilt_bin_path.join(gpa, compile.out_filename);
} }
fn fuzzWorkerRun( fn fuzzWorkerRun(

View File

@ -8,6 +8,8 @@ const Coverage = std.debug.Coverage;
const abi = std.Build.Fuzz.abi; const abi = std.Build.Fuzz.abi;
const log = std.log; const log = std.log;
const assert = std.debug.assert; const assert = std.debug.assert;
const Cache = std.Build.Cache;
const Path = Cache.Path;
const WebServer = @This(); const WebServer = @This();
@ -31,6 +33,10 @@ coverage_mutex: std.Thread.Mutex,
/// Signaled when `coverage_files` changes. /// Signaled when `coverage_files` changes.
coverage_condition: std.Thread.Condition, coverage_condition: std.Thread.Condition,
const fuzzer_bin_name = "fuzzer";
const fuzzer_arch_os_abi = "wasm32-freestanding";
const fuzzer_cpu_features = "baseline+atomics+bulk_memory+multivalue+mutable_globals+nontrapping_fptoint+reference_types+sign_ext";
const CoverageMap = struct { const CoverageMap = struct {
mapped_memory: []align(std.mem.page_size) const u8, mapped_memory: []align(std.mem.page_size) const u8,
coverage: Coverage, coverage: Coverage,
@ -181,9 +187,18 @@ fn serveWasm(
// Do the compilation every request, so that the user can edit the files // Do the compilation every request, so that the user can edit the files
// and see the changes without restarting the server. // and see the changes without restarting the server.
const wasm_binary_path = try buildWasmBinary(ws, arena, optimize_mode); const wasm_base_path = try buildWasmBinary(ws, arena, optimize_mode);
const bin_name = try std.zig.binNameAlloc(arena, .{
.root_name = fuzzer_bin_name,
.target = std.zig.system.resolveTargetQuery(std.Build.parseTargetQuery(.{
.arch_os_abi = fuzzer_arch_os_abi,
.cpu_features = fuzzer_cpu_features,
}) catch unreachable) catch unreachable,
.output_mode = .Exe,
});
// std.http.Server does not have a sendfile API yet. // std.http.Server does not have a sendfile API yet.
const file_contents = try std.fs.cwd().readFileAlloc(gpa, wasm_binary_path, 10 * 1024 * 1024); const bin_path = try wasm_base_path.join(arena, bin_name);
const file_contents = try bin_path.root_dir.handle.readFileAlloc(gpa, bin_path.sub_path, 10 * 1024 * 1024);
defer gpa.free(file_contents); defer gpa.free(file_contents);
try request.respond(file_contents, .{ try request.respond(file_contents, .{
.extra_headers = &.{ .extra_headers = &.{
@ -197,7 +212,7 @@ fn buildWasmBinary(
ws: *WebServer, ws: *WebServer,
arena: Allocator, arena: Allocator,
optimize_mode: std.builtin.OptimizeMode, optimize_mode: std.builtin.OptimizeMode,
) ![]const u8 { ) !Path {
const gpa = ws.gpa; const gpa = ws.gpa;
const main_src_path: Build.Cache.Path = .{ const main_src_path: Build.Cache.Path = .{
@ -219,11 +234,11 @@ fn buildWasmBinary(
ws.zig_exe_path, "build-exe", // ws.zig_exe_path, "build-exe", //
"-fno-entry", // "-fno-entry", //
"-O", @tagName(optimize_mode), // "-O", @tagName(optimize_mode), //
"-target", "wasm32-freestanding", // "-target", fuzzer_arch_os_abi, //
"-mcpu", "baseline+atomics+bulk_memory+multivalue+mutable_globals+nontrapping_fptoint+reference_types+sign_ext", // "-mcpu", fuzzer_cpu_features, //
"--cache-dir", ws.global_cache_directory.path orelse ".", // "--cache-dir", ws.global_cache_directory.path orelse ".", //
"--global-cache-dir", ws.global_cache_directory.path orelse ".", // "--global-cache-dir", ws.global_cache_directory.path orelse ".", //
"--name", "fuzzer", // "--name", fuzzer_bin_name, //
"-rdynamic", // "-rdynamic", //
"-fsingle-threaded", // "-fsingle-threaded", //
"--dep", "Walk", // "--dep", "Walk", //
@ -251,7 +266,7 @@ fn buildWasmBinary(
try sendMessage(child.stdin.?, .exit); try sendMessage(child.stdin.?, .exit);
const Header = std.zig.Server.Message.Header; const Header = std.zig.Server.Message.Header;
var result: ?[]const u8 = null; var result: ?Path = null;
var result_error_bundle = std.zig.ErrorBundle.empty; var result_error_bundle = std.zig.ErrorBundle.empty;
const stdout = poller.fifo(.stdout); const stdout = poller.fifo(.stdout);
@ -288,13 +303,17 @@ fn buildWasmBinary(
.extra = extra_array, .extra = extra_array,
}; };
}, },
.emit_bin_path => { .emit_digest => {
const EbpHdr = std.zig.Server.Message.EmitBinPath; const EbpHdr = std.zig.Server.Message.EmitDigest;
const ebp_hdr = @as(*align(1) const EbpHdr, @ptrCast(body)); const ebp_hdr = @as(*align(1) const EbpHdr, @ptrCast(body));
if (!ebp_hdr.flags.cache_hit) { if (!ebp_hdr.flags.cache_hit) {
log.info("source changes detected; rebuilt wasm component", .{}); log.info("source changes detected; rebuilt wasm component", .{});
} }
result = try arena.dupe(u8, body[@sizeOf(EbpHdr)..]); const digest = body[@sizeOf(EbpHdr)..][0..Cache.bin_digest_len];
result = Path{
.root_dir = ws.global_cache_directory,
.sub_path = try arena.dupe(u8, "o" ++ std.fs.path.sep_str ++ Cache.binToHex(digest.*)),
};
}, },
else => {}, // ignore other messages else => {}, // ignore other messages
} }
@ -568,10 +587,7 @@ fn prepareTables(
}; };
errdefer gop.value_ptr.coverage.deinit(gpa); errdefer gop.value_ptr.coverage.deinit(gpa);
const rebuilt_exe_path: Build.Cache.Path = .{ const rebuilt_exe_path = run_step.rebuilt_executable.?;
.root_dir = Build.Cache.Directory.cwd(),
.sub_path = run_step.rebuilt_executable.?,
};
var debug_info = std.debug.Info.load(gpa, rebuilt_exe_path, &gop.value_ptr.coverage) catch |err| { var debug_info = std.debug.Info.load(gpa, rebuilt_exe_path, &gop.value_ptr.coverage) catch |err| {
log.err("step '{s}': failed to load debug information for '{}': {s}", .{ log.err("step '{s}': failed to load debug information for '{}': {s}", .{
run_step.step.name, rebuilt_exe_path, @errorName(err), run_step.step.name, rebuilt_exe_path, @errorName(err),

View File

@ -317,6 +317,8 @@ const Build = std.Build;
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const assert = std.debug.assert; const assert = std.debug.assert;
const builtin = @import("builtin"); const builtin = @import("builtin");
const Cache = Build.Cache;
const Path = Cache.Path;
pub fn evalChildProcess(s: *Step, argv: []const []const u8) ![]u8 { pub fn evalChildProcess(s: *Step, argv: []const []const u8) ![]u8 {
const run_result = try captureChildProcess(s, std.Progress.Node.none, argv); const run_result = try captureChildProcess(s, std.Progress.Node.none, argv);
@ -373,7 +375,7 @@ pub fn evalZigProcess(
argv: []const []const u8, argv: []const []const u8,
prog_node: std.Progress.Node, prog_node: std.Progress.Node,
watch: bool, watch: bool,
) !?[]const u8 { ) !?Path {
if (s.getZigProcess()) |zp| update: { if (s.getZigProcess()) |zp| update: {
assert(watch); assert(watch);
if (std.Progress.have_ipc) if (zp.progress_ipc_fd) |fd| prog_node.setIpcFd(fd); if (std.Progress.have_ipc) if (zp.progress_ipc_fd) |fd| prog_node.setIpcFd(fd);
@ -477,7 +479,7 @@ pub fn evalZigProcess(
return result; return result;
} }
fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool) !?[]const u8 { fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool) !?Path {
const b = s.owner; const b = s.owner;
const arena = b.allocator; const arena = b.allocator;
@ -487,7 +489,7 @@ fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool) !?[]const u8 {
if (!watch) try sendMessage(zp.child.stdin.?, .exit); if (!watch) try sendMessage(zp.child.stdin.?, .exit);
const Header = std.zig.Server.Message.Header; const Header = std.zig.Server.Message.Header;
var result: ?[]const u8 = null; var result: ?Path = null;
const stdout = zp.poller.fifo(.stdout); const stdout = zp.poller.fifo(.stdout);
@ -531,16 +533,15 @@ fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool) !?[]const u8 {
break; break;
} }
}, },
.emit_bin_path => { .emit_digest => {
const EbpHdr = std.zig.Server.Message.EmitBinPath; const EbpHdr = std.zig.Server.Message.EmitDigest;
const ebp_hdr = @as(*align(1) const EbpHdr, @ptrCast(body)); const ebp_hdr = @as(*align(1) const EbpHdr, @ptrCast(body));
s.result_cached = ebp_hdr.flags.cache_hit; s.result_cached = ebp_hdr.flags.cache_hit;
result = try arena.dupe(u8, body[@sizeOf(EbpHdr)..]); const digest = body[@sizeOf(EbpHdr)..][0..Cache.bin_digest_len];
if (watch) { result = Path{
// This message indicates the end of the update. .root_dir = b.cache_root,
stdout.discard(body.len); .sub_path = try arena.dupe(u8, "o" ++ std.fs.path.sep_str ++ Cache.binToHex(digest.*)),
break; };
}
}, },
.file_system_inputs => { .file_system_inputs => {
s.clearWatchInputs(); s.clearWatchInputs();

View File

@ -17,6 +17,7 @@ const Module = std.Build.Module;
const InstallDir = std.Build.InstallDir; const InstallDir = std.Build.InstallDir;
const GeneratedFile = std.Build.GeneratedFile; const GeneratedFile = std.Build.GeneratedFile;
const Compile = @This(); const Compile = @This();
const Path = std.Build.Cache.Path;
pub const base_id: Step.Id = .compile; pub const base_id: Step.Id = .compile;
@ -1765,7 +1766,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
const zig_args = try getZigArgs(compile, false); const zig_args = try getZigArgs(compile, false);
const maybe_output_bin_path = step.evalZigProcess( const maybe_output_dir = step.evalZigProcess(
zig_args, zig_args,
options.progress_node, options.progress_node,
(b.graph.incremental == true) and options.watch, (b.graph.incremental == true) and options.watch,
@ -1779,53 +1780,51 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
}; };
// Update generated files // Update generated files
if (maybe_output_bin_path) |output_bin_path| { if (maybe_output_dir) |output_dir| {
const output_dir = fs.path.dirname(output_bin_path).?;
if (compile.emit_directory) |lp| { if (compile.emit_directory) |lp| {
lp.path = output_dir; lp.path = b.fmt("{}", .{output_dir});
} }
// -femit-bin[=path] (default) Output machine code // -femit-bin[=path] (default) Output machine code
if (compile.generated_bin) |bin| { if (compile.generated_bin) |bin| {
bin.path = b.pathJoin(&.{ output_dir, compile.out_filename }); bin.path = output_dir.joinString(b.allocator, compile.out_filename) catch @panic("OOM");
} }
const sep = std.fs.path.sep; const sep = std.fs.path.sep_str;
// output PDB if someone requested it // output PDB if someone requested it
if (compile.generated_pdb) |pdb| { if (compile.generated_pdb) |pdb| {
pdb.path = b.fmt("{s}{c}{s}.pdb", .{ output_dir, sep, compile.name }); pdb.path = b.fmt("{}" ++ sep ++ "{s}.pdb", .{ output_dir, compile.name });
} }
// -femit-implib[=path] (default) Produce an import .lib when building a Windows DLL // -femit-implib[=path] (default) Produce an import .lib when building a Windows DLL
if (compile.generated_implib) |implib| { if (compile.generated_implib) |implib| {
implib.path = b.fmt("{s}{c}{s}.lib", .{ output_dir, sep, compile.name }); implib.path = b.fmt("{}" ++ sep ++ "{s}.lib", .{ output_dir, compile.name });
} }
// -femit-h[=path] Generate a C header file (.h) // -femit-h[=path] Generate a C header file (.h)
if (compile.generated_h) |lp| { if (compile.generated_h) |lp| {
lp.path = b.fmt("{s}{c}{s}.h", .{ output_dir, sep, compile.name }); lp.path = b.fmt("{}" ++ sep ++ "{s}.h", .{ output_dir, compile.name });
} }
// -femit-docs[=path] Create a docs/ dir with html documentation // -femit-docs[=path] Create a docs/ dir with html documentation
if (compile.generated_docs) |generated_docs| { if (compile.generated_docs) |generated_docs| {
generated_docs.path = b.pathJoin(&.{ output_dir, "docs" }); generated_docs.path = output_dir.joinString(b.allocator, "docs") catch @panic("OOM");
} }
// -femit-asm[=path] Output .s (assembly code) // -femit-asm[=path] Output .s (assembly code)
if (compile.generated_asm) |lp| { if (compile.generated_asm) |lp| {
lp.path = b.fmt("{s}{c}{s}.s", .{ output_dir, sep, compile.name }); lp.path = b.fmt("{}" ++ sep ++ "{s}.s", .{ output_dir, compile.name });
} }
// -femit-llvm-ir[=path] Produce a .ll file with optimized LLVM IR (requires LLVM extensions) // -femit-llvm-ir[=path] Produce a .ll file with optimized LLVM IR (requires LLVM extensions)
if (compile.generated_llvm_ir) |lp| { if (compile.generated_llvm_ir) |lp| {
lp.path = b.fmt("{s}{c}{s}.ll", .{ output_dir, sep, compile.name }); lp.path = b.fmt("{}" ++ sep ++ "{s}.ll", .{ output_dir, compile.name });
} }
// -femit-llvm-bc[=path] Produce an optimized LLVM module as a .bc file (requires LLVM extensions) // -femit-llvm-bc[=path] Produce an optimized LLVM module as a .bc file (requires LLVM extensions)
if (compile.generated_llvm_bc) |lp| { if (compile.generated_llvm_bc) |lp| {
lp.path = b.fmt("{s}{c}{s}.bc", .{ output_dir, sep, compile.name }); lp.path = b.fmt("{}" ++ sep ++ "{s}.bc", .{ output_dir, compile.name });
} }
} }
@ -1841,7 +1840,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
} }
} }
pub fn rebuildInFuzzMode(c: *Compile, progress_node: std.Progress.Node) ![]const u8 { pub fn rebuildInFuzzMode(c: *Compile, progress_node: std.Progress.Node) !Path {
const gpa = c.step.owner.allocator; const gpa = c.step.owner.allocator;
c.step.result_error_msgs.clearRetainingCapacity(); c.step.result_error_msgs.clearRetainingCapacity();

View File

@ -125,10 +125,10 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
if (install_artifact.dest_dir) |dest_dir| { if (install_artifact.dest_dir) |dest_dir| {
const full_dest_path = b.getInstallPath(dest_dir, install_artifact.dest_sub_path); const full_dest_path = b.getInstallPath(dest_dir, install_artifact.dest_sub_path);
const full_src_path = install_artifact.emitted_bin.?.getPath2(b, step); const src_path = install_artifact.emitted_bin.?.getPath3(b, step);
const p = fs.Dir.updateFile(cwd, full_src_path, cwd, full_dest_path, .{}) catch |err| { const p = fs.Dir.updateFile(src_path.root_dir.handle, src_path.sub_path, cwd, full_dest_path, .{}) catch |err| {
return step.fail("unable to update file from '{s}' to '{s}': {s}", .{ return step.fail("unable to update file from '{s}' to '{s}': {s}", .{
full_src_path, full_dest_path, @errorName(err), src_path.sub_path, full_dest_path, @errorName(err),
}); });
}; };
all_cached = all_cached and p == .fresh; all_cached = all_cached and p == .fresh;
@ -141,22 +141,22 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
} }
if (install_artifact.implib_dir) |implib_dir| { if (install_artifact.implib_dir) |implib_dir| {
const full_src_path = install_artifact.emitted_implib.?.getPath2(b, step); const src_path = install_artifact.emitted_implib.?.getPath3(b, step);
const full_implib_path = b.getInstallPath(implib_dir, fs.path.basename(full_src_path)); const full_implib_path = b.getInstallPath(implib_dir, fs.path.basename(src_path.sub_path));
const p = fs.Dir.updateFile(cwd, full_src_path, cwd, full_implib_path, .{}) catch |err| { const p = fs.Dir.updateFile(src_path.root_dir.handle, src_path.sub_path, cwd, full_implib_path, .{}) catch |err| {
return step.fail("unable to update file from '{s}' to '{s}': {s}", .{ return step.fail("unable to update file from '{s}' to '{s}': {s}", .{
full_src_path, full_implib_path, @errorName(err), src_path.sub_path, full_implib_path, @errorName(err),
}); });
}; };
all_cached = all_cached and p == .fresh; all_cached = all_cached and p == .fresh;
} }
if (install_artifact.pdb_dir) |pdb_dir| { if (install_artifact.pdb_dir) |pdb_dir| {
const full_src_path = install_artifact.emitted_pdb.?.getPath2(b, step); const src_path = install_artifact.emitted_pdb.?.getPath3(b, step);
const full_pdb_path = b.getInstallPath(pdb_dir, fs.path.basename(full_src_path)); const full_pdb_path = b.getInstallPath(pdb_dir, fs.path.basename(src_path.sub_path));
const p = fs.Dir.updateFile(cwd, full_src_path, cwd, full_pdb_path, .{}) catch |err| { const p = fs.Dir.updateFile(src_path.root_dir.handle, src_path.sub_path, cwd, full_pdb_path, .{}) catch |err| {
return step.fail("unable to update file from '{s}' to '{s}': {s}", .{ return step.fail("unable to update file from '{s}' to '{s}': {s}", .{
full_src_path, full_pdb_path, @errorName(err), src_path.sub_path, full_pdb_path, @errorName(err),
}); });
}; };
all_cached = all_cached and p == .fresh; all_cached = all_cached and p == .fresh;
@ -164,11 +164,11 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
if (install_artifact.h_dir) |h_dir| { if (install_artifact.h_dir) |h_dir| {
if (install_artifact.emitted_h) |emitted_h| { if (install_artifact.emitted_h) |emitted_h| {
const full_src_path = emitted_h.getPath2(b, step); const src_path = emitted_h.getPath3(b, step);
const full_h_path = b.getInstallPath(h_dir, fs.path.basename(full_src_path)); const full_h_path = b.getInstallPath(h_dir, fs.path.basename(src_path.sub_path));
const p = fs.Dir.updateFile(cwd, full_src_path, cwd, full_h_path, .{}) catch |err| { const p = fs.Dir.updateFile(src_path.root_dir.handle, src_path.sub_path, cwd, full_h_path, .{}) catch |err| {
return step.fail("unable to update file from '{s}' to '{s}': {s}", .{ return step.fail("unable to update file from '{s}' to '{s}': {s}", .{
full_src_path, full_h_path, @errorName(err), src_path.sub_path, full_h_path, @errorName(err),
}); });
}; };
all_cached = all_cached and p == .fresh; all_cached = all_cached and p == .fresh;
@ -176,22 +176,22 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
for (install_artifact.artifact.installed_headers.items) |installation| switch (installation) { for (install_artifact.artifact.installed_headers.items) |installation| switch (installation) {
.file => |file| { .file => |file| {
const full_src_path = file.source.getPath2(b, step); const src_path = file.source.getPath3(b, step);
const full_h_path = b.getInstallPath(h_dir, file.dest_rel_path); const full_h_path = b.getInstallPath(h_dir, file.dest_rel_path);
const p = fs.Dir.updateFile(cwd, full_src_path, cwd, full_h_path, .{}) catch |err| { const p = fs.Dir.updateFile(src_path.root_dir.handle, src_path.sub_path, cwd, full_h_path, .{}) catch |err| {
return step.fail("unable to update file from '{s}' to '{s}': {s}", .{ return step.fail("unable to update file from '{s}' to '{s}': {s}", .{
full_src_path, full_h_path, @errorName(err), src_path.sub_path, full_h_path, @errorName(err),
}); });
}; };
all_cached = all_cached and p == .fresh; all_cached = all_cached and p == .fresh;
}, },
.directory => |dir| { .directory => |dir| {
const full_src_dir_path = dir.source.getPath2(b, step); const src_dir_path = dir.source.getPath3(b, step);
const full_h_prefix = b.getInstallPath(h_dir, dir.dest_rel_path); const full_h_prefix = b.getInstallPath(h_dir, dir.dest_rel_path);
var src_dir = b.build_root.handle.openDir(full_src_dir_path, .{ .iterate = true }) catch |err| { var src_dir = src_dir_path.root_dir.handle.openDir(src_dir_path.sub_path, .{ .iterate = true }) catch |err| {
return step.fail("unable to open source directory '{s}': {s}", .{ return step.fail("unable to open source directory '{s}': {s}", .{
full_src_dir_path, @errorName(err), src_dir_path.sub_path, @errorName(err),
}); });
}; };
defer src_dir.close(); defer src_dir.close();
@ -208,14 +208,15 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
continue :next_entry; continue :next_entry;
} }
} }
const full_src_entry_path = b.pathJoin(&.{ full_src_dir_path, entry.path });
const src_entry_path = src_dir_path.join(b.allocator, entry.path) catch @panic("OOM");
const full_dest_path = b.pathJoin(&.{ full_h_prefix, entry.path }); const full_dest_path = b.pathJoin(&.{ full_h_prefix, entry.path });
switch (entry.kind) { switch (entry.kind) {
.directory => try cwd.makePath(full_dest_path), .directory => try cwd.makePath(full_dest_path),
.file => { .file => {
const p = fs.Dir.updateFile(cwd, full_src_entry_path, cwd, full_dest_path, .{}) catch |err| { const p = fs.Dir.updateFile(src_entry_path.root_dir.handle, src_entry_path.sub_path, cwd, full_dest_path, .{}) catch |err| {
return step.fail("unable to update file from '{s}' to '{s}': {s}", .{ return step.fail("unable to update file from '{s}' to '{s}': {s}", .{
full_src_entry_path, full_dest_path, @errorName(err), src_entry_path.sub_path, full_dest_path, @errorName(err),
}); });
}; };
all_cached = all_cached and p == .fresh; all_cached = all_cached and p == .fresh;

View File

@ -7,6 +7,7 @@ const mem = std.mem;
const process = std.process; const process = std.process;
const EnvMap = process.EnvMap; const EnvMap = process.EnvMap;
const assert = std.debug.assert; const assert = std.debug.assert;
const Path = Build.Cache.Path;
const Run = @This(); const Run = @This();
@ -93,7 +94,7 @@ cached_test_metadata: ?CachedTestMetadata = null,
/// Populated during the fuzz phase if this run step corresponds to a unit test /// Populated during the fuzz phase if this run step corresponds to a unit test
/// executable that contains fuzz tests. /// executable that contains fuzz tests.
rebuilt_executable: ?[]const u8, rebuilt_executable: ?Path,
/// If this Run step was produced by a Compile step, it is tracked here. /// If this Run step was produced by a Compile step, it is tracked here.
producer: ?*Step.Compile, producer: ?*Step.Compile,
@ -872,7 +873,7 @@ pub fn rerunInFuzzMode(
.artifact => |pa| { .artifact => |pa| {
const artifact = pa.artifact; const artifact = pa.artifact;
const file_path = if (artifact == run.producer.?) const file_path = if (artifact == run.producer.?)
run.rebuilt_executable.? b.fmt("{}", .{run.rebuilt_executable.?})
else else
(artifact.installed_path orelse artifact.generated_bin.?.path.?); (artifact.installed_path orelse artifact.generated_bin.?.path.?);
try argv_list.append(arena, b.fmt("{s}{s}", .{ pa.prefix, file_path })); try argv_list.append(arena, b.fmt("{s}{s}", .{ pa.prefix, file_path }));

View File

@ -153,12 +153,12 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
try argv_list.append(c_macro); try argv_list.append(c_macro);
} }
try argv_list.append(translate_c.source.getPath2(b, step)); const c_source_path = translate_c.source.getPath2(b, step);
try argv_list.append(c_source_path);
const output_path = try step.evalZigProcess(argv_list.items, prog_node, false); const output_dir = try step.evalZigProcess(argv_list.items, prog_node, false);
translate_c.out_basename = fs.path.basename(output_path.?); const basename = std.fs.path.stem(std.fs.path.basename(c_source_path));
const output_dir = fs.path.dirname(output_path.?).?; translate_c.out_basename = b.fmt("{s}.zig", .{basename});
translate_c.output_file.path = output_dir.?.joinString(b.allocator, translate_c.out_basename) catch @panic("OOM");
translate_c.output_file.path = b.pathJoin(&.{ output_dir, translate_c.out_basename });
} }

View File

@ -14,8 +14,8 @@ pub const Message = struct {
zig_version, zig_version,
/// Body is an ErrorBundle. /// Body is an ErrorBundle.
error_bundle, error_bundle,
/// Body is a EmitBinPath. /// Body is a EmitDigest.
emit_bin_path, emit_digest,
/// Body is a TestMetadata /// Body is a TestMetadata
test_metadata, test_metadata,
/// Body is a TestResults /// Body is a TestResults
@ -82,8 +82,8 @@ pub const Message = struct {
}; };
/// Trailing: /// Trailing:
/// * file system path where the emitted binary can be found /// * the hex digest of the cache directory within the /o/ subdirectory.
pub const EmitBinPath = extern struct { pub const EmitDigest = extern struct {
flags: Flags, flags: Flags,
pub const Flags = packed struct(u8) { pub const Flags = packed struct(u8) {
@ -196,17 +196,17 @@ pub fn serveU64Message(s: *Server, tag: OutMessage.Tag, int: u64) !void {
}, &.{std.mem.asBytes(&msg_le)}); }, &.{std.mem.asBytes(&msg_le)});
} }
pub fn serveEmitBinPath( pub fn serveEmitDigest(
s: *Server, s: *Server,
fs_path: []const u8, digest: *const [Cache.bin_digest_len]u8,
header: OutMessage.EmitBinPath, header: OutMessage.EmitDigest,
) !void { ) !void {
try s.serveMessage(.{ try s.serveMessage(.{
.tag = .emit_bin_path, .tag = .emit_digest,
.bytes_len = @intCast(fs_path.len + @sizeOf(OutMessage.EmitBinPath)), .bytes_len = @intCast(digest.len + @sizeOf(OutMessage.EmitDigest)),
}, &.{ }, &.{
std.mem.asBytes(&header), std.mem.asBytes(&header),
fs_path, digest,
}); });
} }
@ -328,3 +328,4 @@ const Allocator = std.mem.Allocator;
const assert = std.debug.assert; const assert = std.debug.assert;
const native_endian = builtin.target.cpu.arch.endian(); const native_endian = builtin.target.cpu.arch.endian();
const need_bswap = native_endian != .little; const need_bswap = native_endian != .little;
const Cache = std.Build.Cache;

View File

@ -39,6 +39,8 @@ const Air = @import("Air.zig");
const Builtin = @import("Builtin.zig"); const Builtin = @import("Builtin.zig");
const LlvmObject = @import("codegen/llvm.zig").Object; const LlvmObject = @import("codegen/llvm.zig").Object;
const dev = @import("dev.zig"); const dev = @import("dev.zig");
pub const Directory = Cache.Directory;
const Path = Cache.Path;
pub const Config = @import("Compilation/Config.zig"); pub const Config = @import("Compilation/Config.zig");
@ -70,9 +72,9 @@ bin_file: ?*link.File,
/// The root path for the dynamic linker and system libraries (as well as frameworks on Darwin) /// The root path for the dynamic linker and system libraries (as well as frameworks on Darwin)
sysroot: ?[]const u8, sysroot: ?[]const u8,
/// This is `null` when not building a Windows DLL, or when `-fno-emit-implib` is used. /// This is `null` when not building a Windows DLL, or when `-fno-emit-implib` is used.
implib_emit: ?Emit, implib_emit: ?Path,
/// This is non-null when `-femit-docs` is provided. /// This is non-null when `-femit-docs` is provided.
docs_emit: ?Emit, docs_emit: ?Path,
root_name: [:0]const u8, root_name: [:0]const u8,
include_compiler_rt: bool, include_compiler_rt: bool,
objects: []Compilation.LinkObject, objects: []Compilation.LinkObject,
@ -269,27 +271,9 @@ llvm_opt_bisect_limit: c_int,
file_system_inputs: ?*std.ArrayListUnmanaged(u8), file_system_inputs: ?*std.ArrayListUnmanaged(u8),
pub const Emit = struct { /// This is the digest of the cache for the current compilation.
/// Where the output will go. /// This digest will be known after update() is called.
directory: Directory, digest: ?[Cache.bin_digest_len]u8 = null,
/// Path to the output file, relative to `directory`.
sub_path: []const u8,
/// Returns the full path to `basename` if it were in the same directory as the
/// `Emit` sub_path.
pub fn basenamePath(emit: Emit, arena: Allocator, basename: []const u8) ![:0]const u8 {
const full_path = if (emit.directory.path) |p|
try std.fs.path.join(arena, &[_][]const u8{ p, emit.sub_path })
else
emit.sub_path;
if (std.fs.path.dirname(full_path)) |dirname| {
return try std.fs.path.joinZ(arena, &.{ dirname, basename });
} else {
return try arena.dupeZ(u8, basename);
}
}
};
pub const default_stack_protector_buffer_size = target_util.default_stack_protector_buffer_size; pub const default_stack_protector_buffer_size = target_util.default_stack_protector_buffer_size;
pub const SemaError = Zcu.SemaError; pub const SemaError = Zcu.SemaError;
@ -868,8 +852,6 @@ pub const LldError = struct {
} }
}; };
pub const Directory = Cache.Directory;
pub const EmitLoc = struct { pub const EmitLoc = struct {
/// If this is `null` it means the file will be output to the cache directory. /// If this is `null` it means the file will be output to the cache directory.
/// When provided, both the open file handle and the path name must outlive the `Compilation`. /// 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
// In the case of incremental cache mode, this `artifact_directory` // In the case of incremental cache mode, this `artifact_directory`
// is computed based on a hash of non-linker inputs, and it is where all // is computed based on a hash of non-linker inputs, and it is where all
// build artifacts are stored (even while in-progress). // build artifacts are stored (even while in-progress).
comp.digest = hash.peekBin();
const digest = hash.final(); const digest = hash.final();
const artifact_sub_dir = "o" ++ std.fs.path.sep_str ++ digest; const artifact_sub_dir = "o" ++ std.fs.path.sep_str ++ digest;
var artifact_dir = try options.local_cache_directory.handle.makeOpenPath(artifact_sub_dir, .{}); var artifact_dir = try options.local_cache_directory.handle.makeOpenPath(artifact_sub_dir, .{});
errdefer artifact_dir.close(); errdefer artifact_dir.close();
@ -1688,8 +1672,8 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
comp.cache_use = .{ .incremental = incremental }; comp.cache_use = .{ .incremental = incremental };
if (options.emit_bin) |emit_bin| { if (options.emit_bin) |emit_bin| {
const emit: Emit = .{ const emit: Path = .{
.directory = emit_bin.directory orelse artifact_directory, .root_dir = emit_bin.directory orelse artifact_directory,
.sub_path = emit_bin.basename, .sub_path = emit_bin.basename,
}; };
comp.bin_file = try link.File.open(arena, comp, emit, lf_open_opts); 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
if (options.emit_implib) |emit_implib| { if (options.emit_implib) |emit_implib| {
comp.implib_emit = .{ comp.implib_emit = .{
.directory = emit_implib.directory orelse artifact_directory, .root_dir = emit_implib.directory orelse artifact_directory,
.sub_path = emit_implib.basename, .sub_path = emit_implib.basename,
}; };
} }
if (options.emit_docs) |emit_docs| { if (options.emit_docs) |emit_docs| {
comp.docs_emit = .{ comp.docs_emit = .{
.directory = emit_docs.directory orelse artifact_directory, .root_dir = emit_docs.directory orelse artifact_directory,
.sub_path = emit_docs.basename, .sub_path = emit_docs.basename,
}; };
} }
@ -2121,9 +2105,11 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
comp.last_update_was_cache_hit = true; comp.last_update_was_cache_hit = true;
log.debug("CacheMode.whole cache hit for {s}", .{comp.root_name}); log.debug("CacheMode.whole cache hit for {s}", .{comp.root_name});
const digest = man.final(); const bin_digest = man.finalBin();
const hex_digest = Cache.binToHex(bin_digest);
comp.wholeCacheModeSetBinFilePath(whole, &digest); comp.digest = bin_digest;
comp.wholeCacheModeSetBinFilePath(whole, &hex_digest);
assert(whole.lock == null); assert(whole.lock == null);
whole.lock = man.toOwnedLock(); whole.lock = man.toOwnedLock();
@ -2155,21 +2141,21 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
if (whole.implib_sub_path) |sub_path| { if (whole.implib_sub_path) |sub_path| {
comp.implib_emit = .{ comp.implib_emit = .{
.directory = tmp_artifact_directory, .root_dir = tmp_artifact_directory,
.sub_path = std.fs.path.basename(sub_path), .sub_path = std.fs.path.basename(sub_path),
}; };
} }
if (whole.docs_sub_path) |sub_path| { if (whole.docs_sub_path) |sub_path| {
comp.docs_emit = .{ comp.docs_emit = .{
.directory = tmp_artifact_directory, .root_dir = tmp_artifact_directory,
.sub_path = std.fs.path.basename(sub_path), .sub_path = std.fs.path.basename(sub_path),
}; };
} }
if (whole.bin_sub_path) |sub_path| { if (whole.bin_sub_path) |sub_path| {
const emit: Emit = .{ const emit: Path = .{
.directory = tmp_artifact_directory, .root_dir = tmp_artifact_directory,
.sub_path = std.fs.path.basename(sub_path), .sub_path = std.fs.path.basename(sub_path),
}; };
comp.bin_file = try link.File.createEmpty(arena, comp, emit, whole.lf_open_opts); 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 {
try man.populateOtherManifest(pwc.manifest, pwc.prefix_map); try man.populateOtherManifest(pwc.manifest, pwc.prefix_map);
} }
const digest = man.final(); const bin_digest = man.finalBin();
const hex_digest = Cache.binToHex(bin_digest);
// Rename the temporary directory into place. // Rename the temporary directory into place.
// Close tmp dir and link.File to avoid open handle during rename. // 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 {
const s = std.fs.path.sep_str; const s = std.fs.path.sep_str;
const tmp_dir_sub_path = "tmp" ++ s ++ std.fmt.hex(tmp_dir_rand_int); const tmp_dir_sub_path = "tmp" ++ s ++ std.fmt.hex(tmp_dir_rand_int);
const o_sub_path = "o" ++ s ++ digest; const o_sub_path = "o" ++ s ++ hex_digest;
// Work around windows `AccessDenied` if any files within this // Work around windows `AccessDenied` if any files within this
// directory are open by closing and reopening the file handles. // 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 {
}, },
); );
}; };
comp.wholeCacheModeSetBinFilePath(whole, &digest); comp.digest = bin_digest;
comp.wholeCacheModeSetBinFilePath(whole, &hex_digest);
// The linker flush functions need to know the final output path // The linker flush functions need to know the final output path
// for debug info purposes because executable debug info contains // for debug info purposes because executable debug info contains
// references object file paths. // references object file paths.
if (comp.bin_file) |lf| { if (comp.bin_file) |lf| {
lf.emit = .{ lf.emit = .{
.directory = comp.local_cache_directory, .root_dir = comp.local_cache_directory,
.sub_path = whole.bin_sub_path.?, .sub_path = whole.bin_sub_path.?,
}; };
@ -2393,9 +2381,10 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
} }
} }
try flush(comp, arena, .main, main_progress_node); try flush(comp, arena, .{
.root_dir = comp.local_cache_directory,
if (try comp.totalErrorCount() != 0) return; .sub_path = o_sub_path,
}, .main, main_progress_node);
// Failure here only means an unnecessary cache miss. // Failure here only means an unnecessary cache miss.
man.writeManifest() catch |err| { man.writeManifest() catch |err| {
@ -2410,8 +2399,10 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
assert(whole.lock == null); assert(whole.lock == null);
whole.lock = man.toOwnedLock(); whole.lock = man.toOwnedLock();
}, },
.incremental => { .incremental => |incremental| {
try flush(comp, arena, .main, main_progress_node); try flush(comp, arena, .{
.root_dir = incremental.artifact_directory,
}, .main, main_progress_node);
}, },
} }
} }
@ -2440,7 +2431,13 @@ pub fn appendFileSystemInput(
std.debug.panic("missing prefix directory: {}, {s}", .{ root, sub_file_path }); std.debug.panic("missing prefix directory: {}, {s}", .{ root, sub_file_path });
} }
fn flush(comp: *Compilation, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) !void { fn flush(
comp: *Compilation,
arena: Allocator,
default_artifact_directory: Path,
tid: Zcu.PerThread.Id,
prog_node: std.Progress.Node,
) !void {
if (comp.bin_file) |lf| { if (comp.bin_file) |lf| {
// This is needed before reading the error flags. // This is needed before reading the error flags.
lf.flush(arena, tid, prog_node) catch |err| switch (err) { 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:
try link.File.C.flushEmitH(zcu); try link.File.C.flushEmitH(zcu);
if (zcu.llvm_object) |llvm_object| { if (zcu.llvm_object) |llvm_object| {
const default_emit = switch (comp.cache_use) { try emitLlvmObject(comp, arena, default_artifact_directory, null, llvm_object, prog_node);
.whole => |whole| .{
.directory = whole.tmp_artifact_directory.?,
.sub_path = "dummy",
},
.incremental => |incremental| .{
.directory = incremental.artifact_directory,
.sub_path = "dummy",
},
};
try emitLlvmObject(comp, arena, default_emit, null, llvm_object, prog_node);
} }
} }
} }
@ -2533,7 +2520,7 @@ fn wholeCacheModeSetBinFilePath(
@memcpy(sub_path[digest_start..][0..digest.len], digest); @memcpy(sub_path[digest_start..][0..digest.len], digest);
comp.implib_emit = .{ comp.implib_emit = .{
.directory = comp.local_cache_directory, .root_dir = comp.local_cache_directory,
.sub_path = sub_path, .sub_path = sub_path,
}; };
} }
@ -2542,7 +2529,7 @@ fn wholeCacheModeSetBinFilePath(
@memcpy(sub_path[digest_start..][0..digest.len], digest); @memcpy(sub_path[digest_start..][0..digest.len], digest);
comp.docs_emit = .{ comp.docs_emit = .{
.directory = comp.local_cache_directory, .root_dir = comp.local_cache_directory,
.sub_path = sub_path, .sub_path = sub_path,
}; };
} }
@ -2745,7 +2732,7 @@ fn emitOthers(comp: *Compilation) void {
pub fn emitLlvmObject( pub fn emitLlvmObject(
comp: *Compilation, comp: *Compilation,
arena: Allocator, arena: Allocator,
default_emit: Emit, default_artifact_directory: Path,
bin_emit_loc: ?EmitLoc, bin_emit_loc: ?EmitLoc,
llvm_object: LlvmObject.Ptr, llvm_object: LlvmObject.Ptr,
prog_node: std.Progress.Node, prog_node: std.Progress.Node,
@ -2756,10 +2743,10 @@ pub fn emitLlvmObject(
try llvm_object.emit(.{ try llvm_object.emit(.{
.pre_ir_path = comp.verbose_llvm_ir, .pre_ir_path = comp.verbose_llvm_ir,
.pre_bc_path = comp.verbose_llvm_bc, .pre_bc_path = comp.verbose_llvm_bc,
.bin_path = try resolveEmitLoc(arena, default_emit, bin_emit_loc), .bin_path = try resolveEmitLoc(arena, default_artifact_directory, bin_emit_loc),
.asm_path = try resolveEmitLoc(arena, default_emit, comp.emit_asm), .asm_path = try resolveEmitLoc(arena, default_artifact_directory, comp.emit_asm),
.post_ir_path = try resolveEmitLoc(arena, default_emit, comp.emit_llvm_ir), .post_ir_path = try resolveEmitLoc(arena, default_artifact_directory, comp.emit_llvm_ir),
.post_bc_path = try resolveEmitLoc(arena, default_emit, comp.emit_llvm_bc), .post_bc_path = try resolveEmitLoc(arena, default_artifact_directory, comp.emit_llvm_bc),
.is_debug = comp.root_mod.optimize_mode == .Debug, .is_debug = comp.root_mod.optimize_mode == .Debug,
.is_small = comp.root_mod.optimize_mode == .ReleaseSmall, .is_small = comp.root_mod.optimize_mode == .ReleaseSmall,
@ -2772,14 +2759,14 @@ pub fn emitLlvmObject(
fn resolveEmitLoc( fn resolveEmitLoc(
arena: Allocator, arena: Allocator,
default_emit: Emit, default_artifact_directory: Path,
opt_loc: ?EmitLoc, opt_loc: ?EmitLoc,
) Allocator.Error!?[*:0]const u8 { ) Allocator.Error!?[*:0]const u8 {
const loc = opt_loc orelse return null; const loc = opt_loc orelse return null;
const slice = if (loc.directory) |directory| const slice = if (loc.directory) |directory|
try directory.joinZ(arena, &.{loc.basename}) try directory.joinZ(arena, &.{loc.basename})
else else
try default_emit.basenamePath(arena, loc.basename); try default_artifact_directory.joinStringZ(arena, loc.basename);
return slice.ptr; return slice.ptr;
} }
@ -3035,7 +3022,7 @@ pub fn saveState(comp: *Compilation) !void {
// Using an atomic file prevents a crash or power failure from corrupting // Using an atomic file prevents a crash or power failure from corrupting
// the previous incremental compilation state. // the previous incremental compilation state.
var af = try lf.emit.directory.handle.atomicFile(basename, .{}); var af = try lf.emit.root_dir.handle.atomicFile(basename, .{});
defer af.deinit(); defer af.deinit();
try af.file.pwritevAll(bufs.items, 0); try af.file.pwritevAll(bufs.items, 0);
try af.finish(); try af.finish();
@ -4000,11 +3987,11 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void {
return comp.lockAndSetMiscFailure(.docs_copy, "no Zig code to document", .{}); return comp.lockAndSetMiscFailure(.docs_copy, "no Zig code to document", .{});
const emit = comp.docs_emit.?; const emit = comp.docs_emit.?;
var out_dir = emit.directory.handle.makeOpenPath(emit.sub_path, .{}) catch |err| { var out_dir = emit.root_dir.handle.makeOpenPath(emit.sub_path, .{}) catch |err| {
return comp.lockAndSetMiscFailure( return comp.lockAndSetMiscFailure(
.docs_copy, .docs_copy,
"unable to create output directory '{}{s}': {s}", "unable to create output directory '{}{s}': {s}",
.{ emit.directory, emit.sub_path, @errorName(err) }, .{ emit.root_dir, emit.sub_path, @errorName(err) },
); );
}; };
defer out_dir.close(); defer out_dir.close();
@ -4024,7 +4011,7 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void {
return comp.lockAndSetMiscFailure( return comp.lockAndSetMiscFailure(
.docs_copy, .docs_copy,
"unable to create '{}{s}/sources.tar': {s}", "unable to create '{}{s}/sources.tar': {s}",
.{ emit.directory, emit.sub_path, @errorName(err) }, .{ emit.root_dir, emit.sub_path, @errorName(err) },
); );
}; };
defer tar_file.close(); defer tar_file.close();
@ -4223,11 +4210,11 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) anye
try comp.updateSubCompilation(sub_compilation, .docs_wasm, prog_node); try comp.updateSubCompilation(sub_compilation, .docs_wasm, prog_node);
const emit = comp.docs_emit.?; const emit = comp.docs_emit.?;
var out_dir = emit.directory.handle.makeOpenPath(emit.sub_path, .{}) catch |err| { var out_dir = emit.root_dir.handle.makeOpenPath(emit.sub_path, .{}) catch |err| {
return comp.lockAndSetMiscFailure( return comp.lockAndSetMiscFailure(
.docs_copy, .docs_copy,
"unable to create output directory '{}{s}': {s}", "unable to create output directory '{}{s}': {s}",
.{ emit.directory, emit.sub_path, @errorName(err) }, .{ emit.root_dir, emit.sub_path, @errorName(err) },
); );
}; };
defer out_dir.close(); defer out_dir.close();
@ -4241,7 +4228,7 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) anye
return comp.lockAndSetMiscFailure(.docs_copy, "unable to copy '{}{s}' to '{}{s}': {s}", .{ return comp.lockAndSetMiscFailure(.docs_copy, "unable to copy '{}{s}' to '{}{s}': {s}", .{
sub_compilation.local_cache_directory, sub_compilation.local_cache_directory,
sub_compilation.cache_use.whole.bin_sub_path.?, sub_compilation.cache_use.whole.bin_sub_path.?,
emit.directory, emit.root_dir,
emit.sub_path, emit.sub_path,
@errorName(err), @errorName(err),
}); });
@ -4403,7 +4390,7 @@ pub fn obtainWin32ResourceCacheManifest(comp: *const Compilation) Cache.Manifest
} }
pub const CImportResult = struct { pub const CImportResult = struct {
out_zig_path: []u8, digest: [Cache.bin_digest_len]u8,
cache_hit: bool, cache_hit: bool,
errors: std.zig.ErrorBundle, errors: std.zig.ErrorBundle,
@ -4413,8 +4400,6 @@ pub const CImportResult = struct {
}; };
/// Caller owns returned memory. /// Caller owns returned memory.
/// This API is currently coupled pretty tightly to stage1's needs; it will need to be reworked
/// a bit when we want to start using it from self-hosted.
pub fn cImport(comp: *Compilation, c_src: []const u8, owner_mod: *Package.Module) !CImportResult { pub fn cImport(comp: *Compilation, c_src: []const u8, owner_mod: *Package.Module) !CImportResult {
dev.check(.translate_c_command); dev.check(.translate_c_command);
@ -4503,7 +4488,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8, owner_mod: *Package.Module
error.OutOfMemory => return error.OutOfMemory, error.OutOfMemory => return error.OutOfMemory,
error.SemanticAnalyzeFail => { error.SemanticAnalyzeFail => {
return CImportResult{ return CImportResult{
.out_zig_path = "", .digest = undefined,
.cache_hit = actual_hit, .cache_hit = actual_hit,
.errors = errors, .errors = errors,
}; };
@ -4528,8 +4513,9 @@ pub fn cImport(comp: *Compilation, c_src: []const u8, owner_mod: *Package.Module
.incremental => {}, .incremental => {},
} }
const digest = man.final(); const bin_digest = man.finalBin();
const o_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest }); const hex_digest = Cache.binToHex(bin_digest);
const o_sub_path = "o" ++ std.fs.path.sep_str ++ hex_digest;
var o_dir = try comp.local_cache_directory.handle.makeOpenPath(o_sub_path, .{}); var o_dir = try comp.local_cache_directory.handle.makeOpenPath(o_sub_path, .{});
defer o_dir.close(); defer o_dir.close();
@ -4541,8 +4527,8 @@ pub fn cImport(comp: *Compilation, c_src: []const u8, owner_mod: *Package.Module
try out_zig_file.writeAll(formatted); try out_zig_file.writeAll(formatted);
break :digest digest; break :digest bin_digest;
} else man.final(); } else man.finalBin();
if (man.have_exclusive_lock) { if (man.have_exclusive_lock) {
// Write the updated manifest. This is a no-op if the manifest is not dirty. Note that it is // 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
}; };
} }
const out_zig_path = try comp.local_cache_directory.join(comp.arena, &.{
"o", &digest, cimport_zig_basename,
});
if (comp.verbose_cimport) {
log.info("C import output: {s}", .{out_zig_path});
}
return CImportResult{ return CImportResult{
.out_zig_path = out_zig_path, .digest = digest,
.cache_hit = actual_hit, .cache_hit = actual_hit,
.errors = std.zig.ErrorBundle.empty, .errors = std.zig.ErrorBundle.empty,
}; };
@ -4800,7 +4780,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
try argv.appendSlice(c_object.src.cache_exempt_flags); try argv.appendSlice(c_object.src.cache_exempt_flags);
const out_obj_path = if (comp.bin_file) |lf| const out_obj_path = if (comp.bin_file) |lf|
try lf.emit.directory.join(arena, &.{lf.emit.sub_path}) try lf.emit.root_dir.join(arena, &.{lf.emit.sub_path})
else else
"/dev/null"; "/dev/null";

View File

@ -183,6 +183,7 @@ const InternPool = @import("InternPool.zig");
const Alignment = InternPool.Alignment; const Alignment = InternPool.Alignment;
const AnalUnit = InternPool.AnalUnit; const AnalUnit = InternPool.AnalUnit;
const ComptimeAllocIndex = InternPool.ComptimeAllocIndex; const ComptimeAllocIndex = InternPool.ComptimeAllocIndex;
const Cache = std.Build.Cache;
pub const default_branch_quota = 1000; pub const default_branch_quota = 1000;
pub const default_reference_trace_len = 2; pub const default_reference_trace_len = 2;
@ -5871,16 +5872,18 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
return sema.failWithOwnedErrorMsg(&child_block, msg); return sema.failWithOwnedErrorMsg(&child_block, msg);
} }
const parent_mod = parent_block.ownerModule(); const parent_mod = parent_block.ownerModule();
const digest = Cache.binToHex(c_import_res.digest);
const c_import_zig_path = try comp.arena.dupe(u8, "o" ++ std.fs.path.sep_str ++ digest);
const c_import_mod = Package.Module.create(comp.arena, .{ const c_import_mod = Package.Module.create(comp.arena, .{
.global_cache_directory = comp.global_cache_directory, .global_cache_directory = comp.global_cache_directory,
.paths = .{ .paths = .{
.root = .{ .root = .{
.root_dir = Compilation.Directory.cwd(), .root_dir = comp.local_cache_directory,
.sub_path = std.fs.path.dirname(c_import_res.out_zig_path) orelse "", .sub_path = c_import_zig_path,
}, },
.root_src_path = std.fs.path.basename(c_import_res.out_zig_path), .root_src_path = "cimport.zig",
}, },
.fully_qualified_name = c_import_res.out_zig_path, .fully_qualified_name = c_import_zig_path,
.cc_argv = parent_mod.cc_argv, .cc_argv = parent_mod.cc_argv,
.inherited = .{}, .inherited = .{},
.global = comp.config, .global = comp.config,

View File

@ -11,6 +11,7 @@ const wasi_libc = @import("wasi_libc.zig");
const Air = @import("Air.zig"); const Air = @import("Air.zig");
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const Cache = std.Build.Cache; const Cache = std.Build.Cache;
const Path = Cache.Path;
const Compilation = @import("Compilation.zig"); const Compilation = @import("Compilation.zig");
const LibCInstallation = std.zig.LibCInstallation; const LibCInstallation = std.zig.LibCInstallation;
const Liveness = @import("Liveness.zig"); const Liveness = @import("Liveness.zig");
@ -56,7 +57,7 @@ pub const File = struct {
/// The owner of this output File. /// The owner of this output File.
comp: *Compilation, comp: *Compilation,
emit: Compilation.Emit, emit: Path,
file: ?fs.File, file: ?fs.File,
/// When linking with LLD, this linker code will output an object file only at /// When linking with LLD, this linker code will output an object file only at
@ -189,7 +190,7 @@ pub const File = struct {
pub fn open( pub fn open(
arena: Allocator, arena: Allocator,
comp: *Compilation, comp: *Compilation,
emit: Compilation.Emit, emit: Path,
options: OpenOptions, options: OpenOptions,
) !*File { ) !*File {
switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt)) { switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt)) {
@ -204,7 +205,7 @@ pub const File = struct {
pub fn createEmpty( pub fn createEmpty(
arena: Allocator, arena: Allocator,
comp: *Compilation, comp: *Compilation,
emit: Compilation.Emit, emit: Path,
options: OpenOptions, options: OpenOptions,
) !*File { ) !*File {
switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt)) { switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt)) {
@ -243,8 +244,8 @@ pub const File = struct {
emit.sub_path, std.crypto.random.int(u32), emit.sub_path, std.crypto.random.int(u32),
}); });
defer gpa.free(tmp_sub_path); defer gpa.free(tmp_sub_path);
try emit.directory.handle.copyFile(emit.sub_path, emit.directory.handle, tmp_sub_path, .{}); try emit.root_dir.handle.copyFile(emit.sub_path, emit.root_dir.handle, tmp_sub_path, .{});
try emit.directory.handle.rename(tmp_sub_path, emit.sub_path); try emit.root_dir.handle.rename(tmp_sub_path, emit.sub_path);
switch (builtin.os.tag) { switch (builtin.os.tag) {
.linux => std.posix.ptrace(std.os.linux.PTRACE.ATTACH, pid, 0, 0) catch |err| { .linux => std.posix.ptrace(std.os.linux.PTRACE.ATTACH, pid, 0, 0) catch |err| {
log.warn("ptrace failure: {s}", .{@errorName(err)}); log.warn("ptrace failure: {s}", .{@errorName(err)});
@ -260,7 +261,7 @@ pub const File = struct {
const use_lld = build_options.have_llvm and comp.config.use_lld; const use_lld = build_options.have_llvm and comp.config.use_lld;
const output_mode = comp.config.output_mode; const output_mode = comp.config.output_mode;
const link_mode = comp.config.link_mode; const link_mode = comp.config.link_mode;
base.file = try emit.directory.handle.createFile(emit.sub_path, .{ base.file = try emit.root_dir.handle.createFile(emit.sub_path, .{
.truncate = false, .truncate = false,
.read = true, .read = true,
.mode = determineMode(use_lld, output_mode, link_mode), .mode = determineMode(use_lld, output_mode, link_mode),
@ -603,7 +604,7 @@ pub const File = struct {
// Until then, we do `lld -r -o output.o input.o` even though the output is the same // Until then, we do `lld -r -o output.o input.o` even though the output is the same
// as the input. For the preprocessing case (`zig cc -E -o foo`) we copy the file // as the input. For the preprocessing case (`zig cc -E -o foo`) we copy the file
// to the final location. See also the corresponding TODO in Coff linking. // to the final location. See also the corresponding TODO in Coff linking.
const full_out_path = try emit.directory.join(gpa, &[_][]const u8{emit.sub_path}); const full_out_path = try emit.root_dir.join(gpa, &[_][]const u8{emit.sub_path});
defer gpa.free(full_out_path); defer gpa.free(full_out_path);
assert(comp.c_object_table.count() == 1); assert(comp.c_object_table.count() == 1);
const the_key = comp.c_object_table.keys()[0]; const the_key = comp.c_object_table.keys()[0];
@ -751,7 +752,7 @@ pub const File = struct {
const comp = base.comp; const comp = base.comp;
const gpa = comp.gpa; const gpa = comp.gpa;
const directory = base.emit.directory; // Just an alias to make it shorter to type. const directory = base.emit.root_dir; // Just an alias to make it shorter to type.
const full_out_path = try directory.join(arena, &[_][]const u8{base.emit.sub_path}); const full_out_path = try directory.join(arena, &[_][]const u8{base.emit.sub_path});
const full_out_path_z = try arena.dupeZ(u8, full_out_path); const full_out_path_z = try arena.dupeZ(u8, full_out_path);
const opt_zcu = comp.module; const opt_zcu = comp.module;
@ -1029,7 +1030,10 @@ pub const File = struct {
llvm_object: LlvmObject.Ptr, llvm_object: LlvmObject.Ptr,
prog_node: std.Progress.Node, prog_node: std.Progress.Node,
) !void { ) !void {
return base.comp.emitLlvmObject(arena, base.emit, .{ return base.comp.emitLlvmObject(arena, .{
.root_dir = base.emit.root_dir,
.sub_path = std.fs.path.dirname(base.emit.sub_path) orelse "",
}, .{
.directory = null, .directory = null,
.basename = base.zcu_object_sub_path.?, .basename = base.zcu_object_sub_path.?,
}, llvm_object, prog_node); }, llvm_object, prog_node);

View File

@ -3,6 +3,7 @@ const mem = std.mem;
const assert = std.debug.assert; const assert = std.debug.assert;
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const fs = std.fs; const fs = std.fs;
const Path = std.Build.Cache.Path;
const C = @This(); const C = @This();
const build_options = @import("build_options"); const build_options = @import("build_options");
@ -104,7 +105,7 @@ pub fn addString(this: *C, s: []const u8) Allocator.Error!String {
pub fn open( pub fn open(
arena: Allocator, arena: Allocator,
comp: *Compilation, comp: *Compilation,
emit: Compilation.Emit, emit: Path,
options: link.File.OpenOptions, options: link.File.OpenOptions,
) !*C { ) !*C {
return createEmpty(arena, comp, emit, options); return createEmpty(arena, comp, emit, options);
@ -113,7 +114,7 @@ pub fn open(
pub fn createEmpty( pub fn createEmpty(
arena: Allocator, arena: Allocator,
comp: *Compilation, comp: *Compilation,
emit: Compilation.Emit, emit: Path,
options: link.File.OpenOptions, options: link.File.OpenOptions,
) !*C { ) !*C {
const target = comp.root_mod.resolved_target.result; const target = comp.root_mod.resolved_target.result;
@ -127,7 +128,7 @@ pub fn createEmpty(
assert(!use_lld); assert(!use_lld);
assert(!use_llvm); assert(!use_llvm);
const file = try emit.directory.handle.createFile(emit.sub_path, .{ const file = try emit.root_dir.handle.createFile(emit.sub_path, .{
// Truncation is done on `flush`. // Truncation is done on `flush`.
.truncate = false, .truncate = false,
}); });

View File

@ -219,7 +219,7 @@ pub const min_text_capacity = padToIdeal(minimum_text_block_size);
pub fn createEmpty( pub fn createEmpty(
arena: Allocator, arena: Allocator,
comp: *Compilation, comp: *Compilation,
emit: Compilation.Emit, emit: Path,
options: link.File.OpenOptions, options: link.File.OpenOptions,
) !*Coff { ) !*Coff {
const target = comp.root_mod.resolved_target.result; const target = comp.root_mod.resolved_target.result;
@ -315,7 +315,7 @@ pub fn createEmpty(
// If using LLD to link, this code should produce an object file so that it // If using LLD to link, this code should produce an object file so that it
// can be passed to LLD. // can be passed to LLD.
const sub_path = if (use_lld) zcu_object_sub_path.? else emit.sub_path; const sub_path = if (use_lld) zcu_object_sub_path.? else emit.sub_path;
self.base.file = try emit.directory.handle.createFile(sub_path, .{ self.base.file = try emit.root_dir.handle.createFile(sub_path, .{
.truncate = true, .truncate = true,
.read = true, .read = true,
.mode = link.File.determineMode(use_lld, output_mode, link_mode), .mode = link.File.determineMode(use_lld, output_mode, link_mode),
@ -416,7 +416,7 @@ pub fn createEmpty(
pub fn open( pub fn open(
arena: Allocator, arena: Allocator,
comp: *Compilation, comp: *Compilation,
emit: Compilation.Emit, emit: Path,
options: link.File.OpenOptions, options: link.File.OpenOptions,
) !*Coff { ) !*Coff {
// TODO: restore saved linker state, don't truncate the file, and // TODO: restore saved linker state, don't truncate the file, and
@ -2714,6 +2714,7 @@ const math = std.math;
const mem = std.mem; const mem = std.mem;
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const Path = std.Build.Cache.Path;
const codegen = @import("../codegen.zig"); const codegen = @import("../codegen.zig");
const link = @import("../link.zig"); const link = @import("../link.zig");

View File

@ -27,7 +27,7 @@ pub fn linkWithLLD(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
const comp = self.base.comp; const comp = self.base.comp;
const gpa = comp.gpa; const gpa = comp.gpa;
const directory = self.base.emit.directory; // Just an alias to make it shorter to type. const directory = self.base.emit.root_dir; // Just an alias to make it shorter to type.
const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path}); const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
// If there is no Zig code to compile, then we should skip flushing the output file because it // 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
try argv.append(try allocPrint(arena, "-OUT:{s}", .{full_out_path})); try argv.append(try allocPrint(arena, "-OUT:{s}", .{full_out_path}));
if (comp.implib_emit) |emit| { if (comp.implib_emit) |emit| {
const implib_out_path = try emit.directory.join(arena, &[_][]const u8{emit.sub_path}); const implib_out_path = try emit.root_dir.join(arena, &[_][]const u8{emit.sub_path});
try argv.append(try allocPrint(arena, "-IMPLIB:{s}", .{implib_out_path})); try argv.append(try allocPrint(arena, "-IMPLIB:{s}", .{implib_out_path}));
} }

View File

@ -204,7 +204,7 @@ pub const SortSection = enum { name, alignment };
pub fn createEmpty( pub fn createEmpty(
arena: Allocator, arena: Allocator,
comp: *Compilation, comp: *Compilation,
emit: Compilation.Emit, emit: Path,
options: link.File.OpenOptions, options: link.File.OpenOptions,
) !*Elf { ) !*Elf {
const target = comp.root_mod.resolved_target.result; const target = comp.root_mod.resolved_target.result;
@ -321,7 +321,7 @@ pub fn createEmpty(
// If using LLD to link, this code should produce an object file so that it // If using LLD to link, this code should produce an object file so that it
// can be passed to LLD. // can be passed to LLD.
const sub_path = if (use_lld) zcu_object_sub_path.? else emit.sub_path; const sub_path = if (use_lld) zcu_object_sub_path.? else emit.sub_path;
self.base.file = try emit.directory.handle.createFile(sub_path, .{ self.base.file = try emit.root_dir.handle.createFile(sub_path, .{
.truncate = true, .truncate = true,
.read = true, .read = true,
.mode = link.File.determineMode(use_lld, output_mode, link_mode), .mode = link.File.determineMode(use_lld, output_mode, link_mode),
@ -401,7 +401,7 @@ pub fn createEmpty(
pub fn open( pub fn open(
arena: Allocator, arena: Allocator,
comp: *Compilation, comp: *Compilation,
emit: Compilation.Emit, emit: Path,
options: link.File.OpenOptions, options: link.File.OpenOptions,
) !*Elf { ) !*Elf {
// TODO: restore saved linker state, don't truncate the file, and // 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
const target = comp.root_mod.resolved_target.result; const target = comp.root_mod.resolved_target.result;
const link_mode = comp.config.link_mode; const link_mode = comp.config.link_mode;
const directory = self.base.emit.directory; // Just an alias to make it shorter to type. const directory = self.base.emit.root_dir; // Just an alias to make it shorter to type.
const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path}); const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
const module_obj_path: ?[]const u8 = if (self.base.zcu_object_sub_path) |path| blk: { const module_obj_path: ?[]const u8 = if (self.base.zcu_object_sub_path) |path| blk: {
if (fs.path.dirname(full_out_path)) |dirname| { if (fs.path.dirname(full_out_path)) |dirname| {
@ -1356,7 +1356,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
const target = self.base.comp.root_mod.resolved_target.result; const target = self.base.comp.root_mod.resolved_target.result;
const link_mode = self.base.comp.config.link_mode; const link_mode = self.base.comp.config.link_mode;
const directory = self.base.emit.directory; // Just an alias to make it shorter to type. const directory = self.base.emit.root_dir; // Just an alias to make it shorter to type.
const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path}); const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
const module_obj_path: ?[]const u8 = if (self.base.zcu_object_sub_path) |path| blk: { const module_obj_path: ?[]const u8 = if (self.base.zcu_object_sub_path) |path| blk: {
if (fs.path.dirname(full_out_path)) |dirname| { 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
const comp = self.base.comp; const comp = self.base.comp;
const gpa = comp.gpa; const gpa = comp.gpa;
const directory = self.base.emit.directory; // Just an alias to make it shorter to type. const directory = self.base.emit.root_dir; // Just an alias to make it shorter to type.
const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path}); const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
// If there is no Zig code to compile, then we should skip flushing the output file because it // 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;
const Archive = @import("Elf/Archive.zig"); const Archive = @import("Elf/Archive.zig");
pub const Atom = @import("Elf/Atom.zig"); pub const Atom = @import("Elf/Atom.zig");
const Cache = std.Build.Cache; const Cache = std.Build.Cache;
const Path = Cache.Path;
const Compilation = @import("../Compilation.zig"); const Compilation = @import("../Compilation.zig");
const ComdatGroupSection = synthetic_sections.ComdatGroupSection; const ComdatGroupSection = synthetic_sections.ComdatGroupSection;
const CopyRelSection = synthetic_sections.CopyRelSection; const CopyRelSection = synthetic_sections.CopyRelSection;

View File

@ -156,7 +156,7 @@ pub fn hashAddFrameworks(man: *Cache.Manifest, hm: []const Framework) !void {
pub fn createEmpty( pub fn createEmpty(
arena: Allocator, arena: Allocator,
comp: *Compilation, comp: *Compilation,
emit: Compilation.Emit, emit: Path,
options: link.File.OpenOptions, options: link.File.OpenOptions,
) !*MachO { ) !*MachO {
const target = comp.root_mod.resolved_target.result; const target = comp.root_mod.resolved_target.result;
@ -221,7 +221,7 @@ pub fn createEmpty(
} }
errdefer self.base.destroy(); errdefer self.base.destroy();
self.base.file = try emit.directory.handle.createFile(emit.sub_path, .{ self.base.file = try emit.root_dir.handle.createFile(emit.sub_path, .{
.truncate = true, .truncate = true,
.read = true, .read = true,
.mode = link.File.determineMode(false, output_mode, link_mode), .mode = link.File.determineMode(false, output_mode, link_mode),
@ -260,7 +260,7 @@ pub fn createEmpty(
pub fn open( pub fn open(
arena: Allocator, arena: Allocator,
comp: *Compilation, comp: *Compilation,
emit: Compilation.Emit, emit: Path,
options: link.File.OpenOptions, options: link.File.OpenOptions,
) !*MachO { ) !*MachO {
// TODO: restore saved linker state, don't truncate the file, and // 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
const sub_prog_node = prog_node.start("MachO Flush", 0); const sub_prog_node = prog_node.start("MachO Flush", 0);
defer sub_prog_node.end(); defer sub_prog_node.end();
const directory = self.base.emit.directory; const directory = self.base.emit.root_dir;
const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path}); const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
const module_obj_path: ?[]const u8 = if (self.base.zcu_object_sub_path) |path| blk: { const module_obj_path: ?[]const u8 = if (self.base.zcu_object_sub_path) |path| blk: {
if (fs.path.dirname(full_out_path)) |dirname| { 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
if (codesig) |*csig| { if (codesig) |*csig| {
try self.writeCodeSignature(csig); // code signing always comes last try self.writeCodeSignature(csig); // code signing always comes last
const emit = self.base.emit; const emit = self.base.emit;
try invalidateKernelCache(emit.directory.handle, emit.sub_path); try invalidateKernelCache(emit.root_dir.handle, emit.sub_path);
} }
} }
@ -597,7 +597,7 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
defer arena_allocator.deinit(); defer arena_allocator.deinit();
const arena = arena_allocator.allocator(); const arena = arena_allocator.allocator();
const directory = self.base.emit.directory; const directory = self.base.emit.root_dir;
const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path}); const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
const module_obj_path: ?[]const u8 = if (self.base.zcu_object_sub_path) |path| blk: { const module_obj_path: ?[]const u8 = if (self.base.zcu_object_sub_path) |path| blk: {
if (fs.path.dirname(full_out_path)) |dirname| { if (fs.path.dirname(full_out_path)) |dirname| {
@ -3199,7 +3199,7 @@ fn copyRangeAllZeroOut(self: *MachO, old_offset: u64, new_offset: u64, size: u64
} }
const InitMetadataOptions = struct { const InitMetadataOptions = struct {
emit: Compilation.Emit, emit: Path,
zo: *ZigObject, zo: *ZigObject,
symbol_count_hint: u64, symbol_count_hint: u64,
program_code_size_hint: u64, program_code_size_hint: u64,
@ -3271,7 +3271,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
); );
defer gpa.free(d_sym_path); defer gpa.free(d_sym_path);
var d_sym_bundle = try options.emit.directory.handle.makeOpenPath(d_sym_path, .{}); var d_sym_bundle = try options.emit.root_dir.handle.makeOpenPath(d_sym_path, .{});
defer d_sym_bundle.close(); defer d_sym_bundle.close();
const d_sym_file = try d_sym_bundle.createFile(options.emit.sub_path, .{ const d_sym_file = try d_sym_bundle.createFile(options.emit.sub_path, .{
@ -4603,6 +4603,7 @@ pub const Atom = @import("MachO/Atom.zig");
const AtomicBool = std.atomic.Value(bool); const AtomicBool = std.atomic.Value(bool);
const Bind = bind.Bind; const Bind = bind.Bind;
const Cache = std.Build.Cache; const Cache = std.Build.Cache;
const Path = Cache.Path;
const CodeSignature = @import("MachO/CodeSignature.zig"); const CodeSignature = @import("MachO/CodeSignature.zig");
const Compilation = @import("../Compilation.zig"); const Compilation = @import("../Compilation.zig");
const DataInCode = synthetic.DataInCode; const DataInCode = synthetic.DataInCode;

View File

@ -53,7 +53,7 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32
if (macho_file.base.isDynLib()) { if (macho_file.base.isDynLib()) {
const emit = macho_file.base.emit; const emit = macho_file.base.emit;
const install_name = macho_file.install_name orelse const install_name = macho_file.install_name orelse
try emit.directory.join(gpa, &.{emit.sub_path}); try emit.root_dir.join(gpa, &.{emit.sub_path});
defer if (macho_file.install_name == null) gpa.free(install_name); defer if (macho_file.install_name == null) gpa.free(install_name);
sizeofcmds += calcInstallNameLen( sizeofcmds += calcInstallNameLen(
@sizeOf(macho.dylib_command), @sizeOf(macho.dylib_command),
@ -237,7 +237,7 @@ pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void {
assert(comp.config.output_mode == .Lib and comp.config.link_mode == .dynamic); assert(comp.config.output_mode == .Lib and comp.config.link_mode == .dynamic);
const emit = macho_file.base.emit; const emit = macho_file.base.emit;
const install_name = macho_file.install_name orelse const install_name = macho_file.install_name orelse
try emit.directory.join(gpa, &.{emit.sub_path}); try emit.root_dir.join(gpa, &.{emit.sub_path});
defer if (macho_file.install_name == null) gpa.free(install_name); defer if (macho_file.install_name == null) gpa.free(install_name);
const curr = comp.version orelse std.SemanticVersion{ const curr = comp.version orelse std.SemanticVersion{
.major = 1, .major = 1,

View File

@ -11,6 +11,7 @@ const builtin = @import("builtin");
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const assert = std.debug.assert; const assert = std.debug.assert;
const log = std.log.scoped(.link); const log = std.log.scoped(.link);
const Path = std.Build.Cache.Path;
const Zcu = @import("../Zcu.zig"); const Zcu = @import("../Zcu.zig");
const InternPool = @import("../InternPool.zig"); const InternPool = @import("../InternPool.zig");
@ -28,7 +29,7 @@ llvm_object: LlvmObject.Ptr,
pub fn createEmpty( pub fn createEmpty(
arena: Allocator, arena: Allocator,
comp: *Compilation, comp: *Compilation,
emit: Compilation.Emit, emit: Path,
options: link.File.OpenOptions, options: link.File.OpenOptions,
) !*NvPtx { ) !*NvPtx {
const target = comp.root_mod.resolved_target.result; const target = comp.root_mod.resolved_target.result;
@ -70,7 +71,7 @@ pub fn createEmpty(
pub fn open( pub fn open(
arena: Allocator, arena: Allocator,
comp: *Compilation, comp: *Compilation,
emit: Compilation.Emit, emit: Path,
options: link.File.OpenOptions, options: link.File.OpenOptions,
) !*NvPtx { ) !*NvPtx {
const target = comp.root_mod.resolved_target.result; const target = comp.root_mod.resolved_target.result;

View File

@ -23,6 +23,7 @@ const mem = std.mem;
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const log = std.log.scoped(.link); const log = std.log.scoped(.link);
const assert = std.debug.assert; const assert = std.debug.assert;
const Path = std.Build.Cache.Path;
base: link.File, base: link.File,
sixtyfour_bit: bool, sixtyfour_bit: bool,
@ -275,7 +276,7 @@ pub fn defaultBaseAddrs(arch: std.Target.Cpu.Arch) Bases {
pub fn createEmpty( pub fn createEmpty(
arena: Allocator, arena: Allocator,
comp: *Compilation, comp: *Compilation,
emit: Compilation.Emit, emit: Path,
options: link.File.OpenOptions, options: link.File.OpenOptions,
) !*Plan9 { ) !*Plan9 {
const target = comp.root_mod.resolved_target.result; const target = comp.root_mod.resolved_target.result;
@ -1199,7 +1200,7 @@ pub fn deinit(self: *Plan9) void {
pub fn open( pub fn open(
arena: Allocator, arena: Allocator,
comp: *Compilation, comp: *Compilation,
emit: Compilation.Emit, emit: Path,
options: link.File.OpenOptions, options: link.File.OpenOptions,
) !*Plan9 { ) !*Plan9 {
const target = comp.root_mod.resolved_target.result; const target = comp.root_mod.resolved_target.result;
@ -1213,7 +1214,7 @@ pub fn open(
const self = try createEmpty(arena, comp, emit, options); const self = try createEmpty(arena, comp, emit, options);
errdefer self.base.destroy(); errdefer self.base.destroy();
const file = try emit.directory.handle.createFile(emit.sub_path, .{ const file = try emit.root_dir.handle.createFile(emit.sub_path, .{
.read = true, .read = true,
.mode = link.File.determineMode( .mode = link.File.determineMode(
use_lld, use_lld,

View File

@ -26,6 +26,7 @@ const std = @import("std");
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const assert = std.debug.assert; const assert = std.debug.assert;
const log = std.log.scoped(.link); const log = std.log.scoped(.link);
const Path = std.Build.Cache.Path;
const Zcu = @import("../Zcu.zig"); const Zcu = @import("../Zcu.zig");
const InternPool = @import("../InternPool.zig"); const InternPool = @import("../InternPool.zig");
@ -54,7 +55,7 @@ object: codegen.Object,
pub fn createEmpty( pub fn createEmpty(
arena: Allocator, arena: Allocator,
comp: *Compilation, comp: *Compilation,
emit: Compilation.Emit, emit: Path,
options: link.File.OpenOptions, options: link.File.OpenOptions,
) !*SpirV { ) !*SpirV {
const gpa = comp.gpa; const gpa = comp.gpa;
@ -95,7 +96,7 @@ pub fn createEmpty(
pub fn open( pub fn open(
arena: Allocator, arena: Allocator,
comp: *Compilation, comp: *Compilation,
emit: Compilation.Emit, emit: Path,
options: link.File.OpenOptions, options: link.File.OpenOptions,
) !*SpirV { ) !*SpirV {
const target = comp.root_mod.resolved_target.result; const target = comp.root_mod.resolved_target.result;
@ -110,7 +111,7 @@ pub fn open(
errdefer spirv.base.destroy(); errdefer spirv.base.destroy();
// TODO: read the file and keep valid parts instead of truncating // TODO: read the file and keep valid parts instead of truncating
const file = try emit.directory.handle.createFile(emit.sub_path, .{ const file = try emit.root_dir.handle.createFile(emit.sub_path, .{
.truncate = true, .truncate = true,
.read = true, .read = true,
}); });

View File

@ -22,6 +22,7 @@ const Air = @import("../Air.zig");
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const Archive = @import("Wasm/Archive.zig"); const Archive = @import("Wasm/Archive.zig");
const Cache = std.Build.Cache; const Cache = std.Build.Cache;
const Path = Cache.Path;
const CodeGen = @import("../arch/wasm/CodeGen.zig"); const CodeGen = @import("../arch/wasm/CodeGen.zig");
const Compilation = @import("../Compilation.zig"); const Compilation = @import("../Compilation.zig");
const Dwarf = @import("Dwarf.zig"); const Dwarf = @import("Dwarf.zig");
@ -346,7 +347,7 @@ pub const StringTable = struct {
pub fn open( pub fn open(
arena: Allocator, arena: Allocator,
comp: *Compilation, comp: *Compilation,
emit: Compilation.Emit, emit: Path,
options: link.File.OpenOptions, options: link.File.OpenOptions,
) !*Wasm { ) !*Wasm {
// TODO: restore saved linker state, don't truncate the file, and // TODO: restore saved linker state, don't truncate the file, and
@ -357,7 +358,7 @@ pub fn open(
pub fn createEmpty( pub fn createEmpty(
arena: Allocator, arena: Allocator,
comp: *Compilation, comp: *Compilation,
emit: Compilation.Emit, emit: Path,
options: link.File.OpenOptions, options: link.File.OpenOptions,
) !*Wasm { ) !*Wasm {
const gpa = comp.gpa; const gpa = comp.gpa;
@ -430,7 +431,7 @@ pub fn createEmpty(
// can be passed to LLD. // can be passed to LLD.
const sub_path = if (use_lld) zcu_object_sub_path.? else emit.sub_path; const sub_path = if (use_lld) zcu_object_sub_path.? else emit.sub_path;
wasm.base.file = try emit.directory.handle.createFile(sub_path, .{ wasm.base.file = try emit.root_dir.handle.createFile(sub_path, .{
.truncate = true, .truncate = true,
.read = true, .read = true,
.mode = if (fs.has_executable_bit) .mode = if (fs.has_executable_bit)
@ -2496,7 +2497,7 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
const sub_prog_node = prog_node.start("Wasm Flush", 0); const sub_prog_node = prog_node.start("Wasm Flush", 0);
defer sub_prog_node.end(); defer sub_prog_node.end();
const directory = wasm.base.emit.directory; // Just an alias to make it shorter to type. const directory = wasm.base.emit.root_dir; // Just an alias to make it shorter to type.
const full_out_path = try directory.join(arena, &[_][]const u8{wasm.base.emit.sub_path}); const full_out_path = try directory.join(arena, &[_][]const u8{wasm.base.emit.sub_path});
const module_obj_path: ?[]const u8 = if (wasm.base.zcu_object_sub_path) |path| blk: { const module_obj_path: ?[]const u8 = if (wasm.base.zcu_object_sub_path) |path| blk: {
if (fs.path.dirname(full_out_path)) |dirname| { if (fs.path.dirname(full_out_path)) |dirname| {
@ -3346,7 +3347,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
const gpa = comp.gpa; const gpa = comp.gpa;
const directory = wasm.base.emit.directory; // Just an alias to make it shorter to type. const directory = wasm.base.emit.root_dir; // Just an alias to make it shorter to type.
const full_out_path = try directory.join(arena, &[_][]const u8{wasm.base.emit.sub_path}); const full_out_path = try directory.join(arena, &[_][]const u8{wasm.base.emit.sub_path});
// If there is no Zig code to compile, then we should skip flushing the output file because it // If there is no Zig code to compile, then we should skip flushing the output file because it

View File

@ -3519,7 +3519,7 @@ fn buildOutputType(
if (test_exec_args.items.len == 0 and target.ofmt == .c) default_exec_args: { if (test_exec_args.items.len == 0 and target.ofmt == .c) default_exec_args: {
// Default to using `zig run` to execute the produced .c code from `zig test`. // Default to using `zig run` to execute the produced .c code from `zig test`.
const c_code_loc = emit_bin_loc orelse break :default_exec_args; const c_code_loc = emit_bin_loc orelse break :default_exec_args;
const c_code_directory = c_code_loc.directory orelse comp.bin_file.?.emit.directory; const c_code_directory = c_code_loc.directory orelse comp.bin_file.?.emit.root_dir;
const c_code_path = try fs.path.join(arena, &[_][]const u8{ const c_code_path = try fs.path.join(arena, &[_][]const u8{
c_code_directory.path orelse ".", c_code_loc.basename, c_code_directory.path orelse ".", c_code_loc.basename,
}); });
@ -4142,7 +4142,7 @@ fn serve(
if (output.errors.errorMessageCount() != 0) { if (output.errors.errorMessageCount() != 0) {
try server.serveErrorBundle(output.errors); try server.serveErrorBundle(output.errors);
} else { } else {
try server.serveEmitBinPath(output.out_zig_path, .{ try server.serveEmitDigest(&output.digest, .{
.flags = .{ .cache_hit = output.cache_hit }, .flags = .{ .cache_hit = output.cache_hit },
}); });
} }
@ -4229,62 +4229,10 @@ fn serveUpdateResults(s: *Server, comp: *Compilation) !void {
return; return;
} }
// This logic is counter-intuitive because the protocol accounts for each if (comp.digest) |digest| {
// emitted artifact possibly being in a different location, which correctly try s.serveEmitDigest(&digest, .{
// matches the behavior of the compiler, however, the build system
// currently always passes flags that makes all build artifacts output to
// the same local cache directory, and relies on them all being in the same
// directory.
//
// So, until the build system and protocol are changed to reflect this,
// this logic must ensure that emit_bin_path is emitted for at least one
// thing, if there are any artifacts.
switch (comp.cache_use) {
.incremental => if (comp.bin_file) |lf| {
const full_path = try lf.emit.directory.join(gpa, &.{lf.emit.sub_path});
defer gpa.free(full_path);
try s.serveEmitBinPath(full_path, .{
.flags = .{ .cache_hit = comp.last_update_was_cache_hit },
});
return;
},
.whole => |whole| if (whole.bin_sub_path) |sub_path| {
const full_path = try comp.local_cache_directory.join(gpa, &.{sub_path});
defer gpa.free(full_path);
try s.serveEmitBinPath(full_path, .{
.flags = .{ .cache_hit = comp.last_update_was_cache_hit },
});
return;
},
}
for ([_]?Compilation.Emit{
comp.docs_emit,
comp.implib_emit,
}) |opt_emit| {
const emit = opt_emit orelse continue;
const full_path = try emit.directory.join(gpa, &.{emit.sub_path});
defer gpa.free(full_path);
try s.serveEmitBinPath(full_path, .{
.flags = .{ .cache_hit = comp.last_update_was_cache_hit }, .flags = .{ .cache_hit = comp.last_update_was_cache_hit },
}); });
return;
}
for ([_]?Compilation.EmitLoc{
comp.emit_asm,
comp.emit_llvm_ir,
comp.emit_llvm_bc,
}) |opt_emit_loc| {
const emit_loc = opt_emit_loc orelse continue;
const directory = emit_loc.directory orelse continue;
const full_path = try directory.join(gpa, &.{emit_loc.basename});
defer gpa.free(full_path);
try s.serveEmitBinPath(full_path, .{
.flags = .{ .cache_hit = comp.last_update_was_cache_hit },
});
return;
} }
// Serve empty error bundle to indicate the update is done. // Serve empty error bundle to indicate the update is done.
@ -4308,7 +4256,7 @@ fn runOrTest(
// A naive `directory.join` here will indeed get the correct path to the binary, // A naive `directory.join` here will indeed get the correct path to the binary,
// however, in the case of cwd, we actually want `./foo` so that the path can be executed. // however, in the case of cwd, we actually want `./foo` so that the path can be executed.
const exe_path = try fs.path.join(arena, &[_][]const u8{ const exe_path = try fs.path.join(arena, &[_][]const u8{
lf.emit.directory.path orelse ".", lf.emit.sub_path, lf.emit.root_dir.path orelse ".", lf.emit.sub_path,
}); });
var argv = std.ArrayList([]const u8).init(gpa); var argv = std.ArrayList([]const u8).init(gpa);
@ -4420,7 +4368,7 @@ fn runOrTestHotSwap(
// tmp zig-cache and use it to spawn the child process. This way we are free to update // tmp zig-cache and use it to spawn the child process. This way we are free to update
// the binary with each requested hot update. // the binary with each requested hot update.
.windows => blk: { .windows => blk: {
try lf.emit.directory.handle.copyFile(lf.emit.sub_path, comp.local_cache_directory.handle, lf.emit.sub_path, .{}); try lf.emit.root_dir.handle.copyFile(lf.emit.sub_path, comp.local_cache_directory.handle, lf.emit.sub_path, .{});
break :blk try fs.path.join(gpa, &[_][]const u8{ break :blk try fs.path.join(gpa, &[_][]const u8{
comp.local_cache_directory.path orelse ".", lf.emit.sub_path, comp.local_cache_directory.path orelse ".", lf.emit.sub_path,
}); });
@ -4429,7 +4377,7 @@ fn runOrTestHotSwap(
// A naive `directory.join` here will indeed get the correct path to the binary, // A naive `directory.join` here will indeed get the correct path to the binary,
// however, in the case of cwd, we actually want `./foo` so that the path can be executed. // however, in the case of cwd, we actually want `./foo` so that the path can be executed.
else => try fs.path.join(gpa, &[_][]const u8{ else => try fs.path.join(gpa, &[_][]const u8{
lf.emit.directory.path orelse ".", lf.emit.sub_path, lf.emit.root_dir.path orelse ".", lf.emit.sub_path,
}), }),
}; };
defer gpa.free(exe_path); defer gpa.free(exe_path);
@ -4539,9 +4487,11 @@ fn cmdTranslateC(
}; };
if (fancy_output) |p| p.cache_hit = true; if (fancy_output) |p| p.cache_hit = true;
const digest = if (try man.hit()) digest: { const bin_digest, const hex_digest = if (try man.hit()) digest: {
if (file_system_inputs) |buf| try man.populateFileSystemInputs(buf); if (file_system_inputs) |buf| try man.populateFileSystemInputs(buf);
break :digest man.final(); const bin_digest = man.finalBin();
const hex_digest = Cache.binToHex(bin_digest);
break :digest .{ bin_digest, hex_digest };
} else digest: { } else digest: {
if (fancy_output) |p| p.cache_hit = false; if (fancy_output) |p| p.cache_hit = false;
var argv = std.ArrayList([]const u8).init(arena); var argv = std.ArrayList([]const u8).init(arena);
@ -4639,8 +4589,10 @@ fn cmdTranslateC(
}; };
} }
const digest = man.final(); const bin_digest = man.finalBin();
const o_sub_path = try fs.path.join(arena, &[_][]const u8{ "o", &digest }); const hex_digest = Cache.binToHex(bin_digest);
const o_sub_path = try fs.path.join(arena, &[_][]const u8{ "o", &hex_digest });
var o_dir = try comp.local_cache_directory.handle.makeOpenPath(o_sub_path, .{}); var o_dir = try comp.local_cache_directory.handle.makeOpenPath(o_sub_path, .{});
defer o_dir.close(); defer o_dir.close();
@ -4656,16 +4608,14 @@ fn cmdTranslateC(
if (file_system_inputs) |buf| try man.populateFileSystemInputs(buf); if (file_system_inputs) |buf| try man.populateFileSystemInputs(buf);
break :digest digest; break :digest .{ bin_digest, hex_digest };
}; };
if (fancy_output) |p| { if (fancy_output) |p| {
p.out_zig_path = try comp.local_cache_directory.join(comp.gpa, &[_][]const u8{ p.digest = bin_digest;
"o", &digest, translated_zig_basename,
});
p.errors = std.zig.ErrorBundle.empty; p.errors = std.zig.ErrorBundle.empty;
} else { } else {
const out_zig_path = try fs.path.join(arena, &[_][]const u8{ "o", &digest, translated_zig_basename }); const out_zig_path = try fs.path.join(arena, &[_][]const u8{ "o", &hex_digest, translated_zig_basename });
const zig_file = comp.local_cache_directory.handle.openFile(out_zig_path, .{}) catch |err| { const zig_file = comp.local_cache_directory.handle.openFile(out_zig_path, .{}) catch |err| {
const path = comp.local_cache_directory.path orelse "."; const path = comp.local_cache_directory.path orelse ".";
fatal("unable to open cached translated zig file '{s}{s}{s}': {s}", .{ path, fs.path.sep_str, out_zig_path, @errorName(err) }); fatal("unable to open cached translated zig file '{s}{s}{s}': {s}", .{ path, fs.path.sep_str, out_zig_path, @errorName(err) });

View File

@ -51,14 +51,15 @@
.install_raw_hex = .{ .install_raw_hex = .{
.path = "install_raw_hex", .path = "install_raw_hex",
}, },
// https://github.com/ziglang/zig/issues/17484 .emit_asm_and_bin = .{
//.emit_asm_and_bin = .{ .path = "emit_asm_and_bin",
// .path = "emit_asm_and_bin", },
//}, .emit_llvm_no_bin = .{
// https://github.com/ziglang/zig/issues/17484 .path = "emit_llvm_no_bin",
//.issue_12588 = .{ },
// .path = "issue_12588", .emit_asm_no_bin = .{
//}, .path = "emit_asm_no_bin",
},
.child_process = .{ .child_process = .{
.path = "child_process", .path = "child_process",
}, },

View File

@ -0,0 +1,19 @@
const std = @import("std");
pub fn build(b: *std.Build) void {
const test_step = b.step("test", "Test it");
b.default_step = test_step;
const optimize: std.builtin.OptimizeMode = .Debug;
const obj = b.addObject(.{
.name = "main",
.root_source_file = b.path("main.zig"),
.optimize = optimize,
.target = b.graph.host,
});
_ = obj.getEmittedAsm();
b.default_step.dependOn(&obj.step);
test_step.dependOn(&obj.step);
}

View File

@ -0,0 +1 @@
pub fn main() void {}

View File

@ -1,6 +1,7 @@
const std = @import("std"); const std = @import("std");
const fatal = std.process.fatal; const fatal = std.process.fatal;
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const Cache = std.Build.Cache;
const 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]"; const 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]";
@ -233,30 +234,52 @@ const Eval = struct {
fatal("error_bundle included unexpected stderr:\n{s}", .{stderr_data}); fatal("error_bundle included unexpected stderr:\n{s}", .{stderr_data});
} }
} }
if (result_error_bundle.errorMessageCount() == 0) { if (result_error_bundle.errorMessageCount() != 0) {
// Empty bundle indicates successful update in a `-fno-emit-bin` build.
try eval.checkSuccessOutcome(update, null, prog_node);
} else {
try eval.checkErrorOutcome(update, result_error_bundle); try eval.checkErrorOutcome(update, result_error_bundle);
} }
// This message indicates the end of the update. // This message indicates the end of the update.
stdout.discard(body.len); stdout.discard(body.len);
return; return;
}, },
.emit_bin_path => { .emit_digest => {
const EbpHdr = std.zig.Server.Message.EmitBinPath; const EbpHdr = std.zig.Server.Message.EmitDigest;
const ebp_hdr = @as(*align(1) const EbpHdr, @ptrCast(body)); const ebp_hdr = @as(*align(1) const EbpHdr, @ptrCast(body));
_ = ebp_hdr; _ = ebp_hdr;
const result_binary = try arena.dupe(u8, body[@sizeOf(EbpHdr)..]);
if (stderr.readableLength() > 0) { if (stderr.readableLength() > 0) {
const stderr_data = try stderr.toOwnedSlice(); const stderr_data = try stderr.toOwnedSlice();
if (eval.allow_stderr) { if (eval.allow_stderr) {
std.log.info("emit_bin_path included stderr:\n{s}", .{stderr_data}); std.log.info("emit_digest included stderr:\n{s}", .{stderr_data});
} else { } else {
fatal("emit_bin_path included unexpected stderr:\n{s}", .{stderr_data}); fatal("emit_digest included unexpected stderr:\n{s}", .{stderr_data});
} }
} }
try eval.checkSuccessOutcome(update, result_binary, prog_node);
if (eval.emit == .none) {
try eval.checkSuccessOutcome(update, null, prog_node);
// This message indicates the end of the update.
stdout.discard(body.len);
return;
}
const digest = body[@sizeOf(EbpHdr)..][0..Cache.bin_digest_len];
const result_dir = ".local-cache" ++ std.fs.path.sep_str ++ "o" ++ std.fs.path.sep_str ++ Cache.binToHex(digest.*);
const name = std.fs.path.stem(std.fs.path.basename(eval.case.root_source_file));
const bin_name = try std.zig.binNameAlloc(arena, .{
.root_name = name,
.target = try std.zig.system.resolveTargetQuery(try std.Build.parseTargetQuery(.{
.arch_os_abi = eval.case.target_query,
.object_format = switch (eval.emit) {
.none => unreachable,
.bin => null,
.c => "c",
},
})),
.output_mode = .Exe,
});
const bin_path = try std.fs.path.join(arena, &.{ result_dir, bin_name });
try eval.checkSuccessOutcome(update, bin_path, prog_node);
// This message indicates the end of the update. // This message indicates the end of the update.
stdout.discard(body.len); stdout.discard(body.len);
return; return;