]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp
Auto merge of #82122 - bstrie:dep4real, r=dtolnay
[rust.git] / compiler / rustc_llvm / llvm-wrapper / ArchiveWrapper.cpp
1 #include "LLVMWrapper.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   GNU,
39   BSD,
40   DARWIN,
41   COFF,
42 };
43
44 static Archive::Kind fromRust(LLVMRustArchiveKind Kind) {
45   switch (Kind) {
46   case LLVMRustArchiveKind::GNU:
47     return Archive::K_GNU;
48   case LLVMRustArchiveKind::BSD:
49     return Archive::K_BSD;
50   case LLVMRustArchiveKind::DARWIN:
51     return Archive::K_DARWIN;
52   case LLVMRustArchiveKind::COFF:
53     return Archive::K_COFF;
54   default:
55     report_fatal_error("Bad ArchiveKind.");
56   }
57 }
58
59 typedef OwningBinary<Archive> *LLVMRustArchiveRef;
60 typedef RustArchiveMember *LLVMRustArchiveMemberRef;
61 typedef Archive::Child *LLVMRustArchiveChildRef;
62 typedef Archive::Child const *LLVMRustArchiveChildConstRef;
63 typedef RustArchiveIterator *LLVMRustArchiveIteratorRef;
64
65 extern "C" LLVMRustArchiveRef LLVMRustOpenArchive(char *Path) {
66   ErrorOr<std::unique_ptr<MemoryBuffer>> BufOr =
67       MemoryBuffer::getFile(Path, -1, false);
68   if (!BufOr) {
69     LLVMRustSetLastError(BufOr.getError().message().c_str());
70     return nullptr;
71   }
72
73   Expected<std::unique_ptr<Archive>> ArchiveOr =
74       Archive::create(BufOr.get()->getMemBufferRef());
75
76   if (!ArchiveOr) {
77     LLVMRustSetLastError(toString(ArchiveOr.takeError()).c_str());
78     return nullptr;
79   }
80
81   OwningBinary<Archive> *Ret = new OwningBinary<Archive>(
82       std::move(ArchiveOr.get()), std::move(BufOr.get()));
83
84   return Ret;
85 }
86
87 extern "C" void LLVMRustDestroyArchive(LLVMRustArchiveRef RustArchive) {
88   delete RustArchive;
89 }
90
91 extern "C" LLVMRustArchiveIteratorRef
92 LLVMRustArchiveIteratorNew(LLVMRustArchiveRef RustArchive) {
93   Archive *Archive = RustArchive->getBinary();
94 #if LLVM_VERSION_GE(10, 0)
95   std::unique_ptr<Error> Err = std::make_unique<Error>(Error::success());
96 #else
97   std::unique_ptr<Error> Err = llvm::make_unique<Error>(Error::success());
98 #endif
99   auto Cur = Archive->child_begin(*Err);
100   if (*Err) {
101     LLVMRustSetLastError(toString(std::move(*Err)).c_str());
102     return nullptr;
103   }
104   auto End = Archive->child_end();
105   return new RustArchiveIterator(Cur, End, std::move(Err));
106 }
107
108 extern "C" LLVMRustArchiveChildConstRef
109 LLVMRustArchiveIteratorNext(LLVMRustArchiveIteratorRef RAI) {
110   if (RAI->Cur == RAI->End)
111     return nullptr;
112
113   // Advancing the iterator validates the next child, and this can
114   // uncover an error. LLVM requires that we check all Errors,
115   // so we only advance the iterator if we actually need to fetch
116   // the next child.
117   // This means we must not advance the iterator in the *first* call,
118   // but instead advance it *before* fetching the child in all later calls.
119   if (!RAI->First) {
120     ++RAI->Cur;
121     if (*RAI->Err) {
122       LLVMRustSetLastError(toString(std::move(*RAI->Err)).c_str());
123       return nullptr;
124     }
125   } else {
126     RAI->First = false;
127   }
128
129   if (RAI->Cur == RAI->End)
130     return nullptr;
131
132   const Archive::Child &Child = *RAI->Cur.operator->();
133   Archive::Child *Ret = new Archive::Child(Child);
134
135   return Ret;
136 }
137
138 extern "C" void LLVMRustArchiveChildFree(LLVMRustArchiveChildRef Child) {
139   delete Child;
140 }
141
142 extern "C" void LLVMRustArchiveIteratorFree(LLVMRustArchiveIteratorRef RAI) {
143   delete RAI;
144 }
145
146 extern "C" const char *
147 LLVMRustArchiveChildName(LLVMRustArchiveChildConstRef Child, size_t *Size) {
148   Expected<StringRef> NameOrErr = Child->getName();
149   if (!NameOrErr) {
150     // rustc_codegen_llvm currently doesn't use this error string, but it might be
151     // useful in the future, and in the mean time this tells LLVM that the
152     // error was not ignored and that it shouldn't abort the process.
153     LLVMRustSetLastError(toString(NameOrErr.takeError()).c_str());
154     return nullptr;
155   }
156   StringRef Name = NameOrErr.get();
157   *Size = Name.size();
158   return Name.data();
159 }
160
161 extern "C" const char *LLVMRustArchiveChildData(LLVMRustArchiveChildRef Child,
162                                                 size_t *Size) {
163   StringRef Buf;
164   Expected<StringRef> BufOrErr = Child->getBuffer();
165   if (!BufOrErr) {
166     LLVMRustSetLastError(toString(BufOrErr.takeError()).c_str());
167     return nullptr;
168   }
169   Buf = BufOrErr.get();
170   *Size = Buf.size();
171   return Buf.data();
172 }
173
174 extern "C" LLVMRustArchiveMemberRef
175 LLVMRustArchiveMemberNew(char *Filename, char *Name,
176                          LLVMRustArchiveChildRef Child) {
177   RustArchiveMember *Member = new RustArchiveMember;
178   Member->Filename = Filename;
179   Member->Name = Name;
180   if (Child)
181     Member->Child = *Child;
182   return Member;
183 }
184
185 extern "C" void LLVMRustArchiveMemberFree(LLVMRustArchiveMemberRef Member) {
186   delete Member;
187 }
188
189 extern "C" LLVMRustResult
190 LLVMRustWriteArchive(char *Dst, size_t NumMembers,
191                      const LLVMRustArchiveMemberRef *NewMembers,
192                      bool WriteSymbtab, LLVMRustArchiveKind RustKind) {
193
194   std::vector<NewArchiveMember> Members;
195   auto Kind = fromRust(RustKind);
196
197   for (size_t I = 0; I < NumMembers; I++) {
198     auto Member = NewMembers[I];
199     assert(Member->Name);
200     if (Member->Filename) {
201       Expected<NewArchiveMember> MOrErr =
202           NewArchiveMember::getFile(Member->Filename, true);
203       if (!MOrErr) {
204         LLVMRustSetLastError(toString(MOrErr.takeError()).c_str());
205         return LLVMRustResult::Failure;
206       }
207       MOrErr->MemberName = sys::path::filename(MOrErr->MemberName);
208       Members.push_back(std::move(*MOrErr));
209     } else {
210       Expected<NewArchiveMember> MOrErr =
211           NewArchiveMember::getOldMember(Member->Child, true);
212       if (!MOrErr) {
213         LLVMRustSetLastError(toString(MOrErr.takeError()).c_str());
214         return LLVMRustResult::Failure;
215       }
216       Members.push_back(std::move(*MOrErr));
217     }
218   }
219
220   auto Result = writeArchive(Dst, Members, WriteSymbtab, Kind, true, false);
221   if (!Result)
222     return LLVMRustResult::Success;
223   LLVMRustSetLastError(toString(std::move(Result)).c_str());
224
225   return LLVMRustResult::Failure;
226 }