| author | |
| committer | |
| log | 00a8742bbf71b5175b52ecdf736fb4a53ab8177f |
| tree | dd54188333e02876d57a6f0a8ecff33d8782b0e7 |
| parent | 0367d684fccf8bf011fe8ac1a984820c824871a8 |
| parent | d741be512b5c13bec77bde5cc0fd70fbd3535bc0 |
| signature |
compiler: default to `.whole` cache mode for self-hosted backends6 files changed, 93 insertions(+), 63 deletions(-)
src/Compilation.zig+12-5| ... | ... | @@ -2397,7 +2397,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void { |
| 2397 | 2397 | |
| 2398 | 2398 | // Work around windows `AccessDenied` if any files within this |
| 2399 | 2399 | // directory are open by closing and reopening the file handles. |
| 2400 | const need_writable_dance = w: { | |
| 2400 | const need_writable_dance: enum { no, lf_only, lf_and_debug } = w: { | |
| 2401 | 2401 | if (builtin.os.tag == .windows) { |
| 2402 | 2402 | if (comp.bin_file) |lf| { |
| 2403 | 2403 | // We cannot just call `makeExecutable` as it makes a false |
| ... | ... | @@ -2410,11 +2410,13 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void { |
| 2410 | 2410 | if (lf.file) |f| { |
| 2411 | 2411 | f.close(); |
| 2412 | 2412 | lf.file = null; |
| 2413 | break :w true; | |
| 2413 | ||
| 2414 | if (lf.closeDebugInfo()) break :w .lf_and_debug; | |
| 2415 | break :w .lf_only; | |
| 2414 | 2416 | } |
| 2415 | 2417 | } |
| 2416 | 2418 | } |
| 2417 | break :w false; | |
| 2419 | break :w .no; | |
| 2418 | 2420 | }; |
| 2419 | 2421 | |
| 2420 | 2422 | renameTmpIntoCache(comp.local_cache_directory, tmp_dir_sub_path, o_sub_path) catch |err| { |
| ... | ... | @@ -2441,8 +2443,13 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void { |
| 2441 | 2443 | }; |
| 2442 | 2444 | |
| 2443 | 2445 | // Has to be after the `wholeCacheModeSetBinFilePath` above. |
| 2444 | if (need_writable_dance) { | |
| 2445 | try lf.makeWritable(); | |
| 2446 | switch (need_writable_dance) { | |
| 2447 | .no => {}, | |
| 2448 | .lf_only => try lf.makeWritable(), | |
| 2449 | .lf_and_debug => { | |
| 2450 | try lf.makeWritable(); | |
| 2451 | try lf.reopenDebugInfo(); | |
| 2452 | }, | |
| 2446 | 2453 | } |
| 2447 | 2454 | } |
| 2448 | 2455 |
src/link.zig+14| ... | ... | @@ -600,6 +600,20 @@ pub const File = struct { |
| 600 | 600 | } |
| 601 | 601 | } |
| 602 | 602 | |
| 603 | /// Some linkers create a separate file for debug info, which we might need to temporarily close | |
| 604 | /// when moving the compilation result directory due to the host OS not allowing moving a | |
| 605 | /// file/directory while a handle remains open. | |
| 606 | /// Returns `true` if a debug info file was closed. In that case, `reopenDebugInfo` may be called. | |
| 607 | pub fn closeDebugInfo(base: *File) bool { | |
| 608 | const macho = base.cast(.macho) orelse return false; | |
| 609 | return macho.closeDebugInfo(); | |
| 610 | } | |
| 611 | ||
| 612 | pub fn reopenDebugInfo(base: *File) !void { | |
| 613 | const macho = base.cast(.macho).?; | |
| 614 | return macho.reopenDebugInfo(); | |
| 615 | } | |
| 616 | ||
| 603 | 617 | pub fn makeExecutable(base: *File) !void { |
| 604 | 618 | dev.check(.make_executable); |
| 605 | 619 | const comp = base.comp; |
src/link/MachO.zig+33-19| ... | ... | @@ -3277,6 +3277,37 @@ const InitMetadataOptions = struct { |
| 3277 | 3277 | program_code_size_hint: u64, |
| 3278 | 3278 | }; |
| 3279 | 3279 | |
| 3280 | pub fn closeDebugInfo(self: *MachO) bool { | |
| 3281 | const d_sym = &(self.d_sym orelse return false); | |
| 3282 | d_sym.file.?.close(); | |
| 3283 | d_sym.file = null; | |
| 3284 | return true; | |
| 3285 | } | |
| 3286 | ||
| 3287 | pub fn reopenDebugInfo(self: *MachO) !void { | |
| 3288 | assert(self.d_sym.?.file == null); | |
| 3289 | ||
| 3290 | assert(!self.base.comp.config.use_llvm); | |
| 3291 | assert(self.base.comp.config.debug_format == .dwarf); | |
| 3292 | ||
| 3293 | const gpa = self.base.comp.gpa; | |
| 3294 | const sep = fs.path.sep_str; | |
| 3295 | const d_sym_path = try std.fmt.allocPrint( | |
| 3296 | gpa, | |
| 3297 | "{s}.dSYM" ++ sep ++ "Contents" ++ sep ++ "Resources" ++ sep ++ "DWARF", | |
| 3298 | .{self.base.emit.sub_path}, | |
| 3299 | ); | |
| 3300 | defer gpa.free(d_sym_path); | |
| 3301 | ||
| 3302 | var d_sym_bundle = try self.base.emit.root_dir.handle.makeOpenPath(d_sym_path, .{}); | |
| 3303 | defer d_sym_bundle.close(); | |
| 3304 | ||
| 3305 | self.d_sym.?.file = try d_sym_bundle.createFile(fs.path.basename(self.base.emit.sub_path), .{ | |
| 3306 | .truncate = false, | |
| 3307 | .read = true, | |
| 3308 | }); | |
| 3309 | } | |
| 3310 | ||
| 3280 | 3311 | // TODO: move to ZigObject |
| 3281 | 3312 | fn initMetadata(self: *MachO, options: InitMetadataOptions) !void { |
| 3282 | 3313 | if (!self.base.isRelocatable()) { |
| ... | ... | @@ -3333,25 +3364,8 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void { |
| 3333 | 3364 | if (options.zo.dwarf) |*dwarf| { |
| 3334 | 3365 | // Create dSYM bundle. |
| 3335 | 3366 | log.debug("creating {s}.dSYM bundle", .{options.emit.sub_path}); |
| 3336 | ||
| 3337 | const gpa = self.base.comp.gpa; | |
| 3338 | const sep = fs.path.sep_str; | |
| 3339 | const d_sym_path = try std.fmt.allocPrint( | |
| 3340 | gpa, | |
| 3341 | "{s}.dSYM" ++ sep ++ "Contents" ++ sep ++ "Resources" ++ sep ++ "DWARF", | |
| 3342 | .{options.emit.sub_path}, | |
| 3343 | ); | |
| 3344 | defer gpa.free(d_sym_path); | |
| 3345 | ||
| 3346 | var d_sym_bundle = try options.emit.root_dir.handle.makeOpenPath(d_sym_path, .{}); | |
| 3347 | defer d_sym_bundle.close(); | |
| 3348 | ||
| 3349 | const d_sym_file = try d_sym_bundle.createFile(options.emit.sub_path, .{ | |
| 3350 | .truncate = false, | |
| 3351 | .read = true, | |
| 3352 | }); | |
| 3353 | ||
| 3354 | self.d_sym = .{ .allocator = gpa, .file = d_sym_file }; | |
| 3367 | self.d_sym = .{ .allocator = self.base.comp.gpa, .file = null }; | |
| 3368 | try self.reopenDebugInfo(); | |
| 3355 | 3369 | try self.d_sym.?.initMetadata(self); |
| 3356 | 3370 | try dwarf.initMetadata(); |
| 3357 | 3371 | } |
src/link/MachO/DebugSymbols.zig+11-11| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | allocator: Allocator, |
| 2 | file: fs.File, | |
| 2 | file: ?fs.File, | |
| 3 | 3 | |
| 4 | 4 | symtab_cmd: macho.symtab_command = .{}, |
| 5 | 5 | uuid_cmd: macho.uuid_command = .{ .uuid = [_]u8{0} ** 16 }, |
| ... | ... | @@ -118,9 +118,9 @@ pub fn growSection( |
| 118 | 118 | }); |
| 119 | 119 | |
| 120 | 120 | if (requires_file_copy) { |
| 121 | const amt = try self.file.copyRangeAll( | |
| 121 | const amt = try self.file.?.copyRangeAll( | |
| 122 | 122 | sect.offset, |
| 123 | self.file, | |
| 123 | self.file.?, | |
| 124 | 124 | new_offset, |
| 125 | 125 | existing_size, |
| 126 | 126 | ); |
| ... | ... | @@ -129,7 +129,7 @@ pub fn growSection( |
| 129 | 129 | |
| 130 | 130 | sect.offset = @intCast(new_offset); |
| 131 | 131 | } else if (sect.offset + allocated_size == std.math.maxInt(u64)) { |
| 132 | try self.file.setEndPos(sect.offset + needed_size); | |
| 132 | try self.file.?.setEndPos(sect.offset + needed_size); | |
| 133 | 133 | } |
| 134 | 134 | |
| 135 | 135 | sect.size = needed_size; |
| ... | ... | @@ -165,7 +165,7 @@ fn detectAllocCollision(self: *DebugSymbols, start: u64, size: u64) !?u64 { |
| 165 | 165 | } |
| 166 | 166 | } |
| 167 | 167 | |
| 168 | if (at_end) try self.file.setEndPos(end); | |
| 168 | if (at_end) try self.file.?.setEndPos(end); | |
| 169 | 169 | return null; |
| 170 | 170 | } |
| 171 | 171 | |
| ... | ... | @@ -195,7 +195,7 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void { |
| 195 | 195 | sym_name, |
| 196 | 196 | file_offset, |
| 197 | 197 | }); |
| 198 | try self.file.pwriteAll(mem.asBytes(&addr), file_offset); | |
| 198 | try self.file.?.pwriteAll(mem.asBytes(&addr), file_offset); | |
| 199 | 199 | } |
| 200 | 200 | |
| 201 | 201 | self.finalizeDwarfSegment(macho_file); |
| ... | ... | @@ -208,7 +208,7 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void { |
| 208 | 208 | |
| 209 | 209 | pub fn deinit(self: *DebugSymbols) void { |
| 210 | 210 | const gpa = self.allocator; |
| 211 | self.file.close(); | |
| 211 | if (self.file) |file| file.close(); | |
| 212 | 212 | self.segments.deinit(gpa); |
| 213 | 213 | self.sections.deinit(gpa); |
| 214 | 214 | self.relocs.deinit(gpa); |
| ... | ... | @@ -320,7 +320,7 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u |
| 320 | 320 | |
| 321 | 321 | assert(stream.pos == needed_size); |
| 322 | 322 | |
| 323 | try self.file.pwriteAll(buffer, @sizeOf(macho.mach_header_64)); | |
| 323 | try self.file.?.pwriteAll(buffer, @sizeOf(macho.mach_header_64)); | |
| 324 | 324 | |
| 325 | 325 | return .{ ncmds, buffer.len }; |
| 326 | 326 | } |
| ... | ... | @@ -346,7 +346,7 @@ fn writeHeader(self: *DebugSymbols, macho_file: *MachO, ncmds: usize, sizeofcmds |
| 346 | 346 | |
| 347 | 347 | log.debug("writing Mach-O header {}", .{header}); |
| 348 | 348 | |
| 349 | try self.file.pwriteAll(mem.asBytes(&header), 0); | |
| 349 | try self.file.?.pwriteAll(mem.asBytes(&header), 0); | |
| 350 | 350 | } |
| 351 | 351 | |
| 352 | 352 | fn allocatedSize(self: *DebugSymbols, start: u64) u64 { |
| ... | ... | @@ -404,7 +404,7 @@ pub fn writeSymtab(self: *DebugSymbols, off: u32, macho_file: *MachO) !u32 { |
| 404 | 404 | internal.writeSymtab(macho_file, self); |
| 405 | 405 | } |
| 406 | 406 | |
| 407 | try self.file.pwriteAll(mem.sliceAsBytes(self.symtab.items), cmd.symoff); | |
| 407 | try self.file.?.pwriteAll(mem.sliceAsBytes(self.symtab.items), cmd.symoff); | |
| 408 | 408 | |
| 409 | 409 | return off + cmd.nsyms * @sizeOf(macho.nlist_64); |
| 410 | 410 | } |
| ... | ... | @@ -412,7 +412,7 @@ pub fn writeSymtab(self: *DebugSymbols, off: u32, macho_file: *MachO) !u32 { |
| 412 | 412 | pub fn writeStrtab(self: *DebugSymbols, off: u32) !u32 { |
| 413 | 413 | const cmd = &self.symtab_cmd; |
| 414 | 414 | cmd.stroff = off; |
| 415 | try self.file.pwriteAll(self.strtab.items, cmd.stroff); | |
| 415 | try self.file.?.pwriteAll(self.strtab.items, cmd.stroff); | |
| 416 | 416 | return off + cmd.strsize; |
| 417 | 417 | } |
| 418 | 418 |
src/link/SpirV.zig+18-27| ... | ... | @@ -61,6 +61,18 @@ pub fn createEmpty( |
| 61 | 61 | const gpa = comp.gpa; |
| 62 | 62 | const target = comp.root_mod.resolved_target.result; |
| 63 | 63 | |
| 64 | assert(!comp.config.use_lld); // Caught by Compilation.Config.resolve | |
| 65 | assert(!comp.config.use_llvm); // Caught by Compilation.Config.resolve | |
| 66 | assert(target.ofmt == .spirv); // Caught by Compilation.Config.resolve | |
| 67 | switch (target.cpu.arch) { | |
| 68 | .spirv, .spirv32, .spirv64 => {}, | |
| 69 | else => unreachable, // Caught by Compilation.Config.resolve. | |
| 70 | } | |
| 71 | switch (target.os.tag) { | |
| 72 | .opencl, .opengl, .vulkan => {}, | |
| 73 | else => unreachable, // Caught by Compilation.Config.resolve. | |
| 74 | } | |
| 75 | ||
| 64 | 76 | const self = try arena.create(SpirV); |
| 65 | 77 | self.* = .{ |
| 66 | 78 | .base = .{ |
| ... | ... | @@ -79,15 +91,11 @@ pub fn createEmpty( |
| 79 | 91 | }; |
| 80 | 92 | errdefer self.deinit(); |
| 81 | 93 | |
| 82 | switch (target.cpu.arch) { | |
| 83 | .spirv, .spirv32, .spirv64 => {}, | |
| 84 | else => unreachable, // Caught by Compilation.Config.resolve. | |
| 85 | } | |
| 86 | ||
| 87 | switch (target.os.tag) { | |
| 88 | .opencl, .opengl, .vulkan => {}, | |
| 89 | else => unreachable, // Caught by Compilation.Config.resolve. | |
| 90 | } | |
| 94 | // TODO: read the file and keep valid parts instead of truncating | |
| 95 | self.base.file = try emit.root_dir.handle.createFile(emit.sub_path, .{ | |
| 96 | .truncate = true, | |
| 97 | .read = true, | |
| 98 | }); | |
| 91 | 99 | |
| 92 | 100 | return self; |
| 93 | 101 | } |
| ... | ... | @@ -98,24 +106,7 @@ pub fn open( |
| 98 | 106 | emit: Path, |
| 99 | 107 | options: link.File.OpenOptions, |
| 100 | 108 | ) !*SpirV { |
| 101 | const target = comp.root_mod.resolved_target.result; | |
| 102 | const use_lld = build_options.have_llvm and comp.config.use_lld; | |
| 103 | const use_llvm = comp.config.use_llvm; | |
| 104 | ||
| 105 | assert(!use_llvm); // Caught by Compilation.Config.resolve. | |
| 106 | assert(!use_lld); // Caught by Compilation.Config.resolve. | |
| 107 | assert(target.ofmt == .spirv); // Caught by Compilation.Config.resolve. | |
| 108 | ||
| 109 | const spirv = try createEmpty(arena, comp, emit, options); | |
| 110 | errdefer spirv.base.destroy(); | |
| 111 | ||
| 112 | // TODO: read the file and keep valid parts instead of truncating | |
| 113 | const file = try emit.root_dir.handle.createFile(emit.sub_path, .{ | |
| 114 | .truncate = true, | |
| 115 | .read = true, | |
| 116 | }); | |
| 117 | spirv.base.file = file; | |
| 118 | return spirv; | |
| 109 | return createEmpty(arena, comp, emit, options); | |
| 119 | 110 | } |
| 120 | 111 | |
| 121 | 112 | pub fn deinit(self: *SpirV) void { |
src/main.zig+5-1| ... | ... | @@ -3470,7 +3470,11 @@ fn buildOutputType( |
| 3470 | 3470 | // incremental cache mode is used for LLVM backend too. |
| 3471 | 3471 | if (create_module.resolved_options.use_llvm) break :b .whole; |
| 3472 | 3472 | |
| 3473 | break :b .incremental; | |
| 3473 | // Eventually, this default should be `.incremental`. However, since incremental | |
| 3474 | // compilation is currently an opt-in feature, it makes a strictly worse default cache mode | |
| 3475 | // than `.whole`. | |
| 3476 | // https://github.com/ziglang/zig/issues/21165 | |
| 3477 | break :b .whole; | |
| 3474 | 3478 | }; |
| 3475 | 3479 | |
| 3476 | 3480 | process.raiseFileDescriptorLimit(); |