diff options
Diffstat (limited to 'src/rustllvm/ArchiveWrapper.cpp')
| -rw-r--r-- | src/rustllvm/ArchiveWrapper.cpp | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/src/rustllvm/ArchiveWrapper.cpp b/src/rustllvm/ArchiveWrapper.cpp new file mode 100644 index 00000000000..2e94c196935 --- /dev/null +++ b/src/rustllvm/ArchiveWrapper.cpp @@ -0,0 +1,168 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#include "rustllvm.h" + +#include "llvm/Object/Archive.h" + +#if LLVM_VERSION_MINOR >= 7 +#include "llvm/Object/ArchiveWriter.h" +#endif + +using namespace llvm; +using namespace llvm::object; + +struct LLVMRustArchiveMember { + const char *filename; + const char *name; + Archive::Child child; + + LLVMRustArchiveMember(): filename(NULL), name(NULL), child(NULL, NULL) {} + ~LLVMRustArchiveMember() {} +}; + +#if LLVM_VERSION_MINOR >= 6 +typedef OwningBinary<Archive> RustArchive; +#define GET_ARCHIVE(a) ((a)->getBinary()) +#else +typedef Archive RustArchive; +#define GET_ARCHIVE(a) (a) +#endif + +extern "C" void* +LLVMRustOpenArchive(char *path) { + ErrorOr<std::unique_ptr<MemoryBuffer>> buf_or = MemoryBuffer::getFile(path, + -1, + false); + if (!buf_or) { + LLVMRustSetLastError(buf_or.getError().message().c_str()); + return nullptr; + } + +#if LLVM_VERSION_MINOR >= 6 + ErrorOr<std::unique_ptr<Archive>> archive_or = + Archive::create(buf_or.get()->getMemBufferRef()); + + if (!archive_or) { + LLVMRustSetLastError(archive_or.getError().message().c_str()); + return nullptr; + } + + OwningBinary<Archive> *ret = new OwningBinary<Archive>( + std::move(archive_or.get()), std::move(buf_or.get())); +#else + std::error_code err; + Archive *ret = new Archive(std::move(buf_or.get()), err); + if (err) { + LLVMRustSetLastError(err.message().c_str()); + return nullptr; + } +#endif + + return ret; +} + +extern "C" void +LLVMRustDestroyArchive(RustArchive *ar) { + delete ar; +} + +struct RustArchiveIterator { + Archive::child_iterator cur; + Archive::child_iterator end; +}; + +extern "C" RustArchiveIterator* +LLVMRustArchiveIteratorNew(RustArchive *ra) { + Archive *ar = GET_ARCHIVE(ra); + RustArchiveIterator *rai = new RustArchiveIterator(); + rai->cur = ar->child_begin(); + rai->end = ar->child_end(); + return rai; +} + +extern "C" const Archive::Child* +LLVMRustArchiveIteratorNext(RustArchiveIterator *rai) { + if (rai->cur == rai->end) + return NULL; + const Archive::Child *cur = rai->cur.operator->(); + Archive::Child *ret = new Archive::Child(*cur); + ++rai->cur; + return ret; +} + +extern "C" void +LLVMRustArchiveChildFree(Archive::Child *child) { + delete child; +} + +extern "C" void +LLVMRustArchiveIteratorFree(RustArchiveIterator *rai) { + delete rai; +} + +extern "C" const char* +LLVMRustArchiveChildName(const Archive::Child *child, size_t *size) { + ErrorOr<StringRef> name_or_err = child->getName(); + if (name_or_err.getError()) + return NULL; + StringRef name = name_or_err.get(); + *size = name.size(); + return name.data(); +} + +extern "C" const char* +LLVMRustArchiveChildData(Archive::Child *child, size_t *size) { + StringRef buf = child->getBuffer(); + *size = buf.size(); + return buf.data(); +} + +extern "C" LLVMRustArchiveMember* +LLVMRustArchiveMemberNew(char *Filename, char *Name, Archive::Child *child) { + LLVMRustArchiveMember *Member = new LLVMRustArchiveMember; + Member->filename = Filename; + Member->name = Name; + if (child) + Member->child = *child; + return Member; +} + +extern "C" void +LLVMRustArchiveMemberFree(LLVMRustArchiveMember *Member) { + delete Member; +} + +extern "C" int +LLVMRustWriteArchive(char *Dst, + size_t NumMembers, + const LLVMRustArchiveMember **NewMembers, + bool WriteSymbtab) { +#if LLVM_VERSION_MINOR >= 7 + std::vector<NewArchiveIterator> Members; + + for (size_t i = 0; i < NumMembers; i++) { + auto Member = NewMembers[i]; + assert(Member->name); + if (Member->filename) { + Members.push_back(NewArchiveIterator(Member->filename, Member->name)); + } else { + Members.push_back(NewArchiveIterator(Member->child, Member->name)); + } + } + auto pair = writeArchive(Dst, Members, WriteSymbtab); + if (!pair.second) + return 0; + LLVMRustSetLastError(pair.second.message().c_str()); +#else + LLVMRustSetLastError("writing archives not supported with this LLVM version"); +#endif + return -1; +} |
