diff options
| author | kcbanner <kcbanner@gmail.com> | 2025-10-08 03:49:13 -0400 |
|---|---|---|
| committer | kcbanner <kcbanner@gmail.com> | 2025-10-09 01:06:09 -0400 |
| commit | 8b6cdc3d8224cf1e97a970f78281db2fcd14b7a2 (patch) | |
| tree | 2b7c53bbec33d5c1d9edde483a51fc196ed602e6 /src/Compilation.zig | |
| parent | 447280d0d98b540aed4df83db7cf95a417d81611 (diff) | |
| download | zig-8b6cdc3d8224cf1e97a970f78281db2fcd14b7a2.tar.gz zig-8b6cdc3d8224cf1e97a970f78281db2fcd14b7a2.zip | |
- Rework common translate-c and cImport logic into `Compilation.translateC`
- Add std.zig.Server.allocErrorBundle, replace duplicates
Diffstat (limited to 'src/Compilation.zig')
| -rw-r--r-- | src/Compilation.zig | 254 |
1 files changed, 151 insertions, 103 deletions
diff --git a/src/Compilation.zig b/src/Compilation.zig index 8a5f902763..3f22508238 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -5640,6 +5640,7 @@ pub fn obtainWin32ResourceCacheManifest(comp: *const Compilation) Cache.Manifest } pub const CImportResult = struct { + // Only valid if `errors` is not empty digest: [Cache.bin_digest_len]u8, cache_hit: bool, errors: std.zig.ErrorBundle, @@ -5649,76 +5650,182 @@ pub const CImportResult = struct { } }; -/// Caller owns returned memory. -pub fn cImport( +pub fn translateC( comp: *Compilation, - c_src: []const u8, + arena: Allocator, + man: *Cache.Manifest, + ext: FileExt, + source: union(enum) { + path: []const u8, + c_src: []const u8, + }, + translated_basename: []const u8, owner_mod: *Package.Module, prog_node: std.Progress.Node, ) !CImportResult { dev.check(.translate_c_command); - const cimport_basename = "cimport.h"; - const translated_basename = "cimport.zig"; + const tmp_basename = std.fmt.hex(std.crypto.random.int(u64)); + const tmp_sub_path = "tmp" ++ fs.path.sep_str ++ tmp_basename; + const cache_dir = comp.dirs.local_cache.handle; + var cache_tmp_dir = try cache_dir.makeOpenPath(tmp_sub_path, .{}); + defer cache_tmp_dir.close(); + + const translated_path = try comp.dirs.local_cache.join(arena, &.{ tmp_sub_path, translated_basename }); + const source_path = switch (source) { + .c_src => |c_src| path: { + const cimport_basename = "cimport.h"; + const out_h_sub_path = tmp_sub_path ++ fs.path.sep_str ++ cimport_basename; + const out_h_path = try comp.dirs.local_cache.join(arena, &.{out_h_sub_path}); + if (comp.verbose_cimport) log.info("writing C import source to {s}", .{out_h_path}); + try cache_dir.writeFile(.{ .sub_path = out_h_sub_path, .data = c_src }); + break :path out_h_path; + }, + .path => |p| p, + }; - var man = comp.obtainCObjectCacheManifest(owner_mod); - defer man.deinit(); + const out_dep_path: ?[]const u8 = blk: { + if (comp.disable_c_depfile) break :blk null; + const c_src_basename = fs.path.basename(source_path); + const dep_basename = try std.fmt.allocPrint(arena, "{s}.d", .{c_src_basename}); + const out_dep_path = try comp.dirs.local_cache.join(arena, &.{ tmp_sub_path, dep_basename }); + break :blk out_dep_path; + }; - man.hash.add(@as(u16, 0x7dd9)); // Random number to distinguish translate-c from compiling C objects - man.hash.addBytes(c_src); + var argv = std.array_list.Managed([]const u8).init(arena); + { + const target = &owner_mod.resolved_target.result; + try argv.appendSlice(&.{ "--zig-integration", "-x", "c" }); - const digest, const is_hit = if (try man.hit()) .{ man.finalBin(), true } else digest: { - var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa); - defer arena_allocator.deinit(); - const arena = arena_allocator.allocator(); + const resource_path = try comp.dirs.zig_lib.join(arena, &.{ "compiler", "aro", "include" }); + try argv.appendSlice(&.{ "-isystem", resource_path }); + try comp.addCommonCCArgs(arena, &argv, ext, out_dep_path, owner_mod, .aro); + try argv.appendSlice(&[_][]const u8{ "-target", try target.zigTriple(arena) }); - const tmp_basename = std.fmt.hex(std.crypto.random.int(u64)); - const tmp_sub_path = "tmp" ++ fs.path.sep_str ++ tmp_basename; - const cache_dir = comp.dirs.local_cache.handle; - const out_h_sub_path = tmp_sub_path ++ fs.path.sep_str ++ cimport_basename; + const mcpu = mcpu: { + var buf: std.ArrayListUnmanaged(u8) = .empty; + defer buf.deinit(comp.gpa); + + try buf.print(comp.gpa, "-mcpu={s}", .{target.cpu.model.name}); + + // TODO better serialization https://github.com/ziglang/zig/issues/4584 + const all_features_list = target.cpu.arch.allFeaturesList(); + try argv.ensureUnusedCapacity(all_features_list.len * 4); + for (all_features_list, 0..) |feature, index_usize| { + const index = @as(std.Target.Cpu.Feature.Set.Index, @intCast(index_usize)); + const is_enabled = target.cpu.features.isEnabled(index); - try cache_dir.makePath(tmp_sub_path); + const plus_or_minus = "-+"[@intFromBool(is_enabled)]; + try buf.print(comp.gpa, "{c}{s}", .{ plus_or_minus, feature.name }); + } + break :mcpu try buf.toOwnedSlice(arena); + }; + try argv.append(mcpu); - const out_h_path = try comp.dirs.local_cache.join(arena, &.{out_h_sub_path}); - const translated_path = try comp.dirs.local_cache.join(arena, &.{ tmp_sub_path, translated_basename }); - const out_dep_path = try std.fmt.allocPrint(arena, "{s}.d", .{out_h_path}); + try argv.appendSlice(comp.global_cc_argv); + try argv.appendSlice(owner_mod.cc_argv); + try argv.appendSlice(&.{ source_path, "-o", translated_path }); + if (comp.verbose_cimport) dump_argv(argv.items); + } - if (comp.verbose_cimport) log.info("writing C import source to {s}", .{out_h_path}); - try cache_dir.writeFile(.{ .sub_path = out_h_sub_path, .data = c_src }); + var stdout: []u8 = undefined; + try @import("main.zig").translateC(comp.gpa, arena, argv.items, prog_node, &stdout); - var argv = std.array_list.Managed([]const u8).init(comp.gpa); - defer argv.deinit(); - try comp.addTranslateCCArgs(arena, &argv, .c, out_dep_path, owner_mod); - try argv.appendSlice(&.{ out_h_path, "-o", translated_path }); + if (out_dep_path) |dep_file_path| add_deps: { + if (comp.verbose_cimport) log.info("processing dep file at {s}", .{dep_file_path}); - if (comp.verbose_cc) dump_argv(argv.items); - var stdout: []u8 = undefined; - try @import("main.zig").translateC(comp.gpa, arena, argv.items, prog_node, &stdout); - if (comp.verbose_cimport and stdout.len != 0) log.info("unexpected stdout: {s}", .{stdout}); + const dep_basename = fs.path.basename(dep_file_path); + // Add the files depended on to the cache system, if a dep file was emitted + man.addDepFilePost(cache_tmp_dir, dep_basename) catch |err| switch (err) { + error.FileNotFound => break :add_deps, + else => |e| return e, + }; - const dep_sub_path = out_h_sub_path ++ ".d"; - if (comp.verbose_cimport) log.info("processing dep file at {s}", .{dep_sub_path}); - try man.addDepFilePost(cache_dir, dep_sub_path); switch (comp.cache_use) { .whole => |whole| if (whole.cache_manifest) |whole_cache_manifest| { whole.cache_manifest_mutex.lock(); defer whole.cache_manifest_mutex.unlock(); - try whole_cache_manifest.addDepFilePost(cache_dir, dep_sub_path); + try whole_cache_manifest.addDepFilePost(cache_tmp_dir, dep_basename); }, .incremental, .none => {}, } - const bin_digest = man.finalBin(); - const hex_digest = Cache.binToHex(bin_digest); - const o_sub_path = "o" ++ fs.path.sep_str ++ hex_digest; + // Just to save disk space, we delete the file because it is never needed again. + cache_tmp_dir.deleteFile(dep_basename) catch |err| { + log.warn("failed to delete '{s}': {t}", .{ dep_file_path, err }); + }; + } + + if (stdout.len > 0) { + var reader: std.Io.Reader = .fixed(stdout); + const MessageHeader = std.zig.Server.Message.Header; + const header = reader.takeStruct(MessageHeader, .little) catch unreachable; + const body = reader.take(header.bytes_len) catch unreachable; + switch (header.tag) { + .error_bundle => { + const error_bundle = try std.zig.Server.allocErrorBundle(comp.gpa, body); + return .{ + .digest = undefined, + .cache_hit = false, + .errors = error_bundle, + }; + }, + else => unreachable, // No other messagse are sent + } + } + + const bin_digest = man.finalBin(); + const hex_digest = Cache.binToHex(bin_digest); + const o_sub_path = "o" ++ fs.path.sep_str ++ hex_digest; - if (comp.verbose_cimport) log.info("renaming {s} to {s}", .{ tmp_sub_path, o_sub_path }); - try renameTmpIntoCache(comp.dirs.local_cache, tmp_sub_path, o_sub_path); + if (comp.verbose_cimport) log.info("renaming {s} to {s}", .{ tmp_sub_path, o_sub_path }); + try renameTmpIntoCache(comp.dirs.local_cache, tmp_sub_path, o_sub_path); - break :digest .{ bin_digest, false }; + return .{ + .digest = bin_digest, + .cache_hit = false, + .errors = ErrorBundle.empty, }; +} - if (man.have_exclusive_lock) { +/// Caller owns returned memory. +pub fn cImport( + comp: *Compilation, + c_src: []const u8, + owner_mod: *Package.Module, + prog_node: std.Progress.Node, +) !CImportResult { + dev.check(.translate_c_command); + + const translated_basename = "cimport.zig"; + + var man = comp.obtainCObjectCacheManifest(owner_mod); + defer man.deinit(); + + man.hash.add(@as(u16, 0x7dd9)); // Random number to distinguish c-import from compiling C objects + man.hash.addBytes(c_src); + + const result: CImportResult = if (try man.hit()) .{ + .digest = man.finalBin(), + .cache_hit = true, + .errors = ErrorBundle.empty, + } else result: { + var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa); + defer arena_allocator.deinit(); + const arena = arena_allocator.allocator(); + + break :result try comp.translateC( + arena, + &man, + .c, + .{ .c_src = c_src }, + translated_basename, + owner_mod, + prog_node, + ); + }; + + if (result.errors.errorMessageCount() == 0 and man.have_exclusive_lock) { // Write the updated manifest. This is a no-op if the manifest is not dirty. Note that it is // possible we had a hit and the manifest is dirty, for example if the file mtime changed but // the contents were the same, we hit the cache but the manifest is dirty and we need to update @@ -5728,11 +5835,7 @@ pub fn cImport( }; } - return .{ - .digest = digest, - .cache_hit = is_hit, - .errors = std.zig.ErrorBundle.empty, - }; + return result; } fn workerUpdateCObject( @@ -6622,19 +6725,7 @@ fn spawnZigRc( // We expect exactly one ErrorBundle, and if any error_bundle header is // sent then it's a fatal error. .error_bundle => { - const EbHdr = std.zig.Server.Message.ErrorBundle; - const eb_hdr = @as(*align(1) const EbHdr, @ptrCast(body)); - const extra_bytes = - body[@sizeOf(EbHdr)..][0 .. @sizeOf(u32) * eb_hdr.extra_len]; - const string_bytes = - body[@sizeOf(EbHdr) + extra_bytes.len ..][0..eb_hdr.string_bytes_len]; - const unaligned_extra = std.mem.bytesAsSlice(u32, extra_bytes); - const extra_array = try comp.gpa.alloc(u32, unaligned_extra.len); - @memcpy(extra_array, unaligned_extra); - const error_bundle = std.zig.ErrorBundle{ - .string_bytes = try comp.gpa.dupe(u8, string_bytes), - .extra = extra_array, - }; + const error_bundle = try std.zig.Server.allocErrorBundle(comp.gpa, body); return comp.failWin32ResourceWithOwnedBundle(win32_resource, error_bundle); }, else => {}, // ignore other messages @@ -6672,49 +6763,6 @@ pub fn tmpFilePath(comp: Compilation, ally: Allocator, suffix: []const u8) error } } -pub fn addTranslateCCArgs( - comp: *Compilation, - arena: Allocator, - argv: *std.array_list.Managed([]const u8), - ext: FileExt, - out_dep_path: ?[]const u8, - owner_mod: *Package.Module, -) !void { - const target = &owner_mod.resolved_target.result; - - try argv.appendSlice(&.{ "-x", "c" }); - - const resource_path = try comp.dirs.zig_lib.join(arena, &.{ "compiler", "aro", "include" }); - try argv.appendSlice(&.{ "-isystem", resource_path }); - - try comp.addCommonCCArgs(arena, argv, ext, out_dep_path, owner_mod, .aro); - - try argv.appendSlice(&[_][]const u8{ "-target", try target.zigTriple(arena) }); - - const mcpu = mcpu: { - var buf: std.ArrayListUnmanaged(u8) = .empty; - defer buf.deinit(comp.gpa); - - try buf.print(comp.gpa, "-mcpu={s}", .{target.cpu.model.name}); - - // TODO better serialization https://github.com/ziglang/zig/issues/4584 - const all_features_list = target.cpu.arch.allFeaturesList(); - try argv.ensureUnusedCapacity(all_features_list.len * 4); - for (all_features_list, 0..) |feature, index_usize| { - const index = @as(std.Target.Cpu.Feature.Set.Index, @intCast(index_usize)); - const is_enabled = target.cpu.features.isEnabled(index); - - const plus_or_minus = "-+"[@intFromBool(is_enabled)]; - try buf.print(comp.gpa, "{c}{s}", .{ plus_or_minus, feature.name }); - } - break :mcpu try buf.toOwnedSlice(arena); - }; - try argv.append(mcpu); - - try argv.appendSlice(comp.global_cc_argv); - try argv.appendSlice(owner_mod.cc_argv); -} - /// Add common C compiler args between translate-c and C object compilation. fn addCommonCCArgs( comp: *const Compilation, |
