diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig index e4f4d6eafefcca250babb49e4a907eba22866d22..a312285db3310ba0fc69dffe55d56e484c293e50 100644 --- a/src/codegen/llvm/bindings.zig +++ b/src/codegen/llvm/bindings.zig @@ -331,6 +331,8 @@ extern fn ZigLLVMWriteArchive( file_names_ptr: [*]const [*:0]const u8, file_names_len: usize, archive_kind: ArchiveKind, + err_file_index_out: *usize, + err_msg_out: *[*:0]u8, ) bool; pub const ParseCommandLineOptions = ZigLLVMParseCommandLineOptions; diff --git a/src/link/Lld.zig b/src/link/Lld.zig index 04ffde350e146aa96a338a62aa953c51f501686f..cf64d3fd5bc51817cc86a7554ac65ee7aa53e373 100644 --- a/src/link/Lld.zig +++ b/src/link/Lld.zig @@ -269,12 +269,12 @@ pub fn flush( .wasm => wasmLink(lld, arena), }; result catch |err| switch (err) { - error.OutOfMemory, error.AlreadyReported => |e| return e, + error.OutOfMemory, error.AlreadyReported, error.Canceled => |e| return e, else => |e| return lld.base.comp.link_diags.fail("failed to link with LLD: {t}", .{e}), }; } -fn linkAsArchive(lld: *Lld, arena: Allocator) !void { +fn linkAsArchive(lld: *Lld, arena: Allocator) link.Error!void { const base = &lld.base; const comp = base.comp; const directory = base.emit.root_dir; // Just an alias to make it shorter to type. @@ -338,7 +338,9 @@ fn linkAsArchive(lld: *Lld, arena: Allocator) !void { const llvm = @import("../codegen/llvm.zig"); const target = &comp.root_mod.resolved_target.result; llvm.initializeLLVMTarget(target.cpu.arch); - const bad = llvm_bindings.WriteArchive( + var err_file_index: usize = undefined; + var err_msg: [*:0]u8 = undefined; + if (llvm_bindings.WriteArchive( full_out_path_z, object_files.items.ptr, object_files.items.len, @@ -346,8 +348,19 @@ fn linkAsArchive(lld: *Lld, arena: Allocator) !void { .windows => .COFF, else => if (target.os.tag.isDarwin()) .DARWIN else .GNU, }, - ); - if (bad) return error.UnableToWriteArchive; + &err_file_index, + &err_msg, + )) { + defer std.c.free(err_msg); + if (err_file_index < object_files.items.len) { + return comp.link_diags.fail("LLD failed to open input file '{s}': {s}", .{ + object_files.items[err_file_index], + err_msg, + }); + } else { + return comp.link_diags.fail("LLD failed to write archive: {s}", .{err_msg}); + } + } } fn addCommonArgs(argv: *std.array_list.Managed([]const u8), coff: bool) !void { diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp index 9bba8e96d5107c6bf20ea2fd7f15e3df243d5bac..6b3ff4a5fbe626b37c0a49f7b734564c6563201e 100644 --- a/src/zig_llvm.cpp +++ b/src/zig_llvm.cpp @@ -473,19 +473,32 @@ void ZigLLVMParseCommandLineOptions(size_t argc, const char *const *argv) { } bool ZigLLVMWriteArchive(const char *archive_name, const char **file_names, size_t file_name_count, - ZigLLVMArchiveKind archive_kind) + ZigLLVMArchiveKind archive_kind, size_t *err_file_index_out, char **err_msg_out) { SmallVector new_members; for (size_t i = 0; i < file_name_count; i += 1) { Expected new_member = NewArchiveMember::getFile(file_names[i], true); Error err = new_member.takeError(); - if (err) return true; + if (err) { + *err_file_index_out = i; + const std::string msg = toString(std::move(err)); + *err_msg_out = (char *)malloc(msg.length() + 1); + strcpy(*err_msg_out, msg.c_str()); + return true; + } new_members.push_back(std::move(*new_member)); } Error err = writeArchive(archive_name, new_members, SymtabWritingMode::NormalSymtab, static_cast(archive_kind), true, false, nullptr); - if (err) return true; + if (err) { + *err_file_index_out = file_name_count; + const std::string msg = toString(std::move(err)); + *err_msg_out = (char *)malloc(msg.length() + 1); + strcpy(*err_msg_out, msg.c_str()); + return true; + } + return false; } diff --git a/src/zig_llvm.h b/src/zig_llvm.h index 64da388d477bfed46e0c4ae2e7da1cd16c73ce57..79ba0272df2f73743705ac832f5d508b5099542d 100644 --- a/src/zig_llvm.h +++ b/src/zig_llvm.h @@ -121,7 +121,12 @@ ZIG_EXTERN_C bool ZigLLDLinkCOFF(int argc, const char **argv, bool can_exit_earl ZIG_EXTERN_C bool ZigLLDLinkELF(int argc, const char **argv, bool can_exit_early, bool disable_output); ZIG_EXTERN_C bool ZigLLDLinkWasm(int argc, const char **argv, bool can_exit_early, bool disable_output); +// On error, populates `*err_file_index_out` and `*err_msg_out` and returns `true`. The caller is +// responsible for freeing `*err_msg_out` using `free`. +// +// If an error occurs reading an input file, `*err_file_index_out` is set to the index of that input +// file in `file_names`. Otherwise, `*err_file_index_out` is set to `file_name_count`. ZIG_EXTERN_C bool ZigLLVMWriteArchive(const char *archive_name, const char **file_names, size_t file_name_count, - ZigLLVMArchiveKind archive_kind); + ZigLLVMArchiveKind archive_kind, size_t *err_file_index_out, char **err_msg_out); #endif