[llvm] r285675 - Allow resolving response file names relative to including file

Serge Pavlov via llvm-commits llvm-commits at lists.llvm.org
Mon Oct 31 23:53:30 PDT 2016


Author: sepavloff
Date: Tue Nov  1 01:53:29 2016
New Revision: 285675

URL: http://llvm.org/viewvc/llvm-project?rev=285675&view=rev
Log:
Allow resolving response file names relative to including file

If a response file included by construct @file itself includes a response file
and that file is specified by relative file name, current behavior is to resolve
the name relative to the current working directory. The change adds additional
flag to ExpandResponseFiles that may be used to resolve nested response file
names relative to including file. With the new mode a set of related response
files may be kept together and reference each other with short position
independent names.

Differential Revision: https://reviews.llvm.org/D24917

Modified:
    llvm/trunk/include/llvm/Support/CommandLine.h
    llvm/trunk/lib/Support/CommandLine.cpp
    llvm/trunk/unittests/Support/CommandLineTest.cpp

Modified: llvm/trunk/include/llvm/Support/CommandLine.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/CommandLine.h?rev=285675&r1=285674&r2=285675&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/CommandLine.h (original)
+++ llvm/trunk/include/llvm/Support/CommandLine.h Tue Nov  1 01:53:29 2016
@@ -1803,10 +1803,12 @@ typedef void (*TokenizerCallback)(String
 /// \param [in,out] Argv Command line into which to expand response files.
 /// \param [in] MarkEOLs Mark end of lines and the end of the response file
 /// with nullptrs in the Argv vector.
+/// \param [in] RelativeNames true if names of nested response files must be
+/// resolved relative to including file.
 /// \return true if all @files were expanded successfully or there were none.
 bool ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer,
                          SmallVectorImpl<const char *> &Argv,
-                         bool MarkEOLs = false);
+                         bool MarkEOLs = false, bool RelativeNames = false);
 
 /// \brief Mark all options not part of this category as cl::ReallyHidden.
 ///

Modified: llvm/trunk/lib/Support/CommandLine.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/CommandLine.cpp?rev=285675&r1=285674&r2=285675&view=diff
==============================================================================
--- llvm/trunk/lib/Support/CommandLine.cpp (original)
+++ llvm/trunk/lib/Support/CommandLine.cpp Tue Nov  1 01:53:29 2016
@@ -871,10 +871,10 @@ static bool hasUTF8ByteOrderMark(ArrayRe
   return (S.size() >= 3 && S[0] == '\xef' && S[1] == '\xbb' && S[2] == '\xbf');
 }
 
