diff --git a/llvm/include/llvm/Object/ArchiveWriter.h b/llvm/include/llvm/Object/ArchiveWriter.h --- a/llvm/include/llvm/Object/ArchiveWriter.h +++ b/llvm/include/llvm/Object/ArchiveWriter.h @@ -26,7 +26,6 @@ sys::TimePoint ModTime; unsigned UID = 0, GID = 0, Perms = 0644; - bool IsNew = false; NewArchiveMember() = default; NewArchiveMember(MemoryBufferRef BufRef); diff --git a/llvm/lib/Object/ArchiveWriter.cpp b/llvm/lib/Object/ArchiveWriter.cpp --- a/llvm/lib/Object/ArchiveWriter.cpp +++ b/llvm/lib/Object/ArchiveWriter.cpp @@ -48,7 +48,6 @@ return BufOrErr.takeError(); NewArchiveMember M; - assert(M.IsNew == false); M.Buf = MemoryBuffer::getMemBuffer(*BufOrErr, false); M.MemberName = M.Buf->getBufferIdentifier(); if (!Deterministic) { @@ -98,7 +97,6 @@ return errorCodeToError(std::error_code(errno, std::generic_category())); NewArchiveMember M; - M.IsNew = true; M.Buf = std::move(*MemberBufferOrErr); M.MemberName = M.Buf->getBufferIdentifier(); if (!Deterministic) { @@ -191,35 +189,6 @@ return Thin || Name.size() >= 16 || Name.contains('/'); } -// Compute the relative path from From to To. -static std::string computeRelativePath(StringRef From, StringRef To) { - if (sys::path::is_absolute(From) || sys::path::is_absolute(To)) - return To; - - StringRef DirFrom = sys::path::parent_path(From); - auto FromI = sys::path::begin(DirFrom); - auto ToI = sys::path::begin(To); - while (*FromI == *ToI) { - ++FromI; - ++ToI; - } - - SmallString<128> Relative; - for (auto FromE = sys::path::end(DirFrom); FromI != FromE; ++FromI) - sys::path::append(Relative, ".."); - - for (auto ToE = sys::path::end(To); ToI != ToE; ++ToI) - sys::path::append(Relative, *ToI); - -#ifdef _WIN32 - // Replace backslashes with slashes so that the path is portable between *nix - // and Windows. - std::replace(Relative.begin(), Relative.end(), '\\', '/'); -#endif - - return Relative.str(); -} - static bool is64BitKind(object::Archive::Kind Kind) { switch (Kind) { case object::Archive::K_GNU: @@ -236,15 +205,7 @@ static void addToStringTable(raw_ostream &Out, StringRef ArcName, const NewArchiveMember &M, bool Thin) { - StringRef ID = M.Buf->getBufferIdentifier(); - if (Thin) { - if (M.IsNew) - Out << computeRelativePath(ArcName, ID); - else - Out << ID; - } else - Out << M.MemberName; - Out << "/\n"; + Out << M.MemberName << "/\n"; } static void printMemberHeader(raw_ostream &Out, uint64_t Pos, @@ -254,7 +215,6 @@ StringRef ArcName, const NewArchiveMember &M, sys::TimePoint ModTime, unsigned Size) { - if (isBSDLike(Kind)) return printBSDMemberHeader(Out, Pos, M.MemberName, ModTime, M.UID, M.GID, M.Perms, Size); diff --git a/llvm/test/tools/llvm-ar/flatten-thin-archive-directories.test b/llvm/test/tools/llvm-ar/flatten-thin-archive-directories.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-ar/flatten-thin-archive-directories.test @@ -0,0 +1,15 @@ +# This test creates a thin archive in a directory and adds it to a thin archive +# in the parent directory. The relative path should be included when flattening +# the archive. + +RUN: mkdir -p %t/foo +RUN: touch %t/foo/a.txt +RUN: rm -f %t/archive.a %t/foo/archive.a + +# These tests must be run in the same directory as %t/archive.a. cd %t is +# included on each line to make debugging this test case easier. +RUN: cd %t && llvm-ar rcST foo/archive.a foo/a.txt +RUN: cd %t && llvm-ar rcST archive.a foo/archive.a +RUN: cd %t && llvm-ar t archive.a | FileCheck %s --match-full-lines + +CHECK: foo/a.txt diff --git a/llvm/tools/llvm-ar/llvm-ar.cpp b/llvm/tools/llvm-ar/llvm-ar.cpp --- a/llvm/tools/llvm-ar/llvm-ar.cpp +++ b/llvm/tools/llvm-ar/llvm-ar.cpp @@ -193,6 +193,9 @@ // on the command line. static std::vector Members; +// Static buffer to hold StringRefs. +static BumpPtrAllocator Alloc; + // Extract the member filename from the command line for the [relpos] argument // associated with a, b, and i modifiers static void getRelPos() { @@ -537,6 +540,35 @@ exit(1); } +// Compute the relative path from From to To. +static std::string computeRelativePath(StringRef From, StringRef To) { + if (sys::path::is_absolute(From) || sys::path::is_absolute(To)) + return To; + + StringRef DirFrom = sys::path::parent_path(From); + auto FromI = sys::path::begin(DirFrom); + auto ToI = sys::path::begin(To); + while (*FromI == *ToI) { + ++FromI; + ++ToI; + } + + SmallString<128> Relative; + for (auto FromE = sys::path::end(DirFrom); FromI != FromE; ++FromI) + sys::path::append(Relative, ".."); + + for (auto ToE = sys::path::end(To); ToI != ToE; ++ToI) + sys::path::append(Relative, *ToI); + +#ifdef _WIN32 + // Replace backslashes with slashes so that the path is portable between *nix + // and Windows. + std::replace(Relative.begin(), Relative.end(), '\\', '/'); +#endif + + return Relative.str(); +} + static void addChildMember(std::vector &Members, const object::Archive::Child &M, bool FlattenArchive = false) { @@ -545,6 +577,15 @@ Expected NMOrErr = NewArchiveMember::getOldMember(M, Deterministic); failIfError(NMOrErr.takeError()); + // If the child member we're trying to add is thin, use the path relative to + // the archive it's in, so the file resolves correctly. + if (Thin && FlattenArchive) { + StringSaver Saver(Alloc); + Expected FileNameOrErr = M.getFullName(); + failIfError(FileNameOrErr.takeError()); + NMOrErr->MemberName = + Saver.save(computeRelativePath(ArchiveName, *FileNameOrErr)); + } if (FlattenArchive && identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) { Expected FileNameOrErr = M.getFullName(); @@ -568,6 +609,13 @@ Expected NMOrErr = NewArchiveMember::getFile(FileName, Deterministic); failIfError(NMOrErr.takeError(), FileName); + StringSaver Saver(Alloc); + // For regular archives, use the basename of the object path for the member + // name. For thin archives, use the full relative paths so the file resolves + // correctly. + NMOrErr->MemberName = + Thin ? Saver.save(computeRelativePath(ArchiveName, FileName)) + : NMOrErr->MemberName = sys::path::filename(NMOrErr->MemberName); if (FlattenArchive && identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) { object::Archive &Lib = readLibrary(FileName); @@ -581,8 +629,6 @@ return; } } - // Use the basename of the object path for the member name. - NMOrErr->MemberName = sys::path::filename(NMOrErr->MemberName); Members.push_back(std::move(*NMOrErr)); } @@ -672,7 +718,7 @@ computeInsertAction(Operation, Child, Name, MemberI); switch (Action) { case IA_AddOldMember: - addChildMember(Ret, Child); + addChildMember(Ret, Child, /*FlattenArchive=*/Thin); break; case IA_AddNewMember: addMember(Ret, *MemberI); @@ -680,7 +726,7 @@ case IA_Delete: break; case IA_MoveOldMember: - addChildMember(Moved, Child); + addChildMember(Moved, Child, /*FlattenArchive=*/Thin); break; case IA_MoveNewMember: addMember(Moved, *MemberI); @@ -899,7 +945,7 @@ { Error Err = Error::success(); for (auto &Member : Lib.children(Err)) - addChildMember(NewMembers, Member); + addChildMember(NewMembers, Member, /*FlattenArchive=*/Thin); failIfError(std::move(Err)); } break; @@ -951,7 +997,6 @@ static int ar_main(int argc, char **argv) { SmallVector Argv(argv, argv + argc); - BumpPtrAllocator Alloc; StringSaver Saver(Alloc); cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, Argv); for (size_t i = 1; i < Argv.size(); ++i) {