diff options
| -rw-r--r-- | lld/lib/Driver/GnuLdDriver.cpp | 49 | ||||
| -rw-r--r-- | lld/test/elf/Inputs/responsefile | 1 | ||||
| -rw-r--r-- | lld/test/elf/responsefile.test | 6 |
3 files changed, 55 insertions, 1 deletions
diff --git a/lld/lib/Driver/GnuLdDriver.cpp b/lld/lib/Driver/GnuLdDriver.cpp index fb57706674b..3358626bee2 100644 --- a/lld/lib/Driver/GnuLdDriver.cpp +++ b/lld/lib/Driver/GnuLdDriver.cpp @@ -32,8 +32,13 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Signals.h" +#include <cstring> +#include <tuple> + using namespace lld; +using llvm::BumpPtrAllocator; + namespace { // Create enum with OPT_xxx values for each option in GnuLdOptions.td @@ -68,8 +73,49 @@ public: GnuLdOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){} }; +class DriverStringSaver : public llvm::cl::StringSaver { +public: + DriverStringSaver(BumpPtrAllocator &alloc) : _alloc(alloc) {} + + const char *SaveString(const char *s) override { + char *p = _alloc.Allocate<char>(strlen(s) + 1); + strcpy(p, s); + return p; + } + +private: + BumpPtrAllocator &_alloc; +}; + } // anonymous namespace +// If a command line option starts with "@", the driver reads its suffix as a +// file, parse its contents as a list of command line options, and insert them +// at the original @file position. If file cannot be read, @file is not expanded +// and left unmodified. @file can appear in a response file, so it's a recursive +// process. +static std::tuple<int, const char **> +maybeExpandResponseFiles(int argc, const char **argv, BumpPtrAllocator &alloc) { + // Expand response files. + SmallVector<const char *, 256> smallvec; + for (int i = 0; i < argc; ++i) + smallvec.push_back(argv[i]); + DriverStringSaver saver(alloc); + llvm::cl::ExpandResponseFiles(saver, llvm::cl::TokenizeGNUCommandLine, smallvec); + + // Pack the results to a C-array. + argc = smallvec.size(); + std::vector<const char *> result; + for (size_t i = 0, e = smallvec.size(); i < e; ++i) + result.push_back(smallvec[i]); + result.push_back(nullptr); // terminate ARGV with NULL + + // Allocate memory for the result and return it. + const char **copy = alloc.Allocate<const char *>(argc + 1); + std::copy(smallvec.begin(), smallvec.end(), copy); + return std::make_tuple(argc, copy); +} + // Get the Input file magic for creating appropriate InputGraph nodes. static error_code getFileMagic(ELFLinkingContext &ctx, StringRef path, llvm::sys::fs::file_magic &magic) { @@ -118,6 +164,8 @@ std::string ELFFileNode::errStr(error_code errc) { bool GnuLdDriver::linkELF(int argc, const char *argv[], raw_ostream &diagnostics) { + BumpPtrAllocator alloc; + std::tie(argc, argv) = maybeExpandResponseFiles(argc, argv, alloc); std::unique_ptr<ELFLinkingContext> options; if (!parse(argc, argv, options, diagnostics)) return false; @@ -133,7 +181,6 @@ bool GnuLdDriver::linkELF(int argc, const char *argv[], if (options->allowLinkWithDynamicLibraries()) options->registry().addSupportELFDynamicSharedObjects( options->useShlibUndefines(), options->targetHandler()); - return link(*options, diagnostics); } diff --git a/lld/test/elf/Inputs/responsefile b/lld/test/elf/Inputs/responsefile new file mode 100644 index 00000000000..2fe657a0e3b --- /dev/null +++ b/lld/test/elf/Inputs/responsefile @@ -0,0 +1 @@ +--inresponsefile diff --git a/lld/test/elf/responsefile.test b/lld/test/elf/responsefile.test new file mode 100644 index 00000000000..5957471bb66 --- /dev/null +++ b/lld/test/elf/responsefile.test @@ -0,0 +1,6 @@ +# RUN: not lld -flavor gnu --abc @%p/Inputs/responsefile --baz >& %t.log +# RUN: FileCheck %s < %t.log + +CHECK: warning: ignoring unknown argument: --abc +CHECK: warning: ignoring unknown argument: --inresponsefile +CHECK: warning: ignoring unknown argument: --baz |

