From 2dd0cb7aeb2d70dcc6e103c29ce2ce3a02bd381a Mon Sep 17 00:00:00 2001
From: Ben Boeckel <ben.boeckel@kitware.com>
Date: Wed, 20 Feb 2019 11:35:47 -0500
Subject: Help: note that Ninja also uses OBJECT_OUTPUTS

---
 Help/prop_sf/OBJECT_OUTPUTS.rst | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Help/prop_sf/OBJECT_OUTPUTS.rst b/Help/prop_sf/OBJECT_OUTPUTS.rst
index 6a28553..1ce4866 100644
--- a/Help/prop_sf/OBJECT_OUTPUTS.rst
+++ b/Help/prop_sf/OBJECT_OUTPUTS.rst
@@ -1,9 +1,9 @@
 OBJECT_OUTPUTS
 --------------
 
-Additional outputs for a Makefile rule.
+Additional outputs for a Ninja or Makefile rule.
 
 Additional outputs created by compilation of this source file.  If any
 of these outputs is missing the object will be recompiled.  This is
-supported only on Makefile generators and will be ignored on other
-generators.
+supported only on the Ninja and Makefile generators and will be ignored on
+other generators.
-- 
cgit v0.12


From 72f9bb29939f3765216e98e672197b3899d75f7d Mon Sep 17 00:00:00 2001
From: Ben Boeckel <ben.boeckel@kitware.com>
Date: Wed, 20 Feb 2019 01:39:55 -0500
Subject: ninja: make dyndep generation language aware

A target may have multiple languages with dyndep rules, separate `.dd`
files should be generated.
---
 Source/cmGlobalNinjaGenerator.cxx | 31 ++++++++++++++++++++-----------
 Source/cmGlobalNinjaGenerator.h   |  3 ++-
 Source/cmNinjaTargetGenerator.cxx | 21 ++++++++++++---------
 Source/cmNinjaTargetGenerator.h   |  3 ++-
 4 files changed, 36 insertions(+), 22 deletions(-)

diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index 018606c..5a85963 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -1593,7 +1593,7 @@ Compilation of source files within a target is split into the following steps:
 
     rule Fortran_DYNDEP
       command = cmake -E cmake_ninja_dyndep \
-                  --tdi=FortranDependInfo.json --dd=$out $in
+                  --tdi=FortranDependInfo.json --lang=Fortran --dd=$out $in
 
     build Fortran.dd: Fortran_DYNDEP src1.f90-pp.f90.ddi src2.f90-pp.f90.ddi
 
@@ -1755,7 +1755,7 @@ int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg,
   return 0;
 }
 
