jackoalan updated this revision to Diff 396055.
jackoalan added a comment.

Make expansion token a parameter of `ExpandResponseFiles` and limit use to 
`readConfigFile`. Elaborate manual entry further and add entry to release notes.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D115604/new/

https://reviews.llvm.org/D115604

Files:
  clang/docs/ReleaseNotes.rst
  clang/docs/UsersManual.rst
  llvm/include/llvm/Support/CommandLine.h
  llvm/lib/Support/CommandLine.cpp
  llvm/unittests/Support/CommandLineTest.cpp

Index: llvm/unittests/Support/CommandLineTest.cpp
===================================================================
--- llvm/unittests/Support/CommandLineTest.cpp
+++ llvm/unittests/Support/CommandLineTest.cpp
@@ -1038,25 +1038,34 @@
   llvm::SmallVector<const char *, 1> Argv;
 
   TempDir TestDir("unittest", /*Unique*/ true);
+  TempDir TestSubDir(TestDir.path("subdir"), /*Unique*/ false);
 
-  llvm::SmallString<128> TestCfg;
-  llvm::sys::path::append(TestCfg, TestDir.path(), "foo");
-
+  llvm::SmallString<128> TestCfg = TestDir.path("foo");
   TempFile ConfigFile(TestCfg, "",
                       "# Comment\n"
                       "-option_1\n"
+                      "-option_2=<CONFIG>/dir1\n"
                       "@subconfig\n"
-                      "-option_3=abcd\n"
-                      "-option_4=\\\n"
+                      "-option_7=abcd\n"
+                      "-option_8=\\\n"
                       "cdef\n");
 
-  llvm::SmallString<128> TestCfg2;
-  llvm::sys::path::append(TestCfg2, TestDir.path(), "subconfig");
+  llvm::SmallString<128> TestCfg2 = TestDir.path("subconfig");
   TempFile ConfigFile2(TestCfg2, "",
-                       "-option_2\n"
+                       "-option_3\n"
+                       "-option_4=<CONFIG>/dir2\n"
+                       "@subdir/subfoo\n"
                        "\n"
                        "   # comment\n");
 
+  llvm::SmallString<128> TestCfg3 = TestSubDir.path("subfoo");
+  TempFile ConfigFile3(TestCfg3, "",
+                       "-option_5=<CONFIG>/dir3\n"
+                       "@<CONFIG>/subfoo2\n");
+
+  llvm::SmallString<128> TestCfg4 = TestSubDir.path("subfoo2");
+  TempFile ConfigFile4(TestCfg4, "", "-option_6=qwerty\n");
+
   // Make sure the current directory is not the directory where config files
   // resides. In this case the code that expands response files will not find
   // 'subconfig' unless it resolves nested inclusions relative to the including
@@ -1071,11 +1080,18 @@
   bool Result = llvm::cl::readConfigFile(ConfigFile.path(), Saver, Argv);
 
   EXPECT_TRUE(Result);
-  EXPECT_EQ(Argv.size(), 4U);
+  EXPECT_EQ(Argv.size(), 8U);
   EXPECT_STREQ(Argv[0], "-option_1");
-  EXPECT_STREQ(Argv[1], "-option_2");
-  EXPECT_STREQ(Argv[2], "-option_3=abcd");
-  EXPECT_STREQ(Argv[3], "-option_4=cdef");
+  EXPECT_STREQ(Argv[1],
+               ("-option_2=" + TestDir.path() + "/dir1").str().c_str());
+  EXPECT_STREQ(Argv[2], "-option_3");
+  EXPECT_STREQ(Argv[3],
+               ("-option_4=" + TestDir.path() + "/dir2").str().c_str());
+  EXPECT_STREQ(Argv[4],
+               ("-option_5=" + TestSubDir.path() + "/dir3").str().c_str());
+  EXPECT_STREQ(Argv[5], "-option_6=qwerty");
+  EXPECT_STREQ(Argv[6], "-option_7=abcd");
+  EXPECT_STREQ(Argv[7], "-option_8=cdef");
 }
 
 TEST(CommandLineTest, PositionalEatArgsError) {
Index: llvm/lib/Support/CommandLine.cpp
===================================================================
--- llvm/lib/Support/CommandLine.cpp
+++ llvm/lib/Support/CommandLine.cpp
@@ -1078,11 +1078,44 @@
   return (S.size() >= 3 && S[0] == '\xef' && S[1] == '\xbb' && S[2] == '\xbf');
 }
 
