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.
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.
13 #include "llvm/Object/Archive.h"
14 #include "llvm/Object/ArchiveWriter.h"
15 #include "llvm/Support/Path.h"
18 using namespace llvm::object;
20 struct RustArchiveMember {
26 : Filename(nullptr), Name(nullptr),
27 #if LLVM_VERSION_GE(3, 8)
28 Child(nullptr, nullptr, nullptr)
30 Child(nullptr, nullptr)
34 ~RustArchiveMember() {}
37 struct RustArchiveIterator {
39 Archive::child_iterator Cur;
40 Archive::child_iterator End;
41 #if LLVM_VERSION_GE(3, 9)
44 RustArchiveIterator() : First(true), Err(Error::success()) {}
46 RustArchiveIterator() : First(true) {}
50 enum class LLVMRustArchiveKind {
58 static Archive::Kind fromRust(LLVMRustArchiveKind Kind) {
60 case LLVMRustArchiveKind::GNU:
61 return Archive::K_GNU;
62 case LLVMRustArchiveKind::MIPS64:
63 return Archive::K_MIPS64;
64 case LLVMRustArchiveKind::BSD:
65 return Archive::K_BSD;
66 case LLVMRustArchiveKind::COFF:
67 return Archive::K_COFF;
69 llvm_unreachable("Bad ArchiveKind.");
73 typedef OwningBinary<Archive> *LLVMRustArchiveRef;
74 typedef RustArchiveMember *LLVMRustArchiveMemberRef;
75 typedef Archive::Child *LLVMRustArchiveChildRef;
76 typedef Archive::Child const *LLVMRustArchiveChildConstRef;
77 typedef RustArchiveIterator *LLVMRustArchiveIteratorRef;
79 extern "C" LLVMRustArchiveRef LLVMRustOpenArchive(char *Path) {
80 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOr =
81 MemoryBuffer::getFile(Path, -1, false);
83 LLVMRustSetLastError(BufOr.getError().message().c_str());
87 #if LLVM_VERSION_LE(3, 8)
88 ErrorOr<std::unique_ptr<Archive>> ArchiveOr =
90 Expected<std::unique_ptr<Archive>> ArchiveOr =
92 Archive::create(BufOr.get()->getMemBufferRef());
95 #if LLVM_VERSION_LE(3, 8)
96 LLVMRustSetLastError(ArchiveOr.getError().message().c_str());
98 LLVMRustSetLastError(toString(ArchiveOr.takeError()).c_str());
103 OwningBinary<Archive> *Ret = new OwningBinary<Archive>(
104 std::move(ArchiveOr.get()), std::move(BufOr.get()));
109 extern "C" void LLVMRustDestroyArchive(LLVMRustArchiveRef RustArchive) {
113 extern "C" LLVMRustArchiveIteratorRef
114 LLVMRustArchiveIteratorNew(LLVMRustArchiveRef RustArchive) {
115 Archive *Archive = RustArchive->getBinary();
116 RustArchiveIterator *RAI = new RustArchiveIterator();
117 #if LLVM_VERSION_LE(3, 8)
118 RAI->Cur = Archive->child_begin();
120 RAI->Cur = Archive->child_begin(RAI->Err);
122 LLVMRustSetLastError(toString(std::move(RAI->Err)).c_str());
127 RAI->End = Archive->child_end();
131 extern "C" LLVMRustArchiveChildConstRef
132 LLVMRustArchiveIteratorNext(LLVMRustArchiveIteratorRef RAI) {
133 if (RAI->Cur == RAI->End)
136 // Advancing the iterator validates the next child, and this can
137 // uncover an error. LLVM requires that we check all Errors,
138 // so we only advance the iterator if we actually need to fetch
140 // This means we must not advance the iterator in the *first* call,
141 // but instead advance it *before* fetching the child in all later calls.
144 #if LLVM_VERSION_GE(3, 9)
146 LLVMRustSetLastError(toString(std::move(RAI->Err)).c_str());
154 if (RAI->Cur == RAI->End)
157 #if LLVM_VERSION_EQ(3, 8)
158 const ErrorOr<Archive::Child> *Cur = RAI->Cur.operator->();
160 LLVMRustSetLastError(Cur->getError().message().c_str());
163 const Archive::Child &Child = Cur->get();
165 const Archive::Child &Child = *RAI->Cur.operator->();
167 Archive::Child *Ret = new Archive::Child(Child);
172 extern "C" void LLVMRustArchiveChildFree(LLVMRustArchiveChildRef Child) {
176 extern "C" void LLVMRustArchiveIteratorFree(LLVMRustArchiveIteratorRef RAI) {
180 extern "C" const char *
181 LLVMRustArchiveChildName(LLVMRustArchiveChildConstRef Child, size_t *Size) {
182 #if LLVM_VERSION_GE(4, 0)
183 Expected<StringRef> NameOrErr = Child->getName();
185 // rustc_llvm currently doesn't use this error string, but it might be
186 // useful in the future, and in the mean time this tells LLVM that the
187 // error was not ignored and that it shouldn't abort the process.
188 LLVMRustSetLastError(toString(NameOrErr.takeError()).c_str());
192 ErrorOr<StringRef> NameOrErr = Child->getName();
193 if (NameOrErr.getError())
196 StringRef Name = NameOrErr.get();
201 extern "C" const char *LLVMRustArchiveChildData(LLVMRustArchiveChildRef Child,
204 #if LLVM_VERSION_GE(4, 0)
205 Expected<StringRef> BufOrErr = Child->getBuffer();
207 LLVMRustSetLastError(toString(BufOrErr.takeError()).c_str());
211 ErrorOr<StringRef> BufOrErr = Child->getBuffer();
212 if (BufOrErr.getError()) {
213 LLVMRustSetLastError(BufOrErr.getError().message().c_str());
217 Buf = BufOrErr.get();
222 extern "C" LLVMRustArchiveMemberRef
223 LLVMRustArchiveMemberNew(char *Filename, char *Name,
224 LLVMRustArchiveChildRef Child) {
225 RustArchiveMember *Member = new RustArchiveMember;
226 Member->Filename = Filename;
229 Member->Child = *Child;
233 extern "C" void LLVMRustArchiveMemberFree(LLVMRustArchiveMemberRef Member) {
237 extern "C" LLVMRustResult
238 LLVMRustWriteArchive(char *Dst, size_t NumMembers,
239 const LLVMRustArchiveMemberRef *NewMembers,
240 bool WriteSymbtab, LLVMRustArchiveKind RustKind) {
242 #if LLVM_VERSION_LE(3, 8)
243 std::vector<NewArchiveIterator> Members;
245 std::vector<NewArchiveMember> Members;
247 auto Kind = fromRust(RustKind);
249 for (size_t I = 0; I < NumMembers; I++) {
250 auto Member = NewMembers[I];
251 assert(Member->Name);
252 if (Member->Filename) {
253 #if LLVM_VERSION_GE(3, 9)
254 Expected<NewArchiveMember> MOrErr =
255 NewArchiveMember::getFile(Member->Filename, true);
257 LLVMRustSetLastError(toString(MOrErr.takeError()).c_str());
258 return LLVMRustResult::Failure;
260 #if LLVM_VERSION_GE(5, 0)
261 MOrErr->MemberName = sys::path::filename(MOrErr->MemberName);
263 Members.push_back(std::move(*MOrErr));
264 #elif LLVM_VERSION_EQ(3, 8)
265 Members.push_back(NewArchiveIterator(Member->Filename));
267 Members.push_back(NewArchiveIterator(Member->Filename, Member->Name));
270 #if LLVM_VERSION_LE(3, 8)
271 Members.push_back(NewArchiveIterator(Member->Child, Member->Name));
273 Expected<NewArchiveMember> MOrErr =
274 NewArchiveMember::getOldMember(Member->Child, true);
276 LLVMRustSetLastError(toString(MOrErr.takeError()).c_str());
277 return LLVMRustResult::Failure;
279 Members.push_back(std::move(*MOrErr));
283 #if LLVM_VERSION_GE(3, 8)
284 auto Pair = writeArchive(Dst, Members, WriteSymbtab, Kind, true, false);
286 auto Pair = writeArchive(Dst, Members, WriteSymbtab, Kind, true);
289 return LLVMRustResult::Success;
290 LLVMRustSetLastError(Pair.second.message().c_str());
291 return LLVMRustResult::Failure;