[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