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 Child(nullptr, nullptr, nullptr)
30 ~RustArchiveMember() {}
33 struct RustArchiveIterator {
35 Archive::child_iterator Cur;
36 Archive::child_iterator End;
39 RustArchiveIterator() : First(true), Err(Error::success()) {}
42 enum class LLVMRustArchiveKind {
49 static Archive::Kind fromRust(LLVMRustArchiveKind 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;
58 report_fatal_error("Bad ArchiveKind.");
62 typedef OwningBinary<Archive> *LLVMRustArchiveRef;
63 typedef RustArchiveMember *LLVMRustArchiveMemberRef;
64 typedef Archive::Child *LLVMRustArchiveChildRef;
65 typedef Archive::Child const *LLVMRustArchiveChildConstRef;
66 typedef RustArchiveIterator *LLVMRustArchiveIteratorRef;
68 extern "C" LLVMRustArchiveRef LLVMRustOpenArchive(char *Path) {
69 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOr =
70 MemoryBuffer::getFile(Path, -1, false);
72 LLVMRustSetLastError(BufOr.getError().message().c_str());
76 Expected<std::unique_ptr<Archive>> ArchiveOr =
77 Archive::create(BufOr.get()->getMemBufferRef());
80 LLVMRustSetLastError(toString(ArchiveOr.takeError()).c_str());
84 OwningBinary<Archive> *Ret = new OwningBinary<Archive>(
85 std::move(ArchiveOr.get()), std::move(BufOr.get()));
90 extern "C" void LLVMRustDestroyArchive(LLVMRustArchiveRef RustArchive) {
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);
100 LLVMRustSetLastError(toString(std::move(RAI->Err)).c_str());
104 RAI->End = Archive->child_end();
108 extern "C" LLVMRustArchiveChildConstRef
109 LLVMRustArchiveIteratorNext(LLVMRustArchiveIteratorRef RAI) {
110 if (RAI->Cur == RAI->End)
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
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.
122 LLVMRustSetLastError(toString(std::move(RAI->Err)).c_str());
129 if (RAI->Cur == RAI->End)
132 const Archive::Child &Child = *RAI->Cur.operator->();
133 Archive::Child *Ret = new Archive::Child(Child);
138 extern "C" void LLVMRustArchiveChildFree(LLVMRustArchiveChildRef Child) {
142 extern "C" void LLVMRustArchiveIteratorFree(LLVMRustArchiveIteratorRef RAI) {
146 extern "C" const char *
147 LLVMRustArchiveChildName(LLVMRustArchiveChildConstRef Child, size_t *Size) {
148 Expected<StringRef> NameOrErr = Child->getName();
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());
156 StringRef Name = NameOrErr.get();
161 extern "C" const char *LLVMRustArchiveChildData(LLVMRustArchiveChildRef Child,
164 Expected<StringRef> BufOrErr = Child->getBuffer();
166 LLVMRustSetLastError(toString(BufOrErr.takeError()).c_str());
169 Buf = BufOrErr.get();
174 extern "C" LLVMRustArchiveMemberRef
175 LLVMRustArchiveMemberNew(char *Filename, char *Name,
176 LLVMRustArchiveChildRef Child) {
177 RustArchiveMember *Member = new RustArchiveMember;
178 Member->Filename = Filename;
181 Member->Child = *Child;
185 extern "C" void LLVMRustArchiveMemberFree(LLVMRustArchiveMemberRef Member) {
189 extern "C" LLVMRustResult
190 LLVMRustWriteArchive(char *Dst, size_t NumMembers,
191 const LLVMRustArchiveMemberRef *NewMembers,
192 bool WriteSymbtab, LLVMRustArchiveKind RustKind) {
194 std::vector<NewArchiveMember> Members;
195 auto Kind = fromRust(RustKind);
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);
204 LLVMRustSetLastError(toString(MOrErr.takeError()).c_str());
205 return LLVMRustResult::Failure;
207 MOrErr->MemberName = sys::path::filename(MOrErr->MemberName);
208 Members.push_back(std::move(*MOrErr));
210 Expected<NewArchiveMember> MOrErr =
211 NewArchiveMember::getOldMember(Member->Child, true);
213 LLVMRustSetLastError(toString(MOrErr.takeError()).c_str());
214 return LLVMRustResult::Failure;
216 Members.push_back(std::move(*MOrErr));
220 auto Result = writeArchive(Dst, Members, WriteSymbtab, Kind, true, false);
222 return LLVMRustResult::Success;
223 LLVMRustSetLastError(toString(std::move(Result)).c_str());
225 return LLVMRustResult::Failure;