llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-flang-parser

Author: Thirumalai Shaktivel (Thirumalai-Shaktivel)

<details>
<summary>Changes</summary>

Implement the GCC/Clang dependency-file flags for flang, which it
previously rejected as unknown arguments: -M, -MM, -MD, -MMD, -MF,
-MT and -MQ.

Feature:
 -  -MD/-MMD : write a .d file alongside a normal compile
 -  -M/-MM   : prescan only; emit deps to stdout by default
 -  -MF      : dependency-file path
 -  -MT/-MQ  : target name (verbatim / Make-quoted)
  (-M==-MM and -MD==-MMD; Fortran has no system/user header split.)

Design:
- `-M`/`-MM`: driver passes `-Eonly -dependency-file - -MT &lt;target&gt;`
  to `-fc1`. `-Eonly` selects `RunPreprocessorOnly`, which runs only
  the prescanner and produces no compiled output. The dependency file
  is the sole result, written to stdout by default.

- `-MD`/`-MMD`: driver passes `-dependency-file foo.d -MT &lt;target&gt;`
  alongside the normal compile action. The object file is produced as
  usual, and the dependency file is written as a side effect.

- `-MF &lt;path&gt;` overrides where the dependency file is written.
  `-MT &lt;target&gt;` sets the target name (the part before the colon in
  the Make rule) verbatim. `-MQ` does the same but additionally
  quotes characters that are special to Make.

- In `-fc1`, `-dependency-file` and `-MT` are stored in the frontend
  options. After the prescan, `writeDependencyFile()` is called
  unconditionally regardless of the action. It collects every file
  opened during prescan — the source plus all `INCLUDE`/`#include`
  files — via `GetIncludedFilePaths()`, then writes the
  `target: source includes...` Make rule to the specified file, or
  stdout if the path is `-`.

---

Patch is 41.63 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/209379.diff


18 Files Affected:

- (modified) clang/include/clang/Basic/MakeSupport.h (+20) 
- (modified) clang/include/clang/Frontend/DependencyOutputOptions.h (+1-3) 
- (modified) clang/include/clang/Options/Options.td (+13-5) 
- (modified) clang/lib/Basic/MakeSupport.cpp (+144) 
- (modified) clang/lib/Driver/ToolChains/Flang.cpp (+104-3) 
- (modified) clang/lib/Frontend/DependencyFile.cpp (+3-134) 
- (modified) flang/docs/FlangDriver.md (+15) 
- (modified) flang/include/flang/Frontend/FrontendAction.h (+2) 
- (modified) flang/include/flang/Frontend/FrontendActions.h (+6) 
- (modified) flang/include/flang/Frontend/FrontendOptions.h (+9) 
- (modified) flang/include/flang/Parser/provenance.h (+5) 
- (modified) flang/lib/Frontend/CompilerInvocation.cpp (+6) 
- (modified) flang/lib/Frontend/FrontendAction.cpp (+42) 
- (modified) flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp (+2) 
- (modified) flang/lib/Parser/provenance.cpp (+15) 
- (added) flang/test/Driver/dependency-file-gen-mod.f90 (+33) 
- (added) flang/test/Driver/dependency-file-gen.f90 (+44) 
- (added) flang/test/Driver/dependency-file.f90 (+106) 


