rust/src/rustllvm/ArchiveWrapper.cpp
Alex Crichton 74e198126b trans: Add kind to writeArchive
Updates our LLVM bindings to be able to write out multiple kinds of archives.
This commit also enables using LLVM instead of the system ar on all current
targets.
2015-07-16 20:25:51 -07:00

180 lines
4.8 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;
#if LLVM_VERSION_MINOR >= 7
ErrorOr<StringRef> buf_or_err = child->getBuffer();
if (buf_or_err.getError()) {
LLVMRustSetLastError(buf_or_err.getError().message().c_str());
return NULL;
}
buf = buf_or_err.get();
#else
buf = child->getBuffer();
#endif
*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,
Archive::Kind Kind) {
#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, Kind, false);
if (!pair.second)
return 0;
LLVMRustSetLastError(pair.second.message().c_str());
#else
LLVMRustSetLastError("writing archives not supported with this LLVM version");
#endif
return -1;
}