+// Substitute token with the file's base path.
+static void ExpandBasePaths(StringRef BasePath, StringRef Token,
+                            StringSaver &Saver, const char *&Arg) {
+  assert(sys::path::is_absolute(BasePath));
+  const StringRef ArgString(Arg);
+
+  SmallString<128> ResponseFile;
+  StringRef::size_type StartPos = 0;
+  for (StringRef::size_type TokenPos = ArgString.find(Token);
+       TokenPos != StringRef::npos;
+       TokenPos = ArgString.find(Token, StartPos)) {
+    // Token may appear more than once per arg (e.g. comma-separated linker
+    // args). Support by using path-append on any subsequent appearances.
+    const StringRef LHS = ArgString.substr(StartPos, TokenPos - StartPos);
+    if (ResponseFile.empty())
+      ResponseFile = LHS;
+    else
+      llvm::sys::path::append(ResponseFile, LHS);
+    ResponseFile.append(BasePath);
+    StartPos = TokenPos + Token.size();
+  }
+
+  if (!ResponseFile.empty()) {
+    // Path-append the remaining arg substring if at least one token appeared.
+    const StringRef Remaining = ArgString.substr(StartPos);
+    if (!Remaining.empty())
+      llvm::sys::path::append(ResponseFile, Remaining);
+    Arg = Saver.save(ResponseFile.str()).data();
+  }
+}
+
 // FName must be an absolute path.
-static llvm::Error ExpandResponseFile(
-    StringRef FName, StringSaver &Saver, TokenizerCallback Tokenizer,
-    SmallVectorImpl<const char *> &NewArgv, bool MarkEOLs, bool RelativeNames,
-    llvm::vfs::FileSystem &FS) {
+static llvm::Error ExpandResponseFile(StringRef FName, StringSaver &Saver,
+                                      TokenizerCallback Tokenizer,
+                                      SmallVectorImpl<const char *> &NewArgv,
+                                      bool MarkEOLs, bool RelativeNames,
+                                      llvm::vfs::FileSystem &FS,
+                                      StringRef ExpandBasePathToken) {
   assert(sys::path::is_absolute(FName));
   llvm::ErrorOr<std::unique_ptr<MemoryBuffer>> MemBufOrErr =
       FS.getBufferForFile(FName);
@@ -1116,8 +1149,15 @@
   // file, replace the included response file names with their full paths
   // obtained by required resolution.
   for (auto &Arg : NewArgv) {
+    if (!Arg)
+      continue;
+
+    // Substitute token with the file's base path.
+    if (!ExpandBasePathToken.empty())
+      ExpandBasePaths(BasePath, ExpandBasePathToken, Saver, Arg);
+
     // Skip non-rsp file arguments.
-    if (!Arg || Arg[0] != '@')
+    if (Arg[0] != '@')
       continue;
 
     StringRef FileName(Arg + 1);
@@ -1129,7 +1169,7 @@
     ResponseFile.push_back('@');
     ResponseFile.append(BasePath);
     llvm::sys::path::append(ResponseFile, FileName);
-    Arg = Saver.save(ResponseFile.c_str()).data();
+    Arg = Saver.save(ResponseFile.str()).data();
   }
   return Error::success();
 }
@@ -1140,7 +1180,8 @@
                              SmallVectorImpl<const char *> &Argv, bool MarkEOLs,
                              bool RelativeNames,
                              llvm::Optional<llvm::StringRef> CurrentDir,
-                             llvm::vfs::FileSystem &FS) {
+                             llvm::vfs::FileSystem &FS,
+                             StringRef ExpandBasePathToken) {
   bool AllExpanded = true;
   struct ResponseFileRecord {
     std::string File;
@@ -1218,7 +1259,7 @@
     SmallVector<const char *, 0> ExpandedArgv;
     if (llvm::Error Err =
             ExpandResponseFile(FName, Saver, Tokenizer, ExpandedArgv, MarkEOLs,
-                               RelativeNames, FS)) {
+                               RelativeNames, FS, ExpandBasePathToken)) {
       // We couldn't read this file, so we leave it in the argument stream and
       // move on.
       // TODO: The error should be propagated up the stack.
@@ -1251,10 +1292,11 @@
 bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer,
                              SmallVectorImpl<const char *> &Argv, bool MarkEOLs,
                              bool RelativeNames,
-                             llvm::Optional<StringRef> CurrentDir) {
+                             llvm::Optional<StringRef> CurrentDir,
+                             StringRef ExpandBasePathToken) {
   return ExpandResponseFiles(Saver, std::move(Tokenizer), Argv, MarkEOLs,
                              RelativeNames, std::move(CurrentDir),
-                             *vfs::getRealFileSystem());
+                             *vfs::getRealFileSystem(), ExpandBasePathToken);
 }
 
 bool cl::expandResponseFiles(int Argc, const char *const *Argv,
@@ -1281,16 +1323,18 @@
     llvm::sys::path::append(AbsPath, CfgFile);
     CfgFile = AbsPath.str();
   }