``````````diff
diff --git a/clang/include/clang/Basic/MakeSupport.h 
b/clang/include/clang/Basic/MakeSupport.h
index c663014ba7bcf..5cd5dd92c5476 100644
--- a/clang/include/clang/Basic/MakeSupport.h
+++ b/clang/include/clang/Basic/MakeSupport.h
@@ -10,6 +10,7 @@
 #define LLVM_CLANG_BASIC_MAKESUPPORT_H
 
 #include "clang/Basic/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/StringRef.h"
 
 namespace clang {
@@ -18,6 +19,25 @@ namespace clang {
 /// Only the characters '$', '#', ' ', '\t' are quoted.
 void quoteMakeTarget(StringRef Target, SmallVectorImpl<char> &Res);
 
+/// DependencyOutputFormat - Format for the compiler dependency file.
+enum class DependencyOutputFormat { Make, NMake };
+
+/// Write Make-style dependency output to the output stream, in the form:
+///   target1 target2 ...: prereq1 prereq2 ...
+///
+/// \param Targets The targets, already quoted for Make via quoteMakeTarget().
+/// \param Files The prerequisites; each is escaped for \p Format when written.
+/// \param Format Escape prerequisites for GNU Make or NMake.
+/// \param PhonyTargets If true, also emit an empty "prereq:" line for each
+///   prerequisite (except \p InputFileIndex), so later deleting a prerequisite
+///   doesn't break the build.
+/// \param InputFileIndex Index in \p Files of the main input, skipped above.
+void printMakeDependencyFile(
+    llvm::raw_ostream &OS, llvm::ArrayRef<std::string> Targets,
+    llvm::ArrayRef<std::string> Files,
+    DependencyOutputFormat Format = DependencyOutputFormat::Make,
+    bool PhonyTargets = false, unsigned InputFileIndex = 0);
+
 } // namespace clang
 
 #endif // LLVM_CLANG_BASIC_MAKESUPPORT_H
diff --git a/clang/include/clang/Frontend/DependencyOutputOptions.h 
b/clang/include/clang/Frontend/DependencyOutputOptions.h
index 98728f4d53b43..c2607b833a9e4 100644
--- a/clang/include/clang/Frontend/DependencyOutputOptions.h
+++ b/clang/include/clang/Frontend/DependencyOutputOptions.h
@@ -10,6 +10,7 @@
 #define LLVM_CLANG_FRONTEND_DEPENDENCYOUTPUTOPTIONS_H
 
 #include "clang/Basic/HeaderInclude.h"
+#include "clang/Basic/MakeSupport.h"
 #include <string>
 #include <vector>
 
@@ -18,9 +19,6 @@ namespace clang {
 /// ShowIncludesDestination - Destination for /showIncludes output.
 enum class ShowIncludesDestination { None, Stdout, Stderr };
 
-/// DependencyOutputFormat - Format for the compiler dependency file.
-enum class DependencyOutputFormat { Make, NMake };
-
 /// ExtraDepKind - The kind of extra dependency file.
 enum ExtraDepKind {
   EDK_SanitizeIgnorelist,
diff --git a/clang/include/clang/Options/Options.td 
b/clang/include/clang/Options/Options.td
index 4974209b8db30..767c9044e44e3 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -807,14 +807,19 @@ def embed_dir_EQ : Joined<["--"], "embed-dir=">, 
Group<Preprocessor_Group>,
     Visibility<[ClangOption, CC1Option]>, MetaVarName<"<dir>">,
     HelpText<"Add directory to embed search path">;
 def MD : Flag<["-"], "MD">, Group<M_Group>,
+    Visibility<[ClangOption, FlangOption]>,
     HelpText<"Write a depfile containing user and system headers">;
 def MMD : Flag<["-"], "MMD">, Group<M_Group>,
+    Visibility<[ClangOption, FlangOption]>,
     HelpText<"Write a depfile containing user headers">;
 def M : Flag<["-"], "M">, Group<M_Group>,
+    Visibility<[ClangOption, FlangOption]>,
     HelpText<"Like -MD, but also implies -E and writes to stdout by default">;
 def MM : Flag<["-"], "MM">, Group<M_Group>,
+    Visibility<[ClangOption, FlangOption]>,
     HelpText<"Like -MMD, but also implies -E and writes to stdout by default">;
 def MF : JoinedOrSeparate<["-"], "MF">, Group<M_Group>,
+    Visibility<[ClangOption, FlangOption]>,
     HelpText<"Write depfile output from -MMD, -MD, -MM, or -M to <file>">,
     MetaVarName<"<file>">;
 def MG : Flag<["-"], "MG">, Group<M_Group>, Visibility<[ClangOption, 
CC1Option]>,
@@ -826,10 +831,10 @@ def MP : Flag<["-"], "MP">, Group<M_Group>, 
Visibility<[ClangOption, CC1Option]>
     HelpText<"Create phony target for each dependency (other than main file)">,
     MarshallingInfoFlag<DependencyOutputOpts<"UsePhonyTargets">>;
 def MQ : JoinedOrSeparate<["-"], "MQ">, Group<M_Group>,
-  Visibility<[ClangOption, CC1Option]>,
+  Visibility<[ClangOption, CC1Option, FlangOption]>,
     HelpText<"Specify name of main file output to quote in depfile">;
 def MT : JoinedOrSeparate<["-"], "MT">, Group<M_Group>,
-  Visibility<[ClangOption, CC1Option]>,
+  Visibility<[ClangOption, CC1Option, FC1Option, FlangOption]>,
     HelpText<"Specify name of main file output in depfile">,
     MarshallingInfoStringVector<DependencyOutputOpts<"Targets">>;
 def MV : Flag<["-"], "MV">, Group<M_Group>, Visibility<[ClangOption, 
CC1Option]>,
@@ -1528,7 +1533,7 @@ def dM : Flag<["-"], "dM">, Group<d_Group>, 
Visibility<[ClangOption, CC1Option,
   HelpText<"Print macro definitions in -E mode instead of normal output">;
 def dead__strip : Flag<["-"], "dead_strip">;
 def dependency_file : Separate<["-"], "dependency-file">,
-  Visibility<[ClangOption, CC1Option]>,
+  Visibility<[ClangOption, CC1Option, FC1Option]>,
   HelpText<"Filename (or -) to write dependency output to">,
   MarshallingInfoString<DependencyOutputOpts<"OutputFile">>;
 def dependency_dot : Separate<["-"], "dependency-dot">,
@@ -8529,8 +8534,6 @@ defm recovery_ast_type : BoolOption<"f", 
"recovery-ast-type",
 
 let Group = Action_Group in {
 
-def Eonly : Flag<["-"], "Eonly">,
-  HelpText<"Just run preprocessor, no output (for timings)">;
 def dump_raw_tokens : Flag<["-"], "dump-raw-tokens">,
   HelpText<"Lex file in raw mode and dump raw tokens">;
 def analyze : Flag<["-"], "analyze">,
@@ -8673,6 +8676,11 @@ def finitial_counter_value_EQ : Joined<["-"], 
"finitial-counter-value=">,
 
 } // let Visibility = [CC1Option]
 
+def Eonly : Flag<["-"], "Eonly">, Group<Action_Group>,
+  Visibility<[CC1Option, FC1Option]>,
+  HelpText<"Just run preprocessor, no output (for timings or dependency "
+           "generation)">;
+
 
//===----------------------------------------------------------------------===//
 // Language Options
 
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/Basic/MakeSupport.cpp b/clang/lib/Basic/MakeSupport.cpp
index 4ddfcc350410c..afc22493aff0d 100644
--- a/clang/lib/Basic/MakeSupport.cpp
+++ b/clang/lib/Basic/MakeSupport.cpp
@@ -7,6 +7,9 @@
 
//===----------------------------------------------------------------------===//
 
 #include "clang/Basic/MakeSupport.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
 
 void clang::quoteMakeTarget(StringRef Target, SmallVectorImpl<char> &Res) {
   for (unsigned i = 0, e = Target.size(); i != e; ++i) {
@@ -33,3 +36,144 @@ void clang::quoteMakeTarget(StringRef Target, 
SmallVectorImpl<char> &Res) {
     Res.push_back(Target[i]);
   }
 }
+
+/// Print the filename, with escaping or quoting that accommodates the three
+/// most likely tools that use dependency files: GNU Make, BSD Make, and
+/// NMake/Jom.
+///
+/// BSD Make is the simplest case: It does no escaping at all.  This means
+/// characters that are normally delimiters, i.e. space and # (the comment
+/// character) simply aren't supported in filenames.
+///
+/// GNU Make does allow space and # in filenames, but to avoid being treated
+/// as a delimiter or comment, these must be escaped with a backslash. Because
+/// backslash is itself the escape character, if a backslash appears in a
+/// filename, it should be escaped as well.  (As a special case, $ is escaped
+/// as $$, which is the normal Make way to handle the $ character.)
+/// For compatibility with BSD Make and historical practice, if GNU Make
+/// un-escapes characters in a filename but doesn't find a match, it will
+/// retry with the unmodified original string.
+///
+/// GCC tries to accommodate both Make formats by escaping any space or #
+/// characters in the original filename, but not escaping backslashes.  The
+/// apparent intent is so that filenames with backslashes will be handled
+/// correctly by BSD Make, and by GNU Make in its fallback mode of using the
+/// unmodified original string; filenames with # or space characters aren't
+/// supported by BSD Make at all, but will be handled correctly by GNU Make
+/// due to the escaping.
+///
+/// A corner case that GCC gets only partly right is when the original filename
+/// has a backslash immediately followed by space or #.  GNU Make would expect
+/// this backslash to be escaped; however GCC escapes the original backslash
+/// only when followed by space, not #.  It will therefore take a dependency
+/// from a directive such as
+///     #include "a\ b\#c.h"
+/// and emit it as
+///     a\\\ b\\#c.h
+/// which GNU Make will interpret as
+///     a\ b\
+/// followed by a comment. Failing to find this file, it will fall back to the
+/// original string, which probably doesn't exist either; in any case it won't
+/// find
+///     a\ b\#c.h
+/// which is the actual filename specified by the include directive.
+///
+/// Clang does what GCC does, rather than what GNU Make expects.
+///
+/// NMake/Jom has a different set of scary characters, but wraps filespecs in
+/// double-quotes to avoid misinterpreting them; see
+/// https://msdn.microsoft.com/en-us/library/dd9y37ha.aspx for NMake info,
+/// 
https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
+/// for Windows file-naming info.
+static void printFilename(llvm::raw_ostream &OS, llvm::StringRef Filename,
+                          clang::DependencyOutputFormat OutputFormat) {
+  // Convert filename to platform native path
+  llvm::SmallString<256> NativePath;
+  llvm::sys::path::native(Filename, NativePath);
+
+  if (OutputFormat == clang::DependencyOutputFormat::NMake) {
+    // Add quotes if needed. These are the characters listed as "special" to
+    // NMake, that are legal in a Windows filespec, and that could cause
+    // misinterpretation of the dependency string.
+    if (NativePath.find_first_of(" #${}^!") != llvm::StringRef::npos)
+      OS << '\"' << NativePath << '\"';
+    else
+      OS << NativePath;
+    return;
+  }
+  assert(OutputFormat == clang::DependencyOutputFormat::Make);
+  for (unsigned i = 0, e = NativePath.size(); i != e; ++i) {
+    if (NativePath[i] == '#') // Handle '#' the broken gcc way.
+      OS << '\\';
+    else if (NativePath[i] == ' ') { // Handle space correctly.
+      OS << '\\';
+      unsigned j = i;
+      while (j > 0 && NativePath[--j] == '\\')
+        OS << '\\';
+    } else if (NativePath[i] == '$') // $ is escaped by $$.
+      OS << '$';
+    OS << NativePath[i];
+  }
+}
+
+void clang::printMakeDependencyFile(llvm::raw_ostream &OS,
+                                    llvm::ArrayRef<std::string> Targets,
+                                    llvm::ArrayRef<std::string> Files,
+                                    DependencyOutputFormat Format,
+                                    bool PhonyTargets,
+                                    unsigned InputFileIndex) {
+  // Write out the dependency targets, trying to avoid overly long
+  // lines when possible. We try our best to emit exactly the same
+  // dependency file as GCC>=10, assuming the included files are the
+  // same.
+  const unsigned MaxColumns = 75;
+  unsigned Columns = 0;
+
+  for (StringRef Target : Targets) {
+    unsigned N = Target.size();
+    if (Columns == 0) {
+      Columns += N;
+    } else if (Columns + N + 2 > MaxColumns) {
+      Columns = N + 2;
+      OS << " \\\n  ";
+    } else {
+      Columns += N + 1;
+      OS << ' ';
+    }
+    // Targets already quoted as needed.
+    OS << Target;
+  }
+
+  OS << ':';
+  Columns += 1;
+
+  // Now add each dependency in the order it was seen, but avoiding
+  // duplicates.
+  for (StringRef File : Files) {
+    if (File == "<stdin>")
+      continue;
+    // Start a new line if this would exceed the column limit. Make
+    // sure to leave space for a trailing " \" in case we need to
+    // break the line on the next iteration.
+    unsigned N = File.size();
+    if (Columns + (N + 1) + 2 > MaxColumns) {
+      OS << " \\\n ";
+      Columns = 2;
+    }
+    OS << ' ';
+    printFilename(OS, File, Format);
+    Columns += N + 1;
+  }
+  OS << '\n';
+
+  // Create phony targets if requested.
+  if (PhonyTargets && !Files.empty()) {
+    unsigned Index = 0;
+    for (auto I = Files.begin(), E = Files.end(); I != E; ++I) {
+      if (Index++ == InputFileIndex)
+        continue;
+      printFilename(OS, *I, Format);
+      OS << ":\n";
+    }
+  }
+}
diff --git a/clang/lib/Driver/ToolChains/Flang.cpp 
b/clang/lib/Driver/ToolChains/Flang.cpp
index d900037230f20..a69913fc4872e 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -11,6 +11,7 @@
 #include "Cuda.h"
 
 #include "clang/Basic/CodeGenOptions.h"
+#include "clang/Basic/MakeSupport.h"
 #include "clang/Driver/CommonArgs.h"
 #include "clang/Options/OptionUtils.h"
 #include "clang/Options/Options.h"
@@ -35,6 +36,100 @@ static void addDashXForInput(const ArgList &Args, const 
InputInfo &Input,
   CmdArgs.push_back(types::getTypeName(Input.getType()));
 }
 
+// Translate the dependency-file options into the arguments understood by
+// `flang -fc1`. The options handled here:
+//   -M    Emit only the dependencies and skip code generation. They are
+//         written to stdout unless -MF redirects them.
+//   -MM   Treated identically to -M. The -MM/-M split exists to omit system
+//         headers, but Fortran has no notion of system vs user headers, so
+//         there is nothing for -MM to exclude.
+//   -MD   Compile normally and produce the object file, while also writing the
+//         dependency file. Its name defaults to the -o value, or the input
+//         file name when -o is absent, with the extension replaced by .d.
+//   -MMD  Treated identically to -MD, for the same reason -MM equals -M.
+//   -MF   Set the path of the dependency file to write.
+//   -MT   Set the dependency target name (the part before the colon).
+//   -MQ   Like -MT, but additionally quotes characters special to Make.
+static void renderDependencyGenerationOptions(Compilation &C,
+                                              const JobAction &JA,
+                                              const ArgList &Args,
+                                              const InputInfo &Output,
+                                              const InputInfoList &Inputs,
+                                              ArgStringList &CmdArgs) {
+  Arg *ArgM = Args.getLastArg(options::OPT_M, options::OPT_MM);
+  Arg *ArgMD = Args.getLastArg(options::OPT_MD, options::OPT_MMD);
+
+  // Drop warnings for -M/-MM so they don't mix into the dependency output.
+  if (ArgM) {
+    CmdArgs.push_back("-w");
+  } else {
+    ArgM = ArgMD;
+  }
+
+  if (!ArgM) {
+    return;
+  }
+
+  // Emit "-MT <target>", quoting Make metacharacters when requested.
+  auto addTarget = [&](StringRef Target, bool Quote) {
+    SmallString<128> Quoted;
+    if (Quote) {
+      clang::quoteMakeTarget(Target, Quoted);
+      Target = Quoted;
+    }
+    CmdArgs.push_back("-MT");
+    CmdArgs.push_back(Args.MakeArgString(Target));
+  };
+
+  // Decide where to write the dependency file.
+  const char *DepFile;
+  if (Arg *MF = Args.getLastArg(options::OPT_MF)) {
+    // -MF gives the path explicitly.
+    DepFile = MF->getValue();
+    C.addFailureResultFile(DepFile, &JA);
+  } else if (Output.getType() == types::TY_Dependencies) {
+    // Plain -M/-MM: the dependency file is the output, so use its name
+    DepFile = Output.getFilename();
+  } else if (!ArgMD) {
+    // -M/-MM with no -o: write the dependencies to stdout.
+    DepFile = "-";
+  } else {
+    // -MD/-MMD: name it after -o, else the input, with a .d extension.
+    SmallString<128> P;
+    if (Arg *OutputOpt = Args.getLastArg(options::OPT_o)) {
+      P = OutputOpt->getValue();
+    } else {
+      P = llvm::sys::path::filename(Inputs[0].getBaseInput());
+    }
+    llvm::sys::path::replace_extension(P, "d");
+    DepFile = Args.MakeArgString(P);
+    C.addFailureResultFile(DepFile, &JA);
+  }
+  CmdArgs.push_back("-dependency-file");
+  CmdArgs.push_back(DepFile);
+
+  // Render the explicit target(s). -MT is verbatim, -MQ is Make-quoted.
+  bool HasTarget = false;
+  for (const Arg *A : Args.filtered(options::OPT_MT, options::OPT_MQ)) {
+    HasTarget = true;
+    A->claim();
+    addTarget(A->getValue(), A->getOption().matches(options::OPT_MQ));
+  }
+
+  // With no explicit target, default to the object file. In -M/-MM mode -o
+  // names the dependency file, not the target, so derive <base>.o instead.
+  if (!HasTarget) {
+    if (Arg *OutputOpt = Args.getLastArg(options::OPT_o);
+        OutputOpt && Output.getType() != types::TY_Dependencies) {
+      addTarget(OutputOpt->getValue(), /*Quote=*/true);
+    } else {
+      SmallString<128> P(llvm::sys::path::filename(Inputs[0].getBaseInput()));
+      llvm::sys::path::replace_extension(P, "o");
+      addTarget(P, /*Quote=*/true);
+    }
+  }
+}
+
 void Flang::addFortranDialectOptions(const ArgList &Args,
                                      ArgStringList &CmdArgs) const {
   Args.addAllArgs(CmdArgs, {options::OPT_ffixed_form,
@@ -1052,9 +1147,13 @@ void Flang::ConstructJob(Compilation &C, const JobAction 
&JA,
   CmdArgs.push_back(Args.MakeArgString(TripleStr));
 
   if (isa<PreprocessJobAction>(JA)) {
-    CmdArgs.push_back("-E");
-    if (Args.getLastArg(options::OPT_dM)) {
-      CmdArgs.push_back("-dM");
+    if (Output.getType() == types::TY_Dependencies) {
+      CmdArgs.push_back("-Eonly");
+    } else {
+      CmdArgs.push_back("-E");
+      if (Args.getLastArg(options::OPT_dM)) {
+        CmdArgs.push_back("-dM");
+      }
     }
   } else if (isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) {
     if (JA.getType() == types::TY_Nothing) {
@@ -1310,6 +1409,8 @@ void Flang::ConstructJob(Compilation &C, const JobAction 
&JA,
   if (Args.getLastArg(options::OPT_save_temps_EQ))
     Args.AddLastArg(CmdArgs, options::OPT_save_temps_EQ);
 
+  renderDependencyGenerationOptions(C, JA, Args, Output, Inputs, CmdArgs);
+
   addDashXForInput(Args, Input, CmdArgs);
 
   bool FRecordCmdLine = false;
diff --git a/clang/lib/Frontend/DependencyFile.cpp 
b/clang/lib/Frontend/DependencyFile.cpp
index 00f4a54269cfa..5702d1dabcc8b 100644
--- a/clang/lib/Frontend/DependencyFile.cpp
+++ b/clang/lib/Frontend/DependencyFile.cpp
@@ -12,6 +12,7 @@
 
 #include "clang/Basic/DiagnosticFrontend.h"
 #include "clang/Basic/FileManager.h"
+#include "clang/Basic/MakeSupport.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Frontend/DependencyOutputOptions.h"
 #include "clang/Frontend/Utils.h"
@@ -293,85 +294,6 @@ void 
DependencyFileGenerator::finishedMainFile(DiagnosticsEngine &Diags) {
   outputDependencyFile(Diags);
 }
 
-/// Print the filename, with escaping or quoting that accommodates the three
-/// most likely tools that use dependency files: GNU Make, BSD Make, and
-/// NMake/Jom.
-///
-/// BSD Make is the simplest case: It does no escaping at all.  This means
-/// characters that are normally delimiters, i.e. space and # (the comment
-/// character) simply aren't supported in filenames.
-///
-/// GNU Make does allow space and # in filenames, but to avoid being treated
-/// as a delimiter or comment, these must be escaped with a backslash. Because
-/// backslash is itself the escape character, if a backslash appears in a
-/// filename, it should be escaped as well.  (As a special case, $ is escaped
-/// as $$, which is the normal Make way to handle the $ character.)
-/// For compatibility with BSD Make and historical practice, if GNU Make
-/// un-escapes characters in a filename but doesn't find a match, it will
-/// retry with the unmodified original string.
-///
-/// GCC tries to accommodate both Make formats by escaping any space or #
-/// characters in the original filename, but not escaping backslashes.  The
-/// apparent intent is so that filenames with backslashes will be handled
-/// correctly by BSD Make, and by GNU Make in its fallback mode of using the
-/// unmodified original string; filenames with # or space characters aren't
-/// supported by BSD Make at all, but will be handled correctly by GNU Make
-/// due to the escaping.
-///
-/// A corner case that GC...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/209379
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to