Index: llvm/include/llvm/Object/ArchiveWriter.h =================================================================== --- llvm/include/llvm/Object/ArchiveWriter.h +++ llvm/include/llvm/Object/ArchiveWriter.h @@ -38,8 +38,9 @@ std::pair writeArchive(StringRef ArcName, std::vector &NewMembers, - bool WriteSymtab, object::Archive::Kind Kind, bool Deterministic, - bool Thin, std::unique_ptr OldArchiveBuf = nullptr); + bool WriteSymtab, bool WriteObjPaths, object::Archive::Kind Kind, + bool Deterministic, bool Thin, + std::unique_ptr OldArchiveBuf = nullptr); } #endif Index: llvm/lib/Object/ArchiveWriter.cpp =================================================================== --- llvm/lib/Object/ArchiveWriter.cpp +++ llvm/lib/Object/ArchiveWriter.cpp @@ -183,19 +183,20 @@ Out.write(uint8_t(0)); } -static bool useStringTable(bool Thin, StringRef Name) { - return Thin || Name.size() >= 16; +static bool useStringTable(bool WriteObjPaths, StringRef Name) { + // Force the use of the string table if we're writing full paths. + return WriteObjPaths || Name.size() >= 16; } static void -printMemberHeader(raw_fd_ostream &Out, object::Archive::Kind Kind, bool Thin, - StringRef Name, +printMemberHeader(raw_fd_ostream &Out, object::Archive::Kind Kind, + bool WriteObjPaths, StringRef Name, std::vector::iterator &StringMapIndexIter, const sys::TimePoint &ModTime, unsigned UID, unsigned GID, unsigned Perms, unsigned Size) { if (isBSDLike(Kind)) return printBSDMemberHeader(Out, Name, ModTime, UID, GID, Perms, Size); - if (!useStringTable(Thin, Name)) + if (!useStringTable(WriteObjPaths, Name)) return printGNUSmallMemberHeader(Out, Name, ModTime, UID, GID, Perms, Size); Out << '/'; printWithSpacePadding(Out, *StringMapIndexIter++, 15); @@ -203,7 +204,8 @@ } // Compute the relative path from From to To. -static std::string computeRelativePath(StringRef From, StringRef To) { +static StringRef computeRelativePath(StringRef From, StringRef To, + SmallString<128> &Relative) { if (sys::path::is_absolute(From) || sys::path::is_absolute(To)) return To; @@ -215,31 +217,54 @@ ++ToI; } - SmallString<128> Relative; - for (auto FromE = sys::path::end(DirFrom); FromI != FromE; ++FromI) - sys::path::append(Relative, ".."); + // Use forward slashes everywhere so that our archives look the same on all + // platforms. + // FIXME: Make it possible for 'lld-link.exe /lib' and 'llvm-lib.exe' to make + // archives with backslashes in them. + sys::path::Style Style = sys::path::Style::posix; - for (auto ToE = sys::path::end(To); ToI != ToE; ++ToI) - sys::path::append(Relative, *ToI); + Relative.clear(); + for (auto FromE = sys::path::end(DirFrom); FromI != FromE; ++FromI) + sys::path::append(Relative, Style, ".."); -#ifdef LLVM_ON_WIN32 - // Replace backslashes with slashes so that the path is portable between *nix - // and Windows. - std::replace(Relative.begin(), Relative.end(), '\\', '/'); -#endif + auto ToE = sys::path::end(To); + sys::path::append(Relative, ToI, ToE, Style); return Relative.str(); } +/// There are three kinds of archive member names: +/// 1. Plain filename: foo.o +/// 2. Plain path: lib/bar/foo.o +/// 3. Relative path from archive for thin archives: ../lib/bar/foo.o +static StringRef computeMemberName(StringRef ArchivePath, StringRef ObjPath, + bool WriteObjPaths, bool Thin, + SmallString<128> &Scratch) { + // The non-thin cases are easy: either return the path, or the filename. + if (!Thin) { + if (WriteObjPaths) + return ObjPath; + return sys::path::filename(ObjPath); + } + // In the thin case, compute the relative paths and return that. + return computeRelativePath(ArchivePath, ObjPath, Scratch); +} + static void writeStringTable(raw_fd_ostream &Out, StringRef ArcName, ArrayRef Members, std::vector &StringMapIndexes, - bool Thin) { + bool Thin, bool WriteObjPaths) { + SmallString<128> Scratch; unsigned StartOffset = 0; for (const NewArchiveMember &M : Members) { StringRef Path = M.Buf->getBufferIdentifier(); - StringRef Name = sys::path::filename(Path); - if (!useStringTable(Thin, Name)) + + // Leave the member name alone if it isn't new. + StringRef Name = Path; + if (M.IsNew) + Name = computeMemberName(ArcName, Path, WriteObjPaths, Thin, Scratch); + + if (!useStringTable(WriteObjPaths, Name)) continue; if (StartOffset == 0) { printWithSpacePadding(Out, "//", 58); @@ -248,15 +273,7 @@ } StringMapIndexes.push_back(Out.tell() - StartOffset); - if (Thin) { - if (M.IsNew) - Out << computeRelativePath(ArcName, Path); - else - Out << M.Buf->getBufferIdentifier(); - } else - Out << Name; - - Out << "/\n"; + Out << Name << "/\n"; } if (StartOffset == 0) return; @@ -372,11 +389,12 @@ } std::pair -llvm::writeArchive(StringRef ArcName, - std::vector &NewMembers, - bool WriteSymtab, object::Archive::Kind Kind, - bool Deterministic, bool Thin, +llvm::writeArchive(StringRef ArcName, std::vector &NewMembers, + bool WriteSymtab, bool WriteObjPaths, + object::Archive::Kind Kind, bool Deterministic, bool Thin, std::unique_ptr OldArchiveBuf) { + if (Thin) + assert(WriteObjPaths && "thin archives require paths for archive members"); assert((!Thin || !isBSDLike(Kind)) && "Only the gnu format has a thin mode"); SmallString<128> TmpArchive; int TmpArchiveFD; @@ -404,7 +422,8 @@ std::vector StringMapIndexes; if (!isBSDLike(Kind)) - writeStringTable(Out, ArcName, NewMembers, StringMapIndexes, Thin); + writeStringTable(Out, ArcName, NewMembers, StringMapIndexes, Thin, + WriteObjPaths); std::vector::iterator StringMapIndexIter = StringMapIndexes.begin(); std::vector MemberOffset; @@ -422,7 +441,7 @@ if (Kind == object::Archive::K_DARWIN) Padding = OffsetToAlignment(M.Buf->getBufferSize(), 8); - printMemberHeader(Out, Kind, Thin, + printMemberHeader(Out, Kind, WriteObjPaths, sys::path::filename(M.Buf->getBufferIdentifier()), StringMapIndexIter, M.ModTime, M.UID, M.GID, M.Perms, M.Buf->getBufferSize() + Padding); Index: llvm/lib/Object/COFFImportFile.cpp =================================================================== --- llvm/lib/Object/COFFImportFile.cpp +++ llvm/lib/Object/COFFImportFile.cpp @@ -516,10 +516,9 @@ OF.createShortImport(*Name, E.Ordinal, ImportType, NameType)); } - std::pair Result = - writeArchive(Path, Members, /*WriteSymtab*/ true, object::Archive::K_GNU, - /*Deterministic*/ true, /*Thin*/ false); - + std::pair Result = writeArchive( + Path, Members, /*WriteSymtab=*/true, /*WriteObjPaths=*/true, + object::Archive::K_GNU, /*Deterministic=*/true, /*Thin=*/false); return Result.second; } Index: llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp =================================================================== --- llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp +++ llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp @@ -155,10 +155,10 @@ Members.emplace_back(std::move(*MOrErr)); } - std::pair Result = - llvm::writeArchive(getOutputPath(&Args, Members[0]), Members, - /*WriteSymtab=*/true, object::Archive::K_GNU, - /*Deterministic*/ true, Args.hasArg(OPT_llvmlibthin)); + std::pair Result = llvm::writeArchive( + getOutputPath(&Args, Members[0]), Members, /*WriteSymtab=*/true, + /*WriteObjPaths=*/true, object::Archive::K_GNU, /*Deterministic=*/true, + Args.hasArg(OPT_llvmlibthin)); if (Result.second) { if (Result.first.empty()) Index: llvm/test/LibDriver/use-paths.test =================================================================== --- /dev/null +++ llvm/test/LibDriver/use-paths.test @@ -0,0 +1,24 @@ +llvm-lib should behave like "link.exe /lib" and use relative paths to describe +archive members. + +First, get in a clean working directory. +RUN: rm -rf %t && mkdir -p %t && cd %t + +Make foo/a.obj and foo/b.obj. +RUN: mkdir foo +RUN: llvm-mc -triple=x86_64-pc-windows-msvc -filetype=obj -o foo/a.obj %S/Inputs/a.s +RUN: llvm-mc -triple=x86_64-pc-windows-msvc -filetype=obj -o foo/b.obj %S/Inputs/b.s + +RUN: llvm-lib -out:foo.lib foo/a.obj foo/b.obj +RUN: llvm-ar t foo.lib | FileCheck %s + +FIXME: We should probably use backslashes on Windows to better match MSVC tools. +CHECK: foo/a.obj +CHECK: foo/b.obj + +Do it again with absolute paths and see that we get something. +RUN: llvm-lib -out:foo.lib %t/foo/a.obj %t/foo/b.obj +RUN: llvm-ar t foo.lib | FileCheck %s --check-prefix=ABS + +ABS: {{.*}}/foo/a.obj +ABS: {{.*}}/foo/b.obj Index: llvm/tools/llvm-ar/llvm-ar.cpp =================================================================== --- llvm/tools/llvm-ar/llvm-ar.cpp +++ llvm/tools/llvm-ar/llvm-ar.cpp @@ -685,7 +685,8 @@ std::pair Result = writeArchive(ArchiveName, NewMembersP ? *NewMembersP : NewMembers, Symtab, - Kind, Deterministic, Thin, std::move(OldArchiveBuf)); + /*WriteObjPaths=*/Thin, Kind, Deterministic, Thin, + std::move(OldArchiveBuf)); failIfError(Result.second, Result.first); }