llvm.org GIT mirror llvm / 0978a16
[llvm-ar][libObject] Fix relative paths when nesting thin archives. Summary: When adding one thin archive to another, we currently chop off the relative path to the flattened members. For instance, when adding `foo/child.a` (which contains `x.txt`) to `parent.a`, when flattening it we should add it as `foo/x.txt` (which exists) instead of `x.txt` (which does not exist). As a note, this also undoes the `IsNew` parameter of handling relative paths in r288280. The unit test there still passes. This was reported as part of testing the kernel build with llvm-ar: https://patchwork.kernel.org/patch/10767545/ (see the second point). Reviewers: mstorsjo, pcc, ruiu, davide, david2050, inglorion Reviewed By: ruiu Subscribers: void, jdoerfert, tpimh, mgorny, hans, nickdesaulniers, hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D57842 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@353995 91177308-0d34-0410-b5e6-96231b3b80d8 Jordan Rupprecht 6 months ago
8 changed file(s) with 115 addition(s) and 72 deletion(s). Raw diff Collapse all Expand all
2525 sys::TimePoint ModTime;
2626 unsigned UID = 0, GID = 0, Perms = 0644;
2727
28 bool IsNew = false;
2928 NewArchiveMember() = default;
3029 NewArchiveMember(MemoryBufferRef BufRef);
3130
3635 bool Deterministic);
3736 };
3837
38 std::string computeArchiveRelativePath(StringRef From, StringRef To);
39
3940 Error writeArchive(StringRef ArcName, ArrayRef NewMembers,
4041 bool WriteSymtab, object::Archive::Kind Kind,
4142 bool Deterministic, bool Thin,
4747 return BufOrErr.takeError();
4848
4949 NewArchiveMember M;
50 assert(M.IsNew == false);
5150 M.Buf = MemoryBuffer::getMemBuffer(*BufOrErr, false);
5251 M.MemberName = M.Buf->getBufferIdentifier();
5352 if (!Deterministic) {
9796 return errorCodeToError(std::error_code(errno, std::generic_category()));
9897
9998 NewArchiveMember M;
100 M.IsNew = true;
10199 M.Buf = std::move(*MemberBufferOrErr);
102100 M.MemberName = M.Buf->getBufferIdentifier();
103101 if (!Deterministic) {
190188 return Thin || Name.size() >= 16 || Name.contains('/');
191189 }
192190
193 // Compute the relative path from From to To.
194 static std::string computeRelativePath(StringRef From, StringRef To) {
195 if (sys::path::is_absolute(From) || sys::path::is_absolute(To))
196 return To;
197
198 StringRef DirFrom = sys::path::parent_path(From);
199 auto FromI = sys::path::begin(DirFrom);
200 auto ToI = sys::path::begin(To);
201 while (*FromI == *ToI) {
202 ++FromI;
203 ++ToI;
204 }
205
206 SmallString<128> Relative;
207 for (auto FromE = sys::path::end(DirFrom); FromI != FromE; ++FromI)
208 sys::path::append(Relative, "..");
209
210 for (auto ToE = sys::path::end(To); ToI != ToE; ++ToI)
211 sys::path::append(Relative, *ToI);
212
213 #ifdef _WIN32
214 // Replace backslashes with slashes so that the path is portable between *nix
215 // and Windows.
216 std::replace(Relative.begin(), Relative.end(), '\\', '/');
217 #endif
218
219 return Relative.str();
220 }
221
222191 static bool is64BitKind(object::Archive::Kind Kind) {
223192 switch (Kind) {
224193 case object::Archive::K_GNU:
233202 llvm_unreachable("not supported for writting");
234203 }
235204
236 static void addToStringTable(raw_ostream &Out, StringRef ArcName,
237 const NewArchiveMember &M, bool Thin) {
238 StringRef ID = M.Buf->getBufferIdentifier();
239 if (Thin) {
240 if (M.IsNew)
241 Out << computeRelativePath(ArcName, ID);
242 else
243 Out << ID;
244 } else
245 Out << M.MemberName;
246 Out << "/\n";
247 }
248
249 static void printMemberHeader(raw_ostream &Out, uint64_t Pos,
250 raw_ostream &StringTable,
251 StringMap &MemberNames,
252 object::Archive::Kind Kind, bool Thin,
253 StringRef ArcName, const NewArchiveMember &M,
254 sys::TimePoint ModTime,
255 unsigned Size) {
256
205 static void
206 printMemberHeader(raw_ostream &Out, uint64_t Pos, raw_ostream &StringTable,
207 StringMap &MemberNames, object::Archive::Kind Kind,
208 bool Thin, const NewArchiveMember &M,
209 sys::TimePoint ModTime, unsigned Size) {
257210 if (isBSDLike(Kind))
258211 return printBSDMemberHeader(Out, Pos, M.MemberName, ModTime, M.UID, M.GID,
259212 M.Perms, Size);
264217 uint64_t NamePos;
265218 if (Thin) {
266219 NamePos = StringTable.tell();
267 addToStringTable(StringTable, ArcName, M, Thin);
220 StringTable << M.MemberName << "/\n";
268221 } else {
269222 auto Insertion = MemberNames.insert({M.MemberName, uint64_t(0)});
270223 if (Insertion.second) {
271224 Insertion.first->second = StringTable.tell();
272 addToStringTable(StringTable, ArcName, M, Thin);
225 StringTable << M.MemberName << "/\n";
273226 }
274227 NamePos = Insertion.first->second;
275228 }
431384
432385 static Expected>
433386 computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
434 object::Archive::Kind Kind, bool Thin, StringRef ArcName,
435 bool Deterministic, ArrayRef NewMembers) {
387 object::Archive::Kind Kind, bool Thin, bool Deterministic,
388 ArrayRef NewMembers) {
436389 static char PaddingData[8] = {'\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'};
437390
438391 // This ignores the symbol table, but we only need the value mod 8 and the
519472 ModTime = sys::toTimePoint(FilenameCount[M.MemberName]++);
520473 else
521474 ModTime = M.ModTime;
522 printMemberHeader(Out, Pos, StringTable, MemberNames, Kind, Thin, ArcName,
523 M, ModTime, Buf.getBufferSize() + MemberPadding);
475 printMemberHeader(Out, Pos, StringTable, MemberNames, Kind, Thin, M,
476 ModTime, Buf.getBufferSize() + MemberPadding);
524477 Out.flush();
525478
526479 Expected> Symbols =
539492 return Ret;
540493 }
541494
542 Error llvm::writeArchive(StringRef ArcName,
543 ArrayRef NewMembers,
544 bool WriteSymtab, object::Archive::Kind Kind,
545 bool Deterministic, bool Thin,
546 std::unique_ptr OldArchiveBuf) {
495 namespace llvm {
496 // Compute the relative path from From to To.
497 std::string computeArchiveRelativePath(StringRef From, StringRef To) {
498 if (sys::path::is_absolute(From) || sys::path::is_absolute(To))
499 return To;
500
501 StringRef DirFrom = sys::path::parent_path(From);
502 auto FromI = sys::path::begin(DirFrom);
503 auto ToI = sys::path::begin(To);
504 while (*FromI == *ToI) {
505 ++FromI;
506 ++ToI;
507 }
508
509 SmallString<128> Relative;
510 for (auto FromE = sys::path::end(DirFrom); FromI != FromE; ++FromI)
511 sys::path::append(Relative, "..");
512
513 for (auto ToE = sys::path::end(To); ToI != ToE; ++ToI)
514 sys::path::append(Relative, *ToI);
515
516 #ifdef _WIN32
517 // Replace backslashes with slashes so that the path is portable between *nix
518 // and Windows.
519 std::replace(Relative.begin(), Relative.end(), '\\', '/');
520 #endif
521
522 return Relative.str();
523 }
524
525 Error writeArchive(StringRef ArcName, ArrayRef NewMembers,
526 bool WriteSymtab, object::Archive::Kind Kind,
527 bool Deterministic, bool Thin,
528 std::unique_ptr OldArchiveBuf) {
547529 assert((!Thin || !isBSDLike(Kind)) && "Only the gnu format has a thin mode");
548530
549531 SmallString<0> SymNamesBuf;
552534 raw_svector_ostream StringTable(StringTableBuf);
553535
554536 Expected> DataOrErr = computeMemberData(
555 StringTable, SymNames, Kind, Thin, ArcName, Deterministic, NewMembers);
537 StringTable, SymNames, Kind, Thin, Deterministic, NewMembers);
556538 if (Error E = DataOrErr.takeError())
557539 return E;
558540 std::vector &Data = *DataOrErr;
629611
630612 return Temp->keep(ArcName);
631613 }
614
615 } // namespace llvm
0 set(LLVM_LINK_COMPONENTS
1 BinaryFormat
2 Object
3 Option
4 Support
5 )
6
7 set(LLVM_TARGET_DEFINITIONS Options.td)
18 tablegen(LLVM Options.inc -gen-opt-parser-defs)
29 add_public_tablegen_target(LibOptionsTableGen)
207207
208208 // Create an archive file.
209209 std::string OutputPath = getOutputPath(&Args, Members[0]);
210 // llvm-lib uses relative paths for both regular and thin archives, unlike
211 // standard GNU ar, which only uses relative paths for thin archives and
212 // basenames for regular archives.
213 for (NewArchiveMember &Member : Members)
214 Member.MemberName =
215 Saver.save(computeArchiveRelativePath(OutputPath, Member.MemberName));
216
210217 if (Error E =
211218 writeArchive(OutputPath, Members,
212219 /*WriteSymtab=*/true, object::Archive::K_GNU,
0 # This test creates a thin archive in a directory and adds it to a thin archive
1 # in the parent directory. The relative path should be included when flattening
2 # the archive.
3
4 RUN: mkdir -p %t/foo
5 RUN: touch %t/foo/a.txt
6 RUN: rm -f %t/archive.a %t/foo/archive.a
7
8 # These tests must be run in the same directory as %t/archive.a. cd %t is
9 # included on each line to make debugging this test case easier.
10 RUN: cd %t && llvm-ar rcST foo/archive.a foo/a.txt
11 RUN: cd %t && llvm-ar rcST archive.a foo/archive.a
12 RUN: cd %t && llvm-ar t archive.a | FileCheck %s --match-full-lines
13
14 CHECK: foo/a.txt
55 # flattened members appearing together.
66
77 RUN: touch %t-a.txt %t-b.txt %t-c.txt %t-d.txt %t-e.txt
8 RUN: rm -f %t-a-plus-b.a %t.a
8 RUN: rm -f %t-a-plus-b.a %t-d-plus-e.a %t.a
99 RUN: llvm-ar rcsT %t-a-plus-b.a %t-a.txt %t-b.txt
1010 RUN: llvm-ar rcs %t-d-plus-e.a %t-d.txt %t-e.txt
1111 RUN: llvm-ar rcsT %t.a %t-a-plus-b.a %t-c.txt %t-d-plus-e.a
0 RUN: rm -rf %t
1 RUN: mkdir -p %t/foo
2 RUN: cd %t
3
4 RUN: llvm-mc -triple=x86_64-pc-windows-msvc -filetype=obj -o foo/obj.o %S/Inputs/a.s
5
6 RUN: llvm-lib -out:archive.a -llvmlibthin foo/obj.o
7 RUN: llvm-ar t archive.a | FileCheck %s --check-prefix=PARENT-DIR --match-full-lines
8 PARENT-DIR: foo/obj.o
9
10 RUN: llvm-lib -out:foo/archive.a -llvmlibthin foo/obj.o
11 RUN: llvm-ar t foo/archive.a | FileCheck %s --check-prefix=SAME-DIR --match-full-lines
12 SAME-DIR: foo/obj.o
191191 // This variable holds the list of member files to proecess, as given
192192 // on the command line.
193193 static std::vector Members;
194
195 // Static buffer to hold StringRefs.
196 static BumpPtrAllocator Alloc;
194197
195198 // Extract the member filename from the command line for the [relpos] argument
196199 // associated with a, b, and i modifiers
544547 Expected NMOrErr =
545548 NewArchiveMember::getOldMember(M, Deterministic);
546549 failIfError(NMOrErr.takeError());
550 // If the child member we're trying to add is thin, use the path relative to
551 // the archive it's in, so the file resolves correctly.
552 if (Thin && FlattenArchive) {
553 StringSaver Saver(Alloc);
554 Expected FileNameOrErr = M.getFullName();
555 failIfError(FileNameOrErr.takeError());
556 NMOrErr->MemberName =
557 Saver.save(computeArchiveRelativePath(ArchiveName, *FileNameOrErr));
558 }
547559 if (FlattenArchive &&
548560 identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) {
549561 Expected FileNameOrErr = M.getFullName();
567579 Expected NMOrErr =
568580 NewArchiveMember::getFile(FileName, Deterministic);
569581 failIfError(NMOrErr.takeError(), FileName);
582 StringSaver Saver(Alloc);
583 // For regular archives, use the basename of the object path for the member
584 // name. For thin archives, use the full relative paths so the file resolves
585 // correctly.
586 NMOrErr->MemberName =
587 Thin ? Saver.save(computeArchiveRelativePath(ArchiveName, FileName))
588 : sys::path::filename(NMOrErr->MemberName);
570589 if (FlattenArchive &&
571590 identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) {
572591 object::Archive &Lib = readLibrary(FileName);
580599 return;
581600 }
582601 }
583 // Use the basename of the object path for the member name.
584 NMOrErr->MemberName = sys::path::filename(NMOrErr->MemberName);
585602 Members.push_back(std::move(*NMOrErr));
586603 }
587604
671688 computeInsertAction(Operation, Child, Name, MemberI);
672689 switch (Action) {
673690 case IA_AddOldMember:
674 addChildMember(Ret, Child);
691 addChildMember(Ret, Child, /*FlattenArchive=*/Thin);
675692 break;
676693 case IA_AddNewMember:
677694 addMember(Ret, *MemberI);
679696 case IA_Delete:
680697 break;
681698 case IA_MoveOldMember:
682 addChildMember(Moved, Child);
699 addChildMember(Moved, Child, /*FlattenArchive=*/Thin);
683700 break;
684701 case IA_MoveNewMember:
685702 addMember(Moved, *MemberI);
898915 {
899916 Error Err = Error::success();
900917 for (auto &Member : Lib.children(Err))
901 addChildMember(NewMembers, Member);
918 addChildMember(NewMembers, Member, /*FlattenArchive=*/Thin);
902919 failIfError(std::move(Err));
903920 }
904921 break;
950967
951968 static int ar_main(int argc, char **argv) {
952969 SmallVector Argv(argv, argv + argc);
953 BumpPtrAllocator Alloc;
954970 StringSaver Saver(Alloc);
955971 cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, Argv);
956972 for (size_t i = 1; i < Argv.size(); ++i) {