]> git.lizzy.rs Git - rust.git/blob - src/rustllvm/ArchiveWrapper.cpp
Auto merge of #55780 - ogoffart:span_source_text, r=petrochenkov
[rust.git] / src / rustllvm / ArchiveWrapper.cpp
1 #include "rustllvm.h"
2
3 #include "llvm/Object/Archive.h"
4 #include "llvm/Object/ArchiveWriter.h"
5 #include "llvm/Support/Path.h"
6
7 using namespace llvm;
8 using namespace llvm::object;
9
10 struct RustArchiveMember {
11   const char *Filename;
12   const char *Name;
13   Archive::Child Child;
14
15   RustArchiveMember()
16       : Filename(nullptr), Name(nullptr),
17         Child(nullptr, nullptr, nullptr)
18   {
19   }
20   ~RustArchiveMember() {}
21 };
22
23 struct RustArchiveIterator {
24   bool First;
25   Archive::child_iterator Cur;
26   Archive::child_iterator End;
27   Error Err;
28
29   RustArchiveIterator() : First(true), Err(Error::success()) {}
30 };
31
32 enum class LLVMRustArchiveKind {
33   Other,
34   GNU,
35   BSD,
36   COFF,
37 };
38
39 static Archive::Kind fromRust(LLVMRustArchiveKind Kind) {
40   switch (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;
47   default:
48     report_fatal_error("Bad ArchiveKind.");
49   }
50 }
51
52 typedef OwningBinary<Archive> *LLVMRustArchiveRef;
53 typedef RustArchiveMember *LLVMRustArchiveMemberRef;
54 typedef Archive::Child *LLVMRustArchiveChildRef;
55 typedef Archive::Child const *LLVMRustArchiveChildConstRef;
56 typedef RustArchiveIterator *LLVMRustArchiveIteratorRef;
57
58 extern "C" LLVMRustArchiveRef LLVMRustOpenArchive(char *Path) {
59   ErrorOr<std::unique_ptr<MemoryBuffer>> BufOr =
60       MemoryBuffer::getFile(Path, -1, false);
61   if (!BufOr) {
62     LLVMRustSetLastError(BufOr.getError().message().c_str());
63     return nullptr;
64   }
65
66   Expected<std::unique_ptr<Archive>> ArchiveOr =
67       Archive::create(BufOr.get()->getMemBufferRef());
68
69   if (!ArchiveOr) {
70     LLVMRustSetLastError(toString(ArchiveOr.takeError()).c_str());
71     return nullptr;
72   }
73
74   OwningBinary<Archive> *Ret = new OwningBinary<Archive>(
75       std::move(ArchiveOr.get()), std::move(BufOr.get()));
76
77   return Ret;
78 }
79
80 extern "C" void LLVMRustDestroyArchive(LLVMRustArchiveRef RustArchive) {
81   delete RustArchive;
82 }
83
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);
89   if (RAI->Err) {
90     LLVMRustSetLastError(toString(std::move(RAI->Err)).c_str());
91     delete RAI;
92     return nullptr;
93   }
94   RAI->End = Archive->child_end();
95   return RAI;
96 }
97
98 extern "C" LLVMRustArchiveChildConstRef
99 LLVMRustArchiveIteratorNext(LLVMRustArchiveIteratorRef RAI) {
100   if (RAI->Cur == RAI->End)
101     return nullptr;
102
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
106   // the next child.
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.
109   if (!RAI->First) {
110     ++RAI->Cur;
111     if (RAI->Err) {
112       LLVMRustSetLastError(toString(std::move(RAI->Err)).c_str());
113       return nullptr;
114     }
115   } else {
116     RAI->First = false;
117   }
118
119   if (RAI->Cur == RAI->End)
120     return nullptr;
121
122   const Archive::Child &Child = *RAI->Cur.operator->();
123   Archive::Child *Ret = new Archive::Child(Child);
124
125   return Ret;
126 }
127
128 extern "C" void LLVMRustArchiveChildFree(LLVMRustArchiveChildRef Child) {
129   delete Child;
130 }
131
132 extern "C" void LLVMRustArchiveIteratorFree(LLVMRustArchiveIteratorRef RAI) {
133   delete RAI;
134 }
135
136 extern "C" const char *
137 LLVMRustArchiveChildName(LLVMRustArchiveChildConstRef Child, size_t *Size) {
138   Expected<StringRef> NameOrErr = Child->getName();
139   if (!NameOrErr) {
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());
144     return nullptr;
145   }
146   StringRef Name = NameOrErr.get();
147   *Size = Name.size();
148   return Name.data();
149 }
150
151 extern "C" const char *LLVMRustArchiveChildData(LLVMRustArchiveChildRef Child,
152                                                 size_t *Size) {
153   StringRef Buf;
154   Expected<StringRef> BufOrErr = Child->getBuffer();
155   if (!BufOrErr) {
156     LLVMRustSetLastError(toString(BufOrErr.takeError()).c_str());
157     return nullptr;
158   }
159   Buf = BufOrErr.get();
160   *Size = Buf.size();
161   return Buf.data();
162 }
163
164 extern "C" LLVMRustArchiveMemberRef
165 LLVMRustArchiveMemberNew(char *Filename, char *Name,
166                          LLVMRustArchiveChildRef Child) {
167   RustArchiveMember *Member = new RustArchiveMember;
168   Member->Filename = Filename;
169   Member->Name = Name;
170   if (Child)
171     Member->Child = *Child;
172   return Member;
173 }
174
175 extern "C" void LLVMRustArchiveMemberFree(LLVMRustArchiveMemberRef Member) {
176   delete Member;
177 }
178
179 extern "C" LLVMRustResult
180 LLVMRustWriteArchive(char *Dst, size_t NumMembers,
181                      const LLVMRustArchiveMemberRef *NewMembers,
182                      bool WriteSymbtab, LLVMRustArchiveKind RustKind) {
183
184   std::vector<NewArchiveMember> Members;
185   auto Kind = fromRust(RustKind);
186
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);
193       if (!MOrErr) {
194         LLVMRustSetLastError(toString(MOrErr.takeError()).c_str());
195         return LLVMRustResult::Failure;
196       }
197       MOrErr->MemberName = sys::path::filename(MOrErr->MemberName);
198       Members.push_back(std::move(*MOrErr));
199     } else {
200       Expected<NewArchiveMember> MOrErr =
201           NewArchiveMember::getOldMember(Member->Child, true);
202       if (!MOrErr) {
203         LLVMRustSetLastError(toString(MOrErr.takeError()).c_str());
204         return LLVMRustResult::Failure;
205       }
206       Members.push_back(std::move(*MOrErr));
207     }
208   }
209
210   auto Result = writeArchive(Dst, Members, WriteSymbtab, Kind, true, false);
211   if (!Result)
212     return LLVMRustResult::Success;
213   LLVMRustSetLastError(toString(std::move(Result)).c_str());
214
215   return LLVMRustResult::Failure;
216 }