[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
This commit is contained in:
Fangrui Song 2022-06-29 10:00:42 -07:00
parent d515211a0c
commit bf223e43fe
4 changed files with 58 additions and 1 deletions

View File

@ -274,6 +274,11 @@ Other
This option allows for MRI scripts to be read through the standard input This option allows for MRI scripts to be read through the standard input
stream. No other options are compatible with this option. 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> .. option:: --rsp-quoting=<type>
This option selects the quoting style ``<type>`` for response files, either This option selects the quoting style ``<type>`` for response files, either
``posix`` or ``windows``. The default when on Windows is ``windows``, otherwise the ``posix`` or ``windows``. The default when on Windows is ``windows``, otherwise the

View File

@ -26,3 +26,7 @@ RUN: rm -f a.o b.o
RUN: llvm-ar x %S/Inputs/absolute-paths.lib RUN: llvm-ar x %S/Inputs/absolute-paths.lib
RUN: llvm-nm a.o | FileCheck %s --check-prefix=CHECK-A RUN: llvm-nm a.o | FileCheck %s --check-prefix=CHECK-A
RUN: llvm-nm b.o | FileCheck %s --check-prefix=CHECK-B 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

View File

@ -34,3 +34,21 @@
# RUN: llvm-ar x %t/archive.a 2>&1 | count 0 # RUN: llvm-ar x %t/archive.a 2>&1 | count 0
# RUN: diff %t/a.txt %t/extracted/a.txt # RUN: diff %t/a.txt %t/extracted/a.txt
# RUN: diff %t/b.txt %t/extracted/b.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

View File

@ -85,6 +85,7 @@ static void printArHelp(StringRef ToolName) {
=aix - aix (big archive) =aix - aix (big archive)
--plugin=<string> - ignored for compatibility --plugin=<string> - ignored for compatibility
-h --help - display this help and exit -h --help - display this help and exit
--output - the directory to extract archive members to
--rsp-quoting - quoting style for response files --rsp-quoting - quoting style for response files
=posix - posix =posix - posix
=windows - windows =windows - windows
@ -237,6 +238,9 @@ static int CountParam = 0;
// command line. // command line.
static std::string ArchiveName; 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<MemoryBuffer>> ArchiveBuffers;
static std::vector<std::unique_ptr<object::Archive>> Archives; static std::vector<std::unique_ptr<object::Archive>> Archives;
@ -454,6 +458,19 @@ static ArchiveOperation parseCommandLine() {
if (AddLibrary && Operation != QuickAppend) if (AddLibrary && Operation != QuickAppend)
badUsage("the 'L' modifier is only applicable to the 'q' operation"); 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 the parsed operation to the caller
return Operation; return Operation;
} }
@ -554,7 +571,15 @@ static void doExtract(StringRef Name, const object::Archive::Child &C) {
failIfError(ModeOrErr.takeError()); failIfError(ModeOrErr.takeError());
sys::fs::perms Mode = ModeOrErr.get(); 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) if (Verbose)
outs() << "x - " << outputFilePath << '\n'; outs() << "x - " << outputFilePath << '\n';
@ -1224,6 +1249,11 @@ static int ar_main(int argc, char **argv) {
continue; continue;
} }
if ((Match = matchFlagWithArg("output", ArgIt, Argv))) {
OutputDir = Match;
continue;
}
if (matchFlagWithArg("plugin", ArgIt, Argv) || if (matchFlagWithArg("plugin", ArgIt, Argv) ||
matchFlagWithArg("rsp-quoting", ArgIt, Argv)) matchFlagWithArg("rsp-quoting", ArgIt, Argv))
continue; continue;