| ... | @@ -5640,6 +5640,7 @@ pub fn obtainWin32ResourceCacheManifest(comp: *const Compilation) Cache.Manifest | ... | @@ -5640,6 +5640,7 @@ pub fn obtainWin32ResourceCacheManifest(comp: *const Compilation) Cache.Manifest |
| 5640 | } | 5640 | } |
| 5641 | | 5641 | |
| 5642 | pub const CImportResult = struct { | 5642 | pub const CImportResult = struct { |
| | 5643 | // Only valid if `errors` is not empty |
| 5643 | digest: [Cache.bin_digest_len]u8, | 5644 | digest: [Cache.bin_digest_len]u8, |
| 5644 | cache_hit: bool, | 5645 | cache_hit: bool, |
| 5645 | errors: std.zig.ErrorBundle, | 5646 | errors: std.zig.ErrorBundle, |
| ... | @@ -5649,76 +5650,182 @@ pub const CImportResult = struct { | ... | @@ -5649,76 +5650,182 @@ pub const CImportResult = struct { |
| 5649 | } | 5650 | } |
| 5650 | }; | 5651 | }; |
| 5651 | | 5652 | |
| 5652 | /// Caller owns returned memory. | 5653 | pub fn translateC( |
| 5653 | pub fn cImport( | | |
| 5654 | comp: *Compilation, | 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 | owner_mod: *Package.Module, | 5663 | owner_mod: *Package.Module, |
| 5657 | prog_node: std.Progress.Node, | 5664 | prog_node: std.Progress.Node, |
| 5658 | ) !CImportResult { | 5665 | ) !CImportResult { |
| 5659 | dev.check(.translate_c_command); | 5666 | dev.check(.translate_c_command); |
| 5660 | | 5667 | |
| 5661 | const cimport_basename = "cimport.h"; | 5668 | const tmp_basename = std.fmt.hex(std.crypto.random.int(u64)); |
| 5662 | const translated_basename = "cimport.zig"; | 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); | 5687 | const out_dep_path: ?[]const u8 = blk: { |
| 5665 | defer man.deinit(); | 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 | 5695 | var argv = std.array_list.Managed([]const u8).init(arena); |
| 5668 | man.hash.addBytes(c_src); | 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: { | 5700 | const resource_path = try comp.dirs.zig_lib.join(arena, &.{ "compiler", "aro", "include" }); |
| 5671 | var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa); | 5701 | try argv.appendSlice(&.{ "-isystem", resource_path }); |
| 5672 | defer arena_allocator.deinit(); | 5702 | try comp.addCommonCCArgs(arena, &argv, ext, out_dep_path, owner_mod, .aro); |
| 5673 | const arena = arena_allocator.allocator(); | 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)); | 5705 | const mcpu = mcpu: { |
| 5676 | const tmp_sub_path = "tmp" ++ fs.path.sep_str ++ tmp_basename; | 5706 | var buf: std.ArrayListUnmanaged(u8) = .empty; |
| 5677 | const cache_dir = comp.dirs.local_cache.handle; | 5707 | defer buf.deinit(comp.gpa); |
| 5678 | const out_h_sub_path = tmp_sub_path ++ fs.path.sep_str ++ cimport_basename; | 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}); | 5725 | try argv.appendSlice(comp.global_cc_argv); |
| 5683 | const translated_path = try comp.dirs.local_cache.join(arena, &.{ tmp_sub_path, translated_basename }); | 5726 | try argv.appendSlice(owner_mod.cc_argv); |
| 5684 | const out_dep_path = try std.fmt.allocPrint(arena, "{s}.d", .{out_h_path}); | 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}); | 5731 | var stdout: []u8 = undefined; |
| 5687 | try cache_dir.writeFile(.{ .sub_path = out_h_sub_path, .data = c_src }); | 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); | 5734 | if (out_dep_path) |dep_file_path| add_deps: { |
| 5690 | defer argv.deinit(); | 5735 | if (comp.verbose_cimport) log.info("processing dep file at {s}", .{dep_file_path}); |
| 5691 | try comp.addTranslateCCArgs(arena, &argv, .c, out_dep_path, owner_mod); | | |
| 5692 | try argv.appendSlice(&.{ out_h_path, "-o", translated_path }); | | |
| 5693 | | 5736 | |
| 5694 | if (comp.verbose_cc) dump_argv(argv.items); | 5737 | const dep_basename = fs.path.basename(dep_file_path); |
| 5695 | var stdout: []u8 = undefined; | 5738 | // Add the files depended on to the cache system, if a dep file was emitted |
| 5696 | try @import("main.zig").translateC(comp.gpa, arena, argv.items, prog_node, &stdout); | 5739 | man.addDepFilePost(cache_tmp_dir, dep_basename) catch |err| switch (err) { |
| 5697 | if (comp.verbose_cimport and stdout.len != 0) log.info("unexpected stdout: {s}", .{stdout}); | 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 | switch (comp.cache_use) { | 5744 | switch (comp.cache_use) { |
| 5703 | .whole => |whole| if (whole.cache_manifest) |whole_cache_manifest| { | 5745 | .whole => |whole| if (whole.cache_manifest) |whole_cache_manifest| { |
| 5704 | whole.cache_manifest_mutex.lock(); | 5746 | whole.cache_manifest_mutex.lock(); |
| 5705 | defer whole.cache_manifest_mutex.unlock(); | 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 | .incremental, .none => {}, | 5750 | .incremental, .none => {}, |
| 5709 | } | 5751 | } |
| 5710 | | 5752 | |
| 5711 | const bin_digest = man.finalBin(); | 5753 | // Just to save disk space, we delete the file because it is never needed again. |
| 5712 | const hex_digest = Cache.binToHex(bin_digest); | 5754 | cache_tmp_dir.deleteFile(dep_basename) catch |err| { |
| 5713 | const o_sub_path = "o" ++ fs.path.sep_str ++ hex_digest; | 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 }); | 5781 | 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); | 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 | // Write the updated manifest. This is a no-op if the manifest is not dirty. Note that it is | 5829 | // Write the updated manifest. This is a no-op if the manifest is not dirty. Note that it is |
| 5723 | // possible we had a hit and the manifest is dirty, for example if the file mtime changed but | 5830 | // possible we had a hit and the manifest is dirty, for example if the file mtime changed but |
| 5724 | // the contents were the same, we hit the cache but the manifest is dirty and we need to update | 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,11 +5835,7 @@ pub fn cImport( |
| 5728 | }; | 5835 | }; |
| 5729 | } | 5836 | } |
| 5730 | | 5837 | |
| 5731 | return .{ | 5838 | return result; |
| 5732 | .digest = digest, | | |
| 5733 | .cache_hit = is_hit, | | |
| 5734 | .errors = std.zig.ErrorBundle.empty, | | |
| 5735 | }; | | |
| 5736 | } | 5839 | } |
| 5737 | | 5840 | |
| 5738 | fn workerUpdateCObject( | 5841 | fn workerUpdateCObject( |
| ... | @@ -6622,19 +6725,7 @@ fn spawnZigRc( | ... | @@ -6622,19 +6725,7 @@ fn spawnZigRc( |
| 6622 | // We expect exactly one ErrorBundle, and if any error_bundle header is | 6725 | // We expect exactly one ErrorBundle, and if any error_bundle header is |
| 6623 | // sent then it's a fatal error. | 6726 | // sent then it's a fatal error. |
| 6624 | .error_bundle => { | 6727 | .error_bundle => { |
| 6625 | const EbHdr = std.zig.Server.Message.ErrorBundle; | 6728 | const error_bundle = try std.zig.Server.allocErrorBundle(comp.gpa, body); |
| 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 | }; | | |
| 6638 | return comp.failWin32ResourceWithOwnedBundle(win32_resource, error_bundle); | 6729 | return comp.failWin32ResourceWithOwnedBundle(win32_resource, error_bundle); |
| 6639 | }, | 6730 | }, |
| 6640 | else => {}, // ignore other messages | 6731 | else => {}, // ignore other messages |
| ... | @@ -6672,49 +6763,6 @@ pub fn tmpFilePath(comp: Compilation, ally: Allocator, suffix: []const u8) error | ... | @@ -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 | /// Add common C compiler args between translate-c and C object compilation. | 6766 | /// Add common C compiler args between translate-c and C object compilation. |
| 6719 | fn addCommonCCArgs( | 6767 | fn addCommonCCArgs( |
| 6720 | comp: *const Compilation, | 6768 | comp: *const Compilation, |