[llvm] r354044 - [llvm-ar] Implement the P modifier.
Jordan Rupprecht via llvm-commits
llvm-commits at lists.llvm.org
Thu Feb 14 10:35:14 PST 2019
Author: rupprecht
Date: Thu Feb 14 10:35:13 2019
New Revision: 354044
URL: http://llvm.org/viewvc/llvm-project?rev=354044&view=rev
Log:
[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
Added:
llvm/trunk/test/tools/llvm-ar/full-path-option.test
Modified:
llvm/trunk/test/tools/llvm-ar/absolute-paths.test
llvm/trunk/tools/llvm-ar/llvm-ar.cpp
Modified: llvm/trunk/test/tools/llvm-ar/absolute-paths.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-ar/absolute-paths.test?rev=354044&r1=354043&r2=354044&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-ar/absolute-paths.test (original)
+++ llvm/trunk/test/tools/llvm-ar/absolute-paths.test Thu Feb 14 10:35:13 2019
@@ -10,11 +10,19 @@ CHECK-LIST: C:/src/llvm-project/build/dn
CHECK-LIST: C:/src/llvm-project/build/dne/a.o
Check that a.o comes out and defines foo.
-RUN: llvm-ar x %S/Inputs/absolute-paths.lib 'C:/src/llvm-project/build/dne/a.o'
+RUN: llvm-ar xP %S/Inputs/absolute-paths.lib 'C:/src/llvm-project/build/dne/a.o'
RUN: llvm-nm a.o | FileCheck %s --check-prefix=CHECK-A
CHECK-A: T foo
Check that b.o comes out and defines bar.
-RUN: llvm-ar x %S/Inputs/absolute-paths.lib C:/src/llvm-project/build/dne/b.o
+RUN: llvm-ar xP %S/Inputs/absolute-paths.lib C:/src/llvm-project/build/dne/b.o
RUN: llvm-nm b.o | FileCheck %s --check-prefix=CHECK-B
CHECK-B: T bar
+
+xP above is only required because we were explicitly extracting items from an
+archive with absolute paths. Extracting all objects doesn't need P because we
+aren't explicitly requesting any individual object.
+RUN: rm -f a.o b.o
+RUN: llvm-ar x %S/Inputs/absolute-paths.lib
+RUN: llvm-nm a.o | FileCheck %s --check-prefix=CHECK-A
+RUN: llvm-nm b.o | FileCheck %s --check-prefix=CHECK-B
Added: llvm/trunk/test/tools/llvm-ar/full-path-option.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-ar/full-path-option.test?rev=354044&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-ar/full-path-option.test (added)
+++ llvm/trunk/test/tools/llvm-ar/full-path-option.test Thu Feb 14 10:35:13 2019
@@ -0,0 +1,108 @@
+# Note: many of these tests depend on relative paths, so we have to cd to a
+# test directory first.
+RUN: mkdir -p %t && cd %t
+RUN: rm -rf a b && mkdir a b
+RUN: echo hello-a > a/foo.txt
+RUN: echo hello-b > b/foo.txt
+RUN: echo hello-parent > foo.txt
+
+# Sanity test that P is accepted.
+RUN: rm -f noop.a && llvm-ar rcP noop.a foo.txt
+RUN: llvm-ar p noop.a | FileCheck %s --check-prefix=ACCEPT
+
+ACCEPT: hello-parent
+
+# Regular (non-thin) archives cannot be created with full path names as
+# members, but P can still affect how lookup works (assuming we're reading an
+# archive not created by GNU ar or llvm-ar).
+# Looking up a/foo.txt in a regular archive will fail with P because it is
+# added to the archive as foo.txt.
+RUN: rm -f display.a
+RUN: llvm-ar rcS display.a a/foo.txt foo.txt b/foo.txt
+RUN: llvm-ar t display.a a/foo.txt | FileCheck %s --check-prefix=DISPLAY-FOUND --match-full-lines
+RUN: not llvm-ar tP display.a a/foo.txt 2>&1 | FileCheck %s --check-prefix=DISPLAY-NOT-FOUND
+
+DISPLAY-FOUND: foo.txt
+DISPLAY-NOT-FOUND: 'a/foo.txt' was not found
+
+# Deleting will fail with P because the members exist as foo.txt, not a/foo.txt.
+RUN: rm -f del1.a
+RUN: llvm-ar rcS del1.a foo.txt
+RUN: llvm-ar dP del1.a a/foo.txt
+RUN: llvm-ar t del1.a a/foo.txt | FileCheck %s --check-prefix=DISPLAY-FOUND --match-full-lines
+RUN: llvm-ar d del1.a a/foo.txt
+RUN: not llvm-ar t del1.a a/foo.txt 2>&1 | FileCheck %s --check-prefix=DISPLAY-NOT-FOUND
+
+# Run several checks that P is implied when using thin archives. None of these
+# checks explicitly use P.
+
+# Creating an archive in one step.
+RUN: rm -f add.a
+RUN: llvm-ar rcST add.a a/foo.txt foo.txt b/foo.txt
+RUN: llvm-ar t add.a | FileCheck %s --check-prefix=ADD --match-full-lines
+
+ADD: a/foo.txt
+ADD-NEXT: foo.txt
+ADD-NEXT: b/foo.txt
+
+# Create an archive incrementally.
+RUN: rm -f add-inc.a
+RUN: llvm-ar rcST add-inc.a a/foo.txt
+RUN: llvm-ar rcST add-inc.a foo.txt
+RUN: llvm-ar rcST add-inc.a b/foo.txt
+RUN: llvm-ar t add-inc.a | FileCheck %s --check-prefix=ADD-INC --match-full-lines
+
+ADD-INC: a/foo.txt
+ADD-INC-NEXT: foo.txt
+ADD-INC-NEXT: b/foo.txt
+
+# Nesting a thin archive with a name conflict.
+RUN: rm -f a/nested.a b/nested.a nested.a
+RUN: llvm-ar rcST a/nested.a a/foo.txt
+RUN: llvm-ar rcST b/nested.a b/foo.txt
+RUN: llvm-ar rcST nested.a a/nested.a foo.txt b/nested.a
+RUN: llvm-ar t nested.a | FileCheck %s --check-prefix=NESTED --match-full-lines
+
+NESTED: a/foo.txt
+NESTED-NEXT: foo.txt
+NESTED-NEXT: b/foo.txt
+
+# Printing members.
+RUN: rm -f add.a
+RUN: llvm-ar rcST add.a a/foo.txt foo.txt b/foo.txt
+RUN: llvm-ar p add.a foo.txt | FileCheck %s --check-prefix=PRINT-PARENT --match-full-lines
+RUN: llvm-ar p add.a a/foo.txt | FileCheck %s --check-prefix=PRINT-A --match-full-lines
+RUN: llvm-ar p add.a b/foo.txt | FileCheck %s --check-prefix=PRINT-B --match-full-lines
+PRINT-PARENT: hello-parent
+PRINT-A: hello-a
+PRINT-B: hello-b
+
+# Listing members.
+RUN: rm -f add.a
+RUN: llvm-ar rcST add.a a/foo.txt foo.txt b/foo.txt
+RUN: llvm-ar t add.a foo.txt | FileCheck %s --check-prefix=LIST-PARENT --match-full-lines
+RUN: llvm-ar t add.a a/foo.txt | FileCheck %s --check-prefix=LIST-A --match-full-lines
+RUN: llvm-ar t add.a b/foo.txt | FileCheck %s --check-prefix=LIST-B --match-full-lines
+LIST-PARENT: foo.txt
+LIST-PARENT-NOT: a/foo.txt
+LIST-PARENT-NOT: b/foo.txt
+LIST-A: a/foo.txt
+LIST-B: b/foo.txt
+
+# Deleting members.
+RUN: rm -f del1.a
+RUN: llvm-ar rcST del1.a a/foo.txt foo.txt b/foo.txt
+RUN: llvm-ar d del1.a foo.txt
+RUN: llvm-ar t del1.a | FileCheck %s --check-prefix=DEL-1 --match-full-lines
+
+DEL-1-NOT: foo.txt
+DEL-1: a/foo.txt
+DEL-1-NEXT: b/foo.txt
+
+RUN: rm -f del2.a
+RUN: llvm-ar rcST del2.a a/foo.txt foo.txt b/foo.txt
+RUN: llvm-ar d del2.a a/foo.txt
+RUN: llvm-ar t del2.a | FileCheck %s --check-prefix=DEL-2 --match-full-lines
+DEL-2-NOT: a/foo.txt
+DEL-2: foo.txt
+DEL-2-NEXT: b/foo.txt
Modified: llvm/trunk/tools/llvm-ar/llvm-ar.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-ar/llvm-ar.cpp?rev=354044&r1=354043&r2=354044&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-ar/llvm-ar.cpp (original)
+++ llvm/trunk/tools/llvm-ar/llvm-ar.cpp Thu Feb 14 10:35:13 2019
@@ -98,6 +98,7 @@ MODIFIERS:
[l] - ignored for compatibility
[L] - add archive's contents
[o] - preserve original dates
+ [P] - use full names when matching (implied for thin archives)
[s] - create an archive index (cf. ranlib)
[S] - do not build a symbol table
[T] - create a thin archive
@@ -168,16 +169,17 @@ enum ArchiveOperation {
};
// Modifiers to follow operation to vary behavior
-static bool AddAfter = false; ///< 'a' modifier
-static bool AddBefore = false; ///< 'b' modifier
-static bool Create = false; ///< 'c' modifier
-static bool OriginalDates = false; ///< 'o' modifier
-static bool OnlyUpdate = false; ///< 'u' modifier
-static bool Verbose = false; ///< 'v' modifier
-static bool Symtab = true; ///< 's' modifier
-static bool Deterministic = true; ///< 'D' and 'U' modifiers
-static bool Thin = false; ///< 'T' modifier
-static bool AddLibrary = false; ///< 'L' modifier
+static bool AddAfter = false; ///< 'a' modifier
+static bool AddBefore = false; ///< 'b' modifier
+static bool Create = false; ///< 'c' modifier
+static bool OriginalDates = false; ///< 'o' modifier
+static bool CompareFullPath = false; ///< 'P' modifier
+static bool OnlyUpdate = false; ///< 'u' modifier
+static bool Verbose = false; ///< 'v' modifier
+static bool Symtab = true; ///< 's' modifier
+static bool Deterministic = true; ///< 'D' and 'U' modifiers
+static bool Thin = false; ///< 'T' modifier
+static bool AddLibrary = false; ///< 'L' modifier
// Relative Positional Argument (for insert/move). This variable holds
// the name of the archive member to which the 'a', 'b' or 'i' modifier
@@ -297,6 +299,9 @@ static ArchiveOperation parseCommandLine
case 'o':
OriginalDates = true;
break;
+ case 'P':
+ CompareFullPath = true;
+ break;
case 's':
Symtab = true;
MaybeJustCreateSymTab = true;
@@ -333,6 +338,8 @@ static ArchiveOperation parseCommandLine
break;
case 'T':
Thin = true;
+ // Thin archives store path names, so P should be forced.
+ CompareFullPath = true;
break;
case 'L':
AddLibrary = true;
@@ -439,6 +446,10 @@ static void doDisplayTable(StringRef Nam
outs() << Name << "\n";
}
+static StringRef normalizePath(StringRef Path) {
+ return CompareFullPath ? Path : sys::path::filename(Path);
+}
+
// Implement the 'x' operation. This function extracts files back to the file
// system.
static void doExtract(StringRef Name, const object::Archive::Child &C) {
@@ -510,7 +521,9 @@ static void performReadOperation(Archive
StringRef Name = NameOrErr.get();
if (Filter) {
- auto I = find(Members, Name);
+ auto I = find_if(Members, [Name](StringRef Path) {
+ return Name == normalizePath(Path);
+ });
if (I == Members.end())
continue;
Members.erase(I);
@@ -618,9 +631,8 @@ static InsertAction computeInsertAction(
if (Operation == QuickAppend || Members.empty())
return IA_AddOldMember;
- auto MI = find_if(Members, [Name](StringRef Path) {
- return Name == sys::path::filename(Path);
- });
+ auto MI = find_if(
+ Members, [Name](StringRef Path) { return Name == normalizePath(Path); });
if (MI == Members.end())
return IA_AddOldMember;
@@ -634,7 +646,7 @@ static InsertAction computeInsertAction(
return IA_MoveOldMember;
if (Operation == ReplaceOrInsert) {
- StringRef PosName = sys::path::filename(RelPos);
+ StringRef PosName = normalizePath(RelPos);
if (!OnlyUpdate) {
if (PosName.empty())
return IA_AddNewMember;
@@ -668,7 +680,7 @@ computeNewArchiveMembers(ArchiveOperatio
std::vector<NewArchiveMember> Ret;
std::vector<NewArchiveMember> Moved;
int InsertPos = -1;
- StringRef PosName = sys::path::filename(RelPos);
+ StringRef PosName = normalizePath(RelPos);
if (OldArchive) {
Error Err = Error::success();
for (auto &Child : OldArchive->children(Err)) {
@@ -860,6 +872,8 @@ static int performOperation(ArchiveOpera
EC = errorToErrorCode(std::move(Err));
failIfError(EC,
"error loading '" + ArchiveName + "': " + EC.message() + "!");
+ if (Archive.isThin())
+ CompareFullPath = true;
performOperation(Operation, &Archive, std::move(Buf.get()), NewMembers);
return 0;
}
@@ -933,7 +947,7 @@ static void runMRIScript() {
ArchiveName = Rest;
break;
case MRICommand::Delete: {
- StringRef Name = sys::path::filename(Rest);
+ StringRef Name = normalizePath(Rest);
llvm::erase_if(NewMembers,
[=](NewArchiveMember &M) { return M.MemberName == Name; });
break;
More information about the llvm-commits
mailing list