]> git.lizzy.rs Git - rust.git/blob - src/rustllvm/ArchiveWrapper.cpp
Auto merge of #56842 - scottmcm:vecdeque-rotate, r=alexcrichton
[rust.git] / src / rustllvm / ArchiveWrapper.cpp
1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 #include "rustllvm.h"
12
13 #include "llvm/Object/Archive.h"
14 #include "llvm/Object/ArchiveWriter.h"
15 #include "llvm/Support/Path.h"
16
17 using namespace llvm;
18 using namespace llvm::object;
19
20 struct RustArchiveMember {
21   const char *Filename;
22   const char *Name;
23   Archive::Child Child;
24
25   RustArchiveMember()
26       : Filename(nullptr), Name(nullptr),
27         Child(nullptr, nullptr, nullptr)
28   {
29   }
30   ~RustArchiveMember() {}
31 };
32
33 struct RustArchiveIterator {
34   bool First;
35   Archive::child_iterator Cur;
36   Archive::child_iterator End;
37   Error Err;
38
39   RustArchiveIterator() : First(true), Err(Error::success()) {}
40 };
41
42 enum class LLVMRustArchiveKind {
43   Other,
44   GNU,
45   BSD,
46   COFF,
47 };
48
49 static Archive::Kind fromRust(LLVMRustArchiveKind Kind) {
50   switch (Kind) {
51   case LLVMRustArchiveKind::GNU:
52     return Archive::K_GNU;
53   case LLVMRustArchiveKind::BSD:
54     return Archive::K_BSD;
55   case LLVMRustArchiveKind::COFF:
56     return Archive::K_COFF;
57   default:
58     report_fatal_error("Bad ArchiveKind.");
59   }
60 }
61
62 typedef OwningBinary<Archive> *LLVMRustArchiveRef;
63 typedef RustArchiveMember *LLVMRustArchiveMemberRef;
64 typedef Archive::Child *LLVMRustArchiveChildRef;
65 typedef Archive::Child const *LLVMRustArchiveChildConstRef;
66 typedef RustArchiveIterator *LLVMRustArchiveIteratorRef;
67
68 extern "C" LLVMRustArchiveRef LLVMRustOpenArchive(char *Path) {
69   ErrorOr<std::unique_ptr<MemoryBuffer>> BufOr =
70       MemoryBuffer::getFile(Path, -1, false);
71   if (!BufOr) {
72     LLVMRustSetLastError(BufOr.getError().message().c_str());
73     return nullptr;
74   }
75
76   Expected<std::unique_ptr<Archive>> ArchiveOr =
77       Archive::create(BufOr.get()->getMemBufferRef());
78
79   if (!ArchiveOr) {
80     LLVMRustSetLastError(toString(ArchiveOr.takeError()).c_str());
81     return nullptr;
82   }
83
84   OwningBinary<Archive> *Ret = new OwningBinary<Archive>(
85       std::move(ArchiveOr.get()), std::move(BufOr.get()));
86
87   return Ret;
88 }
89
90 extern "C" void LLVMRustDestroyArchive(LLVMRustArchiveRef RustArchive) {
91   delete RustArchive;
92 }
93
94 extern "C" LLVMRustArchiveIteratorRef
95 LLVMRustArchiveIteratorNew(LLVMRustArchiveRef RustArchive) {
96   Archive *Archive = RustArchive->getBinary();
97   RustArchiveIterator *RAI = new RustArchiveIterator();
98   RAI->Cur = Archive->child_begin(RAI->Err);
99   if (RAI->Err) {
100     LLVMRustSetLastError(toString(std::move(RAI->Err)).c_str());
101     delete RAI;
102     return nullptr;
103   }
104   RAI->End = Archive->child_end();
105   return RAI;
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 }