summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/lib/Driver/GnuLdDriver.cpp49
-rw-r--r--lld/test/elf/Inputs/responsefile1
-rw-r--r--lld/test/elf/responsefile.test6
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
OpenPOWER on IntegriCloud