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;
29 RustArchiveIterator() : First(true), Err(Error::success()) {}
32 enum class LLVMRustArchiveKind {
39 static Archive::Kind fromRust(LLVMRustArchiveKind Kind) {
41 case LLVMRustArchiveKind::GNU:
42 return Archive::K_GNU;
43 case LLVMRustArchiveKind::BSD:
44 return Archive::K_BSD;
45 case LLVMRustArchiveKind::COFF:
46 return Archive::K_COFF;
48 report_fatal_error("Bad ArchiveKind.");
52 typedef OwningBinary<Archive> *LLVMRustArchiveRef;
53 typedef RustArchiveMember *LLVMRustArchiveMemberRef;
54 typedef Archive::Child *LLVMRustArchiveChildRef;
55 typedef Archive::Child const *LLVMRustArchiveChildConstRef;
56 typedef RustArchiveIterator *LLVMRustArchiveIteratorRef;
58 extern "C" LLVMRustArchiveRef LLVMRustOpenArchive(char *Path) {
59 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOr =
60 MemoryBuffer::getFile(Path, -1, false);
62 LLVMRustSetLastError(BufOr.getError().message().c_str());
66 Expected<std::unique_ptr<Archive>> ArchiveOr =
67 Archive::create(BufOr.get()->getMemBufferRef());
70 LLVMRustSetLastError(toString(ArchiveOr.takeError()).c_str());
74 OwningBinary<Archive> *Ret = new OwningBinary<Archive>(
75 std::move(ArchiveOr.get()), std::move(BufOr.get()));
80 extern "C" void LLVMRustDestroyArchive(LLVMRustArchiveRef RustArchive) {
84 extern "C" LLVMRustArchiveIteratorRef
85 LLVMRustArchiveIteratorNew(LLVMRustArchiveRef RustArchive) {
86 Archive *Archive = RustArchive->getBinary();
87 RustArchiveIterator *RAI = new RustArchiveIterator();
88 RAI->Cur = Archive->child_begin(RAI->Err);
90 LLVMRustSetLastError(toString(std::move(RAI->Err)).c_str());
94 RAI->End = Archive->child_end();
98 extern "C" LLVMRustArchiveChildConstRef
99 LLVMRustArchiveIteratorNext(LLVMRustArchiveIteratorRef RAI) {
100 if (RAI->Cur == RAI->End)
103 // Advancing the iterator validates the next child, and this can
104 // uncover an error. LLVM requires that we check all Errors,
105 // so we only advance the iterator if we actually need to fetch
107 // This means we must not advance the iterator in the *first* call,
108 // but instead advance it *before* fetching the child in all later calls.
112 LLVMRustSetLastError(toString(std::move(RAI->Err)).c_str());
119 if (RAI->Cur == RAI->End)
122 const Archive::Child &Child = *RAI->Cur.operator->();
123 Archive::Child *Ret = new Archive::Child(Child);
128 extern "C" void LLVMRustArchiveChildFree(LLVMRustArchiveChildRef Child) {
132 extern "C" void LLVMRustArchiveIteratorFree(LLVMRustArchiveIteratorRef RAI) {
136 extern "C" const char *
137 LLVMRustArchiveChildName(LLVMRustArchiveChildConstRef Child, size_t *Size) {
138 Expected<StringRef> NameOrErr = Child->getName();
140 // rustc_codegen_llvm currently doesn't use this error string, but it might be
141 // useful in the future, and in the mean time this tells LLVM that the
142 // error was not ignored and that it shouldn't abort the process.
143 LLVMRustSetLastError(toString(NameOrErr.takeError()).c_str());
146 StringRef Name = NameOrErr.get();
151 extern "C" const char *LLVMRustArchiveChildData(LLVMRustArchiveChildRef Child,
154 Expected<StringRef> BufOrErr = Child->getBuffer();
156 LLVMRustSetLastError(toString(BufOrErr.takeError()).c_str());
159 Buf = BufOrErr.get();
164 extern "C" LLVMRustArchiveMemberRef
165 LLVMRustArchiveMemberNew(char *Filename, char *Name,
166 LLVMRustArchiveChildRef Child) {
167 RustArchiveMember *Member = new RustArchiveMember;
168 Member->Filename = Filename;
171 Member->Child = *Child;
175 extern "C" void LLVMRustArchiveMemberFree(LLVMRustArchiveMemberRef Member) {
179 extern "C" LLVMRustResult
180 LLVMRustWriteArchive(char *Dst, size_t NumMembers,
181 const LLVMRustArchiveMemberRef *NewMembers,
182 bool WriteSymbtab, LLVMRustArchiveKind RustKind) {
184 std::vector<NewArchiveMember> Members;
185 auto Kind = fromRust(RustKind);
187 for (size_t I = 0; I < NumMembers; I++) {
188 auto Member = NewMembers[I];
189 assert(Member->Name);
190 if (Member->Filename) {
191 Expected<NewArchiveMember> MOrErr =
192 NewArchiveMember::getFile(Member->Filename, true);
194 LLVMRustSetLastError(toString(MOrErr.takeError()).c_str());
195 return LLVMRustResult::Failure;
197 MOrErr->MemberName = sys::path::filename(MOrErr->MemberName);
198 Members.push_back(std::move(*MOrErr));
200 Expected<NewArchiveMember> MOrErr =
201 NewArchiveMember::getOldMember(Member->Child, true);
203 LLVMRustSetLastError(toString(MOrErr.takeError()).c_str());
204 return LLVMRustResult::Failure;
206 Members.push_back(std::move(*MOrErr));
210 auto Result = writeArchive(Dst, Members, WriteSymbtab, Kind, true, false);
212 return LLVMRustResult::Success;
213 LLVMRustSetLastError(toString(std::move(Result)).c_str());
215 return LLVMRustResult::Failure;