3 #include "llvm/Object/Archive.h"
4 #include "llvm/Object/ArchiveWriter.h"
5 #include "llvm/Support/Path.h"
8 using namespace llvm::object;
10 struct RustArchiveMember {
16 : Filename(nullptr), Name(nullptr),
17 Child(nullptr, nullptr, nullptr)
20 ~RustArchiveMember() {}
23 struct RustArchiveIterator {
25 Archive::child_iterator Cur;
26 Archive::child_iterator End;
27 std::unique_ptr<Error> Err;
29 RustArchiveIterator(Archive::child_iterator Cur, Archive::child_iterator End,
30 std::unique_ptr<Error> Err)
34 Err(std::move(Err)) {}
37 enum class LLVMRustArchiveKind {
45 static Archive::Kind fromRust(LLVMRustArchiveKind Kind) {
47 case LLVMRustArchiveKind::GNU:
48 return Archive::K_GNU;
49 case LLVMRustArchiveKind::BSD:
50 return Archive::K_BSD;
51 case LLVMRustArchiveKind::DARWIN:
52 return Archive::K_DARWIN;
53 case LLVMRustArchiveKind::COFF:
54 return Archive::K_COFF;
56 report_fatal_error("Bad ArchiveKind.");
60 typedef OwningBinary<Archive> *LLVMRustArchiveRef;
61 typedef RustArchiveMember *LLVMRustArchiveMemberRef;
62 typedef Archive::Child *LLVMRustArchiveChildRef;
63 typedef Archive::Child const *LLVMRustArchiveChildConstRef;
64 typedef RustArchiveIterator *LLVMRustArchiveIteratorRef;
66 extern "C" LLVMRustArchiveRef LLVMRustOpenArchive(char *Path) {
67 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOr =
68 MemoryBuffer::getFile(Path, -1, false);
70 LLVMRustSetLastError(BufOr.getError().message().c_str());
74 Expected<std::unique_ptr<Archive>> ArchiveOr =
75 Archive::create(BufOr.get()->getMemBufferRef());
78 LLVMRustSetLastError(toString(ArchiveOr.takeError()).c_str());
82 OwningBinary<Archive> *Ret = new OwningBinary<Archive>(
83 std::move(ArchiveOr.get()), std::move(BufOr.get()));
88 extern "C" void LLVMRustDestroyArchive(LLVMRustArchiveRef RustArchive) {
92 extern "C" LLVMRustArchiveIteratorRef
93 LLVMRustArchiveIteratorNew(LLVMRustArchiveRef RustArchive) {
94 Archive *Archive = RustArchive->getBinary();
95 #if LLVM_VERSION_GE(10, 0)
96 std::unique_ptr<Error> Err = std::make_unique<Error>(Error::success());
98 std::unique_ptr<Error> Err = llvm::make_unique<Error>(Error::success());
100 auto Cur = Archive->child_begin(*Err);
102 LLVMRustSetLastError(toString(std::move(*Err)).c_str());
105 auto End = Archive->child_end();
106 return new RustArchiveIterator(Cur, End, std::move(Err));
109 extern "C" LLVMRustArchiveChildConstRef
110 LLVMRustArchiveIteratorNext(LLVMRustArchiveIteratorRef RAI) {
111 if (RAI->Cur == RAI->End)
114 // Advancing the iterator validates the next child, and this can
115 // uncover an error. LLVM requires that we check all Errors,
116 // so we only advance the iterator if we actually need to fetch
118 // This means we must not advance the iterator in the *first* call,
119 // but instead advance it *before* fetching the child in all later calls.
123 LLVMRustSetLastError(toString(std::move(*RAI->Err)).c_str());
130 if (RAI->Cur == RAI->End)
133 const Archive::Child &Child = *RAI->Cur.operator->();
134 Archive::Child *Ret = new Archive::Child(Child);
139 extern "C" void LLVMRustArchiveChildFree(LLVMRustArchiveChildRef Child) {
143 extern "C" void LLVMRustArchiveIteratorFree(LLVMRustArchiveIteratorRef RAI) {
147 extern "C" const char *
148 LLVMRustArchiveChildName(LLVMRustArchiveChildConstRef Child, size_t *Size) {
149 Expected<StringRef> NameOrErr = Child->getName();
151 // rustc_codegen_llvm currently doesn't use this error string, but it might be
152 // useful in the future, and in the mean time this tells LLVM that the
153 // error was not ignored and that it shouldn't abort the process.
154 LLVMRustSetLastError(toString(NameOrErr.takeError()).c_str());
157 StringRef Name = NameOrErr.get();
162 extern "C" const char *LLVMRustArchiveChildData(LLVMRustArchiveChildRef Child,
165 Expected<StringRef> BufOrErr = Child->getBuffer();
167 LLVMRustSetLastError(toString(BufOrErr.takeError()).c_str());
170 Buf = BufOrErr.get();
175 extern "C" LLVMRustArchiveMemberRef
176 LLVMRustArchiveMemberNew(char *Filename, char *Name,
177 LLVMRustArchiveChildRef Child) {
178 RustArchiveMember *Member = new RustArchiveMember;
179 Member->Filename = Filename;
182 Member->Child = *Child;
186 extern "C" void LLVMRustArchiveMemberFree(LLVMRustArchiveMemberRef Member) {
190 extern "C" LLVMRustResult
191 LLVMRustWriteArchive(char *Dst, size_t NumMembers,
192 const LLVMRustArchiveMemberRef *NewMembers,
193 bool WriteSymbtab, LLVMRustArchiveKind RustKind) {
195 std::vector<NewArchiveMember> Members;
196 auto Kind = fromRust(RustKind);
198 for (size_t I = 0; I < NumMembers; I++) {
199 auto Member = NewMembers[I];
200 assert(Member->Name);
201 if (Member->Filename) {
202 Expected<NewArchiveMember> MOrErr =
203 NewArchiveMember::getFile(Member->Filename, true);
205 LLVMRustSetLastError(toString(MOrErr.takeError()).c_str());
206 return LLVMRustResult::Failure;
208 MOrErr->MemberName = sys::path::filename(MOrErr->MemberName);
209 Members.push_back(std::move(*MOrErr));
211 Expected<NewArchiveMember> MOrErr =
212 NewArchiveMember::getOldMember(Member->Child, true);
214 LLVMRustSetLastError(toString(MOrErr.takeError()).c_str());
215 return LLVMRustResult::Failure;
217 Members.push_back(std::move(*MOrErr));
221 auto Result = writeArchive(Dst, Members, WriteSymbtab, Kind, true, false);
223 return LLVMRustResult::Success;
224 LLVMRustSetLastError(toString(std::move(Result)).c_str());
226 return LLVMRustResult::Failure;