[llvm] bf223e4 - [llvm-ar] Add --output to specify output directory

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 29 10:00:47 PDT 2022


Author: Fangrui Song
Date: 2022-06-29T10:00:43-07:00
New Revision: bf223e43fe68da22f185a12c1a2fe36a726f4fe9

URL: https://github.com/llvm/llvm-project/commit/bf223e43fe68da22f185a12c1a2fe36a726f4fe9
DIFF: https://github.com/llvm/llvm-project/commit/bf223e43fe68da22f185a12c1a2fe36a726f4fe9.diff

LOG: [llvm-ar] Add --output to specify output directory

>From binutils 2.34 onwards, ar supports --output to specify a directory
where archive members should be extracted to. Port this feature.

Reviewed By: jhenderson

Differential Revision: https://reviews.llvm.org/D128626

Added: 
    

Modified: 
    llvm/docs/CommandGuide/llvm-ar.rst
    llvm/test/tools/llvm-ar/absolute-paths.test
    llvm/test/tools/llvm-ar/extract.test
    llvm/tools/llvm-ar/llvm-ar.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/docs/CommandGuide/llvm-ar.rst b/llvm/docs/CommandGuide/llvm-ar.rst
index 0f3625274fa7..6d594f49fbb9 100644
--- a/llvm/docs/CommandGuide/llvm-ar.rst
+++ b/llvm/docs/CommandGuide/llvm-ar.rst
@@ -274,6 +274,11 @@ Other
  This option allows for MRI scripts to be read through the standard input
  stream. No other options are compatible with this option.
 
+.. option:: --output=<dir>
+
+ Specify a directory where archive members should be extracted to. By default the
+ current working directory is used.
+
 .. option:: --rsp-quoting=<type>
  This option selects the quoting style ``<type>`` for response files, either
  ``posix`` or ``windows``. The default when on Windows is ``windows``, otherwise the

diff  --git a/llvm/test/tools/llvm-ar/absolute-paths.test b/llvm/test/tools/llvm-ar/absolute-paths.test
index b24c67088218..175b5ba994c8 100644
--- a/llvm/test/tools/llvm-ar/absolute-paths.test
+++ b/llvm/test/tools/llvm-ar/absolute-paths.test
@@ -26,3 +26,7 @@ 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
+
+RUN: mkdir dir
+RUN: llvm-ar x %S/Inputs/absolute-paths.lib --output=dir/
+RUN: cmp a.o dir/a.o

diff  --git a/llvm/test/tools/llvm-ar/extract.test b/llvm/test/tools/llvm-ar/extract.test
index d680e3e84838..ccad703f3a14 100644
--- a/llvm/test/tools/llvm-ar/extract.test
+++ b/llvm/test/tools/llvm-ar/extract.test
@@ -34,3 +34,21 @@
 # RUN: llvm-ar x %t/archive.a 2>&1 | count 0
 # RUN: 
diff  %t/a.txt %t/extracted/a.txt
 # RUN: 
diff  %t/b.txt %t/extracted/b.txt
+
+## --output specifies the directory to extract archive members to. `1/2` is created by llvm-ar.
+# RUN: llvm-ar --output=1/2 x %t/archive.a
+# RUN: 
diff  %t/a.txt %t/extracted/1/2/a.txt
+# RUN: 
diff  %t/b.txt %t/extracted/1/2/b.txt
+
+## --output can be used with an absolute path and can be specified elsewhere on the command line.
+# RUN: rm 1/2/a.txt
+# RUN: llvm-ar xv %t/archive.a a.txt --output %t/extracted/1/2/../2 | FileCheck %s --check-prefix=OUTPUT-A
+# RUN: 
diff  %t/a.txt %t/extracted/1/2/a.txt
+# OUTPUT-A: x - {{.*}}extracted{{.*}}a.txt
+
+# RUN: not llvm-ar x --output=%t/a.txt %t/archive.a 2>&1 | FileCheck %s --check-prefix=OUTPUT-NOTDIR
+# RUN: not llvm-ar x --output=%t/b.txt/a.txt %t/archive.a 2>&1 | FileCheck %s --check-prefix=OUTPUT-NOTDIR
+# OUTPUT-NOTDIR: error: '{{.*}}a.txt' is not a directory
+
+# RUN: not llvm-ar rc --output=1/2 %t/archive.a %t/a.txt 2>&1 | FileCheck %s --check-prefix=OUTPUT-ERR
+# OUTPUT-ERR: error: --output is only applicable to the 'x' operation

diff  --git a/llvm/tools/llvm-ar/llvm-ar.cpp b/llvm/tools/llvm-ar/llvm-ar.cpp
index 29b41ecf4833..e964dc8256a5 100644
--- a/llvm/tools/llvm-ar/llvm-ar.cpp
+++ b/llvm/tools/llvm-ar/llvm-ar.cpp
@@ -85,6 +85,7 @@ static void printArHelp(StringRef ToolName) {
     =aix                -   aix (big archive)
   --plugin=<string>     - ignored for compatibility
   -h --help             - display this help and exit
+  --output              - the directory to extract archive members to
   --rsp-quoting         - quoting style for response files
     =posix              -   posix
     =windows            -   windows
@@ -237,6 +238,9 @@ static int CountParam = 0;
 // command line.
 static std::string ArchiveName;
 
+// Output directory specified by --output.
+static std::string OutputDir;
+
 static std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
 static std::vector<std::unique_ptr<object::Archive>> Archives;
 
@@ -454,6 +458,19 @@ static ArchiveOperation parseCommandLine() {
   if (AddLibrary && Operation != QuickAppend)
     badUsage("the 'L' modifier is only applicable to the 'q' operation");
 
+  if (!OutputDir.empty()) {
+    if (Operation != Extract)
+      badUsage("--output is only applicable to the 'x' operation");
+    bool IsDir = false;
+    // If OutputDir is not a directory, create_directories may still succeed if
+    // all components of the path prefix are directories. Test is_directory as
+    // well.
+    if (!sys::fs::create_directories(OutputDir))
+      sys::fs::is_directory(OutputDir, IsDir);
+    if (!IsDir)
+      fail("'" + OutputDir + "' is not a directory");
+  }
+
   // Return the parsed operation to the caller
   return Operation;
 }
@@ -554,7 +571,15 @@ static void doExtract(StringRef Name, const object::Archive::Child &C) {
   failIfError(ModeOrErr.takeError());
   sys::fs::perms Mode = ModeOrErr.get();
 
-  llvm::StringRef outputFilePath = sys::path::filename(Name);
+  StringRef outputFilePath;
+  SmallString<128> path;
+  if (OutputDir.empty()) {
+    outputFilePath = sys::path::filename(Name);
+  } else {
+    sys::path::append(path, OutputDir, sys::path::filename(Name));
+    outputFilePath = path.str();
+  }
+
   if (Verbose)
     outs() << "x - " << outputFilePath << '\n';
 
@@ -1224,6 +1249,11 @@ static int ar_main(int argc, char **argv) {
       continue;
     }
 
+    if ((Match = matchFlagWithArg("output", ArgIt, Argv))) {
+      OutputDir = Match;
+      continue;
+    }
+
     if (matchFlagWithArg("plugin", ArgIt, Argv) ||
         matchFlagWithArg("rsp-quoting", ArgIt, Argv))
       continue;


        


More information about the llvm-commits mailing list