| ... | ... | @@ -5640,6 +5640,7 @@ pub fn obtainWin32ResourceCacheManifest(comp: *const Compilation) Cache.Manifest |
| 5640 | 5640 | } |
| 5641 | 5641 | |
| 5642 | 5642 | pub const CImportResult = struct { |
| 5643 | // Only valid if `errors` is not empty |
| 5643 | 5644 | digest: [Cache.bin_digest_len]u8, |
| 5644 | 5645 | cache_hit: bool, |
| 5645 | 5646 | errors: std.zig.ErrorBundle, |
| ... | ... | @@ -5649,76 +5650,182 @@ pub const CImportResult = struct { |
| 5649 | 5650 | } |
| 5650 | 5651 | }; |
| 5651 | 5652 | |
| 5652 | | /// Caller owns returned memory. |
| 5653 | | pub fn cImport( |
| 5653 | pub fn translateC( |
| 5654 | 5654 | comp: *Compilation, |
| 5655 | | c_src: []const u8, |
| 5655 | arena: Allocator, |
| 5656 | man: *Cache.Manifest, |
| 5657 | ext: FileExt, |
| 5658 | source: union(enum) { |
| 5659 | path: []const u8, |
| 5660 | c_src: []const u8, |
| 5661 | }, |
| 5662 | translated_basename: []const u8, |
| 5656 | 5663 | owner_mod: *Package.Module, |
| 5657 | 5664 | prog_node: std.Progress.Node, |
| 5658 | 5665 | ) !CImportResult { |
| 5659 | 5666 | dev.check(.translate_c_command); |
| 5660 | 5667 | |
| 5661 | | const cimport_basename = "cimport.h"; |
| 5662 | | const translated_basename = "cimport.zig"; |
| 5668 | const tmp_basename = std.fmt.hex(std.crypto.random.int(u64)); |
| 5669 | const tmp_sub_path = "tmp" ++ fs.path.sep_str ++ tmp_basename; |
| 5670 | const cache_dir = comp.dirs.local_cache.handle; |
| 5671 | var cache_tmp_dir = try cache_dir.makeOpenPath(tmp_sub_path, .{}); |
| 5672 | defer cache_tmp_dir.close(); |
| 5673 | |
| 5674 | const translated_path = try comp.dirs.local_cache.join(arena, &.{ tmp_sub_path, translated_basename }); |
| 5675 | const source_path = switch (source) { |
| 5676 | .c_src => |c_src| path: { |
| 5677 | const cimport_basename = "cimport.h"; |
| 5678 | const out_h_sub_path = tmp_sub_path ++ fs.path.sep_str ++ cimport_basename; |
| 5679 | const out_h_path = try comp.dirs.local_cache.join(arena, &.{out_h_sub_path}); |
| 5680 | if (comp.verbose_cimport) log.info("writing C import source to {s}", .{out_h_path}); |
| 5681 | try cache_dir.writeFile(.{ .sub_path = out_h_sub_path, .data = c_src }); |
| 5682 | break :path out_h_path; |
| 5683 | }, |
| 5684 | .path => |p| p, |
| 5685 | }; |
| 5663 | 5686 | |
| 5664 | | var man = comp.obtainCObjectCacheManifest(owner_mod); |
| 5665 | | defer man.deinit(); |
| 5687 | const out_dep_path: ?[]const u8 = blk: { |
| 5688 | if (comp.disable_c_depfile) break :blk null; |
| 5689 | const c_src_basename = fs.path.basename(source_path); |
| 5690 | const dep_basename = try std.fmt.allocPrint(arena, "{s}.d", .{c_src_basename}); |
| 5691 | const out_dep_path = try comp.dirs.local_cache.join(arena, &.{ tmp_sub_path, dep_basename }); |
| 5692 | break :blk out_dep_path; |
| 5693 | }; |
| 5666 | 5694 | |
| 5667 | | man.hash.add(@as(u16, 0x7dd9)); // Random number to distinguish translate-c from compiling C objects |
| 5668 | | man.hash.addBytes(c_src); |
| 5695 | var argv = std.array_list.Managed([]const u8).init(arena); |
| 5696 | { |
| 5697 | const target = &owner_mod.resolved_target.result; |
| 5698 | try argv.appendSlice(&.{ "--zig-integration", "-x", "c" }); |
| 5669 | 5699 | |
| 5670 | | const digest, const is_hit = if (try man.hit()) .{ man.finalBin(), true } else digest: { |
| 5671 | | var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa); |
| 5672 | | defer arena_allocator.deinit(); |
| 5673 | | const arena = arena_allocator.allocator(); |
| 5700 | const resource_path = try comp.dirs.zig_lib.join(arena, &.{ "compiler", "aro", "include" }); |
| 5701 | try argv.appendSlice(&.{ "-isystem", resource_path }); |
| 5702 | try comp.addCommonCCArgs(arena, &argv, ext, out_dep_path, owner_mod, .aro); |
| 5703 | try argv.appendSlice(&[_][]const u8{ "-target", try target.zigTriple(arena) }); |
| 5674 | 5704 | |
| 5675 | | const tmp_basename = std.fmt.hex(std.crypto.random.int(u64)); |
| 5676 | | const tmp_sub_path = "tmp" ++ fs.path.sep_str ++ tmp_basename; |
| 5677 | | const cache_dir = comp.dirs.local_cache.handle; |
| 5678 | | const out_h_sub_path = tmp_sub_path ++ fs.path.sep_str ++ cimport_basename; |
| 5705 | const mcpu = mcpu: { |
| 5706 | var buf: std.ArrayListUnmanaged(u8) = .empty; |
| 5707 | defer buf.deinit(comp.gpa); |
| 5708 | |
| 5709 | try buf.print(comp.gpa, "-mcpu={s}", .{target.cpu.model.name}); |
| 5710 | |
| 5711 | // TODO better serialization https://github.com/ziglang/zig/issues/4584 |
| 5712 | const all_features_list = target.cpu.arch.allFeaturesList(); |
| 5713 | try argv.ensureUnusedCapacity(all_features_list.len * 4); |
| 5714 | for (all_features_list, 0..) |feature, index_usize| { |
| 5715 | const index = @as(std.Target.Cpu.Feature.Set.Index, @intCast(index_usize)); |
| 5716 | const is_enabled = target.cpu.features.isEnabled(index); |
| 5679 | 5717 | |
| 5680 | | try cache_dir.makePath(tmp_sub_path); |
| 5718 | const plus_or_minus = "-+"[@intFromBool(is_enabled)]; |
| 5719 | try buf.print(comp.gpa, "{c}{s}", .{ plus_or_minus, feature.name }); |
| 5720 | } |
| 5721 | break :mcpu try buf.toOwnedSlice(arena); |
| 5722 | }; |
| 5723 | try argv.append(mcpu); |
| 5681 | 5724 | |
| 5682 | | const out_h_path = try comp.dirs.local_cache.join(arena, &.{out_h_sub_path}); |
| 5683 | | const translated_path = try comp.dirs.local_cache.join(arena, &.{ tmp_sub_path, translated_basename }); |
| 5684 | | const out_dep_path = try std.fmt.allocPrint(arena, "{s}.d", .{out_h_path}); |
| 5725 | try argv.appendSlice(comp.global_cc_argv); |
| 5726 | try argv.appendSlice(owner_mod.cc_argv); |
| 5727 | try argv.appendSlice(&.{ source_path, "-o", translated_path }); |
| 5728 | if (comp.verbose_cimport) dump_argv(argv.items); |
| 5729 | } |
| 5685 | 5730 | |
| 5686 | | if (comp.verbose_cimport) log.info("writing C import source to {s}", .{out_h_path}); |
| 5687 | | try cache_dir.writeFile(.{ .sub_path = out_h_sub_path, .data = c_src }); |
| 5731 | var stdout: []u8 = undefined; |
| 5732 | try @import("main.zig").translateC(comp.gpa, arena, argv.items, prog_node, &stdout); |
| 5688 | 5733 | |
| 5689 | | var argv = std.array_list.Managed([]const u8).init(comp.gpa); |
| 5690 | | defer argv.deinit(); |
| 5691 | | try comp.addTranslateCCArgs(arena, &argv, .c, out_dep_path, owner_mod); |
| 5692 | | try argv.appendSlice(&.{ out_h_path, "-o", translated_path }); |
| 5734 | if (out_dep_path) |dep_file_path| add_deps: { |
| 5735 | if (comp.verbose_cimport) log.info("processing dep file at {s}", .{dep_file_path}); |
| 5693 | 5736 | |
| 5694 | | if (comp.verbose_cc) dump_argv(argv.items); |
| 5695 | | var stdout: []u8 = undefined; |
| 5696 | | try @import("main.zig").translateC(comp.gpa, arena, argv.items, prog_node, &stdout); |
| 5697 | | if (comp.verbose_cimport and stdout.len != 0) log.info("unexpected stdout: {s}", .{stdout}); |
| 5737 | const dep_basename = fs.path.basename(dep_file_path); |
| 5738 | // Add the files depended on to the cache system, if a dep file was emitted |
| 5739 | man.addDepFilePost(cache_tmp_dir, dep_basename) catch |err| switch (err) { |
| 5740 | error.FileNotFound => break :add_deps, |
| 5741 | else => |e| return e, |
| 5742 | }; |
| 5698 | 5743 | |
| 5699 | | const dep_sub_path = out_h_sub_path ++ ".d"; |
| 5700 | | if (comp.verbose_cimport) log.info("processing dep file at {s}", .{dep_sub_path}); |
| 5701 | | try man.addDepFilePost(cache_dir, dep_sub_path); |
| 5702 | 5744 | switch (comp.cache_use) { |
| 5703 | 5745 | .whole => |whole| if (whole.cache_manifest) |whole_cache_manifest| { |
| 5704 | 5746 | whole.cache_manifest_mutex.lock(); |
| 5705 | 5747 | defer whole.cache_manifest_mutex.unlock(); |
| 5706 | | try whole_cache_manifest.addDepFilePost(cache_dir, dep_sub_path); |
| 5748 | try whole_cache_manifest.addDepFilePost(cache_tmp_dir, dep_basename); |
| 5707 | 5749 | }, |
| 5708 | 5750 | .incremental, .none => {}, |
| 5709 | 5751 | } |
| 5710 | 5752 | |
| 5711 | | const bin_digest = man.finalBin(); |
| 5712 | | const hex_digest = Cache.binToHex(bin_digest); |
| 5713 | | const o_sub_path = "o" ++ fs.path.sep_str ++ hex_digest; |
| 5753 | // Just to save disk space, we delete the file because it is never needed again. |
| 5754 | cache_tmp_dir.deleteFile(dep_basename) catch |err| { |
| 5755 | log.warn("failed to delete '{s}': {t}", .{ dep_file_path, err }); |
| 5756 | }; |
| 5757 | } |
| 5758 | |
| 5759 | if (stdout.len > 0) { |
| 5760 | var reader: std.Io.Reader = .fixed(stdout); |
| 5761 | const MessageHeader = std.zig.Server.Message.Header; |
| 5762 | const header = reader.takeStruct(MessageHeader, .little) catch unreachable; |
| 5763 | const body = reader.take(header.bytes_len) catch unreachable; |
| 5764 | switch (header.tag) { |
| 5765 | .error_bundle => { |
| 5766 | const error_bundle = try std.zig.Server.allocErrorBundle(comp.gpa, body); |
| 5767 | return .{ |
| 5768 | .digest = undefined, |
| 5769 | .cache_hit = false, |
| 5770 | .errors = error_bundle, |
| 5771 | }; |
| 5772 | }, |
| 5773 | else => unreachable, // No other messagse are sent |
| 5774 | } |
| 5775 | } |
| 5776 | |
| 5777 | const bin_digest = man.finalBin(); |
| 5778 | const hex_digest = Cache.binToHex(bin_digest); |
| 5779 | const o_sub_path = "o" ++ fs.path.sep_str ++ hex_digest; |
| 5714 | 5780 | |
| 5715 | | if (comp.verbose_cimport) log.info("renaming {s} to {s}", .{ tmp_sub_path, o_sub_path }); |
| 5716 | | try renameTmpIntoCache(comp.dirs.local_cache, tmp_sub_path, o_sub_path); |
| 5781 | if (comp.verbose_cimport) log.info("renaming {s} to {s}", .{ tmp_sub_path, o_sub_path }); |
| 5782 | try renameTmpIntoCache(comp.dirs.local_cache, tmp_sub_path, o_sub_path); |
| 5717 | 5783 | |
| 5718 | | break :digest .{ bin_digest, false }; |
| 5784 | return .{ |
| 5785 | .digest = bin_digest, |
| 5786 | .cache_hit = false, |
| 5787 | .errors = ErrorBundle.empty, |
| 5719 | 5788 | }; |
| 5789 | } |
| 5720 | 5790 | |
| 5721 | | if (man.have_exclusive_lock) { |
| 5791 | /// Caller owns returned memory. |
| 5792 | pub fn cImport( |
| 5793 | comp: *Compilation, |
| 5794 | c_src: []const u8, |
| 5795 | owner_mod: *Package.Module, |
| 5796 | prog_node: std.Progress.Node, |
| 5797 | ) !CImportResult { |
| 5798 | dev.check(.translate_c_command); |
| 5799 | |
| 5800 | const translated_basename = "cimport.zig"; |
| 5801 | |
| 5802 | var man = comp.obtainCObjectCacheManifest(owner_mod); |
| 5803 | defer man.deinit(); |
| 5804 | |
| 5805 | man.hash.add(@as(u16, 0x7dd9)); // Random number to distinguish c-import from compiling C objects |
| 5806 | man.hash.addBytes(c_src); |
| 5807 | |
| 5808 | const result: CImportResult = if (try man.hit()) .{ |
| 5809 | .digest = man.finalBin(), |
| 5810 | .cache_hit = true, |
| 5811 | .errors = ErrorBundle.empty, |
| 5812 | } else result: { |
| 5813 | var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa); |
| 5814 | defer arena_allocator.deinit(); |
| 5815 | const arena = arena_allocator.allocator(); |
| 5816 | |
| 5817 | break :result try comp.translateC( |
| 5818 | arena, |
| 5819 | &man, |
| 5820 | .c, |
| 5821 | .{ .c_src = c_src }, |
| 5822 | translated_basename, |
| 5823 | owner_mod, |
| 5824 | prog_node, |
| 5825 | ); |
| 5826 | }; |
| 5827 | |
| 5828 | if (result.errors.errorMessageCount() == 0 and man.have_exclusive_lock) { |
| 5722 | 5829 | // Write the updated manifest. This is a no-op if the manifest is not dirty. Note that it is |
| 5723 | 5830 | // possible we had a hit and the manifest is dirty, for example if the file mtime changed but |
| 5724 | 5831 | // 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( |
| 5728 | 5835 | }; |
| 5729 | 5836 | } |
| 5730 | 5837 | |
| 5731 | | return .{ |
| 5732 | | .digest = digest, |
| 5733 | | .cache_hit = is_hit, |
| 5734 | | .errors = std.zig.ErrorBundle.empty, |
| 5735 | | }; |
| 5838 | return result; |
| 5736 | 5839 | } |
| 5737 | 5840 | |
| 5738 | 5841 | fn workerUpdateCObject( |
| ... | ... | @@ -6622,19 +6725,7 @@ fn spawnZigRc( |
| 6622 | 6725 | // We expect exactly one ErrorBundle, and if any error_bundle header is |
| 6623 | 6726 | // sent then it's a fatal error. |
| 6624 | 6727 | .error_bundle => { |
| 6625 | | const EbHdr = std.zig.Server.Message.ErrorBundle; |
| 6626 | | const eb_hdr = @as(*align(1) const EbHdr, @ptrCast(body)); |
| 6627 | | const extra_bytes = |
| 6628 | | body[@sizeOf(EbHdr)..][0 .. @sizeOf(u32) * eb_hdr.extra_len]; |
| 6629 | | const string_bytes = |
| 6630 | | body[@sizeOf(EbHdr) + extra_bytes.len ..][0..eb_hdr.string_bytes_len]; |
| 6631 | | const unaligned_extra = std.mem.bytesAsSlice(u32, extra_bytes); |
| 6632 | | const extra_array = try comp.gpa.alloc(u32, unaligned_extra.len); |
| 6633 | | @memcpy(extra_array, unaligned_extra); |
| 6634 | | const error_bundle = std.zig.ErrorBundle{ |
| 6635 | | .string_bytes = try comp.gpa.dupe(u8, string_bytes), |
| 6636 | | .extra = extra_array, |
| 6637 | | }; |
| 6728 | const error_bundle = try std.zig.Server.allocErrorBundle(comp.gpa, body); |
| 6638 | 6729 | return comp.failWin32ResourceWithOwnedBundle(win32_resource, error_bundle); |
| 6639 | 6730 | }, |
| 6640 | 6731 | else => {}, // ignore other messages |
| ... | ... | @@ -6672,49 +6763,6 @@ pub fn tmpFilePath(comp: Compilation, ally: Allocator, suffix: []const u8) error |
| 6672 | 6763 | } |
| 6673 | 6764 | } |
| 6674 | 6765 | |
| 6675 | | pub fn addTranslateCCArgs( |
| 6676 | | comp: *Compilation, |
| 6677 | | arena: Allocator, |
| 6678 | | argv: *std.array_list.Managed([]const u8), |
| 6679 | | ext: FileExt, |
| 6680 | | out_dep_path: ?[]const u8, |
| 6681 | | owner_mod: *Package.Module, |
| 6682 | | ) !void { |
| 6683 | | const target = &owner_mod.resolved_target.result; |
| 6684 | | |
| 6685 | | try argv.appendSlice(&.{ "-x", "c" }); |
| 6686 | | |
| 6687 | | const resource_path = try comp.dirs.zig_lib.join(arena, &.{ "compiler", "aro", "include" }); |
| 6688 | | try argv.appendSlice(&.{ "-isystem", resource_path }); |
| 6689 | | |
| 6690 | | try comp.addCommonCCArgs(arena, argv, ext, out_dep_path, owner_mod, .aro); |
| 6691 | | |
| 6692 | | try argv.appendSlice(&[_][]const u8{ "-target", try target.zigTriple(arena) }); |
| 6693 | | |
| 6694 | | const mcpu = mcpu: { |
| 6695 | | var buf: std.ArrayListUnmanaged(u8) = .empty; |
| 6696 | | defer buf.deinit(comp.gpa); |
| 6697 | | |
| 6698 | | try buf.print(comp.gpa, "-mcpu={s}", .{target.cpu.model.name}); |
| 6699 | | |
| 6700 | | // TODO better serialization https://github.com/ziglang/zig/issues/4584 |
| 6701 | | const all_features_list = target.cpu.arch.allFeaturesList(); |
| 6702 | | try argv.ensureUnusedCapacity(all_features_list.len * 4); |
| 6703 | | for (all_features_list, 0..) |feature, index_usize| { |
| 6704 | | const index = @as(std.Target.Cpu.Feature.Set.Index, @intCast(index_usize)); |
| 6705 | | const is_enabled = target.cpu.features.isEnabled(index); |
| 6706 | | |
| 6707 | | const plus_or_minus = "-+"[@intFromBool(is_enabled)]; |
| 6708 | | try buf.print(comp.gpa, "{c}{s}", .{ plus_or_minus, feature.name }); |
| 6709 | | } |
| 6710 | | break :mcpu try buf.toOwnedSlice(arena); |
| 6711 | | }; |
| 6712 | | try argv.append(mcpu); |
| 6713 | | |
| 6714 | | try argv.appendSlice(comp.global_cc_argv); |
| 6715 | | try argv.appendSlice(owner_mod.cc_argv); |
| 6716 | | } |
| 6717 | | |
| 6718 | 6766 | /// Add common C compiler args between translate-c and C object compilation. |
| 6719 | 6767 | fn addCommonCCArgs( |
| 6720 | 6768 | comp: *const Compilation, |