Browse Source

Merge topic 'ninja_rule_class'

6136ab5e17 Ninja: Use cmNinjaRule as sole parameter in the WriteRule and AddRule methods
6a23fbce47 Ninja: Add cmNinjaRule class

Acked-by: Kitware Robot <[email protected]>
Merge-request: !3393
Brad King 6 years ago
parent
commit
9dad42d21a

+ 76 - 111
Source/cmGlobalNinjaGenerator.cxx

@@ -238,14 +238,11 @@ void cmGlobalNinjaGenerator::WritePhonyBuild(
 
 void cmGlobalNinjaGenerator::AddCustomCommandRule()
 {
-  this->AddRule("CUSTOM_COMMAND", "$COMMAND", "$DESC",
-                "Rule for running custom commands.",
-                /*depfile*/ "",
-                /*deptype*/ "",
-                /*rspfile*/ "",
-                /*rspcontent*/ "",
-                /*restat*/ "", // bound on each build statement as needed
-                /*generator*/ false);
+  cmNinjaRule rule("CUSTOM_COMMAND");
+  rule.Command = "$COMMAND";
+  rule.Description = "$DESC";
+  rule.Comment = "Rule for running custom commands.";
+  this->AddRule(rule);
 }
 
 void cmGlobalNinjaGenerator::WriteCustomCommandBuild(
@@ -293,15 +290,11 @@ void cmGlobalNinjaGenerator::WriteCustomCommandBuild(
 
 void cmGlobalNinjaGenerator::AddMacOSXContentRule()
 {
-  this->AddRule("COPY_OSX_CONTENT", CMakeCmd() + " -E copy $in $out",
-                "Copying OS X Content $out",
-                "Rule for copying OS X bundle content file.",
-                /*depfile*/ "",
-                /*deptype*/ "",
-                /*rspfile*/ "",
-                /*rspcontent*/ "",
-                /*restat*/ "",
-                /*generator*/ false);
+  cmNinjaRule rule("COPY_OSX_CONTENT");
+  rule.Command = CMakeCmd() + " -E copy $in $out";
+  rule.Description = "Copying OS X Content $out";
+  rule.Comment = "Rule for copying OS X bundle content file.";
+  this->AddRule(rule);
 }
 
 void cmGlobalNinjaGenerator::WriteMacOSXContentBuild(const std::string& input,
@@ -320,40 +313,36 @@ void cmGlobalNinjaGenerator::WriteMacOSXContentBuild(const std::string& input,
                    cmNinjaDeps(), cmNinjaVars());
 }
 
-void cmGlobalNinjaGenerator::WriteRule(
-  std::ostream& os, const std::string& name, const std::string& command,
-  const std::string& description, const std::string& comment,
-  const std::string& depfile, const std::string& deptype,
-  const std::string& rspfile, const std::string& rspcontent,
-  const std::string& restat, bool generator)
+void cmGlobalNinjaGenerator::WriteRule(std::ostream& os,
+                                       cmNinjaRule const& rule)
 {
   // -- Parameter checks
   // Make sure the rule has a name.
-  if (name.empty()) {
+  if (rule.Name.empty()) {
     cmSystemTools::Error("No name given for WriteRule! called with comment: " +
-                         comment);
+                         rule.Comment);
     return;
   }
 
   // Make sure a command is given.
-  if (command.empty()) {
+  if (rule.Command.empty()) {
     cmSystemTools::Error(
-      "No command given for WriteRule! called with comment: " + comment);
+      "No command given for WriteRule! called with comment: " + rule.Comment);
     return;
   }
 
   // Make sure response file content is given
-  if (!rspfile.empty() && rspcontent.empty()) {
+  if (!rule.RspFile.empty() && rule.RspContent.empty()) {
     cmSystemTools::Error("rspfile but no rspfile_content given for WriteRule! "
                          "called with comment: " +
-                         comment);
+                         rule.Comment);
     return;
   }
 
   // -- Write rule
   // Write rule intro
-  cmGlobalNinjaGenerator::WriteComment(os, comment);
-  os << "rule " << name << '\n';
+  cmGlobalNinjaGenerator::WriteComment(os, rule.Comment);
+  os << "rule " << rule.Name << '\n';
 
   // Write rule key/value pairs
   auto writeKV = [&os](const char* key, std::string const& value) {
@@ -363,16 +352,16 @@ void cmGlobalNinjaGenerator::WriteRule(
     }
   };
 
-  writeKV("depfile", depfile);
-  writeKV("deps", deptype);
-  writeKV("command", command);
-  writeKV("description", description);
-  if (!rspfile.empty()) {
-    writeKV("rspfile", rspfile);
-    writeKV("rspfile_content", rspcontent);
+  writeKV("depfile", rule.DepFile);
+  writeKV("deps", rule.DepType);
+  writeKV("command", rule.Command);
+  writeKV("description", rule.Description);
+  if (!rule.RspFile.empty()) {
+    writeKV("rspfile", rule.RspFile);
+    writeKV("rspfile_content", rule.RspContent);
   }
-  writeKV("restat", restat);
-  if (generator) {
+  writeKV("restat", rule.Restat);
+  if (rule.Generator) {
     writeKV("generator", "1");
   }
 
@@ -697,23 +686,16 @@ cmGlobalNinjaGenerator::GenerateBuildCommand(
 
 // Non-virtual public methods.
 
-void cmGlobalNinjaGenerator::AddRule(
-  const std::string& name, const std::string& command,
-  const std::string& description, const std::string& comment,
-  const std::string& depfile, const std::string& deptype,
-  const std::string& rspfile, const std::string& rspcontent,
-  const std::string& restat, bool generator)
+void cmGlobalNinjaGenerator::AddRule(cmNinjaRule const& rule)
 {
   // Do not add the same rule twice.
-  if (!this->Rules.insert(name).second) {
+  if (!this->Rules.insert(rule.Name).second) {
     return;
   }
   // Store command length
-  this->RuleCmdLength[name] = static_cast<int>(command.size());
+  this->RuleCmdLength[rule.Name] = static_cast<int>(rule.Command.size());
   // Write rule
-  cmGlobalNinjaGenerator::WriteRule(*this->RulesFileStream, name, command,
-                                    description, comment, depfile, deptype,
-                                    rspfile, rspcontent, restat, generator);
+  cmGlobalNinjaGenerator::WriteRule(*this->RulesFileStream, rule);
 }
 
 bool cmGlobalNinjaGenerator::HasRule(const std::string& name)
@@ -1329,21 +1311,18 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os)
   cmLocalGenerator* lg = this->LocalGenerators[0];
 
   {
-    std::string cmd = CMakeCmd();
-    cmd += " -S";
-    cmd += lg->ConvertToOutputFormat(lg->GetSourceDirectory(),
-                                     cmOutputConverter::SHELL);
-    cmd += " -B";
-    cmd += lg->ConvertToOutputFormat(lg->GetBinaryDirectory(),
-                                     cmOutputConverter::SHELL);
-    WriteRule(*this->RulesFileStream, "RERUN_CMAKE", cmd,
-              "Re-running CMake...", "Rule for re-running cmake.",
-              /*depfile=*/"",
-              /*deptype=*/"",
-              /*rspfile=*/"",
-              /*rspcontent*/ "",
-              /*restat=*/"",
-              /*generator=*/true);
+    cmNinjaRule rule("RERUN_CMAKE");
+    rule.Command = CMakeCmd();
+    rule.Command += " -S";
+    rule.Command += lg->ConvertToOutputFormat(lg->GetSourceDirectory(),
+                                              cmOutputConverter::SHELL);
+    rule.Command += " -B";
+    rule.Command += lg->ConvertToOutputFormat(lg->GetBinaryDirectory(),
+                                              cmOutputConverter::SHELL);
+    rule.Description = "Re-running CMake...";
+    rule.Comment = "Rule for re-running cmake.";
+    rule.Generator = true;
+    WriteRule(*this->RulesFileStream, rule);
   }
 
   cmNinjaDeps implicitDeps;
@@ -1365,20 +1344,15 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os)
   cmake* cm = this->GetCMakeInstance();
   if (this->SupportsManifestRestat() && cm->DoWriteGlobVerifyTarget()) {
     {
-      std::string cmd = CMakeCmd();
-      cmd += " -P ";
-      cmd += lg->ConvertToOutputFormat(cm->GetGlobVerifyScript(),
-                                       cmOutputConverter::SHELL);
-
-      WriteRule(*this->RulesFileStream, "VERIFY_GLOBS", cmd,
-                "Re-checking globbed directories...",
-                "Rule for re-checking globbed directories.",
-                /*depfile=*/"",
-                /*deptype=*/"",
-                /*rspfile=*/"",
-                /*rspcontent*/ "",
-                /*restat=*/"",
-                /*generator=*/true);
+      cmNinjaRule rule("VERIFY_GLOBS");
+      rule.Command = CMakeCmd();
+      rule.Command += " -P ";
+      rule.Command += lg->ConvertToOutputFormat(cm->GetGlobVerifyScript(),
+                                                cmOutputConverter::SHELL);
+      rule.Description = "Re-checking globbed directories...";
+      rule.Comment = "Rule for re-checking globbed directories.";
+      rule.Generator = true;
+      this->WriteRule(*this->RulesFileStream, rule);
     }
 
     std::string verifyForce = cm->GetGlobVerifyScript() + "_force";
@@ -1514,19 +1488,14 @@ bool cmGlobalNinjaGenerator::WriteTargetCleanAdditional(std::ostream& os)
 
   // Write rule
   {
-    std::string cmd = CMakeCmd();
-    cmd += " -P ";
-    cmd += lgr->ConvertToOutputFormat(this->NinjaOutputPath(cleanScriptRel),
-                                      cmOutputConverter::SHELL);
-    WriteRule(*this->RulesFileStream, "CLEAN_ADDITIONAL", cmd,
-              "Cleaning additional files...",
-              "Rule for cleaning additional files.",
-              /*depfile=*/"",
-              /*deptype=*/"",
-              /*rspfile=*/"",
-              /*rspcontent*/ "",
-              /*restat=*/"",
-              /*generator=*/false);
+    cmNinjaRule rule("CLEAN_ADDITIONAL");
+    rule.Command = CMakeCmd();
+    rule.Command += " -P ";
+    rule.Command += lgr->ConvertToOutputFormat(
+      this->NinjaOutputPath(cleanScriptRel), cmOutputConverter::SHELL);
+    rule.Description = "Cleaning additional files...";
+    rule.Comment = "Rule for cleaning additional files.";
+    WriteRule(*this->RulesFileStream, rule);
   }
 
   // Write build
@@ -1553,15 +1522,13 @@ void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os)
 
   // -- Default clean target
   // Write rule
-  WriteRule(*this->RulesFileStream, "CLEAN", NinjaCmd() + " -t clean",
-            "Cleaning all built files...",
-            "Rule for cleaning all built files.",
-            /*depfile=*/"",
-            /*deptype=*/"",
-            /*rspfile=*/"",
-            /*rspcontent*/ "",
-            /*restat=*/"",
-            /*generator=*/false);
+  {
+    cmNinjaRule rule("CLEAN");
+    rule.Command = NinjaCmd() + " -t clean";
+    rule.Description = "Cleaning all built files...";
+    rule.Comment = "Rule for cleaning all built files.";
+    WriteRule(*this->RulesFileStream, rule);
+  }
 
   // Write build
   {
@@ -1584,15 +1551,13 @@ void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os)
 
 void cmGlobalNinjaGenerator::WriteTargetHelp(std::ostream& os)
 {
-  WriteRule(*this->RulesFileStream, "HELP", NinjaCmd() + " -t targets",
-            "All primary targets available:",
-            "Rule for printing all primary targets available.",
-            /*depfile=*/"",
-            /*deptype=*/"",
-            /*rspfile=*/"",
-            /*rspcontent*/ "",
-            /*restat=*/"",
-            /*generator=*/false);
+  {
+    cmNinjaRule rule("HELP");
+    rule.Command = NinjaCmd() + " -t targets";
+    rule.Description = "All primary targets available:";
+    rule.Comment = "Rule for printing all primary targets available.";
+    WriteRule(*this->RulesFileStream, rule);
+  }
   WriteBuild(os, "Print all primary targets available.", "HELP",
              /*outputs=*/cmNinjaDeps(1, this->NinjaOutputPath("help")),
              /*implicitOuts=*/cmNinjaDeps(),

+ 3 - 15
Source/cmGlobalNinjaGenerator.h

@@ -138,18 +138,10 @@ public:
                                const std::string& output);
 
   /**
-   * Write a rule statement named @a name to @a os with the @a comment,
-   * the mandatory @a command, the @a depfile and the @a description.
-   * It also writes the variables bound to this rule statement.
+   * Write a rule statement to @a os.
    * @warning no escaping of any kind is done here.
    */
-  static void WriteRule(std::ostream& os, const std::string& name,
-                        const std::string& command,
-                        const std::string& description,
-                        const std::string& comment, const std::string& depfile,
-                        const std::string& deptype, const std::string& rspfile,
-                        const std::string& rspcontent,
-                        const std::string& restat, bool generator);
+  static void WriteRule(std::ostream& os, cmNinjaRule const& rule);
 
   /**
    * Write a variable named @a name to @a os with value @a value and an
@@ -273,11 +265,7 @@ public:
    * Call WriteRule() behind the scene but perform some check before like:
    * - Do not add twice the same rule.
    */
-  void AddRule(const std::string& name, const std::string& command,
-               const std::string& description, const std::string& comment,
-               const std::string& depfile, const std::string& deptype,
-               const std::string& rspfile, const std::string& rspcontent,
-               const std::string& restat, bool generator);
+  void AddRule(cmNinjaRule const& rule);
 
   bool HasRule(const std::string& name);
 

+ 65 - 88
Source/cmNinjaNormalTargetGenerator.cxx

@@ -162,13 +162,8 @@ struct cmNinjaRemoveNoOpCommands
 
 void cmNinjaNormalTargetGenerator::WriteDeviceLinkRule(bool useResponseFile)
 {
-  cmStateEnums::TargetType targetType = this->GetGeneratorTarget()->GetType();
-  std::string ruleName = this->LanguageLinkerDeviceRule();
-  // Select whether to use a response file for objects.
-  std::string rspfile;
-  std::string rspcontent;
-
-  if (!this->GetGlobalGenerator()->HasRule(ruleName)) {
+  cmNinjaRule rule(this->LanguageLinkerDeviceRule());
+  if (!this->GetGlobalGenerator()->HasRule(rule.Name)) {
     cmRulePlaceholderExpander::RuleVariables vars;
     vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str();
     vars.CMTargetType =
@@ -192,16 +187,16 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkRule(bool useResponseFile)
       } else {
         responseFlag = "@";
       }
-      rspfile = "$RSP_FILE";
-      responseFlag += rspfile;
+      rule.RspFile = "$RSP_FILE";
+      responseFlag += rule.RspFile;
 
       // build response file content
       if (this->GetGlobalGenerator()->IsGCCOnWindows()) {
-        rspcontent = "$in";
+        rule.RspContent = "$in";
       } else {
-        rspcontent = "$in_newline";
+        rule.RspContent = "$in_newline";
       }
-      rspcontent += " $LINK_LIBRARIES";
+      rule.RspContent += " $LINK_LIBRARIES";
       vars.Objects = responseFlag.c_str();
       vars.LinkLibraries = "";
     }
@@ -220,7 +215,7 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkRule(bool useResponseFile)
     vars.Manifests = "$MANIFESTS";
 
     std::string langFlags;
-    if (targetType != cmStateEnums::EXECUTABLE) {
+    if (this->GetGeneratorTarget()->GetType() != cmStateEnums::EXECUTABLE) {
       langFlags += "$LANGUAGE_COMPILE_FLAGS $ARCH_FLAGS";
       vars.LanguageCompileFlags = langFlags.c_str();
     }
@@ -247,39 +242,35 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkRule(bool useResponseFile)
     // If there is no ranlib the command will be ":".  Skip it.
     cmEraseIf(linkCmds, cmNinjaRemoveNoOpCommands());
 
-    std::string linkCmd =
-      this->GetLocalGenerator()->BuildCommandLine(linkCmds);
+    rule.Command = this->GetLocalGenerator()->BuildCommandLine(linkCmds);
 
     // Write the linker rule with response file if needed.
-    std::ostringstream comment;
-    comment << "Rule for linking " << this->TargetLinkLanguage << " "
-            << this->GetVisibleTypeName() << ".";
-    std::ostringstream description;
-    description << "Linking " << this->TargetLinkLanguage << " "
-                << this->GetVisibleTypeName() << " $TARGET_FILE";
-    this->GetGlobalGenerator()->AddRule(ruleName, linkCmd, description.str(),
-                                        comment.str(),
-                                        /*depfile*/ "",
-                                        /*deptype*/ "", rspfile, rspcontent,
-                                        /*restat*/ "$RESTAT",
-                                        /*generator*/ false);
+    rule.Comment = "Rule for linking ";
+    rule.Comment += this->TargetLinkLanguage;
+    rule.Comment += " ";
+    rule.Comment += this->GetVisibleTypeName();
+    rule.Comment += ".";
+    rule.Description = "Linking ";
+    rule.Description += this->TargetLinkLanguage;
+    rule.Description += " ";
+    rule.Description += this->GetVisibleTypeName();
+    rule.Description += " $TARGET_FILE";
+    rule.Restat = "$RESTAT";
+
+    this->GetGlobalGenerator()->AddRule(rule);
   }
 }
 
 void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile)
 {
   cmStateEnums::TargetType targetType = this->GetGeneratorTarget()->GetType();
-  std::string ruleName = this->LanguageLinkerRule();
 
-  // Select whether to use a response file for objects.
-  std::string rspfile;
-  std::string rspcontent;
-
-  if (!this->GetGlobalGenerator()->HasRule(ruleName)) {
+  std::string linkRuleName = this->LanguageLinkerRule();
+  if (!this->GetGlobalGenerator()->HasRule(linkRuleName)) {
+    cmNinjaRule rule(std::move(linkRuleName));
     cmRulePlaceholderExpander::RuleVariables vars;
     vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str();
-    vars.CMTargetType =
-      cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType());
+    vars.CMTargetType = cmState::GetTargetTypeName(targetType);
 
     vars.Language = this->TargetLinkLanguage.c_str();
 
@@ -311,16 +302,16 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile)
       } else {
         responseFlag = "@";
       }
-      rspfile = "$RSP_FILE";
-      responseFlag += rspfile;
+      rule.RspFile = "$RSP_FILE";
+      responseFlag += rule.RspFile;
 
       // build response file content
       if (this->GetGlobalGenerator()->IsGCCOnWindows()) {
-        rspcontent = "$in";
+        rule.RspContent = "$in";
       } else {
-        rspcontent = "$in_newline";
+        rule.RspContent = "$in_newline";
       }
-      rspcontent += " $LINK_PATH $LINK_LIBRARIES";
+      rule.RspContent += " $LINK_PATH $LINK_LIBRARIES";
       if (this->TargetLinkLanguage == "Swift") {
         vars.SwiftSources = responseFlag.c_str();
       } else {
@@ -389,22 +380,21 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile)
 
     linkCmds.insert(linkCmds.begin(), "$PRE_LINK");
     linkCmds.emplace_back("$POST_BUILD");
-    std::string linkCmd =
-      this->GetLocalGenerator()->BuildCommandLine(linkCmds);
+    rule.Command = this->GetLocalGenerator()->BuildCommandLine(linkCmds);
 
     // Write the linker rule with response file if needed.
-    std::ostringstream comment;
-    comment << "Rule for linking " << this->TargetLinkLanguage << " "
-            << this->GetVisibleTypeName() << ".";
-    std::ostringstream description;
-    description << "Linking " << this->TargetLinkLanguage << " "
-                << this->GetVisibleTypeName() << " $TARGET_FILE";
-    this->GetGlobalGenerator()->AddRule(ruleName, linkCmd, description.str(),
-                                        comment.str(),
-                                        /*depfile*/ "",
-                                        /*deptype*/ "", rspfile, rspcontent,
-                                        /*restat*/ "$RESTAT",
-                                        /*generator*/ false);
+    rule.Comment = "Rule for linking ";
+    rule.Comment += this->TargetLinkLanguage;
+    rule.Comment += " ";
+    rule.Comment += this->GetVisibleTypeName();
+    rule.Comment += ".";
+    rule.Description = "Linking ";
+    rule.Description += this->TargetLinkLanguage;
+    rule.Description += " ";
+    rule.Description += this->GetVisibleTypeName();
+    rule.Description += " $TARGET_FILE";
+    rule.Restat = "$RESTAT";
+    this->GetGlobalGenerator()->AddRule(rule);
   }
 
   if (this->TargetNames.Output != this->TargetNames.Real &&
@@ -413,41 +403,28 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile)
       this->GetLocalGenerator()->ConvertToOutputFormat(
         cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL);
     if (targetType == cmStateEnums::EXECUTABLE) {
-      std::vector<std::string> commandLines;
-      commandLines.push_back(cmakeCommand +
-                             " -E cmake_symlink_executable $in $out");
-      commandLines.emplace_back("$POST_BUILD");
-
-      this->GetGlobalGenerator()->AddRule(
-        "CMAKE_SYMLINK_EXECUTABLE",
-        this->GetLocalGenerator()->BuildCommandLine(commandLines),
-        "Creating executable symlink $out",
-        "Rule for creating "
-        "executable symlink.",
-        /*depfile*/ "",
-        /*deptype*/ "",
-        /*rspfile*/ "",
-        /*rspcontent*/ "",
-        /*restat*/ "",
-        /*generator*/ false);
+      cmNinjaRule rule("CMAKE_SYMLINK_EXECUTABLE");
+      {
+        std::vector<std::string> cmd;
+        cmd.push_back(cmakeCommand + " -E cmake_symlink_executable $in $out");
+        cmd.emplace_back("$POST_BUILD");
+        rule.Command = this->GetLocalGenerator()->BuildCommandLine(cmd);
+      }
+      rule.Description = "Creating executable symlink $out";
+      rule.Comment = "Rule for creating executable symlink.";
+      this->GetGlobalGenerator()->AddRule(rule);
     } else {
-      std::vector<std::string> commandLines;
-      commandLines.push_back(cmakeCommand +
-                             " -E cmake_symlink_library $in $SONAME $out");
-      commandLines.emplace_back("$POST_BUILD");
-
-      this->GetGlobalGenerator()->AddRule(
-        "CMAKE_SYMLINK_LIBRARY",
-        this->GetLocalGenerator()->BuildCommandLine(commandLines),
-        "Creating library symlink $out",
-        "Rule for creating "
-        "library symlink.",
-        /*depfile*/ "",
-        /*deptype*/ "",
-        /*rspfile*/ "",
-        /*rspcontent*/ "",
-        /*restat*/ "",
-        /*generator*/ false);
+      cmNinjaRule rule("CMAKE_SYMLINK_LIBRARY");
+      {
+        std::vector<std::string> cmd;
+        cmd.push_back(cmakeCommand +
+                      " -E cmake_symlink_library $in $SONAME $out");
+        cmd.emplace_back("$POST_BUILD");
+        rule.Command = this->GetLocalGenerator()->BuildCommandLine(cmd);
+      }
+      rule.Description = "Creating library symlink $out";
+      rule.Comment = "Rule for creating library symlink.";
+      this->GetGlobalGenerator()->AddRule(rule);
     }
   }
 }

+ 56 - 72
Source/cmNinjaTargetGenerator.cxx

@@ -495,9 +495,10 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
       cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
 
   if (explicitPP) {
+    cmNinjaRule rule(this->LanguagePreprocessRule(lang));
     // Explicit preprocessing always uses a depfile.
-    std::string const ppDeptype; // no deps= for multiple outputs
-    std::string const ppDepfile = "$DEP_FILE";
+    rule.DepType = ""; // no deps= for multiple outputs
+    rule.DepFile = "$DEP_FILE";
 
     cmRulePlaceholderExpander::RuleVariables ppVars;
     ppVars.CMTargetName = vars.CMTargetName;
@@ -505,7 +506,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
     ppVars.Language = vars.Language;
     ppVars.Object = "$out"; // for RULE_LAUNCH_COMPILE
     ppVars.PreprocessedSource = "$out";
-    ppVars.DependencyFile = ppDepfile.c_str();
+    ppVars.DependencyFile = rule.DepFile.c_str();
 
     // Preprocessing uses the original source,
     // compilation uses preprocessed output.
@@ -524,17 +525,15 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
     ppVars.Includes = vars.Includes;
 
     // If using a response file, move defines, includes, and flags into it.
-    std::string ppRspFile;
-    std::string ppRspContent;
     if (!responseFlag.empty()) {
-      ppRspFile = "$RSP_FILE";
-      ppRspContent = " ";
-      ppRspContent += ppVars.Defines;
-      ppRspContent += " ";
-      ppRspContent += ppVars.Includes;
-      ppRspContent += " ";
-      ppRspContent += ppFlags;
-      ppFlags = responseFlag + ppRspFile;
+      rule.RspFile = "$RSP_FILE";
+      rule.RspContent = " ";
+      rule.RspContent += ppVars.Defines;
+      rule.RspContent += " ";
+      rule.RspContent += ppVars.Includes;
+      rule.RspContent += " ";
+      rule.RspContent += ppFlags;
+      ppFlags = responseFlag + rule.RspFile;
       ppVars.Defines = "";
       ppVars.Includes = "";
     }
@@ -570,31 +569,25 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
       }
       ppCmds.emplace_back(std::move(ccmd));
     }
-    std::string const ppCmdLine =
-      this->GetLocalGenerator()->BuildCommandLine(ppCmds);
+    rule.Command = this->GetLocalGenerator()->BuildCommandLine(ppCmds);
 
     // Write the rule for preprocessing file of the given language.
-    std::string ppComment = "Rule for preprocessing ";
-    ppComment += lang;
-    ppComment += " files.";
-    std::string ppDesc = "Building ";
-    ppDesc += lang;
-    ppDesc += " preprocessed $out";
-    this->GetGlobalGenerator()->AddRule(
-      this->LanguagePreprocessRule(lang), ppCmdLine, ppDesc, ppComment,
-      ppDepfile, ppDeptype, ppRspFile, ppRspContent,
-      /*restat*/ "",
-      /*generator*/ false);
+    rule.Comment = "Rule for preprocessing ";
+    rule.Comment += lang;
+    rule.Comment += " files.";
+    rule.Description = "Building ";
+    rule.Description += lang;
+    rule.Description += " preprocessed $out";
+    this->GetGlobalGenerator()->AddRule(rule);
   }
 
   if (needDyndep) {
     // Write the rule for ninja dyndep file generation.
-
+    cmNinjaRule rule(this->LanguageDyndepRule(lang));
     // Command line length is almost always limited -> use response file for
     // dyndep rules
-    std::string ddRspFile = "$out.rsp";
-    std::string ddRspContent = "$in";
-    std::string ddCmdLine;
+    rule.RspFile = "$out.rsp";
+    rule.RspContent = "$in";
 
     // Run CMake dependency scanner on the source file (using the preprocessed
     // source if that was performed).
@@ -608,53 +601,49 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
         ccmd += lang;
         ccmd += " --dd=$out ";
         ccmd += "@";
-        ccmd += ddRspFile;
+        ccmd += rule.RspFile;
         ddCmds.emplace_back(std::move(ccmd));
       }
-      ddCmdLine = this->GetLocalGenerator()->BuildCommandLine(ddCmds);
+      rule.Command = this->GetLocalGenerator()->BuildCommandLine(ddCmds);
     }
