llvm.org GIT mirror llvm / 2c8ca87
[llvm-ar] Implement the P modifier. Summary: GNU ar has a `P` modifier that changes filename comparisons to use full paths instead of the basename. As noted in the GNU docs, regular archives are not created with full path names, so P is used to deal with archives created by other archive programs (e.g. see the updated `absolute-paths.test` test case). Since thin archives use full path names -- paths are relative to the archive -- it seems very error prone to not imply P when dealing with thin archives, so P is implied in those cases. (I think this is a deviation from GNU ar that makes sense). This fixes PR37436 via https://github.com/ClangBuiltLinux/linux/issues/33. Reviewers: mstorsjo, pcc, ruiu, davide, david2050, rnk Subscribers: tpimh, llvm-commits, nickdesaulniers Tags: #llvm Differential Revision: https://reviews.llvm.org/D57927 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@354044 91177308-0d34-0410-b5e6-96231b3b80d8 Jordan Rupprecht 6 months ago
3 changed file(s) with 149 addition(s) and 19 deletion(s). Raw diff Collapse all Expand all
99 CHECK-LIST: C:/src/llvm-project/build/dne/a.o
1010
1111 Check that a.o comes out and defines foo.
12 RUN: llvm-ar x %S/Inputs/absolute-paths.lib 'C:/src/llvm-project/build/dne/a.o'
12 RUN: llvm-ar xP %S/Inputs/absolute-paths.lib 'C:/src/llvm-project/build/dne/a.o'
1313 RUN: llvm-nm a.o | FileCheck %s --check-prefix=CHECK-A
1414 CHECK-A: T foo
1515
1616 Check that b.o comes out and defines bar.
17 RUN: llvm-ar x %S/Inputs/absolute-paths.lib C:/src/llvm-project/build/dne/b.o
17 RUN: llvm-ar xP %S/Inputs/absolute-paths.lib C:/src/llvm-project/build/dne/b.o
1818 RUN: llvm-nm b.o | FileCheck %s --check-prefix=CHECK-B
1919 CHECK-B: T bar
20
21 xP above is only required because we were explicitly extracting items from an
22 archive with absolute paths. Extracting all objects doesn't need P because we
23 aren't explicitly requesting any individual object.
24 RUN: rm -f a.o b.o
25 RUN: llvm-ar x %S/Inputs/absolute-paths.lib
26 RUN: llvm-nm a.o | FileCheck %s --check-prefix=CHECK-A
27 RUN: llvm-nm b.o | FileCheck %s --check-prefix=CHECK-B
0 # Note: many of these tests depend on relative paths, so we have to cd to a
1 # test directory first.
2 RUN: mkdir -p %t && cd %t
3 RUN: rm -rf a b && mkdir a b
4 RUN: echo hello-a > a/foo.txt
5 RUN: echo hello-b > b/foo.txt
6 RUN: echo hello-parent > foo.txt
7
8 # Sanity test that P is accepted.
9 RUN: rm -f noop.a && llvm-ar rcP noop.a foo.txt
10 RUN: llvm-ar p noop.a | FileCheck %s --check-prefix=ACCEPT
11
12 ACCEPT: hello-parent
13
14 # Regular (non-thin) archives cannot be created with full path names as
15 # members, but P can still affect how lookup works (assuming we're reading an
16 # archive not created by GNU ar or llvm-ar).
17 # Looking up a/foo.txt in a regular archive will fail with P because it is
18 # added to the archive as foo.txt.
19 RUN: rm -f display.a
20 RUN: llvm-ar rcS display.a a/foo.txt foo.txt b/foo.txt
21 RUN: llvm-ar t display.a a/foo.txt | FileCheck %s --check-prefix=DISPLAY-FOUND --match-full-lines
22 RUN: not llvm-ar tP display.a a/foo.txt 2>&1 | FileCheck %s --check-prefix=DISPLAY-NOT-FOUND
23
24 DISPLAY-FOUND: foo.txt
25 DISPLAY-NOT-FOUND: 'a/foo.txt' was not found
26
27 # Deleting will fail with P because the members exist as foo.txt, not a/foo.txt.
28 RUN: rm -f del1.a
29 RUN: llvm-ar rcS del1.a foo.txt
30 RUN: llvm-ar dP del1.a a/foo.txt
31 RUN: llvm-ar t del1.a a/foo.txt | FileCheck %s --check-prefix=DISPLAY-FOUND --match-full-lines
32 RUN: llvm-ar d del1.a a/foo.txt
33 RUN: not llvm-ar t del1.a a/foo.txt 2>&1 | FileCheck %s --check-prefix=DISPLAY-NOT-FOUND
34
35 # Run several checks that P is implied when using thin archives. None of these
36 # checks explicitly use P.
37
38 # Creating an archive in one step.
39 RUN: rm -f add.a
40 RUN: llvm-ar rcST add.a a/foo.txt foo.txt b/foo.txt
41 RUN: llvm-ar t add.a | FileCheck %s --check-prefix=ADD --match-full-lines
42
43 ADD: a/foo.txt
44 ADD-NEXT: foo.txt
45 ADD-NEXT: b/foo.txt
46
47 # Create an archive incrementally.
48 RUN: rm -f add-inc.a
49 RUN: llvm-ar rcST add-inc.a a/foo.txt
50 RUN: llvm-ar rcST add-inc.a foo.txt
51 RUN: llvm-ar rcST add-inc.a b/foo.txt
52 RUN: llvm-ar t add-inc.a | FileCheck %s --check-prefix=ADD-INC --match-full-lines
53
54 ADD-INC: a/foo.txt
55 ADD-INC-NEXT: foo.txt
56 ADD-INC-NEXT: b/foo.txt
57
58 # Nesting a thin archive with a name conflict.
59 RUN: rm -f a/nested.a b/nested.a nested.a
60 RUN: llvm-ar rcST a/nested.a a/foo.txt
61 RUN: llvm-ar rcST b/nested.a b/foo.txt
62 RUN: llvm-ar rcST nested.a a/nested.a foo.txt b/nested.a
63 RUN: llvm-ar t nested.a | FileCheck %s --check-prefix=NESTED --match-full-lines
64
65 NESTED: a/foo.txt
66 NESTED-NEXT: foo.txt
67 NESTED-NEXT: b/foo.txt
68
69 # Printing members.
70 RUN: rm -f add.a
71 RUN: llvm-ar rcST add.a a/foo.txt foo.txt b/foo.txt
72 RUN: llvm-ar p add.a foo.txt | FileCheck %s --check-prefix=PRINT-PARENT --match-full-lines
73 RUN: llvm-ar p add.a a/foo.txt | FileCheck %s --check-prefix=PRINT-A --match-full-lines
74 RUN: llvm-ar p add.a b/foo.txt | FileCheck %s --check-prefix=PRINT-B --match-full-lines
75 PRINT-PARENT: hello-parent
76 PRINT-A: hello-a
77 PRINT-B: hello-b
78
79 # Listing members.
80 RUN: rm -f add.a
81 RUN: llvm-ar rcST add.a a/foo.txt foo.txt b/foo.txt
82 RUN: llvm-ar t add.a foo.txt | FileCheck %s --check-prefix=LIST-PARENT --match-full-lines
83 RUN: llvm-ar t add.a a/foo.txt | FileCheck %s --check-prefix=LIST-A --match-full-lines
84 RUN: llvm-ar t add.a b/foo.txt | FileCheck %s --check-prefix=LIST-B --match-full-lines
85 LIST-PARENT: foo.txt
86 LIST-PARENT-NOT: a/foo.txt
87 LIST-PARENT-NOT: b/foo.txt
88 LIST-A: a/foo.txt
89 LIST-B: b/foo.txt
90
91 # Deleting members.
92 RUN: rm -f del1.a
93 RUN: llvm-ar rcST del1.a a/foo.txt foo.txt b/foo.txt
94 RUN: llvm-ar d del1.a foo.txt
95 RUN: llvm-ar t del1.a | FileCheck %s --check-prefix=DEL-1 --match-full-lines
96
97 DEL-1-NOT: foo.txt
98 DEL-1: a/foo.txt
99 DEL-1-NEXT: b/foo.txt
100
101 RUN: rm -f del2.a
102 RUN: llvm-ar rcST del2.a a/foo.txt foo.txt b/foo.txt
103 RUN: llvm-ar d del2.a a/foo.txt
104 RUN: llvm-ar t del2.a | FileCheck %s --check-prefix=DEL-2 --match-full-lines
105 DEL-2-NOT: a/foo.txt
106 DEL-2: foo.txt
107 DEL-2-NEXT: b/foo.txt
9797 [l] - ignored for compatibility
9898 [L] - add archive's contents
9999 [o] - preserve original dates
100 [P] - use full names when matching (implied for thin archives)
100101 [s] - create an archive index (cf. ranlib)
101102 [S] - do not build a symbol table
102103 [T] - create a thin archive
167168 };
168169
169170 // Modifiers to follow operation to vary behavior
170 static bool AddAfter = false; ///< 'a' modifier
171 static bool AddBefore = false; ///< 'b' modifier
172 static bool Create = false; ///< 'c' modifier
173 static bool OriginalDates = false; ///< 'o' modifier
174 static bool OnlyUpdate = false; ///< 'u' modifier
175 static bool Verbose = false; ///< 'v' modifier
176 static bool Symtab = true; ///< 's' modifier
177 static bool Deterministic = true; ///< 'D' and 'U' modifiers
178 static bool Thin = false; ///< 'T' modifier
179 static bool AddLibrary = false; ///< 'L' modifier
171 static bool AddAfter = false; ///< 'a' modifier
172 static bool AddBefore = false; ///< 'b' modifier
173 static bool Create = false; ///< 'c' modifier
174 static bool OriginalDates = false; ///< 'o' modifier
175 static bool CompareFullPath = false; ///< 'P' modifier
176 static bool OnlyUpdate = false; ///< 'u' modifier
177 static bool Verbose = false; ///< 'v' modifier
178 static bool Symtab = true; ///< 's' modifier
179 static bool Deterministic = true; ///< 'D' and 'U' modifiers
180 static bool Thin = false; ///< 'T' modifier
181 static bool AddLibrary = false; ///< 'L' modifier
180182
181183 // Relative Positional Argument (for insert/move). This variable holds
182184 // the name of the archive member to which the 'a', 'b' or 'i' modifier
296298 case 'o':
297299 OriginalDates = true;
298300 break;
301 case 'P':
302 CompareFullPath = true;
303 break;
299304 case 's':
300305 Symtab = true;
301306 MaybeJustCreateSymTab = true;
332337 break;
333338 case 'T':
334339 Thin = true;
340 // Thin archives store path names, so P should be forced.
341 CompareFullPath = true;
335342 break;
336343 case 'L':
337344 AddLibrary = true;
438445 outs() << Name << "\n";
439446 }
440447
448 static StringRef normalizePath(StringRef Path) {
449 return CompareFullPath ? Path : sys::path::filename(Path);
450 }
451
441452 // Implement the 'x' operation. This function extracts files back to the file
442453 // system.
443454 static void doExtract(StringRef Name, const object::Archive::Child &C) {
509520 StringRef Name = NameOrErr.get();
510521
511522 if (Filter) {
512 auto I = find(Members, Name);
523 auto I = find_if(Members, [Name](StringRef Path) {
524 return Name == normalizePath(Path);
525 });
513526 if (I == Members.end())
514527 continue;
515528 Members.erase(I);
617630 if (Operation == QuickAppend || Members.empty())
618631 return IA_AddOldMember;
619632
620 auto MI = find_if(Members, [Name](StringRef Path) {
621 return Name == sys::path::filename(Path);
622 });
633 auto MI = find_if(
634 Members, [Name](StringRef Path) { return Name == normalizePath(Path); });
623635
624636 if (MI == Members.end())
625637 return IA_AddOldMember;
633645 return IA_MoveOldMember;
634646
635647 if (Operation == ReplaceOrInsert) {
636 StringRef PosName = sys::path::filename(RelPos);
648 StringRef PosName = normalizePath(RelPos);
637649 if (!OnlyUpdate) {
638650 if (PosName.empty())
639651 return IA_AddNewMember;
667679 std::vector Ret;
668680 std::vector Moved;
669681 int InsertPos = -1;
670 StringRef PosName = sys::path::filename(RelPos);
682 StringRef PosName = normalizePath(RelPos);
671683 if (OldArchive) {
672684 Error Err = Error::success();
673685 for (auto &Child : OldArchive->children(Err)) {
859871 EC = errorToErrorCode(std::move(Err));
860872 failIfError(EC,
861873 "error loading '" + ArchiveName + "': " + EC.message() + "!");
874 if (Archive.isThin())
875 CompareFullPath = true;
862876 performOperation(Operation, &Archive, std::move(Buf.get()), NewMembers);
863877 return 0;
864878 }
932946 ArchiveName = Rest;
933947 break;
934948 case MRICommand::Delete: {
935 StringRef Name = sys::path::filename(Rest);
949 StringRef Name = normalizePath(Rest);
936950 llvm::erase_if(NewMembers,
937951 [=](NewArchiveMember &M) { return M.MemberName == Name; });
938952 break;