summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/cmNinjaTargetGenerator.cxx167
1 files changed, 98 insertions, 69 deletions
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index b58434f..36fad08 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -509,6 +509,91 @@ void cmNinjaTargetGenerator::WriteLanguageRules(const std::string& language,
this->WriteCompileRule(language, config);
}
+namespace {
+// Create the command to run the dependency scanner
+std::string GetScanCommand(const std::string& cmakeCmd, const std::string& tdi,
+ const std::string& lang, const std::string& ppFile,
+ bool needDyndep, const std::string& ddiFile)
+{
+ std::string ccmd =
+ cmStrCat(cmakeCmd, " -E cmake_ninja_depends --tdi=", tdi, " --lang=", lang,
+ " --pp=", ppFile, " --dep=$DEP_FILE");
+ if (needDyndep) {
+ ccmd = cmStrCat(ccmd, " --obj=$OBJ_FILE --ddi=", ddiFile);
+ }
+ return ccmd;
+}
+
+// Helper function to create dependency scanning rule, with optional
+// explicit preprocessing step if preprocessCommand is non-empty
+cmNinjaRule GetPreprocessScanRule(
+ const std::string& ruleName, cmRulePlaceholderExpander::RuleVariables& vars,
+ const std::string& responseFlag, const std::string& flags,
+ const std::string& launcher,
+ cmRulePlaceholderExpander* const rulePlaceholderExpander,
+ std::string scanCommand, cmLocalNinjaGenerator* generator,
+ const std::string& preprocessCommand = "")
+{
+ cmNinjaRule rule(ruleName);
+ // Explicit preprocessing always uses a depfile.
+ rule.DepType = ""; // no deps= for multiple outputs
+ rule.DepFile = "$DEP_FILE";
+
+ cmRulePlaceholderExpander::RuleVariables ppVars;
+ ppVars.CMTargetName = vars.CMTargetName;
+ ppVars.CMTargetType = vars.CMTargetType;
+ ppVars.Language = vars.Language;
+ ppVars.Object = "$out"; // for RULE_LAUNCH_COMPILE
+ ppVars.PreprocessedSource = "$out";
+ ppVars.DependencyFile = rule.DepFile.c_str();
+
+ // Preprocessing uses the original source, compilation uses
+ // preprocessed output or original source
+ ppVars.Source = vars.Source;
+ vars.Source = "$in";
+
+ // Copy preprocessor definitions to the preprocessor rule.
+ ppVars.Defines = vars.Defines;
+
+ // Copy include directories to the preprocessor rule. The Fortran
+ // compilation rule still needs them for the INCLUDE directive.
+ ppVars.Includes = vars.Includes;
+
+ // Preprocessing and compilation use the same flags.
+ std::string ppFlags = flags;
+
+ // If using a response file, move defines, includes, and flags into it.
+ if (!responseFlag.empty()) {
+ rule.RspFile = "$RSP_FILE";
+ rule.RspContent =
+ cmStrCat(' ', ppVars.Defines, ' ', ppVars.Includes, ' ', ppFlags);
+ ppFlags = cmStrCat(responseFlag, rule.RspFile);
+ ppVars.Defines = "";
+ ppVars.Includes = "";
+ }
+
+ ppVars.Flags = ppFlags.c_str();
+
+ // Rule for preprocessing source file.
+ std::vector<std::string> ppCmds;
+
+ if (!preprocessCommand.empty()) {
+ // Lookup the explicit preprocessing rule.
+ cmExpandList(preprocessCommand, ppCmds);
+ for (std::string& i : ppCmds) {
+ i = cmStrCat(launcher, i);
+ rulePlaceholderExpander->ExpandRuleVariables(generator, i, ppVars);
+ }
+ }
+
+ // Run CMake dependency scanner on either preprocessed output or source file
+ ppCmds.emplace_back(std::move(scanCommand));
+ rule.Command = generator->BuildCommandLine(ppCmds);
+
+ return rule;
+}
+}
+
void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
const std::string& config)
{
@@ -566,82 +651,26 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
if (explicitPP) {
- cmNinjaRule rule(this->LanguagePreprocessRule(lang, config));
- // Explicit preprocessing always uses a depfile.
- rule.DepType = ""; // no deps= for multiple outputs
- rule.DepFile = "$DEP_FILE";
+ // Combined preprocessing and dependency scanning
+ const auto ppScanCommand = GetScanCommand(
+ cmakeCmd, tdi, lang, "$out", needDyndep, "$DYNDEP_INTERMEDIATE_FILE");
+ const auto ppVar = cmStrCat("CMAKE_", lang, "_PREPROCESS_SOURCE");
- cmRulePlaceholderExpander::RuleVariables ppVars;
- ppVars.CMTargetName = vars.CMTargetName;
- ppVars.CMTargetType = vars.CMTargetType;
- ppVars.Language = vars.Language;
- ppVars.Object = "$out"; // for RULE_LAUNCH_COMPILE
- ppVars.PreprocessedSource = "$out";
- ppVars.DependencyFile = rule.DepFile.c_str();
+ auto ppRule = GetPreprocessScanRule(
+ this->LanguagePreprocessRule(lang, config), vars, responseFlag, flags,
+ launcher, rulePlaceholderExpander.get(), ppScanCommand,
+ this->GetLocalGenerator(), mf->GetRequiredDefinition(ppVar));
- // Preprocessing uses the original source,
- // compilation uses preprocessed output.
- ppVars.Source = vars.Source;
- vars.Source = "$in";
+ // Write the rule for preprocessing file of the given language.
+ ppRule.Comment = cmStrCat("Rule for preprocessing ", lang, " files.");
+ ppRule.Description = cmStrCat("Building ", lang, " preprocessed $out");
- // Preprocessing and compilation use the same flags.
- std::string ppFlags = flags;
+ this->GetGlobalGenerator()->AddRule(ppRule);
if (!compilePPWithDefines) {
- // Move preprocessor definitions to the preprocessor rule.
- ppVars.Defines = vars.Defines;
+ // Remove preprocessor definitions from compilation step
vars.Defines = "";
- } else {
- // Copy preprocessor definitions to the preprocessor rule.
- ppVars.Defines = vars.Defines;
- }
-
- // Copy include directories to the preprocessor rule. The Fortran
- // compilation rule still needs them for the INCLUDE directive.
- ppVars.Includes = vars.Includes;
-
- // If using a response file, move defines, includes, and flags into it.
- if (!responseFlag.empty()) {
- rule.RspFile = "$RSP_FILE";
- rule.RspContent =
- cmStrCat(' ', ppVars.Defines, ' ', ppVars.Includes, ' ', ppFlags);
- ppFlags = cmStrCat(responseFlag, rule.RspFile);
- ppVars.Defines = "";
- ppVars.Includes = "";
- }
-
- ppVars.Flags = ppFlags.c_str();
-
- // Rule for preprocessing source file.
- std::vector<std::string> ppCmds;
- {
- // Lookup the explicit preprocessing rule.
- std::string ppVar = cmStrCat("CMAKE_", lang, "_PREPROCESS_SOURCE");
- cmExpandList(this->GetMakefile()->GetRequiredDefinition(ppVar), ppCmds);
- }
-
- for (std::string& i : ppCmds) {
- i = cmStrCat(launcher, i);
- rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(),
- i, ppVars);
- }
-
- // Run CMake dependency scanner on preprocessed output.
- {
- std::string ccmd =
- cmStrCat(cmakeCmd, " -E cmake_ninja_depends --tdi=", tdi,
- " --lang=", lang, " --pp=$out --dep=$DEP_FILE");
- if (needDyndep) {
- ccmd += " --obj=$OBJ_FILE --ddi=$DYNDEP_INTERMEDIATE_FILE";
- }
- ppCmds.emplace_back(std::move(ccmd));
}
- rule.Command = this->GetLocalGenerator()->BuildCommandLine(ppCmds);
-
- // Write the rule for preprocessing file of the given language.
- rule.Comment = cmStrCat("Rule for preprocessing ", lang, " files.");
- rule.Description = cmStrCat("Building ", lang, " preprocessed $out");
- this->GetGlobalGenerator()->AddRule(rule);
}
if (needDyndep) {