]> git.lizzy.rs Git - rust.git/blob - src/rustllvm/ArchiveWrapper.cpp
Rollup merge of #68767 - kubo39:patch-macos, r=shepmaster
[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   std::unique_ptr<Error> Err;
28
29   RustArchiveIterator(Archive::child_iterator Cur, Archive::child_iterator End,
30       std::unique_ptr<Error> Err)
31     : First(true),
32       Cur(Cur),
33       End(End),
34       Err(std::move(Err)) {}
35 };
36
37 enum class LLVMRustArchiveKind {
38   Other,
39   GNU,
40   BSD,
41   DARWIN,
42   COFF,
43 };
44
45 static Archive::Kind fromRust(LLVMRustArchiveKind Kind) {
46   switch (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;
55   default:
56     report_fatal_error("Bad ArchiveKind.");
57   }
58 }
59
60 typedef OwningBinary<Archive> *LLVMRustArchiveRef;
61 typedef RustArchiveMember *LLVMRustArchiveMemberRef;
62 typedef Archive::Child *LLVMRustArchiveChildRef;
63 typedef Archive::Child const *LLVMRustArchiveChildConstRef;
64 typedef RustArchiveIterator *LLVMRustArchiveIteratorRef;
65
66 extern "C" LLVMRustArchiveRef LLVMRustOpenArchive(char *Path) {
67   ErrorOr<std::unique_ptr<MemoryBuffer>> BufOr =
68       MemoryBuffer::getFile(Path, -1, false);
69   if (!BufOr) {
70     LLVMRustSetLastError(BufOr.getError().message().c_str());
71     return nullptr;
72   }
73
74   Expected<std::unique_ptr<Archive>> ArchiveOr =
75       Archive::create(BufOr.get()->getMemBufferRef());
76
77   if (!ArchiveOr) {
78     LLVMRustSetLastError(toString(ArchiveOr.takeError()).c_str());
79     return nullptr;
80   }
81
82   OwningBinary<Archive> *Ret = new OwningBinary<Archive>(
83       std::move(ArchiveOr.get()), std::move(BufOr.get()));
84
85   return Ret;
86 }
87
88 extern "C" void LLVMRustDestroyArchive(LLVMRustArchiveRef RustArchive) {
89   delete RustArchive;
90 }
91
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());
97 #else
98   std::unique_ptr<Error> Err = llvm::make_unique<Error>(Error::success());
99 #endif
100   auto Cur = Archive->child_begin(*Err);
101   if (*Err) {
102     LLVMRustSetLastError(toString(std::move(*Err)).c_str());
103     return nullptr;
104   }
105   auto End = Archive->child_end();
106   return new RustArchiveIterator(Cur, End, std::move(Err));
107 }
108
109 extern "C" LLVMRustArchiveChildConstRef
110 LLVMRustArchiveIteratorNext(LLVMRustArchiveIteratorRef RAI) {
111   if (RAI->Cur == RAI->End)
112     return nullptr;
113
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
117   // the next child.
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.
120   if (!RAI->First) {
121     ++RAI->Cur;
122     if (*RAI->Err) {
123       LLVMRustSetLastError(toString(std::move(*RAI->Err)).c_str());
124       return nullptr;
125     }
126   } else {
127     RAI->First = false;
128   }
129
130   if (RAI->Cur == RAI->End)
131     return nullptr;
132
133   const Archive::Child &Child = *RAI->Cur.operator->();
134   Archive::Child *Ret = new Archive::Child(Child);
135
136   return Ret;
137 }
138
139 extern "C" void LLVMRustArchiveChildFree(LLVMRustArchiveChildRef Child) {
140   delete Child;
141 }
142
143 extern "C" void LLVMRustArchiveIteratorFree(LLVMRustArchiveIteratorRef RAI) {
144   delete RAI;
145 }
146
147 extern "C" const char *
148 LLVMRustArchiveChildName(LLVMRustArchiveChildConstRef Child, size_t *Size) {
149   Expected<StringRef> NameOrErr = Child->getName();
150   if (!NameOrErr) {
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());
155     return nullptr;
156   }
157   StringRef Name = NameOrErr.get();
158   *Size = Name.size();
159   return Name.data();
160 }
161
162 extern "C" const char *LLVMRustArchiveChildData(LLVMRustArchiveChildRef Child,
163                                                 size_t *Size) {
164   StringRef Buf;
165   Expected<StringRef> BufOrErr = Child->getBuffer();
166   if (!BufOrErr) {
167     LLVMRustSetLastError(toString(BufOrErr.takeError()).c_str());
168     return nullptr;
169   }
170   Buf = BufOrErr.get();
171   *Size = Buf.size();
172   return Buf.data();
173 }
174
175 extern "C" LLVMRustArchiveMemberRef
176 LLVMRustArchiveMemberNew(char *Filename, char *Name,
177                          LLVMRustArchiveChildRef Child) {
178   RustArchiveMember *Member = new RustArchiveMember;
179   Member->Filename = Filename;
180   Member->Name = Name;
181   if (Child)
182     Member->Child = *Child;
183   return Member;
184 }
185
186 extern "C" void LLVMRustArchiveMemberFree(LLVMRustArchiveMemberRef Member) {
187   delete Member;
188 }
189
190 extern "C" LLVMRustResult
191 LLVMRustWriteArchive(char *Dst, size_t NumMembers,
192                      const LLVMRustArchiveMemberRef *NewMembers,
193                      bool WriteSymbtab, LLVMRustArchiveKind RustKind) {
194
195   std::vector<NewArchiveMember> Members;
196   auto Kind = fromRust(RustKind);
197
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);
204       if (!MOrErr) {
205         LLVMRustSetLastError(toString(MOrErr.takeError()).c_str());
206         return LLVMRustResult::Failure;
207       }
208       MOrErr->MemberName = sys::path::filename(MOrErr->MemberName);
209       Members.push_back(std::move(*MOrErr));
210     } else {
211       Expected<NewArchiveMember> MOrErr =
212           NewArchiveMember::getOldMember(Member->Child, true);
213       if (!MOrErr) {
214         LLVMRustSetLastError(toString(MOrErr.takeError()).c_str());
215         return LLVMRustResult::Failure;
216       }
217       Members.push_back(std::move(*MOrErr));
218     }
219   }
220
221   auto Result = writeArchive(Dst, Members, WriteSymbtab, Kind, true, false);
222   if (!Result)
223     return LLVMRustResult::Success;
224   LLVMRustSetLastError(toString(std::move(Result)).c_str());
225
226   return LLVMRustResult::Failure;
227 }