[PATCH] [ELF] Support response file.

Rui Ueyama ruiu at google.com
Thu Mar 27 20:25:23 PDT 2014


Hi Bigcheese,

Response file is a command line argument in the form of @file. The GNU-
compatible driver expands the file contents, replacing @file argument.

http://llvm-reviews.chandlerc.com/D3210

Files:
  lib/Driver/GnuLdDriver.cpp
  test/elf/Inputs/responsefile
  test/elf/responsefile.test

Index: lib/Driver/GnuLdDriver.cpp
===================================================================
--- lib/Driver/GnuLdDriver.cpp
+++ lib/Driver/GnuLdDriver.cpp
@@ -32,8 +32,12 @@
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Support/Signals.h"
 
+#include <tuple>
+
 using namespace lld;
 
+using llvm::BumpPtrAllocator;
+
 namespace {
 
 // Create enum with OPT_xxx values for each option in GnuLdOptions.td
@@ -68,8 +72,64 @@
   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 {
+    return (new (_alloc) std::string(s))->c_str();
+  }
+
+private:
+  BumpPtrAllocator &_alloc;
+};
+
 } // anonymous namespace
 
+static bool
+readFile(StringRef path, StringRef &result, BumpPtrAllocator &alloc) {
+  std::unique_ptr<MemoryBuffer> buf;
+  if (MemoryBuffer::getFile(path, buf))
+    return false;
+  result = *new (alloc) std::string(buf->getBufferStart(), buf->getBufferSize());
+  return true;
+}
+
+// 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) {
+  bool expanded = false;
+  std::vector<const char *> result;
+  for (int i = 0; i < argc; ++i) {
+    if (argv[i][0] != '@') {
+      result.push_back(argv[i]);
+      continue;
+    }
+
+    // This is a response file. Read it. If it fails, process @file literally.
+    StringRef contents;
+    if (!readFile(StringRef(argv[i]).substr(1), contents, alloc))
+      continue;
+    DriverStringSaver saver(alloc);
+    SmallVector<const char *, 0> args;
+    llvm::cl::TokenizeGNUCommandLine(contents, saver, args);
+    for (const char *s : args)
+      result.push_back(s);
+    expanded = true;
+  }
+  if (!expanded)
+    return std::make_tuple(argc, argv);
+  argc = result.size();
+  result.push_back(nullptr);  // terminate ARGV with NULL
+  auto *resultCopy = new (alloc) std::vector<const char *>(result);
+  argv = &(*resultCopy)[0];
+  return maybeExpandResponseFiles(argc, argv, alloc);
+}
+
 // Get the Input file magic for creating appropriate InputGraph nodes.
 static error_code getFileMagic(ELFLinkingContext &ctx, StringRef path,
                                llvm::sys::fs::file_magic &magic) {
@@ -105,6 +165,8 @@
 
 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;
@@ -120,7 +182,6 @@
   if (options->allowLinkWithDynamicLibraries())
     options->registry().addSupportELFDynamicSharedObjects(
         options->useShlibUndefines(), options->targetHandler());
-
   return link(*options, diagnostics);
 }
 
Index: test/elf/Inputs/responsefile
===================================================================
--- /dev/null
+++ test/elf/Inputs/responsefile
@@ -0,0 +1 @@
+--inresponsefile
Index: test/elf/responsefile.test
===================================================================
--- /dev/null
+++ 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
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D3210.1.patch
Type: text/x-patch
Size: 3903 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20140327/8e955e9d/attachment.bin>


More information about the llvm-commits mailing list