summaryrefslogtreecommitdiffstats
path: root/Source/cmNinjaTargetGenerator.cxx
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2020-11-24 19:56:25 (GMT)
committerBrad King <brad.king@kitware.com>2021-01-05 14:34:55 (GMT)
commit4b233591179f9fe266e9157ef89e0a97854aa54c (patch)
tree42e79122cc54c444ee5bf09eb796c4b2bc35c412 /Source/cmNinjaTargetGenerator.cxx
parentf814d3b3c6f5ba45854da06c341af57bad2590b4 (diff)
downloadCMake-4b233591179f9fe266e9157ef89e0a97854aa54c.zip
CMake-4b233591179f9fe266e9157ef89e0a97854aa54c.tar.gz
CMake-4b233591179f9fe266e9157ef89e0a97854aa54c.tar.bz2
ninja: Add experimental infrastructure for C++20 module dependency scanning
Optionally enable this infrastructure through an undocumented `CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP` variable. Currently this is experimental and intended for use by compiler writers to implement their scanning tools. Warn as such when the feature is activated. Later when compilers provide the needed scanning tools we can enable this variable from our corresponding compiler information modules. It is never meant to be set by project code. When enabled, generate a build graph similar to what we use for Fortran module dependencies. There are some differences needed because we can scan dependencies without explicit preprocessing, and can directly compile the original source afterward. Co-Author: Ben Boeckel <ben.boeckel@kitware.com>
Diffstat (limited to 'Source/cmNinjaTargetGenerator.cxx')
-rw-r--r--Source/cmNinjaTargetGenerator.cxx84
1 files changed, 64 insertions, 20 deletions
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index d3f4a00..124e885 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -35,6 +35,7 @@
#include "cmRange.h"
#include "cmRulePlaceholderExpander.h"
#include "cmSourceFile.h"
+#include "cmStandardLevelResolver.h"
#include "cmState.h"
#include "cmStateTypes.h"
#include "cmStringAlgorithms.h"
@@ -146,9 +147,26 @@ std::string cmNinjaTargetGenerator::LanguageDyndepRule(
'_', config);
}
-bool cmNinjaTargetGenerator::NeedDyndep(std::string const& lang) const
+bool cmNinjaTargetGenerator::NeedCxxModuleSupport(
+ std::string const& lang, std::string const& config) const
{
- return lang == "Fortran";
+ if (lang != "CXX") {
+ return false;
+ }
+ if (!this->Makefile->IsOn("CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP")) {
+ return false;
+ }
+ cmGeneratorTarget const* tgt = this->GetGeneratorTarget();
+ cmStandardLevelResolver standardResolver(this->Makefile);
+ bool const uses_cxx20 =
+ standardResolver.HaveStandardAvailable(tgt, "CXX", config, "cxx_std_20");
+ return uses_cxx20 && this->GetGlobalGenerator()->CheckCxxModuleSupport();
+}
+
+bool cmNinjaTargetGenerator::NeedDyndep(std::string const& lang,
+ std::string const& config) const
+{
+ return lang == "Fortran" || this->NeedCxxModuleSupport(lang, config);
}
std::string cmNinjaTargetGenerator::OrderDependsTargetForTarget(
@@ -531,6 +549,7 @@ cmNinjaRule GetScanRule(
scanVars.Language = vars.Language;
scanVars.Object = "$OBJ_FILE";
scanVars.PreprocessedSource = "$out";
+ scanVars.DynDepFile = "$DYNDEP_INTERMEDIATE_FILE";
scanVars.DependencyFile = rule.DepFile.c_str();
scanVars.DependencyTarget = "$out";
@@ -585,7 +604,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
cmMakefile* mf = this->GetMakefile();
// For some cases we scan to dynamically discover dependencies.
- bool const needDyndep = this->NeedDyndep(lang);
+ bool const needDyndep = this->NeedDyndep(lang, config);
bool const compilationPreprocesses = !this->NeedExplicitPreprocessing(lang);
std::string flags = "$FLAGS";
@@ -623,16 +642,26 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
// 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);
+ std::string scanRuleName;
+ if (compilationPreprocesses) {
+ scanRuleName = this->LanguageScanRule(lang, config);
+ std::string const& scanCommand = mf->GetRequiredDefinition(
+ cmStrCat("CMAKE_EXPERIMENTAL_", lang, "_SCANDEP_SOURCE"));
+ cmExpandList(scanCommand, scanCommands);
+ for (std::string& i : scanCommands) {
+ i = cmStrCat(launcher, i);
+ }
+ } else {
+ 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"));
}
- scanCommands.emplace_back(GetScanCommand(cmakeCmd, tdi, lang, "$out",
- "$DYNDEP_INTERMEDIATE_FILE"));
auto scanRule = GetScanRule(
scanRuleName, vars, responseFlag, flags, rulePlaceholderExpander.get(),
@@ -640,12 +669,18 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
scanRule.Comment =
cmStrCat("Rule for generating ", lang, " dependencies.");
- scanRule.Description = cmStrCat("Building ", lang, " preprocessed $out");
+ if (compilationPreprocesses) {
+ scanRule.Description =
+ cmStrCat("Scanning $in for ", lang, " dependencies");
+ } else {
+ scanRule.Description =
+ cmStrCat("Building ", lang, " preprocessed $out");
+ }
this->GetGlobalGenerator()->AddRule(scanRule);
}
- {
+ if (!compilationPreprocesses) {
// Compilation will not preprocess, so it does not need the defines
// unless the compiler wants them for some other purpose.
if (!this->CompileWithDefines(lang)) {
@@ -1258,7 +1293,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
}
// For some cases we scan to dynamically discover dependencies.
- bool const needDyndep = this->NeedDyndep(language);
+ bool const needDyndep = this->NeedDyndep(language, config);
bool const compilationPreprocesses =
!this->NeedExplicitPreprocessing(language);
@@ -1440,17 +1475,26 @@ void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang,
tdi["compiler-id"] = this->Makefile->GetSafeDefinition(
cmStrCat("CMAKE_", lang, "_COMPILER_ID"));
+ std::string mod_dir;
if (lang == "Fortran") {
- std::string mod_dir = this->GeneratorTarget->GetFortranModuleDirectory(
+ mod_dir = this->GeneratorTarget->GetFortranModuleDirectory(
this->Makefile->GetHomeOutputDirectory());
- if (mod_dir.empty()) {
- mod_dir = this->Makefile->GetCurrentBinaryDirectory();
- }
- tdi["module-dir"] = mod_dir;
+ } else if (lang == "CXX") {
+ mod_dir =
+ cmSystemTools::CollapseFullPath(this->GeneratorTarget->ObjectDirectory);
+ }
+ if (mod_dir.empty()) {
+ mod_dir = this->Makefile->GetCurrentBinaryDirectory();
+ }
+ tdi["module-dir"] = mod_dir;
+
+ if (lang == "Fortran") {
tdi["submodule-sep"] =
this->Makefile->GetSafeDefinition("CMAKE_Fortran_SUBMODULE_SEP");
tdi["submodule-ext"] =
this->Makefile->GetSafeDefinition("CMAKE_Fortran_SUBMODULE_EXT");
+ } else if (lang == "CXX") {
+ // No extra information necessary.
}
tdi["dir-cur-bld"] = this->Makefile->GetCurrentBinaryDirectory();