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