diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2025-08-11 19:44:29 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2025-09-24 20:01:19 -0700 |
| commit | 9e979e5a9dbee39d45ac7dc4fbedb63ddcae8e99 (patch) | |
| tree | 39e76a847d026849299c4756a3b124a4e2801199 /src/Compilation.zig | |
| parent | ea169e6ccfa0792629bebaa64e9d41fb5dd2a594 (diff) | |
| download | zig-9e979e5a9dbee39d45ac7dc4fbedb63ddcae8e99.tar.gz zig-9e979e5a9dbee39d45ac7dc4fbedb63ddcae8e99.zip | |
Compilation: re-implement cImport
Diffstat (limited to 'src/Compilation.zig')
| -rw-r--r-- | src/Compilation.zig | 89 |
1 files changed, 83 insertions, 6 deletions
diff --git a/src/Compilation.zig b/src/Compilation.zig index 74ec79b35f..d0f33f123d 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -5655,12 +5655,89 @@ pub const CImportResult = struct { }; /// Caller owns returned memory. -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, + prog_node: std.Progress.Node, +) !CImportResult { dev.check(.translate_c_command); - _ = comp; - _ = c_src; - _ = owner_mod; - @panic("TODO execute 'zig translate-c' as a sub process and use the results"); + + const cimport_basename = "cimport.h"; + const translated_basename = "cimport.zig"; + + var man = comp.obtainCObjectCacheManifest(owner_mod); + defer man.deinit(); + + man.hash.add(@as(u16, 0x7dd9)); // Random number to distinguish translate-c from compiling C objects + man.hash.addBytes(c_src); + + 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 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; + + try cache_dir.makePath(tmp_sub_path); + + 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}); + + 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 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 (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_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); + }, + .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; + + if (comp.verbose_cimport) log.info("renaming {s} to {s}", .{ tmp_sub_path, o_sub_path }); + try fs.rename(cache_dir, tmp_sub_path, cache_dir, o_sub_path); + + break :digest .{ bin_digest, false }; + }; + + if (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 + // it to prevent doing a full file content comparison the next time around. + man.writeManifest() catch |err| { + log.warn("failed to write cache manifest for C import: {s}", .{@errorName(err)}); + }; + } + + return .{ + .digest = digest, + .cache_hit = is_hit, + .errors = std.zig.ErrorBundle.empty, + }; } fn workerUpdateCObject( @@ -6964,7 +7041,7 @@ fn addCommonCCArgs( pub fn addCCArgs( comp: *const Compilation, arena: Allocator, - argv: *std.ArrayList([]const u8), + argv: *std.array_list.Managed([]const u8), ext: FileExt, out_dep_path: ?[]const u8, mod: *Package.Module, |