-  if (llvm::Error Err =
-          ExpandResponseFile(CfgFile, Saver, cl::tokenizeConfigFile, Argv,
-                             /*MarkEOLs=*/false, /*RelativeNames=*/true,
-                             *llvm::vfs::getRealFileSystem())) {
+  constexpr StringLiteral ExpandBasePathToken("<CONFIG>");
+  if (llvm::Error Err = ExpandResponseFile(
+          CfgFile, Saver, cl::tokenizeConfigFile, Argv,
+          /*MarkEOLs=*/false, /*RelativeNames=*/true,
+          *llvm::vfs::getRealFileSystem(), ExpandBasePathToken)) {
     // TODO: The error should be propagated up the stack.
     llvm::consumeError(std::move(Err));
     return false;
   }
   return ExpandResponseFiles(Saver, cl::tokenizeConfigFile, Argv,
-                             /*MarkEOLs=*/false, /*RelativeNames=*/true);
+                             /*MarkEOLs=*/false, /*RelativeNames=*/true,
+                             llvm::None, ExpandBasePathToken);
 }
 
 static void initCommonOptions();
Index: llvm/include/llvm/Support/CommandLine.h
===================================================================
--- llvm/include/llvm/Support/CommandLine.h
+++ llvm/include/llvm/Support/CommandLine.h
@@ -2103,12 +2103,15 @@
 /// \param [in] FS File system used for all file access when running the tool.
 /// \param [in] CurrentDir Path used to resolve relative rsp files. If set to
 /// None, process' cwd is used instead.
+/// \param [in] ExpandBasePathToken If not empty, token which expands to the
+/// base path of the current response 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,
                          bool RelativeNames,
                          llvm::Optional<llvm::StringRef> CurrentDir,
-                         llvm::vfs::FileSystem &FS);
+                         llvm::vfs::FileSystem &FS,
+                         StringRef ExpandBasePathToken = {});
 
 /// An overload of ExpandResponseFiles() that uses
 /// llvm::vfs::getRealFileSystem().
@@ -2116,7 +2119,8 @@
     StringSaver &Saver, TokenizerCallback Tokenizer,
     SmallVectorImpl<const char *> &Argv, bool MarkEOLs = false,
     bool RelativeNames = false,
-    llvm::Optional<llvm::StringRef> CurrentDir = llvm::None);
+    llvm::Optional<llvm::StringRef> CurrentDir = llvm::None,
+    StringRef ExpandBasePathToken = {});
 
 /// A convenience helper which concatenates the options specified by the
 /// environment variable EnvVar and command line options, then expands response
Index: clang/docs/UsersManual.rst
===================================================================
--- clang/docs/UsersManual.rst
+++ clang/docs/UsersManual.rst
@@ -843,6 +843,8 @@
 option tells Clang to put double-quotes around the entire filename, which
 is the convention used by NMake and Jom.
 
+.. _configuration-files:
+
 Configuration files
 -------------------
 
@@ -917,6 +919,22 @@
 `~/.llvm/target.cfg` contains the directive `@os/linux.opts`, the file
 `linux.opts` is searched for in the directory `~/.llvm/os`.
 
+To generate paths relative to the configuration file, the `<CONFIG>` token may
+be used. This will expand to the absolute path of the directory containing the
+configuration file.
+
+A potential `<CONFIG>` use-case may be search paths in a portable (i.e. not
+installed) SDK directory for embedded development. The user may only need to
+specify a root configuration file to establish every aspect of the SDK with the
+compiler:
+
+::
+
+    --target=foo
+    -isystem <CONFIG>/include
+    -L <CONFIG>/lib
+    -T <CONFIG>/ldscripts/link.ld
+
 Language and Target-Independent Features
 ========================================
 
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -63,6 +63,9 @@
 
 - Maximum _ExtInt size was decreased from 16,777,215 bits to 8,388,608 bits.
   Motivation for this was discussed in PR51829.
+- Configuration file syntax extended with ``<CONFIG>`` token. This expands to
+  the base path of the current config file. See :ref:`configuration-files` for
+  details.
 
 New Compiler Flags
 ------------------
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to