llvm.org GIT mirror llvm / 19263d1
[llvm-ar] Flatten thin archives. Summary: Normal behavior for GNU ar is to flatten thin archives when adding them to another thin archive, i.e. add the members directly instead of nesting the archive. Some refactoring done as part of this patch to ease things: - Consolidate `addMember`/`addLibMember` methods - Rename `addMember` to `addChildMember` to make it more visibly different at the call site that an archive child is passed instead of a regular member - Pass in a separate vector and splice it back into position instead of passing a vector + optional Pos (which makes expanding libs tricky) This fixes PR37530 as raised by https://github.com/ClangBuiltLinux/linux/issues/279. Reviewers: mstorsjo, pcc, ruiu Reviewed By: mstorsjo Subscribers: llvm-commits, tpimh, nickdesaulniers Differential Revision: https://reviews.llvm.org/D56508 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@351120 91177308-0d34-0410-b5e6-96231b3b80d8 Jordan Rupprecht 7 months ago
9 changed file(s) with 96 addition(s) and 48 deletion(s). Raw diff Collapse all Expand all
0 !
1 // 14 `
2 a.txt/
3 b.txt/
4 /0 0 0 0 644 11 `
5 /7 0 0 0 644 11 `
0 !
1 // 20 `
2 a-plus-b.a/
3 c.txt/
4
5 /0 0 0 0 644 202 `
6 /12 0 0 0 644 11 `
0 # Since llvm-ar cannot create thin archives that contain any thin archives,
1 # nested-thin-archive.a is a manually constructed thin archive that contains
2 # another (unflattened) thin archive.
3 # This test ensures that flat archives are recursively flattened.
4
5 RUN: rm -f %t.a
6 RUN: llvm-ar rcsT %t.a %S/Inputs/nested-thin-archive.a %S/Inputs/d.txt
7 RUN: llvm-ar t %t.a | FileCheck %s
8
9 CHECK: a.txt
10 CHECK-NEXT: b.txt
11 CHECK-NEXT: c.txt
12 CHECK-NEXT: d.txt
0 # This test creates a thin archive that contains a thin archive, a regular
1 # archive, and a file.
2 #
3 # The inner thin archive should be flattened, but the regular archive should
4 # not. The order of members in the archive should match the input order, with
5 # flattened members appearing together.
6
7 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
9 RUN: llvm-ar rcsT %t-a-plus-b.a %t-a.txt %t-b.txt
10 RUN: llvm-ar rcs %t-d-plus-e.a %t-d.txt %t-e.txt
11 RUN: llvm-ar rcsT %t.a %t-a-plus-b.a %t-c.txt %t-d-plus-e.a
12 RUN: llvm-ar t %t.a | FileCheck %s
13
14 CHECK: a.txt
15 CHECK-NEXT: b.txt
16 CHECK-NEXT: c.txt
17 CHECK-NEXT: -d-plus-e.a
535535 exit(1);
536536 }
537537
538 static void addMember(std::vector &Members,
539 StringRef FileName, int Pos = -1) {
540 Expected NMOrErr =
541 NewArchiveMember::getFile(FileName, Deterministic);
542 failIfError(NMOrErr.takeError(), FileName);
543
544 // Use the basename of the object path for the member name.
545 NMOrErr->MemberName = sys::path::filename(NMOrErr->MemberName);
546
547 if (Pos == -1)
548 Members.push_back(std::move(*NMOrErr));
549 else
550 Members[Pos] = std::move(*NMOrErr);
551 }
552
553 static void addMember(std::vector &Members,
554 const object::Archive::Child &M, int Pos = -1) {
538 static void addChildMember(std::vector &Members,
539 const object::Archive::Child &M,
540 bool FlattenArchive = false) {
555541 if (Thin && !M.getParent()->isThin())
556542 fail("Cannot convert a regular archive to a thin one");
557543 Expected NMOrErr =
558544 NewArchiveMember::getOldMember(M, Deterministic);
559545 failIfError(NMOrErr.takeError());
560 if (Pos == -1)
561 Members.push_back(std::move(*NMOrErr));
562 else
563 Members[Pos] = std::move(*NMOrErr);
564 }
565
566 static void addLibMember(std::vector &Members,
567 StringRef FileName) {
546 if (FlattenArchive &&
547 identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) {
548 Expected FileNameOrErr = M.getName();
549 failIfError(FileNameOrErr.takeError());
550 object::Archive &Lib = readLibrary(*FileNameOrErr);
551 // When creating thin archives, only flatten if the member is also thin.
552 if (!Thin || Lib.isThin()) {
553 Error Err = Error::success();
554 // Only Thin archives are recursively flattened.
555 for (auto &Child : Lib.children(Err))
556 addChildMember(Members, Child, /*FlattenArchive=*/Thin);
557 failIfError(std::move(Err));
558 return;
559 }
560 }
561 Members.push_back(std::move(*NMOrErr));
562 }
563
564 static void addMember(std::vector &Members,
565 StringRef FileName, bool FlattenArchive = false) {
568566 Expected NMOrErr =
569567 NewArchiveMember::getFile(FileName, Deterministic);
570568 failIfError(NMOrErr.takeError(), FileName);
571 if (identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) {
569 if (FlattenArchive &&
570 identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) {
572571 object::Archive &Lib = readLibrary(FileName);
573 Error Err = Error::success();
574
575 for (auto &Child : Lib.children(Err))
576 addMember(Members, Child);
577
578 failIfError(std::move(Err));
579 } else {
580 // Use the basename of the object path for the member name.
581 NMOrErr->MemberName = sys::path::filename(NMOrErr->MemberName);
582 Members.push_back(std::move(*NMOrErr));
583 }
572 // When creating thin archives, only flatten if the member is also thin.
573 if (!Thin || Lib.isThin()) {
574 Error Err = Error::success();
575 // Only Thin archives are recursively flattened.
576 for (auto &Child : Lib.children(Err))
577 addChildMember(Members, Child, /*FlattenArchive=*/Thin);
578 failIfError(std::move(Err));
579 return;
580 }
581 }
582 // Use the basename of the object path for the member name.
583 NMOrErr->MemberName = sys::path::filename(NMOrErr->MemberName);
584 Members.push_back(std::move(*NMOrErr));
584585 }
585586
586587 enum InsertAction {
669670 computeInsertAction(Operation, Child, Name, MemberI);
670671 switch (Action) {
671672 case IA_AddOldMember:
672 addMember(Ret, Child);
673 addChildMember(Ret, Child);
673674 break;
674675 case IA_AddNewMember:
675676 addMember(Ret, *MemberI);
677678 case IA_Delete:
678679 break;
679680 case IA_MoveOldMember:
680 addMember(Moved, Child);
681 addChildMember(Moved, Child);
681682 break;
682683 case IA_MoveNewMember:
683684 addMember(Moved, *MemberI);
708709 if (AddLibrary) {
709710 assert(Operation == QuickAppend);
710711 for (auto &Member : Members)
711 addLibMember(Ret, Member);
712 addMember(Ret, Member, /*FlattenArchive=*/true);
712713 return Ret;
713714 }
714715
715 for (unsigned I = 0; I != Members.size(); ++I)
716 Ret.insert(Ret.begin() + InsertPos, NewArchiveMember());
717 Pos = InsertPos;
718 for (auto &Member : Members) {
719 addMember(Ret, Member, Pos);
720 ++Pos;
721 }
716 std::vector NewMembers;
717 for (auto &Member : Members)
718 addMember(NewMembers, Member, /*FlattenArchive=*/Thin);
719 Ret.reserve(Ret.size() + NewMembers.size());
720 std::move(NewMembers.begin(), NewMembers.end(),
721 std::inserter(Ret, std::next(Ret.begin(), InsertPos)));
722722
723723 return Ret;
724724 }
896896 {
897897 Error Err = Error::success();
898898 for (auto &Member : Lib.children(Err))
899 addMember(NewMembers, Member);
899 addChildMember(NewMembers, Member);
900900 failIfError(std::move(Err));
901901 }
902902 break;