-    std::string ddComment = "Rule to generate ninja dyndep files for ";
-    ddComment += lang;
-    ddComment += ".";
-    std::string ddDesc = "Generating ";
-    ddDesc += lang;
-    ddDesc += " dyndep file $out";
-    this->GetGlobalGenerator()->AddRule(this->LanguageDyndepRule(lang),
-                                        ddCmdLine, ddDesc, ddComment,
-                                        /*depfile*/ "",
-                                        /*deps*/ "", ddRspFile, ddRspContent,
-                                        /*restat*/ "",
-                                        /*generator*/ false);
+    rule.Comment = "Rule to generate ninja dyndep files for ";
+    rule.Comment += lang;
+    rule.Comment += ".";
+    rule.Description = "Generating ";
+    rule.Description += lang;
+    rule.Description += " dyndep file $out";
+    this->GetGlobalGenerator()->AddRule(rule);
   }
 
+  cmNinjaRule rule(this->LanguageCompilerRule(lang));
   // If using a response file, move defines, includes, and flags into it.
-  std::string rspfile;
-  std::string rspcontent;
   if (!responseFlag.empty()) {
-    rspfile = "$RSP_FILE";
-    rspcontent =
-      std::string(" ") + vars.Defines + " " + vars.Includes + " " + flags;
-    flags = responseFlag + rspfile;
+    rule.RspFile = "$RSP_FILE";
+    rule.RspContent = " ";
+    rule.RspContent += vars.Defines;
+    rule.RspContent += " ";
+    rule.RspContent += vars.Includes;
+    rule.RspContent += " ";
+    rule.RspContent += flags;
+    flags = responseFlag + rule.RspFile;
     vars.Defines = "";
     vars.Includes = "";
   }
 
   // Tell ninja dependency format so all deps can be loaded into a database
