rustc: Handle duplicate names merging archives
When linking an archive statically to an rlib, the compiler will extract all contents of the archive and add them all to the rlib being generated. The current method of extraction is to run `ar x`, dumping all files into a temporary directory. Object archives, however, are allowed to have multiple entries with the same file name, so there is no method for them to extract their contents into a directory in a lossless fashion. This commit adds iterator support to the `ArchiveRO` structure which hooks into LLVM's support for reading object archives. This iterator is then used to inspect each object in turn and extract it to a unique location for later assembly.
This commit is contained in:
parent
77acda1c8e
commit
9ab0475d94
12 changed files with 265 additions and 85 deletions
|
@ -770,37 +770,68 @@ LLVMRustOpenArchive(char *path) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
extern "C" const char*
|
||||
#if LLVM_VERSION_MINOR >= 6
|
||||
LLVMRustArchiveReadSection(OwningBinary<Archive> *ob, char *name, size_t *size) {
|
||||
|
||||
Archive *ar = ob->getBinary();
|
||||
typedef OwningBinary<Archive> RustArchive;
|
||||
#define GET_ARCHIVE(a) ((a)->getBinary())
|
||||
#else
|
||||
LLVMRustArchiveReadSection(Archive *ar, char *name, size_t *size) {
|
||||
typedef Archive RustArchive;
|
||||
#define GET_ARCHIVE(a) (a)
|
||||
#endif
|
||||
|
||||
Archive::child_iterator child = ar->child_begin(),
|
||||
end = ar->child_end();
|
||||
for (; child != end; ++child) {
|
||||
ErrorOr<StringRef> name_or_err = child->getName();
|
||||
if (name_or_err.getError()) continue;
|
||||
StringRef sect_name = name_or_err.get();
|
||||
if (sect_name.trim(" ") == name) {
|
||||
StringRef buf = child->getBuffer();
|
||||
*size = buf.size();
|
||||
return buf.data();
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
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*
|
||||
LLVMRustArchiveIteratorCurrent(RustArchiveIterator *rai) {
|
||||
if (rai->cur == rai->end)
|
||||
return NULL;
|
||||
const Archive::Child &ret = *rai->cur;
|
||||
return &ret;
|
||||
}
|
||||
|
||||
extern "C" void
|
||||
#if LLVM_VERSION_MINOR >= 6
|
||||
LLVMRustDestroyArchive(OwningBinary<Archive> *ar) {
|
||||
#else
|
||||
LLVMRustDestroyArchive(Archive *ar) {
|
||||
#endif
|
||||
delete ar;
|
||||
LLVMRustArchiveIteratorNext(RustArchiveIterator *rai) {
|
||||
if (rai->cur == rai->end)
|
||||
return;
|
||||
++rai->cur;
|
||||
}
|
||||
|
||||
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" void
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue