summaryrefslogtreecommitdiffstats
path: root/Source/cmNinjaTargetGenerator.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmNinjaTargetGenerator.cxx')
-rw-r--r--Source/cmNinjaTargetGenerator.cxx420
1 files changed, 201 insertions, 219 deletions
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index d41cbd2..9075563 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -12,7 +12,9 @@
#include <utility>
#include <cm/memory>
+#include <cm/string_view>
#include <cmext/algorithm>
+#include <cmext/string_view>
#include <cm3p/json/value.h>
#include <cm3p/json/writer.h>
@@ -105,7 +107,7 @@ std::string cmNinjaTargetGenerator::LanguageCompilerRule(
'_', config);
}
-std::string cmNinjaTargetGenerator::LanguagePreprocessRule(
+std::string cmNinjaTargetGenerator::LanguagePreprocessAndScanRule(
std::string const& lang, const std::string& config) const
{
return cmStrCat(
@@ -114,7 +116,7 @@ std::string cmNinjaTargetGenerator::LanguagePreprocessRule(
'_', config);
}
-std::string cmNinjaTargetGenerator::LanguageDependencyRule(
+std::string cmNinjaTargetGenerator::LanguageScanRule(
std::string const& lang, const std::string& config) const
{
return cmStrCat(
@@ -129,14 +131,7 @@ bool cmNinjaTargetGenerator::NeedExplicitPreprocessing(
return lang == "Fortran";
}
-bool cmNinjaTargetGenerator::UsePreprocessedSource(
- std::string const& lang) const
-{
- return lang == "Fortran";
-}
-
-bool cmNinjaTargetGenerator::CompilePreprocessedSourceWithDefines(
- std::string const& lang) const
+bool cmNinjaTargetGenerator::CompileWithDefines(std::string const& lang) const
{
return this->Makefile->IsOn(
cmStrCat("CMAKE_", lang, "_COMPILE_WITH_DEFINES"));
@@ -190,7 +185,15 @@ std::string cmNinjaTargetGenerator::ComputeFlagsForObject(
}
}
- std::string flags = this->GetFlags(language, config, filterArch);
+ std::string flags;
+ // Explicitly add the explicit language flag before any other flag
+ // so user flags can override it.
+ this->GeneratorTarget->AddExplicitLanguageFlags(flags, *source);
+
+ if (!flags.empty()) {
+ flags += " ";
+ }
+ flags += this->GetFlags(language, config, filterArch);
// Add Fortran format flags.
if (language == "Fortran") {
@@ -252,32 +255,6 @@ void cmNinjaTargetGenerator::AddIncludeFlags(std::string& languageFlags,
this->LocalGenerator->AppendFlags(languageFlags, includeFlags);
}
-bool cmNinjaTargetGenerator::NeedDepTypeMSVC(const std::string& lang) const
-{
- std::string const& deptype = this->GetMakefile()->GetSafeDefinition(
- cmStrCat("CMAKE_NINJA_DEPTYPE_", lang));
- if (deptype == "msvc") {
- return true;
- }
- if (deptype == "intel") {
- // Ninja does not really define "intel", but we use it to switch based
- // on whether this environment supports "gcc" or "msvc" deptype.
- if (!this->GetGlobalGenerator()->SupportsMultilineDepfile()) {
- // This ninja version is too old to support the Intel depfile format.
- // Fall back to msvc deptype.
- return true;
- }
- if ((this->Makefile->GetHomeDirectory().find(' ') != std::string::npos) ||
- (this->Makefile->GetHomeOutputDirectory().find(' ') !=
- std::string::npos)) {
- // The Intel compiler does not properly escape spaces in a depfile.
- // Fall back to msvc deptype.
- return true;
- }
- }
- return false;
-}
-
// TODO: Refactor with
// void cmMakefileTargetGenerator::WriteTargetLanguageFlags().
std::string cmNinjaTargetGenerator::ComputeDefines(cmSourceFile const* source,
@@ -527,82 +504,61 @@ 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)
+ 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;
+ return cmStrCat(cmakeCmd, " -E cmake_ninja_depends --tdi=", tdi,
+ " --lang=", lang, " --src=$in", " --pp=", ppFile,
+ " --dep=$DEP_FILE --obj=$OBJ_FILE --ddi=", ddiFile);
}
-// 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,
+// Helper function to create dependency scanning rule that may or may
+// not perform explicit preprocessing too.
+cmNinjaRule GetScanRule(
+ const std::string& ruleName,
+ cmRulePlaceholderExpander::RuleVariables const& 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 = "")
+ cmLocalNinjaGenerator* generator, std::vector<std::string> scanCmds)
{
cmNinjaRule rule(ruleName);
- // Explicit preprocessing always uses a depfile.
+ // Scanning always uses a depfile for preprocessor dependencies.
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;
+ cmRulePlaceholderExpander::RuleVariables scanVars;
+ scanVars.CMTargetName = vars.CMTargetName;
+ scanVars.CMTargetType = vars.CMTargetType;
+ scanVars.Language = vars.Language;
+ scanVars.Object = "$out"; // for RULE_LAUNCH_COMPILE
+ scanVars.PreprocessedSource = "$out";
+ scanVars.DependencyFile = rule.DepFile.c_str();
+ scanVars.DependencyTarget = "$out";
- // Copy include directories to the preprocessor rule. The Fortran
- // compilation rule still needs them for the INCLUDE directive.
- ppVars.Includes = vars.Includes;
+ // Scanning needs the same preprocessor settings as direct compilation would.
+ scanVars.Source = vars.Source;
+ scanVars.Defines = vars.Defines;
+ scanVars.Includes = vars.Includes;
- // Preprocessing and compilation use the same flags.
- std::string ppFlags = flags;
+ // Scanning needs the compilation flags too.
+ std::string scanFlags = 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 = "";
+ cmStrCat(' ', scanVars.Defines, ' ', scanVars.Includes, ' ', scanFlags);
+ scanFlags = cmStrCat(responseFlag, rule.RspFile);
+ scanVars.Defines = "";
+ scanVars.Includes = "";
}
- ppVars.Flags = ppFlags.c_str();
-
- // Rule for preprocessing source file.
- std::vector<std::string> ppCmds;
+ scanVars.Flags = scanFlags.c_str();
- 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);
- }
+ // Rule for scanning a source file.
+ for (std::string& scanCmd : scanCmds) {
+ rulePlaceholderExpander->ExpandRuleVariables(generator, scanCmd, scanVars);
}
-
- // Run CMake dependency scanner on either preprocessed output or source file
- ppCmds.emplace_back(std::move(scanCommand));
- rule.Command = generator->BuildCommandLine(ppCmds);
+ rule.Command = generator->BuildCommandLine(scanCmds);
return rule;
}
@@ -628,11 +584,9 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
cmMakefile* mf = this->GetMakefile();
- // For some cases we do an explicit preprocessor invocation.
- bool const explicitPP = this->NeedExplicitPreprocessing(lang);
- bool const compilePPWithDefines = this->UsePreprocessedSource(lang) &&
- this->CompilePreprocessedSourceWithDefines(lang);
+ // For some cases we scan to dynamically discover dependencies.
bool const needDyndep = this->NeedDyndep(lang);
+ bool const compilationPreprocesses = !this->NeedExplicitPreprocessing(lang);
std::string flags = "$FLAGS";
@@ -655,56 +609,68 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
cmLocalGenerator::SHELL);
std::string launcher;
- const char* val = this->GetLocalGenerator()->GetRuleLauncher(
+ cmProp val = this->GetLocalGenerator()->GetRuleLauncher(
this->GetGeneratorTarget(), "RULE_LAUNCH_COMPILE");
if (cmNonempty(val)) {
- launcher = cmStrCat(val, ' ');
+ launcher = cmStrCat(*val, ' ');
}
std::string const cmakeCmd =
this->GetLocalGenerator()->ConvertToOutputFormat(
cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
- if (explicitPP) {
- // 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");
-
- auto ppRule = GetPreprocessScanRule(
- this->LanguagePreprocessRule(lang, config), vars, responseFlag, flags,
- launcher, rulePlaceholderExpander.get(), ppScanCommand,
- this->GetLocalGenerator(), mf->GetRequiredDefinition(ppVar));
+ if (needDyndep) {
+ // Rule to scan dependencies of sources that need preprocessing.
+ {
+ std::vector<std::string> scanCommands;
+ std::string const& scanRuleName =
+ this->LanguagePreprocessAndScanRule(lang, config);
+ std::string const& ppCommmand = mf->GetRequiredDefinition(
+ cmStrCat("CMAKE_", lang, "_PREPROCESS_SOURCE"));
+ cmExpandList(ppCommmand, scanCommands);
+ for (std::string& i : scanCommands) {
+ i = cmStrCat(launcher, i);
+ }
+ scanCommands.emplace_back(GetScanCommand(cmakeCmd, tdi, lang, "$out",
+ "$DYNDEP_INTERMEDIATE_FILE"));
- // 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");
+ auto scanRule = GetScanRule(
+ scanRuleName, vars, responseFlag, flags, rulePlaceholderExpander.get(),
+ this->GetLocalGenerator(), std::move(scanCommands));
- this->GetGlobalGenerator()->AddRule(ppRule);
+ scanRule.Comment =
+ cmStrCat("Rule for generating ", lang, " dependencies.");
+ scanRule.Description = cmStrCat("Building ", lang, " preprocessed $out");
- if (!compilePPWithDefines) {
- // Remove preprocessor definitions from compilation step
- vars.Defines = "";
+ this->GetGlobalGenerator()->AddRule(scanRule);
}
- // Just dependency scanning for files that have preprocessing turned off
- const auto scanCommand =
- GetScanCommand(cmakeCmd, tdi, lang, "$in", needDyndep, "$out");
+ {
+ // Compilation will not preprocess, so it does not need the defines
+ // unless the compiler wants them for some other purpose.
+ if (!this->CompileWithDefines(lang)) {
+ vars.Defines = "";
+ }
- auto scanRule = GetPreprocessScanRule(
- this->LanguageDependencyRule(lang, config), vars, "", flags, launcher,
- rulePlaceholderExpander.get(), scanCommand, this->GetLocalGenerator());
+ // Rule to scan dependencies of sources that do not need preprocessing.
+ std::string const& scanRuleName = this->LanguageScanRule(lang, config);
+ std::vector<std::string> scanCommands;
+ scanCommands.emplace_back(
+ GetScanCommand(cmakeCmd, tdi, lang, "$in", "$out"));
- // Write the rule for generating dependencies for the given language.
- scanRule.Comment = cmStrCat("Rule for generating ", lang,
- " dependencies on non-preprocessed files.");
- scanRule.Description =
- cmStrCat("Generating ", lang, " dependencies for $in");
+ auto scanRule = GetScanRule(
+ scanRuleName, vars, "", flags, rulePlaceholderExpander.get(),
+ this->GetLocalGenerator(), std::move(scanCommands));
- this->GetGlobalGenerator()->AddRule(scanRule);
- }
+ // Write the rule for generating dependencies for the given language.
+ scanRule.Comment = cmStrCat("Rule for generating ", lang,
+ " dependencies on non-preprocessed files.");
+ scanRule.Description =
+ cmStrCat("Generating ", lang, " dependencies for $in");
+
+ this->GetGlobalGenerator()->AddRule(scanRule);
+ }
- if (needDyndep) {
// Write the rule for ninja dyndep file generation.
cmNinjaRule rule(this->LanguageDyndepRule(lang, config));
// Command line length is almost always limited -> use response file for
@@ -743,12 +709,8 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
// Tell ninja dependency format so all deps can be loaded into a database
std::string cldeps;
- if (explicitPP) {
- // The explicit preprocessing step will handle dependency scanning.
- } else if (this->NeedDepTypeMSVC(lang)) {
- rule.DepType = "msvc";
- rule.DepFile.clear();
- flags += " /showIncludes";
+ if (!compilationPreprocesses) {
+ // The compiler will not do preprocessing, so it has no such dependencies.
} else if (mf->IsOn(cmStrCat("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.
@@ -764,16 +726,23 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
"\" \"", cl, "\" ");
}
} else {
- rule.DepType = "gcc";
- rule.DepFile = "$DEP_FILE";
+ const auto& depType = this->GetMakefile()->GetSafeDefinition(
+ cmStrCat("CMAKE_", lang, "_DEPFILE_FORMAT"));
+ if (depType == "msvc"_s) {
+ rule.DepType = "msvc";
+ rule.DepFile.clear();
+ } else {
+ rule.DepType = "gcc";
+ rule.DepFile = "$DEP_FILE";
+ }
+ vars.DependencyFile = rule.DepFile.c_str();
+ vars.DependencyTarget = "$out";
+
const std::string flagsName = cmStrCat("CMAKE_DEPFILE_FLAGS_", lang);
std::string depfileFlags = mf->GetSafeDefinition(flagsName);
if (!depfileFlags.empty()) {
- cmSystemTools::ReplaceString(depfileFlags, "<DEPFILE>", "$DEP_FILE");
- cmSystemTools::ReplaceString(depfileFlags, "<OBJECT>", "$out");
- cmSystemTools::ReplaceString(
- depfileFlags, "<CMAKE_C_COMPILER>",
- cmToCStr(mf->GetDefinition("CMAKE_C_COMPILER")));
+ rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(),
+ depfileFlags, vars);
flags += cmStrCat(' ', depfileFlags);
}
}
@@ -815,15 +784,21 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
}
// Maybe insert an include-what-you-use runner.
- if (!compileCmds.empty() && (lang == "C" || lang == "CXX")) {
- std::string const iwyu_prop = cmStrCat(lang, "_INCLUDE_WHAT_YOU_USE");
- cmProp iwyu = this->GeneratorTarget->GetProperty(iwyu_prop);
+ if (!compileCmds.empty() &&
+ (lang == "C" || lang == "CXX" || lang == "OBJC" || lang == "OBJCXX")) {
std::string const tidy_prop = cmStrCat(lang, "_CLANG_TIDY");
cmProp tidy = this->GeneratorTarget->GetProperty(tidy_prop);
- std::string const cpplint_prop = cmStrCat(lang, "_CPPLINT");
- cmProp cpplint = this->GeneratorTarget->GetProperty(cpplint_prop);
- std::string const cppcheck_prop = cmStrCat(lang, "_CPPCHECK");
- cmProp cppcheck = this->GeneratorTarget->GetProperty(cppcheck_prop);
+ cmProp iwyu = nullptr;
+ cmProp cpplint = nullptr;
+ cmProp cppcheck = nullptr;
+ if (lang == "C" || lang == "CXX") {
+ std::string const iwyu_prop = cmStrCat(lang, "_INCLUDE_WHAT_YOU_USE");
+ iwyu = this->GeneratorTarget->GetProperty(iwyu_prop);
+ std::string const cpplint_prop = cmStrCat(lang, "_CPPLINT");
+ cpplint = this->GeneratorTarget->GetProperty(cpplint_prop);
+ std::string const cppcheck_prop = cmStrCat(lang, "_CPPCHECK");
+ cppcheck = this->GeneratorTarget->GetProperty(cppcheck_prop);
+ }
if (cmNonempty(iwyu) || cmNonempty(tidy) || cmNonempty(cpplint) ||
cmNonempty(cppcheck)) {
std::string run_iwyu = cmStrCat(cmakeCmd, " -E __run_co_compile");
@@ -887,6 +862,14 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
compileCmds.front().insert(0, cldeps);
}
+ const auto& extraCommands = this->GetMakefile()->GetSafeDefinition(
+ cmStrCat("CMAKE_", lang, "_DEPENDS_EXTRA_COMMANDS"));
+ if (!extraCommands.empty()) {
+ auto commandList = cmExpandedList(extraCommands);
+ compileCmds.insert(compileCmds.end(), commandList.cbegin(),
+ commandList.cend());
+ }
+
for (std::string& i : compileCmds) {
i = cmStrCat(launcher, i);
rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(), i,
@@ -1062,78 +1045,81 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements(
}
namespace {
-cmNinjaBuild GetPreprocessOrScanBuild(
- const std::string& ruleName, const std::string& ppFileName, bool compilePP,
- bool compilePPWithDefines, cmNinjaBuild& objBuild, cmNinjaVars& vars,
- const std::string& depFileName, bool needDyndep,
- const std::string& objectFileName)
+cmNinjaBuild GetScanBuildStatement(const std::string& ruleName,
+ const std::string& ppFileName,
+ bool compilePP, bool compilePPWithDefines,
+ cmNinjaBuild& objBuild, cmNinjaVars& vars,
+ const std::string& objectFileName,
+ cmLocalGenerator* lg)
{
- // Explicit preprocessing and dependency
- cmNinjaBuild ppBuild(ruleName);
+ cmNinjaBuild scanBuild(ruleName);
if (!ppFileName.empty()) {
- ppBuild.Outputs.push_back(ppFileName);
- ppBuild.RspFile = cmStrCat(ppFileName, ".rsp");
+ scanBuild.RspFile = cmStrCat(ppFileName, ".rsp");
} else {
- ppBuild.RspFile = "$out.rsp";
+ scanBuild.RspFile = "$out.rsp";
}
if (compilePP) {
- // Move compilation dependencies to the preprocessing build statement.
- std::swap(ppBuild.ExplicitDeps, objBuild.ExplicitDeps);
- std::swap(ppBuild.ImplicitDeps, objBuild.ImplicitDeps);
- std::swap(ppBuild.OrderOnlyDeps, objBuild.OrderOnlyDeps);
- std::swap(ppBuild.Variables["IN_ABS"], vars["IN_ABS"]);
+ // Move compilation dependencies to the scan/preprocessing build statement.
+ std::swap(scanBuild.ExplicitDeps, objBuild.ExplicitDeps);
+ std::swap(scanBuild.ImplicitDeps, objBuild.ImplicitDeps);
+ std::swap(scanBuild.OrderOnlyDeps, objBuild.OrderOnlyDeps);
+ std::swap(scanBuild.Variables["IN_ABS"], vars["IN_ABS"]);
// The actual compilation will now use the preprocessed source.
objBuild.ExplicitDeps.push_back(ppFileName);
} else {
- // Copy compilation dependencies to the preprocessing build statement.
- ppBuild.ExplicitDeps = objBuild.ExplicitDeps;
- ppBuild.ImplicitDeps = objBuild.ImplicitDeps;
- ppBuild.OrderOnlyDeps = objBuild.OrderOnlyDeps;
- ppBuild.Variables["IN_ABS"] = vars["IN_ABS"];
+ // Copy compilation dependencies to the scan/preprocessing build statement.
+ scanBuild.ExplicitDeps = objBuild.ExplicitDeps;
+ scanBuild.ImplicitDeps = objBuild.ImplicitDeps;
+ scanBuild.OrderOnlyDeps = objBuild.OrderOnlyDeps;
+ scanBuild.Variables["IN_ABS"] = vars["IN_ABS"];
}
- // Preprocessing and compilation generally use the same flags.
- ppBuild.Variables["FLAGS"] = vars["FLAGS"];
+ // Scanning and compilation generally use the same flags.
+ scanBuild.Variables["FLAGS"] = vars["FLAGS"];
if (compilePP && !compilePPWithDefines) {
- // Move preprocessor definitions to the preprocessor build statement.
- std::swap(ppBuild.Variables["DEFINES"], vars["DEFINES"]);
+ // Move preprocessor definitions to the scan/preprocessor build statement.
+ std::swap(scanBuild.Variables["DEFINES"], vars["DEFINES"]);
} else {
- // Copy preprocessor definitions to the preprocessor build statement.
- ppBuild.Variables["DEFINES"] = vars["DEFINES"];
+ // Copy preprocessor definitions to the scan/preprocessor build statement.
+ scanBuild.Variables["DEFINES"] = vars["DEFINES"];
}
// Copy include directories to the preprocessor build statement. The
// Fortran compilation build statement still needs them for the INCLUDE
// directive.
- ppBuild.Variables["INCLUDES"] = vars["INCLUDES"];
+ scanBuild.Variables["INCLUDES"] = vars["INCLUDES"];
+
+ // Tell dependency scanner the object file that will result from
+ // compiling the source.
+ scanBuild.Variables["OBJ_FILE"] = objectFileName;
+
+ // Tell dependency scanner where to store dyndep intermediate results.
+ std::string const& ddiFile = cmStrCat(objectFileName, ".ddi");
+ scanBuild.Variables["DYNDEP_INTERMEDIATE_FILE"] = ddiFile;
+
+ // Outputs of the scan/preprocessor build statement.
+ if (!ppFileName.empty()) {
+ scanBuild.Outputs.push_back(ppFileName);
+ scanBuild.ImplicitOuts.push_back(ddiFile);
+ } else {
+ scanBuild.Outputs.push_back(ddiFile);
+ }
- // Explicit preprocessing always uses a depfile.
- ppBuild.Variables["DEP_FILE"] = depFileName;
+ // Scanning always uses a depfile for preprocessor dependencies.
+ std::string const& depFileName = cmStrCat(scanBuild.Outputs.front(), ".d");
+ scanBuild.Variables["DEP_FILE"] =
+ lg->ConvertToOutputFormat(depFileName, cmOutputConverter::SHELL);
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
- // compiling the source.
- ppBuild.Variables["OBJ_FILE"] = objectFileName;
-
- // Tell dependency scanner where to store dyndep intermediate results.
- std::string const ddiFile = cmStrCat(objectFileName, ".ddi");
- if (ppFileName.empty()) {
- ppBuild.Outputs.push_back(ddiFile);
- } else {
- ppBuild.Variables["DYNDEP_INTERMEDIATE_FILE"] = ddiFile;
- ppBuild.ImplicitOuts.push_back(ddiFile);
- }
- }
- return ppBuild;
+ return scanBuild;
}
}
@@ -1170,7 +1156,8 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
vars["DEFINES"] = this->ComputeDefines(source, language, config);
vars["INCLUDES"] = this->ComputeIncludes(source, language, config);
- if (!this->NeedDepTypeMSVC(language)) {
+ if (this->GetMakefile()->GetSafeDefinition(
+ cmStrCat("CMAKE_", language, "_DEPFILE_FORMAT")) != "msvc"_s) {
bool replaceExt(false);
if (!language.empty()) {
std::string repVar =
@@ -1270,13 +1257,12 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
sourceFileName, objBuild.OrderOnlyDeps);
}
- // For some cases we need to generate a ninja dyndep file.
+ // For some cases we scan to dynamically discover dependencies.
bool const needDyndep = this->NeedDyndep(language);
+ bool const compilationPreprocesses =
+ !this->NeedExplicitPreprocessing(language);
- // For some cases we do an explicit preprocessor invocation.
- bool const explicitPP = this->NeedExplicitPreprocessing(language);
- if (explicitPP) {
-
+ if (needDyndep) {
// If source/target has preprocessing turned off, we still need to
// generate an explicit dependency step
const auto srcpp = source->GetSafeProperty("Fortran_PREPROCESS");
@@ -1288,27 +1274,24 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
preprocess = cmOutputConverter::GetFortranPreprocess(tgtpp);
}
- bool const compilePP = this->UsePreprocessedSource(language) &&
+ bool const compilePP = !compilationPreprocesses &&
(preprocess != cmOutputConverter::FortranPreprocess::NotNeeded);
bool const compilePPWithDefines =
- compilePP && this->CompilePreprocessedSourceWithDefines(language);
-
- std::string const ppFileName = compilePP
- ? this->ConvertToNinjaPath(this->GetPreprocessedFilePath(source, config))
- : "";
+ compilePP && this->CompileWithDefines(language);
- std::string const buildName = compilePP
- ? this->LanguagePreprocessRule(language, config)
- : this->LanguageDependencyRule(language, config);
-
- const auto depExtension = compilePP ? ".pp.d" : ".d";
- const std::string depFileName =
- this->GetLocalGenerator()->ConvertToOutputFormat(
- cmStrCat(objectFileName, depExtension), cmOutputConverter::SHELL);
+ std::string scanRuleName;
+ std::string ppFileName;
+ if (compilePP) {
+ scanRuleName = this->LanguagePreprocessAndScanRule(language, config);
+ ppFileName = this->ConvertToNinjaPath(
+ this->GetPreprocessedFilePath(source, config));
+ } else {
+ scanRuleName = this->LanguageScanRule(language, config);
+ }
- cmNinjaBuild ppBuild = GetPreprocessOrScanBuild(
- buildName, ppFileName, compilePP, compilePPWithDefines, objBuild, vars,
- depFileName, needDyndep, objectFileName);
+ cmNinjaBuild ppBuild = GetScanBuildStatement(
+ scanRuleName, ppFileName, compilePP, compilePPWithDefines, objBuild,
+ vars, objectFileName, this->LocalGenerator);
if (compilePP) {
// In case compilation requires flags that are incompatible with
@@ -1330,7 +1313,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
vars["INCLUDES"] = cmStrCat(sourceDirectoryFlag, ' ', vars["INCLUDES"]);
}
- if (firstForConfig && needDyndep) {
+ if (firstForConfig) {
std::string const ddiFile = cmStrCat(objectFileName, ".ddi");
this->Configs[config].DDIFiles[language].push_back(ddiFile);
}
@@ -1340,8 +1323,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig),
ppBuild, commandLineLengthLimit);
- }
- if (needDyndep) {
+
std::string const dyndep = this->GetDyndepFilePath(language, config);
objBuild.OrderOnlyDeps.push_back(dyndep);
vars["dyndep"] = dyndep;