| ... | ... | @@ -1319,7 +1319,7 @@ pub const cache_helpers = struct { |
| 1319 | 1319 | } |
| 1320 | 1320 | } |
| 1321 | 1321 | |
| 1322 | | pub fn hashCSource(man: *Cache.Manifest, c_source: CSourceFile) !void { |
| 1322 | pub fn hashCSource(man: *Cache.Manifest, c_source: CSourceFile) Allocator.Error!void { |
| 1323 | 1323 | _ = try man.addInputPath(.initCwd(c_source.src_path), .{}); |
| 1324 | 1324 | // Hash the extra flags, with special care to call addFile for file parameters. |
| 1325 | 1325 | // TODO this logic can likely be improved by utilizing clang_options_data.zig. |
| ... | ... | @@ -5156,16 +5156,16 @@ fn workerUpdateCObject( |
| 5156 | 5156 | comp: *Compilation, |
| 5157 | 5157 | c_object: *CObject, |
| 5158 | 5158 | progress_node: std.Progress.Node, |
| 5159 | | ) void { |
| 5159 | ) Io.Cancelable!void { |
| 5160 | 5160 | comp.updateCObject(c_object, progress_node) catch |err| switch (err) { |
| 5161 | | error.AlreadyReported => return, |
| 5162 | | else => { |
| 5163 | | comp.reportRetryableCObjectError(c_object, err) catch |oom| switch (oom) { |
| 5164 | | // Swallowing this error is OK because it's implied to be OOM when |
| 5165 | | // there is a missing failed_c_objects error message. |
| 5166 | | error.OutOfMemory => {}, |
| 5167 | | }; |
| 5161 | error.OutOfMemory => switch (comp.failCObjRetryable(c_object, "failed to update C object: out of memory", .{})) { |
| 5162 | // Swallowing this error is OK because it's implied to be OOM when |
| 5163 | // there is a missing failed_c_objects error message. |
| 5164 | error.OutOfMemory => return, |
| 5165 | error.AlreadyReported => return, |
| 5168 | 5166 | }, |
| 5167 | error.Canceled => |e| return e, |
| 5168 | error.AlreadyReported => return, |
| 5169 | 5169 | }; |
| 5170 | 5170 | } |
| 5171 | 5171 | |
| ... | ... | @@ -5428,15 +5428,6 @@ fn buildLibZigC(comp: *Compilation, prog_node: std.Progress.Node) void { |
| 5428 | 5428 | }; |
| 5429 | 5429 | } |
| 5430 | 5430 | |
| 5431 | | fn reportRetryableCObjectError(comp: *Compilation, c_object: *CObject, err: anyerror) error{OutOfMemory}!void { |
| 5432 | | c_object.status = .failure_retryable; |
| 5433 | | |
| 5434 | | switch (comp.failCObj(c_object, "{t}", .{err})) { |
| 5435 | | error.AlreadyReported => return, |
| 5436 | | else => |e| return e, |
| 5437 | | } |
| 5438 | | } |
| 5439 | | |
| 5440 | 5431 | fn reportRetryableWin32ResourceError( |
| 5441 | 5432 | comp: *Compilation, |
| 5442 | 5433 | win32_resource: *Win32Resource, |
| ... | ... | @@ -5470,7 +5461,11 @@ fn reportRetryableWin32ResourceError( |
| 5470 | 5461 | } |
| 5471 | 5462 | } |
| 5472 | 5463 | |
| 5473 | | fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Progress.Node) !void { |
| 5464 | fn updateCObject( |
| 5465 | comp: *Compilation, |
| 5466 | c_object: *CObject, |
| 5467 | c_obj_prog_node: std.Progress.Node, |
| 5468 | ) (Allocator.Error || Io.Cancelable || error{AlreadyReported})!void { |
| 5474 | 5469 | if (comp.config.c_frontend == .aro) { |
| 5475 | 5470 | return comp.failCObj(c_object, "aro does not support compiling C objects yet", .{}); |
| 5476 | 5471 | } |
| ... | ... | @@ -5624,7 +5619,14 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr |
| 5624 | 5619 | // We can't know the digest until we do the C compiler invocation, |
| 5625 | 5620 | // so we need a temporary filename. |
| 5626 | 5621 | const out_obj_path = try comp.tmpFilePath(arena, o_basename); |
| 5627 | | var zig_cache_tmp_dir = try comp.dirs.local_cache.handle.createDirPathOpen(io, "tmp", .{}); |
| 5622 | var zig_cache_tmp_dir = comp.dirs.local_cache.handle.createDirPathOpen(io, "tmp", .{}) catch |err| switch (err) { |
| 5623 | error.Canceled => |e| return e, |
| 5624 | else => |e| return comp.failCObjRetryable( |
| 5625 | c_object, |
| 5626 | "failed to open '{f}{c}tmp': {t}", |
| 5627 | .{ comp.dirs.local_cache, fs.path.sep, e }, |
| 5628 | ), |
| 5629 | }; |
| 5628 | 5630 | defer zig_cache_tmp_dir.close(io); |
| 5629 | 5631 | |
| 5630 | 5632 | const out_diag_path = if (comp.clang_passthrough_mode or !ext.clangSupportsDiagnostics()) |
| ... | ... | @@ -5703,18 +5705,45 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr |
| 5703 | 5705 | else => std.process.abort(), |
| 5704 | 5706 | } |
| 5705 | 5707 | } else { |
| 5706 | | var child = try std.process.spawn(io, .{ |
| 5708 | var child = std.process.spawn(io, .{ |
| 5707 | 5709 | .argv = argv.items, |
| 5708 | 5710 | .stdin = .ignore, |
| 5709 | 5711 | .stdout = .ignore, |
| 5710 | 5712 | .stderr = .pipe, |
| 5711 | | }); |
| 5713 | }) catch |err| switch (err) { |
| 5714 | error.Canceled, |
| 5715 | error.OutOfMemory, |
| 5716 | => |e| return e, |
| 5717 | else => |e| return comp.failCObjRetryable( |
| 5718 | c_object, |
| 5719 | "failed to spawn zig clang '{s}': {t}", |
| 5720 | .{ argv.items[0], e }, |
| 5721 | ), |
| 5722 | }; |
| 5712 | 5723 | |
| 5713 | 5724 | var stderr_reader = child.stderr.?.readerStreaming(io, &.{}); |
| 5714 | | const stderr = try stderr_reader.interface.allocRemaining(arena, .limited(std.math.maxInt(u32))); |
| 5725 | const stderr = stderr_reader.interface.allocRemaining(arena, .limited(std.math.maxInt(u32))) catch |err| switch (err) { |
| 5726 | error.OutOfMemory => |e| return e, |
| 5727 | error.StreamTooLong => return comp.failCObjRetryable( |
| 5728 | c_object, |
| 5729 | "failed to read stderr of zig clang '{s}': exceeded maximum size", |
| 5730 | .{argv.items[0]}, |
| 5731 | ), |
| 5732 | error.ReadFailed => return comp.failCObjRetryable( |
| 5733 | c_object, |
| 5734 | "failed to read stderr of zig clang '{s}': {t}", |
| 5735 | .{ argv.items[0], stderr_reader.err.? }, |
| 5736 | ), |
| 5737 | }; |
| 5715 | 5738 | |
| 5716 | | const term = child.wait(io) catch |err| |
| 5717 | | return comp.failCObj(c_object, "failed to spawn zig clang {s}: {t}", .{ argv.items[0], err }); |
| 5739 | const term = child.wait(io) catch |err| switch (err) { |
| 5740 | error.Canceled => |e| return e, |
| 5741 | else => |e| return comp.failCObj( |
| 5742 | c_object, |
| 5743 | "failed to spawn zig clang '{s}': {t}", |
| 5744 | .{ argv.items[0], e }, |
| 5745 | ), |
| 5746 | }; |
| 5718 | 5747 | |
| 5719 | 5748 | switch (term) { |
| 5720 | 5749 | .exited => |code| if (code != 0) if (out_diag_path) |diag_file_path| { |
| ... | ... | @@ -5756,14 +5785,27 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr |
| 5756 | 5785 | }; |
| 5757 | 5786 | } |
| 5758 | 5787 | |
| 5759 | | if (out_dep_path) |dep_file_path| { |
| 5760 | | const dep_basename = fs.path.basename(dep_file_path); |
| 5788 | if (out_dep_path) |raw_dep_file_path| { |
| 5789 | const dep_file_path: std.Build.Cache.Path = .{ |
| 5790 | .root_dir = .{ |
| 5791 | .handle = zig_cache_tmp_dir, |
| 5792 | .path = "tmp", |
| 5793 | }, |
| 5794 | .sub_path = fs.path.basename(raw_dep_file_path), |
| 5795 | }; |
| 5761 | 5796 | |
| 5762 | 5797 | if (comp.file_system_inputs != null) { |
| 5763 | 5798 | // TODO instead of this rely on passing the manifest contents directly |
| 5764 | 5799 | |
| 5765 | 5800 | // Use the same file size limit as the cache code does for dependency files. |
| 5766 | | const dep_file_contents = try zig_cache_tmp_dir.readFileAlloc(io, dep_basename, gpa, .unlimited); |
| 5801 | const dep_file_contents = dep_file_path.root_dir.handle.readFileAlloc(io, dep_file_path.sub_path, gpa, .unlimited) catch |err| switch (err) { |
| 5802 | error.OutOfMemory, error.Canceled => |e| return e, |
| 5803 | else => |e| return comp.failCObjRetryable( |
| 5804 | c_object, |
| 5805 | "failed to read '{f}': {t}", |
| 5806 | .{ dep_file_path, e }, |
| 5807 | ), |
| 5808 | }; |
| 5767 | 5809 | defer gpa.free(dep_file_contents); |
| 5768 | 5810 | |
| 5769 | 5811 | var str_buf: std.ArrayList(u8) = .empty; |
| ... | ... | @@ -5778,36 +5820,65 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr |
| 5778 | 5820 | try token.resolve(gpa, &str_buf); |
| 5779 | 5821 | break :p try .fromUnresolved(arena, comp.dirs, &.{str_buf.items}); |
| 5780 | 5822 | }, |
| 5781 | | else => |err_token| { |
| 5782 | | log.err("failed parsing {s}: {f}", .{ dep_basename, err_token }); |
| 5783 | | return error.InvalidDepFile; |
| 5784 | | }, |
| 5823 | else => |err_token| return comp.failCObjRetryable( |
| 5824 | c_object, |
| 5825 | "failed parsing '{f}': {f}", |
| 5826 | .{ dep_file_path, err_token }, |
| 5827 | ), |
| 5785 | 5828 | }; |
| 5786 | 5829 | try comp.appendFileSystemInput(input_path); |
| 5787 | 5830 | } |
| 5788 | 5831 | } |
| 5789 | 5832 | |
| 5790 | 5833 | // Add the files depended on to the cache system. |
| 5791 | | var diagnostic: Cache.Manifest.AddDiscoveredDepFileDiagnostic = undefined; |
| 5792 | | try man.addDiscoveredDepFile(.{ |
| 5793 | | .root_dir = .{ |
| 5794 | | .handle = zig_cache_tmp_dir, |
| 5795 | | .path = "tmp", |
| 5796 | | }, |
| 5797 | | .sub_path = dep_basename, |
| 5798 | | }, &diagnostic); |
| 5834 | var diags: Cache.Manifest.AddDiscoveredDepFileDiagnostic = undefined; |
| 5835 | man.addDiscoveredDepFile(dep_file_path, &diags) catch |err| switch (err) { |
| 5836 | error.OutOfMemory, |
| 5837 | error.Canceled, |
| 5838 | => |e| return e, |
| 5839 | |
| 5840 | error.InvalidDepFile => return comp.failCObjRetryable( |
| 5841 | c_object, |
| 5842 | "failed to parse '{f}': {f}", |
| 5843 | .{ dep_file_path, diags.dep_tokenizer }, |
| 5844 | ), |
| 5845 | error.FileSystemFailure => return comp.failCObjRetryable( |
| 5846 | c_object, |
| 5847 | "failed to parse '{f}': {f}", |
| 5848 | .{ dep_file_path, diags.add_discovered_path }, |
| 5849 | ), |
| 5850 | else => |e| return comp.failCObjRetryable( |
| 5851 | c_object, |
| 5852 | "failed to read '{f}': {t}", |
| 5853 | .{ dep_file_path, e }, |
| 5854 | ), |
| 5855 | }; |
| 5799 | 5856 | switch (comp.cache_use) { |
| 5800 | 5857 | .whole => |whole| { |
| 5801 | 5858 | if (whole.cache_manifest) |whole_cache_manifest| { |
| 5802 | 5859 | try whole.cache_manifest_mutex.lock(io); |
| 5803 | 5860 | defer whole.cache_manifest_mutex.unlock(io); |
| 5804 | | try whole_cache_manifest.addDiscoveredDepFile(.{ |
| 5805 | | .root_dir = .{ |
| 5806 | | .handle = zig_cache_tmp_dir, |
| 5807 | | .path = "tmp", |
| 5808 | | }, |
| 5809 | | .sub_path = dep_basename, |
| 5810 | | }, &diagnostic); |
| 5861 | whole_cache_manifest.addDiscoveredDepFile(dep_file_path, &diags) catch |err| switch (err) { |
| 5862 | error.OutOfMemory, |
| 5863 | error.Canceled, |
| 5864 | => |e| return e, |
| 5865 | |
| 5866 | error.InvalidDepFile => return comp.failCObjRetryable( |
| 5867 | c_object, |
| 5868 | "failed to parse '{f}': {f}", |
| 5869 | .{ dep_file_path, diags.dep_tokenizer }, |
| 5870 | ), |
| 5871 | error.FileSystemFailure => return comp.failCObjRetryable( |
| 5872 | c_object, |
| 5873 | "failed to parse '{f}': {f}", |
| 5874 | .{ dep_file_path, diags.add_discovered_path }, |
| 5875 | ), |
| 5876 | else => |e| return comp.failCObjRetryable( |
| 5877 | c_object, |
| 5878 | "failed to read '{f}': {t}", |
| 5879 | .{ dep_file_path, e }, |
| 5880 | ), |
| 5881 | }; |
| 5811 | 5882 | } |
| 5812 | 5883 | }, |
| 5813 | 5884 | .incremental, .none => {}, |
| ... | ... | @@ -5832,10 +5903,33 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr |
| 5832 | 5903 | |
| 5833 | 5904 | // Rename into place. |
| 5834 | 5905 | const o_sub_path = try fs.path.join(arena, &.{ "o", &digest }); |
| 5835 | | var o_dir = try comp.dirs.local_cache.handle.createDirPathOpen(io, o_sub_path, .{}); |
| 5906 | var o_dir = comp.dirs.local_cache.handle.createDirPathOpen(io, o_sub_path, .{}) catch |err| switch (err) { |
| 5907 | error.Canceled => |e| return e, |
| 5908 | else => |e| return comp.failCObjRetryable( |
| 5909 | c_object, |
| 5910 | "failed to create '{f}{c}{s}': {t}", |
| 5911 | .{ comp.dirs.local_cache, fs.path.sep, o_sub_path, e }, |
| 5912 | ), |
| 5913 | }; |
| 5836 | 5914 | defer o_dir.close(io); |
| 5837 | 5915 | const tmp_basename = fs.path.basename(out_obj_path); |
| 5838 | | try Io.Dir.rename(zig_cache_tmp_dir, tmp_basename, o_dir, o_basename, io); |
| 5916 | Io.Dir.rename(zig_cache_tmp_dir, tmp_basename, o_dir, o_basename, io) catch |err| switch (err) { |
| 5917 | error.Canceled => |e| return e, |
| 5918 | else => |e| return comp.failCObjRetryable( |
| 5919 | c_object, |
| 5920 | "failed to rename 'tmp{c}{s}' into '{f}{c}{s}{c}{s}': {t}", |
| 5921 | .{ |
| 5922 | fs.path.sep, |
| 5923 | tmp_basename, |
| 5924 | comp.dirs.local_cache, |
| 5925 | fs.path.sep, |
| 5926 | o_sub_path, |
| 5927 | fs.path.sep, |
| 5928 | o_basename, |
| 5929 | e, |
| 5930 | }, |
| 5931 | ), |
| 5932 | }; |
| 5839 | 5933 | break :d digest; |
| 5840 | 5934 | }; |
| 5841 | 5935 | |
| ... | ... | @@ -6785,6 +6879,16 @@ pub fn addCCArgs( |
| 6785 | 6879 | try argv.appendSlice(mod.cc_argv); |
| 6786 | 6880 | } |
| 6787 | 6881 | |
| 6882 | fn failCObjRetryable( |
| 6883 | comp: *Compilation, |
| 6884 | c_object: *CObject, |
| 6885 | comptime format: []const u8, |
| 6886 | args: anytype, |
| 6887 | ) error{ OutOfMemory, AlreadyReported } { |
| 6888 | defer c_object.status = .failure_retryable; |
| 6889 | return comp.failCObj(c_object, format, args); |
| 6890 | } |
| 6891 | |
| 6788 | 6892 | fn failCObj( |
| 6789 | 6893 | comp: *Compilation, |
| 6790 | 6894 | c_object: *CObject, |