-  std::string deptype;
-  std::string depfile;
   std::string cldeps;
   if (explicitPP) {
     // The explicit preprocessing step will handle dependency scanning.
   } else if (this->NeedDepTypeMSVC(lang)) {
-    deptype = "msvc";
-    depfile.clear();
+    rule.DepType = "msvc";
+    rule.DepFile.clear();
     flags += " /showIncludes";
   } else if (mf->IsOn("CMAKE_NINJA_CMCLDEPS_" + lang)) {
     // For the MS resource compiler we need cmcldeps, but skip dependencies
     // for source-file try_compile cases because they are always fresh.
     if (!mf->GetIsSourceFileTryCompile()) {
-      deptype = "gcc";
-      depfile = "$DEP_FILE";
+      rule.DepType = "gcc";
+      rule.DepFile = "$DEP_FILE";
       const std::string cl = mf->GetDefinition("CMAKE_C_COMPILER")
         ? mf->GetSafeDefinition("CMAKE_C_COMPILER")
         : mf->GetSafeDefinition("CMAKE_CXX_COMPILER");
@@ -665,8 +654,8 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
       cldeps += "\" \"" + cl + "\" ";
     }
   } else {
-    deptype = "gcc";
-    depfile = "$DEP_FILE";
+    rule.DepType = "gcc";
+    rule.DepFile = "$DEP_FILE";
     const std::string flagsName = "CMAKE_DEPFILE_FLAGS_" + lang;
     std::string depfileFlags = mf->GetSafeDefinition(flagsName);
     if (!depfileFlags.empty()) {
@@ -679,7 +668,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
   }
 
   vars.Flags = flags.c_str();
-  vars.DependencyFile = depfile.c_str();
+  vars.DependencyFile = rule.DepFile.c_str();
 
   // Rule for compiling object file.
   std::vector<std::string> compileCmds;
@@ -784,21 +773,16 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
                                                  vars);
   }
 