-static bool ExpandResponseFile(const char *FName, StringSaver &Saver,
+static bool ExpandResponseFile(StringRef FName, StringSaver &Saver,
                                TokenizerCallback Tokenizer,
                                SmallVectorImpl<const char *> &NewArgv,
-                               bool MarkEOLs = false) {
+                               bool MarkEOLs, bool RelativeNames) {
   ErrorOr<std::unique_ptr<MemoryBuffer>> MemBufOrErr =
       MemoryBuffer::getFile(FName);
   if (!MemBufOrErr)
@@ -899,6 +899,25 @@ static bool ExpandResponseFile(const cha
   // Tokenize the contents into NewArgv.
   Tokenizer(Str, Saver, NewArgv, MarkEOLs);
 
+  // If names of nested response files should be resolved relative to including
+  // file, replace the included response file names with their full paths
+  // obtained by required resolution.
+  if (RelativeNames)
+    for (unsigned I = 0; I < NewArgv.size(); ++I)
+      if (NewArgv[I]) {
+        StringRef Arg = NewArgv[I];
+        if (Arg.front() == '@') {
+          StringRef FileName = Arg.drop_front();
+          if (llvm::sys::path::is_relative(FileName)) {
+            SmallString<128> ResponseFile;
+            ResponseFile.append(1, '@');
+            llvm::sys::path::append(
+                ResponseFile, llvm::sys::path::parent_path(FName), FileName);
+            NewArgv[I] = Saver.save(ResponseFile.c_str()).data();
+          }
+        }
+      }
+
   return true;
 }
 
@@ -906,7 +925,7 @@ static bool ExpandResponseFile(const cha
 /// StringSaver and tokenization strategy.
 bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer,
                              SmallVectorImpl<const char *> &Argv,
-                             bool MarkEOLs) {
+                             bool MarkEOLs, bool RelativeNames) {
   unsigned RspFiles = 0;
   bool AllExpanded = true;
 
@@ -930,11 +949,9 @@ bool cl::ExpandResponseFiles(StringSaver
 
     // Replace this response file argument with the tokenization of its
     // contents.  Nested response files are expanded in subsequent iterations.
-    // FIXME: If a nested response file uses a relative path, is it relative to
-    // the cwd of the process or the response file?
     SmallVector<const char *, 0> ExpandedArgv;
     if (!ExpandResponseFile(Arg + 1, Saver, Tokenizer, ExpandedArgv,
-                            MarkEOLs)) {
+                            MarkEOLs, RelativeNames)) {
       // We couldn't read this file, so we leave it in the argument stream and
       // move on.
       AllExpanded = false;

Modified: llvm/trunk/unittests/Support/CommandLineTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/CommandLineTest.cpp?rev=285675&r1=285674&r2=285675&view=diff
==============================================================================
--- llvm/trunk/unittests/Support/CommandLineTest.cpp (original)
+++ llvm/trunk/unittests/Support/CommandLineTest.cpp Tue Nov  1 01:53:29 2016
@@ -7,11 +7,15 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/Config/config.h"
 #include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
 #include "llvm/Support/StringSaver.h"
 #include "gtest/gtest.h"
+#include <fstream>
 #include <stdlib.h>
 #include <string>
 
@@ -505,4 +509,65 @@ TEST(CommandLineTest, GetRegisteredSubco
   }
 }
 
+TEST(CommandLineTest, ResponseFiles) {
+  llvm::SmallString<128> TestDir;
+  std::error_code EC =
+    llvm::sys::fs::createUniqueDirectory("unittest", TestDir);
+  EXPECT_TRUE(!EC);
+
+  // Create included response file of first level.
+  llvm::SmallString<128> IncludedFileName;
+  llvm::sys::path::append(IncludedFileName, TestDir, "resp1");
+  std::ofstream IncludedFile(IncludedFileName.c_str());
+  EXPECT_TRUE(IncludedFile.is_open());
+  IncludedFile << "-option_1 -option_2\n"
+                  "@incdir/resp2\n"
+                  "-option_3=abcd\n";
+  IncludedFile.close();
+
+  // Directory for included file.
+  llvm::SmallString<128> IncDir;
+  llvm::sys::path::append(IncDir, TestDir, "incdir");
+  EC = llvm::sys::fs::create_directory(IncDir);
+  EXPECT_TRUE(!EC);
+
+  // Create included response file of second level.
+  llvm::SmallString<128> IncludedFileName2;
+  llvm::sys::path::append(IncludedFileName2, IncDir, "resp2");
+  std::ofstream IncludedFile2(IncludedFileName2.c_str());
+  EXPECT_TRUE(IncludedFile2.is_open());
+  IncludedFile2 << "-option_21 -option_22\n";
+  IncludedFile2 << "-option_23=abcd\n";
+  IncludedFile2.close();
+
+  // Prepare 'file' with reference to response file.
+  SmallString<128> IncRef;
+  IncRef.append(1, '@');
+  IncRef.append(IncludedFileName.c_str());
+  llvm::SmallVector<const char *, 4> Argv =
+                          { "test/test", "-flag_1", IncRef.c_str(), "-flag_2" };
+
+  // Expand response files.
+  llvm::BumpPtrAllocator A;
+  llvm::StringSaver Saver(A);
+  bool Res = llvm::cl::ExpandResponseFiles(
+                    Saver, llvm::cl::TokenizeGNUCommandLine, Argv, false, true);
+  EXPECT_TRUE(Res);
+  EXPECT_EQ(Argv.size(), 9);
+  EXPECT_STREQ(Argv[0], "test/test");
+  EXPECT_STREQ(Argv[1], "-flag_1");
+  EXPECT_STREQ(Argv[2], "-option_1");
+  EXPECT_STREQ(Argv[3], "-option_2");
+  EXPECT_STREQ(Argv[4], "-option_21");
+  EXPECT_STREQ(Argv[5], "-option_22");
+  EXPECT_STREQ(Argv[6], "-option_23=abcd");
+  EXPECT_STREQ(Argv[7], "-option_3=abcd");
+  EXPECT_STREQ(Argv[8], "-flag_2");
+
+  llvm::sys::fs::remove(IncludedFileName2);
+  llvm::sys::fs::remove(IncDir);
+  llvm::sys::fs::remove(IncludedFileName);
+  llvm::sys::fs::remove(TestDir);
+}
+
 }  // anonymous namespace




More information about the llvm-commits mailing list