-struct cmFortranObjectInfo
+struct cmDyndepObjectInfo
 {
   std::string Object;
   std::vector<std::string> Provides;
@@ -1767,7 +1767,8 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
   std::string const& dir_cur_src, std::string const& dir_cur_bld,
   std::string const& arg_dd, std::vector<std::string> const& arg_ddis,
   std::string const& module_dir,
-  std::vector<std::string> const& linked_target_dirs)
+  std::vector<std::string> const& linked_target_dirs,
+  std::string const& arg_lang)
 {
   // Setup path conversions.
   {
@@ -1784,7 +1785,7 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
     this->LocalGenerators.push_back(lgd.release());
   }
 
-  std::vector<cmFortranObjectInfo> objects;
+  std::vector<cmDyndepObjectInfo> objects;
   for (std::string const& arg_ddi : arg_ddis) {
     // Load the ddi file and compute the module file paths it provides.
     Json::Value ddio;
@@ -1797,7 +1798,7 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
       return false;
     }
 
-    cmFortranObjectInfo info;
+    cmDyndepObjectInfo info;
     info.Object = ddi["object"].asString();
     Json::Value const& ddi_provides = ddi["provides"];
     if (ddi_provides.isArray()) {
@@ -1819,7 +1820,8 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
 
   // Populate the module map with those provided by linked targets first.
   for (std::string const& linked_target_dir : linked_target_dirs) {
-    std::string const ltmn = linked_target_dir + "/FortranModules.json";
+    std::string const ltmn =
+      linked_target_dir + "/" + arg_lang + "Modules.json";
     Json::Value ltm;
     cmsys::ifstream ltmf(ltmn.c_str(), std::ios::in | std::ios::binary);
     Json::Reader reader;
@@ -1840,7 +1842,7 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
   // We do this after loading the modules provided by linked targets
   // in case we have one of the same name that must be preferred.
   Json::Value tm = Json::objectValue;
-  for (cmFortranObjectInfo const& object : objects) {
+  for (cmDyndepObjectInfo const& object : objects) {
     for (std::string const& p : object.Provides) {
       std::string const mod = module_dir + p;
       mod_files[p] = mod;
@@ -1851,7 +1853,7 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
   cmGeneratedFileStream ddf(arg_dd);
   ddf << "ninja_dyndep_version = 1.0\n";
 
-  for (cmFortranObjectInfo const& object : objects) {
+  for (cmDyndepObjectInfo const& object : objects) {
     std::string const ddComment;
     std::string const ddRule = "dyndep";
     cmNinjaDeps ddOutputs;
@@ -1882,7 +1884,7 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
   // Store the map of modules provided by this target in a file for
   // use by dependents that reference this target in linked-target-dirs.
   std::string const target_mods_file =
-    cmSystemTools::GetFilenamePath(arg_dd) + "/FortranModules.json";
+    cmSystemTools::GetFilenamePath(arg_dd) + "/" + arg_lang + "Modules.json";
   cmGeneratedFileStream tmf(target_mods_file);
   tmf << tm;
 
@@ -1896,11 +1898,14 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
     cmSystemTools::HandleResponseFile(argBeg, argEnd);
 
   std::string arg_dd;
+  std::string arg_lang;
   std::string arg_tdi;
   std::vector<std::string> arg_ddis;
   for (std::string const& arg : arg_full) {
     if (cmHasLiteralPrefix(arg, "--tdi=")) {
       arg_tdi = arg.substr(6);
+    } else if (cmHasLiteralPrefix(arg, "--lang=")) {
+      arg_lang = arg.substr(7);
     } else if (cmHasLiteralPrefix(arg, "--dd=")) {
       arg_dd = arg.substr(5);
     } else if (!cmHasLiteralPrefix(arg, "--") &&
@@ -1915,6 +1920,10 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
     cmSystemTools::Error("-E cmake_ninja_dyndep requires value for --tdi=");
     return 1;
   }
+  if (arg_lang.empty()) {
+    cmSystemTools::Error("-E cmake_ninja_dyndep requires value for --lang=");
+    return 1;
+  }
   if (arg_dd.empty()) {
     cmSystemTools::Error("-E cmake_ninja_dyndep requires value for --dd=");
     return 1;
@@ -1955,8 +1964,8 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
     static_cast<cmGlobalNinjaGenerator*>(cm.CreateGlobalGenerator("Ninja")));
   if (!ggd ||
       !ggd->WriteDyndepFile(dir_top_src, dir_top_bld, dir_cur_src, dir_cur_bld,
-                            arg_dd, arg_ddis, module_dir,
-                            linked_target_dirs)) {
+                            arg_dd, arg_ddis, module_dir, linked_target_dirs,
+                            arg_lang)) {
     return 1;
   }
   return 0;
diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h
index c619e67..69210ec 100644
--- a/Source/cmGlobalNinjaGenerator.h
+++ b/Source/cmGlobalNinjaGenerator.h
@@ -365,7 +365,8 @@ public:
                        std::string const& arg_dd,
                        std::vector<std::string> const& arg_ddis,
                        std::string const& module_dir,
-                       std::vector<std::string> const& linked_target_dirs);
+                       std::vector<std::string> const& linked_target_dirs,
+                       std::string const& arg_lang);
 
 protected:
   void Generate() override;
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index 6013cd0..6a08d5c 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -594,7 +594,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
     ddCmds.push_back(cmake +
                      " -E cmake_ninja_dyndep"
                      " --tdi=" +
-                     tdi +
+                     tdi + " --lang=" + lang +
                      " --dd=$out"
                      " " +
                      ddInput);
@@ -868,24 +868,27 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements()
     this->WriteObjectBuildStatement(sf);
   }
 
-  if (!this->DDIFiles.empty()) {
+  for (auto const& langDDIFiles : this->DDIFiles) {
+    std::string const& language = langDDIFiles.first;
+    cmNinjaDeps const& ddiFiles = langDDIFiles.second;
+
     std::string const ddComment;
-    std::string const ddRule = this->LanguageDyndepRule("Fortran");
+    std::string const ddRule = this->LanguageDyndepRule(language);
     cmNinjaDeps ddOutputs;
     cmNinjaDeps ddImplicitOuts;
-    cmNinjaDeps const& ddExplicitDeps = this->DDIFiles;
+    cmNinjaDeps const& ddExplicitDeps = ddiFiles;
     cmNinjaDeps ddImplicitDeps;
     cmNinjaDeps ddOrderOnlyDeps;
     cmNinjaVars ddVars;
 
-    this->WriteTargetDependInfo("Fortran");
+    this->WriteTargetDependInfo(language);
 
-    ddOutputs.push_back(this->GetDyndepFilePath("Fortran"));
+    ddOutputs.push_back(this->GetDyndepFilePath(language));
 
     // Make sure dyndep files for all our dependencies have already
-    // been generated so that the 'FortranModules.json' files they
+    // been generated so that the '<LANG>Modules.json' files they
     // produced as side-effects are available for us to read.
-    // Ideally we should depend on the 'FortranModules.json' files
+    // Ideally we should depend on the '<LANG>Modules.json' files
     // from our dependencies directly, but we don't know which of
     // our dependencies produces them.  Fixing this will require
     // refactoring the Ninja generator to generate targets in
@@ -1099,7 +1102,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
       std::string const ddiFile = ppFileName + ".ddi";
       ppVars["DYNDEP_INTERMEDIATE_FILE"] = ddiFile;
       ppImplicitOuts.push_back(ddiFile);
-      this->DDIFiles.push_back(ddiFile);
+      this->DDIFiles[language].push_back(ddiFile);
     }
 
     this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(),
diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h
index 373c693..2ffd256 100644
--- a/Source/cmNinjaTargetGenerator.h
+++ b/Source/cmNinjaTargetGenerator.h
@@ -10,6 +10,7 @@
 #include "cmNinjaTypes.h"
 #include "cmOSXBundleGenerator.h"
 
+#include <map>
 #include <set>
 #include <string>
 #include <vector>
@@ -165,7 +166,7 @@ private:
   cmLocalNinjaGenerator* LocalGenerator;
   /// List of object files for this target.
   cmNinjaDeps Objects;
-  cmNinjaDeps DDIFiles; // TODO: Make per-language.
+  std::map<std::string, cmNinjaDeps> DDIFiles;
   std::vector<cmCustomCommand const*> CustomCommands;
   cmNinjaDeps ExtraFiles;
 };
-- 
cgit v0.12


From 2c0a7bc770367e80ce1fc68ea6cb9c9543e854e4 Mon Sep 17 00:00:00 2001
From: Ben Boeckel <ben.boeckel@kitware.com>
Date: Wed, 20 Feb 2019 04:57:07 -0500
Subject: ninja: pass language to cmake_ninja_depends

---
 Source/cmGlobalNinjaGenerator.cxx | 119 ++++++++++++++++++++++++++------------
 Source/cmNinjaTargetGenerator.cxx |   6 +-
 2 files changed, 85 insertions(+), 40 deletions(-)

diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index 5a85963..74d3e8d 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -1574,7 +1574,8 @@ Compilation of source files within a target is split into the following steps:
       command = gfortran -cpp $DEFINES $INCLUDES $FLAGS -E $in -o $out &&
                 cmake -E cmake_ninja_depends \
                   --tdi=FortranDependInfo.json --pp=$out --dep=$DEP_FILE \
-                  --obj=$OBJ_FILE --ddi=$DYNDEP_INTERMEDIATE_FILE
+                  --obj=$OBJ_FILE --ddi=$DYNDEP_INTERMEDIATE_FILE \
+                  --lang=Fortran
 
     build src.f90-pp.f90 | src.f90-pp.f90.ddi: Fortran_PREPROCESS src.f90
       OBJ_FILE = src.f90.o
@@ -1633,6 +1634,19 @@ Compilation of source files within a target is split into the following steps:
    (because the latter consumes the module).
 */
 
+struct cmSourceInfo
+{
+  // Set of provided and required modules.
+  std::set<std::string> Provides;
+  std::set<std::string> Requires;
+
+  // Set of files included in the translation unit.
+  std::set<std::string> Includes;
+};
+
+static std::unique_ptr<cmSourceInfo> cmcmd_cmake_ninja_depends_fortran(
+  std::string const& arg_tdi, std::string const& arg_pp);
+
 int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg,
                               std::vector<std::string>::const_iterator argEnd)
 {
@@ -1641,6 +1655,7 @@ int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg,
   std::string arg_dep;
   std::string arg_obj;
   std::string arg_ddi;
+  std::string arg_lang;
   for (std::string const& arg : cmMakeRange(argBeg, argEnd)) {
     if (cmHasLiteralPrefix(arg, "--tdi=")) {
       arg_tdi = arg.substr(6);
@@ -1652,6 +1667,8 @@ int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg,
       arg_obj = arg.substr(6);
     } else if (cmHasLiteralPrefix(arg, "--ddi=")) {
       arg_ddi = arg.substr(6);
+    } else if (cmHasLiteralPrefix(arg, "--lang=")) {
+      arg_lang = arg.substr(7);
     } else {
       cmSystemTools::Error("-E cmake_ninja_depends unknown argument: " + arg);
       return 1;
@@ -1677,7 +1694,61 @@ int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg,
     cmSystemTools::Error("-E cmake_ninja_depends requires value for --ddi=");
     return 1;
   }
+  if (arg_lang.empty()) {
+    cmSystemTools::Error("-E cmake_ninja_depends requires value for --lang=");
+    return 1;
+  }
+
+  std::unique_ptr<cmSourceInfo> info;
+  if (arg_lang == "Fortran") {
+    info = cmcmd_cmake_ninja_depends_fortran(arg_tdi, arg_pp);
+  } else {
+    cmSystemTools::Error("-E cmake_ninja_depends does not understand the " +
+                         arg_lang + " language");
+    return 1;
+  }
 
+  if (!info) {
+    // The error message is already expected to have been output.
+    return 1;
+  }
+
+  {
+    cmGeneratedFileStream depfile(arg_dep);
+    depfile << cmSystemTools::ConvertToUnixOutputPath(arg_pp) << ":";
+    for (std::string const& include : info->Includes) {
+      depfile << " \\\n " << cmSystemTools::ConvertToUnixOutputPath(include);
+    }
+    depfile << "\n";
+  }
+
+  Json::Value ddi(Json::objectValue);
+  ddi["object"] = arg_obj;
+
+  Json::Value& ddi_provides = ddi["provides"] = Json::arrayValue;
+  for (std::string const& provide : info->Provides) {
+    ddi_provides.append(provide);
+  }
+  Json::Value& ddi_requires = ddi["requires"] = Json::arrayValue;
+  for (std::string const& r : info->Requires) {
+    // Require modules not provided in the same source.
+    if (!info->Provides.count(r)) {
+      ddi_requires.append(r);
+    }
+  }
+
+  cmGeneratedFileStream ddif(arg_ddi);
+  ddif << ddi;
+  if (!ddif) {
+    cmSystemTools::Error("-E cmake_ninja_depends failed to write " + arg_ddi);
+    return 1;
+  }
+  return 0;
+}
+
+std::unique_ptr<cmSourceInfo> cmcmd_cmake_ninja_depends_fortran(
+  std::string const& arg_tdi, std::string const& arg_pp)
+{
   cmFortranCompiler fc;
   std::vector<std::string> includes;
   {
@@ -1689,7 +1760,7 @@ int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg,
       if (!reader.parse(tdif, tdio, false)) {
         cmSystemTools::Error("-E cmake_ninja_depends failed to parse " +
                              arg_tdi + reader.getFormattedErrorMessages());
-        return 1;
+        return nullptr;
       }
     }
 
@@ -1710,49 +1781,23 @@ int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg,
     fc.SModExt = tdi_submodule_ext.asString();
   }
 
-  cmFortranSourceInfo info;
+  cmFortranSourceInfo finfo;
   std::set<std::string> defines;
-  cmFortranParser parser(fc, includes, defines, info);
+  cmFortranParser parser(fc, includes, defines, finfo);
   if (!cmFortranParser_FilePush(&parser, arg_pp.c_str())) {
     cmSystemTools::Error("-E cmake_ninja_depends failed to open " + arg_pp);
-    return 1;
+    return nullptr;
   }
   if (cmFortran_yyparse(parser.Scanner) != 0) {
     // Failed to parse the file.
-    return 1;
-  }
-
-  {
-    cmGeneratedFileStream depfile(arg_dep);
-    depfile << cmSystemTools::ConvertToUnixOutputPath(arg_pp) << ":";
-    for (std::string const& include : info.Includes) {
-      depfile << " \\\n " << cmSystemTools::ConvertToUnixOutputPath(include);
-    }
-    depfile << "\n";
+    return nullptr;
   }
 
-  Json::Value ddi(Json::objectValue);
-  ddi["object"] = arg_obj;
-
-  Json::Value& ddi_provides = ddi["provides"] = Json::arrayValue;
-  for (std::string const& provide : info.Provides) {
-    ddi_provides.append(provide);
-  }
-  Json::Value& ddi_requires = ddi["requires"] = Json::arrayValue;
-  for (std::string const& r : info.Requires) {
-    // Require modules not provided in the same source.
-    if (!info.Provides.count(r)) {
-      ddi_requires.append(r);
-    }
-  }
-
-  cmGeneratedFileStream ddif(arg_ddi);
-  ddif << ddi;
-  if (!ddif) {
-    cmSystemTools::Error("-E cmake_ninja_depends failed to write " + arg_ddi);
-    return 1;
-  }
-  return 0;
+  auto info = cm::make_unique<cmSourceInfo>();
+  info->Provides = finfo.Provides;
+  info->Requires = finfo.Requires;
+  info->Includes = finfo.Includes;
+  return info;
 }
 
 struct cmDyndepObjectInfo
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index 6a08d5c..28d4a07 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -558,7 +558,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
       cmake +
       " -E cmake_ninja_depends"
       " --tdi=" +
-      tdi +
+      tdi + " --lang=" + lang +
       " --pp=$out"
       " --dep=$DEP_FILE" +
       (needDyndep ? " --obj=$OBJ_FILE --ddi=$DYNDEP_INTERMEDIATE_FILE" : ""));
@@ -1062,8 +1062,8 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
 
     // In case compilation requires flags that are incompatible with
     // preprocessing, include them here.
-    std::string const postFlag =
-      this->Makefile->GetSafeDefinition("CMAKE_Fortran_POSTPROCESS_FLAG");
+    std::string const postFlag = this->Makefile->GetSafeDefinition(
+      "CMAKE_" + language + "_POSTPROCESS_FLAG");
     this->LocalGenerator->AppendFlags(vars["FLAGS"], postFlag);
 
     // Move preprocessor definitions to the preprocessor build statement.
-- 
cgit v0.12


From 933dd9164210a2f08dae6e1333ab7e5c30e3b012 Mon Sep 17 00:00:00 2001
From: Ben Boeckel <ben.boeckel@kitware.com>
Date: Wed, 20 Feb 2019 12:13:33 -0500
Subject: ninja: do not assume explicit preprocessing uses that output

In Fortran, this is OK, but for C++, compiling preprocessed source
generally results in poorer diagnostic messages and can also be
ill-formed anyways.
---
 Source/cmNinjaTargetGenerator.cxx | 78 ++++++++++++++++++++++++++-------------
 Source/cmNinjaTargetGenerator.h   |  1 +
 2 files changed, 53 insertions(+), 26 deletions(-)

diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index 28d4a07..4998ac8 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -102,6 +102,12 @@ bool cmNinjaTargetGenerator::NeedExplicitPreprocessing(
   return lang == "Fortran";
 }
 
+bool cmNinjaTargetGenerator::UsePreprocessedSource(
+  std::string const& lang) const
+{
+  return lang == "Fortran";
+}
+
 std::string cmNinjaTargetGenerator::LanguageDyndepRule(
   const std::string& lang) const
 {
@@ -1035,6 +1041,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
   // For some cases we do an explicit preprocessor invocation.
   bool const explicitPP = this->NeedExplicitPreprocessing(language);
   if (explicitPP) {
+    bool const compilePP = this->UsePreprocessedSource(language);
     std::string const ppComment;
     std::string const ppRule = this->LanguagePreprocessRule(language);
     cmNinjaDeps ppOutputs;
@@ -1048,50 +1055,69 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
       this->ConvertToNinjaPath(this->GetPreprocessedFilePath(source));
     ppOutputs.push_back(ppFileName);
 
-    // Move compilation dependencies to the preprocessing build statement.
-    std::swap(ppExplicitDeps, explicitDeps);
-    std::swap(ppImplicitDeps, implicitDeps);
-    std::swap(ppOrderOnlyDeps, orderOnlyDeps);
-    std::swap(ppVars["IN_ABS"], vars["IN_ABS"]);
+    if (compilePP) {
+      // Move compilation dependencies to the preprocessing build statement.
+      std::swap(ppExplicitDeps, explicitDeps);
+      std::swap(ppImplicitDeps, implicitDeps);
+      std::swap(ppOrderOnlyDeps, orderOnlyDeps);
+      std::swap(ppVars["IN_ABS"], vars["IN_ABS"]);
 
-    // The actual compilation will now use the preprocessed source.
-    explicitDeps.push_back(ppFileName);
+      // The actual compilation will now use the preprocessed source.
+      explicitDeps.push_back(ppFileName);
+    } else {
+      // Copy compilation dependencies to the preprocessing build statement.
+      ppExplicitDeps = explicitDeps;
+      ppImplicitDeps = implicitDeps;
+      ppOrderOnlyDeps = orderOnlyDeps;
+      ppVars["IN_ABS"] = vars["IN_ABS"];
+    }
 
     // Preprocessing and compilation generally use the same flags.
     ppVars["FLAGS"] = vars["FLAGS"];
 
-    // In case compilation requires flags that are incompatible with
-    // preprocessing, include them here.
-    std::string const postFlag = this->Makefile->GetSafeDefinition(
-      "CMAKE_" + language + "_POSTPROCESS_FLAG");
-    this->LocalGenerator->AppendFlags(vars["FLAGS"], postFlag);
+    if (compilePP) {
+      // In case compilation requires flags that are incompatible with
+      // preprocessing, include them here.
+      std::string const postFlag = this->Makefile->GetSafeDefinition(
+        "CMAKE_" + language + "_POSTPROCESS_FLAG");
+      this->LocalGenerator->AppendFlags(vars["FLAGS"], postFlag);
+    }
 
-    // Move preprocessor definitions to the preprocessor build statement.
-    std::swap(ppVars["DEFINES"], vars["DEFINES"]);
+    if (compilePP) {
+      // Move preprocessor definitions to the preprocessor build statement.
+      std::swap(ppVars["DEFINES"], vars["DEFINES"]);
+    } else {
+      // Copy preprocessor definitions to the preprocessor build statement.
+      ppVars["DEFINES"] = vars["DEFINES"];
+    }
 
     // Copy include directories to the preprocessor build statement.  The
     // Fortran compilation build statement still needs them for the INCLUDE
     // directive.
     ppVars["INCLUDES"] = vars["INCLUDES"];
 
-    // Prepend source file's original directory as an include directory
-    // so e.g. Fortran INCLUDE statements can look for files in it.
-    std::vector<std::string> sourceDirectory;
-    sourceDirectory.push_back(
-      cmSystemTools::GetParentDirectory(source->GetFullPath()));
+    if (compilePP) {
+      // Prepend source file's original directory as an include directory
+      // so e.g. Fortran INCLUDE statements can look for files in it.
+      std::vector<std::string> sourceDirectory;
+      sourceDirectory.push_back(
+        cmSystemTools::GetParentDirectory(source->GetFullPath()));
 
-    std::string sourceDirectoryFlag = this->LocalGenerator->GetIncludeFlags(
-      sourceDirectory, this->GeneratorTarget, language, false, false,
-      this->GetConfigName());
+      std::string sourceDirectoryFlag = this->LocalGenerator->GetIncludeFlags(
+        sourceDirectory, this->GeneratorTarget, language, false, false,
+        this->GetConfigName());
 
-    vars["INCLUDES"] = sourceDirectoryFlag + " " + vars["INCLUDES"];
+      vars["INCLUDES"] = sourceDirectoryFlag + " " + vars["INCLUDES"];
+    }
 
     // Explicit preprocessing always uses a depfile.
     ppVars["DEP_FILE"] = this->GetLocalGenerator()->ConvertToOutputFormat(
       ppFileName + ".d", cmOutputConverter::SHELL);
-    // The actual compilation does not need a depfile because it
-    // depends on the already-preprocessed source.
-    vars.erase("DEP_FILE");
+    if (compilePP) {
+      // The actual compilation does not need a depfile because it
+      // depends on the already-preprocessed source.
+      vars.erase("DEP_FILE");
+    }
 
     if (needDyndep) {
       // Tell dependency scanner the object file that will result from
diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h
index 2ffd256..6a42da0 100644
--- a/Source/cmNinjaTargetGenerator.h
+++ b/Source/cmNinjaTargetGenerator.h
@@ -65,6 +65,7 @@ protected:
   bool NeedExplicitPreprocessing(std::string const& lang) const;
   std::string LanguageDyndepRule(std::string const& lang) const;
   bool NeedDyndep(std::string const& lang) const;
+  bool UsePreprocessedSource(std::string const& lang) const;
 
   std::string OrderDependsTargetForTarget();
 
-- 
cgit v0.12


From 7c78adca8e0285c198e03163c2bb722cd86b389d Mon Sep 17 00:00:00 2001
From: Ben Boeckel <ben.boeckel@kitware.com>
Date: Wed, 20 Feb 2019 01:41:26 -0500
Subject: cmNinjaTargetGenerator: remove "preprocessed" mentions in dyndep

Not all languages compile the preprocessed source (or even have
preprocessed sources at all).
---
 Source/cmNinjaTargetGenerator.cxx | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index 4998ac8..6e140fb 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -594,7 +594,8 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
     std::string ddRspContent = "$in";
     std::string ddInput = "@" + ddRspFile;
 
-    // Run CMake dependency scanner on preprocessed output.
+    // Run CMake dependency scanner on the source file (using the preprocessed
+    // source if that was performed).
     std::string const cmake = this->GetLocalGenerator()->ConvertToOutputFormat(
       cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
     ddCmds.push_back(cmake +
@@ -1121,7 +1122,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
 
     if (needDyndep) {
       // Tell dependency scanner the object file that will result from
-      // compiling the preprocessed source.
+      // compiling the source.
       ppVars["OBJ_FILE"] = objectFileName;
 
       // Tell dependency scanner where to store dyndep intermediate results.
-- 
cgit v0.12


From f22c18b1c1554b573c684efcb5c921c17c9b0f1d Mon Sep 17 00:00:00 2001
From: Ben Boeckel <ben.boeckel@kitware.com>
Date: Wed, 20 Feb 2019 13:20:28 -0500
Subject: ninja: name dyndep internal files using the object file

Now that preprocessing outputs are not necessarily used all the way
through, the output name is a better base name to use for these files.
---
 Source/cmGlobalNinjaGenerator.cxx | 8 ++++----
 Source/cmNinjaTargetGenerator.cxx | 4 ++--
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index 74d3e8d..d21fd35 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -1577,10 +1577,10 @@ Compilation of source files within a target is split into the following steps:
                   --obj=$OBJ_FILE --ddi=$DYNDEP_INTERMEDIATE_FILE \
                   --lang=Fortran
 
-    build src.f90-pp.f90 | src.f90-pp.f90.ddi: Fortran_PREPROCESS src.f90
+    build src.f90-pp.f90 | src.f90.o.ddi: Fortran_PREPROCESS src.f90
       OBJ_FILE = src.f90.o
-      DEP_FILE = src.f90-pp.f90.d
-      DYNDEP_INTERMEDIATE_FILE = src.f90-pp.f90.ddi
+      DEP_FILE = src.f90.o.d
+      DYNDEP_INTERMEDIATE_FILE = src.f90.o.ddi
 
    The ``cmake -E cmake_ninja_depends`` tool reads the preprocessed output
    and generates the ninja depfile for preprocessor dependencies.  It also
@@ -1596,7 +1596,7 @@ Compilation of source files within a target is split into the following steps:
       command = cmake -E cmake_ninja_dyndep \
                   --tdi=FortranDependInfo.json --lang=Fortran --dd=$out $in
 
-    build Fortran.dd: Fortran_DYNDEP src1.f90-pp.f90.ddi src2.f90-pp.f90.ddi
+    build Fortran.dd: Fortran_DYNDEP src1.f90.o.ddi src2.f90.o.ddi
 
    The ``cmake -E cmake_ninja_dyndep`` tool reads the "ddi" files from all
    sources in the target and the ``FortranModules.json`` files from targets
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index 6e140fb..8d11408 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -1113,7 +1113,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
 
     // Explicit preprocessing always uses a depfile.
     ppVars["DEP_FILE"] = this->GetLocalGenerator()->ConvertToOutputFormat(
-      ppFileName + ".d", cmOutputConverter::SHELL);
+      objectFileName + ".d", cmOutputConverter::SHELL);
     if (compilePP) {
       // The actual compilation does not need a depfile because it
       // depends on the already-preprocessed source.
@@ -1126,7 +1126,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
       ppVars["OBJ_FILE"] = objectFileName;
 
       // Tell dependency scanner where to store dyndep intermediate results.
-      std::string const ddiFile = ppFileName + ".ddi";
+      std::string const ddiFile = objectFileName + ".ddi";
       ppVars["DYNDEP_INTERMEDIATE_FILE"] = ddiFile;
       ppImplicitOuts.push_back(ddiFile);
       this->DDIFiles[language].push_back(ddiFile);
-- 
cgit v0.12