-  std::string cmdLine =
-    this->GetLocalGenerator()->BuildCommandLine(compileCmds);
+  rule.Command = this->GetLocalGenerator()->BuildCommandLine(compileCmds);
 
   // Write the rule for compiling file of the given language.
-  std::string comment = "Rule for compiling ";
-  comment += lang;
-  comment += " files.";
-  std::string description = "Building ";
-  description += lang;
-  description += " object $out";
-  this->GetGlobalGenerator()->AddRule(this->LanguageCompilerRule(lang),
-                                      cmdLine, description, comment, depfile,
-                                      deptype, rspfile, rspcontent,
-                                      /*restat*/ "",
-                                      /*generator*/ false);
+  rule.Comment = "Rule for compiling ";
+  rule.Comment += lang;
+  rule.Comment += " files.";
+  rule.Description = "Building ";
+  rule.Description += lang;
+  rule.Description += " object $out";
+  this->GetGlobalGenerator()->AddRule(rule);
 }
 
 void cmNinjaTargetGenerator::WriteObjectBuildStatements()

+ 21 - 0
Source/cmNinjaTypes.h

@@ -8,6 +8,7 @@
 #include <map>
 #include <set>
 #include <string>
+#include <utility>
 #include <vector>
 
 enum cmNinjaTargetDepends
@@ -20,4 +21,24 @@ typedef std::vector<std::string> cmNinjaDeps;
 typedef std::set<std::string> cmNinjaOuts;
 typedef std::map<std::string, std::string> cmNinjaVars;
 
+class cmNinjaRule
+{
+public:
+  cmNinjaRule(std::string name)
+    : Name(std::move(name))
+  {
+  }
+
+  std::string Name;
+  std::string Command;
+  std::string Description;
+  std::string Comment;
+  std::string DepFile;
+  std::string DepType;
+  std::string RspFile;
+  std::string RspContent;
+  std::string Restat;
+  bool Generator = false;
+};
+
 #endif // ! cmNinjaTypes_h