diff --git a/llvm/docs/CommandGuide/llvm-objcopy.rst b/llvm/docs/CommandGuide/llvm-objcopy.rst --- a/llvm/docs/CommandGuide/llvm-objcopy.rst +++ b/llvm/docs/CommandGuide/llvm-objcopy.rst @@ -129,6 +129,10 @@ Display the version of this program. +.. option:: @ + + Read command-line options and commands from response file ``. + COFF-SPECIFIC OPTIONS --------------------- diff --git a/llvm/docs/CommandGuide/llvm-strip.rst b/llvm/docs/CommandGuide/llvm-strip.rst --- a/llvm/docs/CommandGuide/llvm-strip.rst +++ b/llvm/docs/CommandGuide/llvm-strip.rst @@ -103,6 +103,10 @@ Display the version of this program. +.. option:: @ + + Read command-line options and commands from response file ``. + COFF-SPECIFIC OPTIONS --------------------- diff --git a/llvm/test/tools/llvm-objcopy/ELF/help-message.test b/llvm/test/tools/llvm-objcopy/ELF/help-message.test --- a/llvm/test/tools/llvm-objcopy/ELF/help-message.test +++ b/llvm/test/tools/llvm-objcopy/ELF/help-message.test @@ -14,6 +14,10 @@ # OBJCOPY-USAGE: USAGE: llvm-objcopy +# OBJCOPY-USAGE: @FILE + # STRIP-USAGE: USAGE: llvm-strip +# STRIP-USAGE: @FILE + # UNKNOWN-ARG: unknown argument '{{-+}}abcabc' # NO-INPUT-FILES: no input file specified diff --git a/llvm/test/tools/llvm-objcopy/ELF/response-file.test b/llvm/test/tools/llvm-objcopy/ELF/response-file.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/ELF/response-file.test @@ -0,0 +1,21 @@ +## Check that we support response files. +# RUN: yaml2obj %s -o %t.o +# RUN: echo "--strip-debug %t.o" > %t-response +# RUN: llvm-objcopy @%t-response %t2.o +# RUN: llvm-strip @%t-response + +# RUN: llvm-readobj -S %t.o | FileCheck %s +# RUN: llvm-readobj -S %t2.o | FileCheck %s +# RUN: cmp %t.o %t2.o + +# CHECK-NOT: .debug_foo + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .debug_foo + Type: SHT_PROGBITS diff --git a/llvm/tools/llvm-objcopy/CopyConfig.cpp b/llvm/tools/llvm-objcopy/CopyConfig.cpp --- a/llvm/tools/llvm-objcopy/CopyConfig.cpp +++ b/llvm/tools/llvm-objcopy/CopyConfig.cpp @@ -407,6 +407,13 @@ return Result; } +static void printHelp(const opt::OptTable &OptTable, raw_ostream &OS, + StringRef ToolName) { + OptTable.PrintHelp(OS, (ToolName + " input [output]").str().c_str(), + (ToolName + " tool").str().c_str()); + OS << "\nPass @FILE as argument to read options from FILE.\n"; +} + // ParseObjcopyOptions returns the config and sets the input arguments. If a // help flag is set then ParseObjcopyOptions will print the help messege and // exit. @@ -418,12 +425,12 @@ T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount); if (InputArgs.size() == 0) { - T.PrintHelp(errs(), "llvm-objcopy input [output]", "objcopy tool"); + printHelp(T, errs(), "llvm-objcopy"); exit(1); } if (InputArgs.hasArg(OBJCOPY_help)) { - T.PrintHelp(outs(), "llvm-objcopy input [output]", "objcopy tool"); + printHelp(T, outs(), "llvm-objcopy"); exit(0); } @@ -770,12 +777,12 @@ T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount); if (InputArgs.size() == 0) { - T.PrintHelp(errs(), "llvm-strip [options] file...", "strip tool"); + printHelp(T, errs(), "llvm-strip"); exit(1); } if (InputArgs.hasArg(STRIP_help)) { - T.PrintHelp(outs(), "llvm-strip [options] file...", "strip tool"); + printHelp(T, outs(), "llvm-strip"); exit(0); } diff --git a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp --- a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp +++ b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp @@ -29,6 +29,7 @@ #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorOr.h" @@ -36,6 +37,7 @@ #include "llvm/Support/Memory.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" +#include "llvm/Support/StringSaver.h" #include "llvm/Support/WithColor.h" #include "llvm/Support/raw_ostream.h" #include @@ -310,9 +312,23 @@ InitLLVM X(argc, argv); ToolName = argv[0]; bool IsStrip = sys::path::stem(ToolName).contains("strip"); + + // Expand response files. + SmallVector NewArgv(argv, argv + argc); + BumpPtrAllocator A; + StringSaver Saver(A); + cl::ExpandResponseFiles(Saver, + Triple(sys::getProcessTriple()).isOSWindows() + ? cl::TokenizeWindowsCommandLine + : cl::TokenizeGNUCommandLine, + NewArgv); + argv = const_cast(&NewArgv[0]); + argc = static_cast(NewArgv.size()); + Expected DriverConfig = - IsStrip ? parseStripOptions(makeArrayRef(argv + 1, argc), reportWarning) - : parseObjcopyOptions(makeArrayRef(argv + 1, argc)); + IsStrip + ? parseStripOptions(makeArrayRef(argv + 1, argc - 1), reportWarning) + : parseObjcopyOptions(makeArrayRef(argv + 1, argc - 1)); if (!DriverConfig) { logAllUnhandledErrors(DriverConfig.takeError(), WithColor::error(errs(), ToolName));