]> git.proxmox.com Git - rustc.git/blob - src/rustllvm/ArchiveWrapper.cpp
New upstream version 1.15.0+dfsg1
[rustc.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
16 using namespace llvm;
17 using namespace llvm::object;
18
19 struct RustArchiveMember {
20 const char *filename;
21 const char *name;
22 Archive::Child child;
23
24 RustArchiveMember(): filename(NULL), name(NULL),
25 #if LLVM_VERSION_GE(3, 8)
26 child(NULL, NULL, NULL)
27 #else
28 child(NULL, NULL)
29 #endif
30 {}
31 ~RustArchiveMember() {}
32 };
33
34
35 struct RustArchiveIterator {
36 Archive::child_iterator cur;
37 Archive::child_iterator end;
38 #if LLVM_VERSION_GE(3, 9)
39 Error err;
40
41 RustArchiveIterator() : err(Error::success()) { }
42 #endif
43 };
44
45 enum class LLVMRustArchiveKind {
46 Other,
47 GNU,
48 MIPS64,
49 BSD,
50 COFF,
51 };
52
53 static Archive::Kind
54 from_rust(LLVMRustArchiveKind kind)
55 {
56 switch (kind) {
57 case LLVMRustArchiveKind::GNU:
58 return Archive::K_GNU;
59 case LLVMRustArchiveKind::MIPS64:
60 return Archive::K_MIPS64;
61 case LLVMRustArchiveKind::BSD:
62 return Archive::K_BSD;
63 case LLVMRustArchiveKind::COFF:
64 return Archive::K_COFF;
65 default:
66 llvm_unreachable("Bad ArchiveKind.");
67 }
68 }
69
70 typedef OwningBinary<Archive> *LLVMRustArchiveRef;
71 typedef RustArchiveMember *LLVMRustArchiveMemberRef;
72 typedef Archive::Child *LLVMRustArchiveChildRef;
73 typedef Archive::Child const *LLVMRustArchiveChildConstRef;
74 typedef RustArchiveIterator *LLVMRustArchiveIteratorRef;
75
76 extern "C" LLVMRustArchiveRef
77 LLVMRustOpenArchive(char *path) {
78 ErrorOr<std::unique_ptr<MemoryBuffer>> buf_or = MemoryBuffer::getFile(path,
79 -1,
80 false);
81 if (!buf_or) {
82 LLVMRustSetLastError(buf_or.getError().message().c_str());
83 return nullptr;
84 }
85
86 #if LLVM_VERSION_LE(3, 8)
87 ErrorOr<std::unique_ptr<Archive>> archive_or =
88 #else
89 Expected<std::unique_ptr<Archive>> archive_or =
90 #endif
91 Archive::create(buf_or.get()->getMemBufferRef());
92
93 if (!archive_or) {
94 #if LLVM_VERSION_LE(3, 8)
95 LLVMRustSetLastError(archive_or.getError().message().c_str());
96 #else
97 LLVMRustSetLastError(toString(archive_or.takeError()).c_str());
98 #endif
99 return nullptr;
100 }
101
102 OwningBinary<Archive> *ret = new OwningBinary<Archive>(
103 std::move(archive_or.get()), std::move(buf_or.get()));
104
105 return ret;
106 }
107
108 extern "C" void
109 LLVMRustDestroyArchive(LLVMRustArchiveRef ar) {
110 delete ar;
111 }
112
113 extern "C" LLVMRustArchiveIteratorRef
114 LLVMRustArchiveIteratorNew(LLVMRustArchiveRef ra) {
115 Archive *ar = ra->getBinary();
116 RustArchiveIterator *rai = new RustArchiveIterator();
117 #if LLVM_VERSION_LE(3, 8)
118 rai->cur = ar->child_begin();
119 #else
120 rai->cur = ar->child_begin(rai->err);
121 if (rai->err) {
122 LLVMRustSetLastError(toString(std::move(rai->err)).c_str());
123 return NULL;
124 }
125 #endif
126 rai->end = ar->child_end();
127 return rai;
128 }
129
130 extern "C" LLVMRustArchiveChildConstRef
131 LLVMRustArchiveIteratorNext(LLVMRustArchiveIteratorRef rai) {
132 #if LLVM_VERSION_GE(3, 9)
133 if (rai->err) {
134 LLVMRustSetLastError(toString(std::move(rai->err)).c_str());
135 return NULL;
136 }
137 #endif
138 if (rai->cur == rai->end)
139 return NULL;
140 #if LLVM_VERSION_EQ(3, 8)
141 const ErrorOr<Archive::Child>* cur = rai->cur.operator->();
142 if (!*cur) {
143 LLVMRustSetLastError(cur->getError().message().c_str());
144 return NULL;
145 }
146 const Archive::Child &child = cur->get();
147 #else
148 const Archive::Child &child = *rai->cur.operator->();
149 #endif
150 Archive::Child *ret = new Archive::Child(child);
151
152 ++rai->cur;
153 return ret;
154 }
155
156 extern "C" void
157 LLVMRustArchiveChildFree(LLVMRustArchiveChildRef child) {
158 delete child;
159 }
160
161 extern "C" void
162 LLVMRustArchiveIteratorFree(LLVMRustArchiveIteratorRef rai) {
163 delete rai;
164 }
165
166 extern "C" const char*
167 LLVMRustArchiveChildName(LLVMRustArchiveChildConstRef child, size_t *size) {
168 #if LLVM_VERSION_GE(4, 0)
169 Expected<StringRef> name_or_err = child->getName();
170 if (!name_or_err) {
171 // rustc_llvm currently doesn't use this error string, but it might be useful
172 // in the future, and in the mean time this tells LLVM that the error was
173 // not ignored and that it shouldn't abort the process.
174 LLVMRustSetLastError(toString(name_or_err.takeError()).c_str());
175 return NULL;
176 }
177 #else
178 ErrorOr<StringRef> name_or_err = child->getName();
179 if (name_or_err.getError())
180 return NULL;
181 #endif
182 StringRef name = name_or_err.get();
183 *size = name.size();
184 return name.data();
185 }
186
187 extern "C" const char*
188 LLVMRustArchiveChildData(LLVMRustArchiveChildRef child, size_t *size) {
189 StringRef buf;
190 #if LLVM_VERSION_GE(4, 0)
191 Expected<StringRef> buf_or_err = child->getBuffer();
192 if (!buf_or_err) {
193 LLVMRustSetLastError(toString(buf_or_err.takeError()).c_str());
194 return NULL;
195 }
196 #else
197 ErrorOr<StringRef> buf_or_err = child->getBuffer();
198 if (buf_or_err.getError()) {
199 LLVMRustSetLastError(buf_or_err.getError().message().c_str());
200 return NULL;
201 }
202 #endif
203 buf = buf_or_err.get();
204 *size = buf.size();
205 return buf.data();
206 }
207
208 extern "C" LLVMRustArchiveMemberRef
209 LLVMRustArchiveMemberNew(char *Filename, char *Name,
210 LLVMRustArchiveChildRef child) {
211 RustArchiveMember *Member = new RustArchiveMember;
212 Member->filename = Filename;
213 Member->name = Name;
214 if (child)
215 Member->child = *child;
216 return Member;
217 }
218
219 extern "C" void
220 LLVMRustArchiveMemberFree(LLVMRustArchiveMemberRef Member) {
221 delete Member;
222 }
223
224 extern "C" LLVMRustResult
225 LLVMRustWriteArchive(char *Dst,
226 size_t NumMembers,
227 const LLVMRustArchiveMemberRef *NewMembers,
228 bool WriteSymbtab,
229 LLVMRustArchiveKind rust_kind) {
230
231 #if LLVM_VERSION_LE(3, 8)
232 std::vector<NewArchiveIterator> Members;
233 #else
234 std::vector<NewArchiveMember> Members;
235 #endif
236 auto Kind = from_rust(rust_kind);
237
238 for (size_t i = 0; i < NumMembers; i++) {
239 auto Member = NewMembers[i];
240 assert(Member->name);
241 if (Member->filename) {
242 #if LLVM_VERSION_GE(3, 9)
243 Expected<NewArchiveMember> MOrErr = NewArchiveMember::getFile(Member->filename, true);
244 if (!MOrErr) {
245 LLVMRustSetLastError(toString(MOrErr.takeError()).c_str());
246 return LLVMRustResult::Failure;
247 }
248 Members.push_back(std::move(*MOrErr));
249 #elif LLVM_VERSION_EQ(3, 8)
250 Members.push_back(NewArchiveIterator(Member->filename));
251 #else
252 Members.push_back(NewArchiveIterator(Member->filename, Member->name));
253 #endif
254 } else {
255 #if LLVM_VERSION_LE(3, 8)
256 Members.push_back(NewArchiveIterator(Member->child, Member->name));
257 #else
258 Expected<NewArchiveMember> MOrErr = NewArchiveMember::getOldMember(Member->child, true);
259 if (!MOrErr) {
260 LLVMRustSetLastError(toString(MOrErr.takeError()).c_str());
261 return LLVMRustResult::Failure;
262 }
263 Members.push_back(std::move(*MOrErr));
264 #endif
265 }
266 }
267 #if LLVM_VERSION_GE(3, 8)
268 auto pair = writeArchive(Dst, Members, WriteSymbtab, Kind, true, false);
269 #else
270 auto pair = writeArchive(Dst, Members, WriteSymbtab, Kind, true);
271 #endif
272 if (!pair.second)
273 return LLVMRustResult::Success;
274 LLVMRustSetLastError(pair.second.message().c_str());
275 return LLVMRustResult::Failure;
276 }