169 lines
4.5 KiB
C++
169 lines
4.5 KiB
C++
|
|
// 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;
|
||
|
|
}
|