diff options
-rw-r--r-- | Source/cmGeneratorTarget.cxx | 31 | ||||
-rw-r--r-- | Source/cmGlobalVisualStudio7Generator.cxx | 4 | ||||
-rw-r--r-- | Source/cmGlobalXCodeGenerator.cxx | 4 | ||||
-rw-r--r-- | Source/cmMakefileTargetGenerator.cxx | 6 | ||||
-rw-r--r-- | Source/cmStandardLevelResolver.cxx | 157 | ||||
-rw-r--r-- | Source/cmStandardLevelResolver.h | 3 | ||||
-rw-r--r-- | Source/cmVisualStudio10TargetGenerator.cxx | 6 | ||||
-rw-r--r-- | Tests/RunCMake/CXXModules/NoCXX-stderr.txt | 12 | ||||
-rw-r--r-- | Tests/RunCMake/CXXModules/NoCXX20-stderr.txt | 14 | ||||
-rw-r--r-- | Tests/RunCMake/CXXModules/NoCXX20ModuleFlag-stderr.txt | 12 | ||||
-rw-r--r-- | Tests/RunCMake/CXXModules/NoDyndepSupport-stderr.txt | 8 |
11 files changed, 194 insertions, 63 deletions
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 70f51b0..db4be63 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -9100,25 +9100,34 @@ void cmGeneratorTarget::CheckCxxModuleStatus(std::string const& config) const case cmGeneratorTarget::Cxx20SupportLevel::MissingCxx: this->Makefile->IssueMessage( MessageType::FATAL_ERROR, - cmStrCat("The \"", this->GetName(), - "\" target has C++ module sources but the \"CXX\" language " - "has not been enabled")); + cmStrCat("The target named \"", this->GetName(), + "\" has C++ sources that export modules but the \"CXX\" " + "language has not been enabled")); break; case cmGeneratorTarget::Cxx20SupportLevel::MissingExperimentalFlag: this->Makefile->IssueMessage( MessageType::FATAL_ERROR, - cmStrCat("The \"", this->GetName(), - "\" target has C++ module sources but its experimental " - "support has not been requested")); + cmStrCat("The target named \"", this->GetName(), + "\" has C++ sources that export modules but its " + "experimental support has not been requested")); break; - case cmGeneratorTarget::Cxx20SupportLevel::NoCxx20: + case cmGeneratorTarget::Cxx20SupportLevel::NoCxx20: { + cmStandardLevelResolver standardResolver(this->Makefile); + auto effStandard = + standardResolver.GetEffectiveStandard(this, "CXX", config); + if (effStandard.empty()) { + effStandard = "; no C++ standard found"; + } else { + effStandard = cmStrCat("; found \"cxx_std_", effStandard, '"'); + } this->Makefile->IssueMessage( MessageType::FATAL_ERROR, cmStrCat( - "The \"", this->GetName(), - "\" target has C++ module sources but is not using at least " - "\"cxx_std_20\"")); - break; + "The target named \"", this->GetName(), + "\" has C++ sources that export modules but does not include " + "\"cxx_std_20\" (or newer) among its `target_compile_features`", + effStandard)); + } break; case cmGeneratorTarget::Cxx20SupportLevel::Supported: // All is well. break; diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx index b2657a7..6953ec6 100644 --- a/Source/cmGlobalVisualStudio7Generator.cxx +++ b/Source/cmGlobalVisualStudio7Generator.cxx @@ -438,8 +438,8 @@ void cmGlobalVisualStudio7Generator::WriteTargetsToSolution( if (target->HaveCxx20ModuleSources() && !this->SupportsCxxModuleDyndep()) { root->GetMakefile()->IssueMessage( MessageType::FATAL_ERROR, - cmStrCat("The \"", target->GetName(), - "\" target contains C++ module sources which are not " + cmStrCat("The target named \"", target->GetName(), + "\" contains C++ sources that export modules which is not " "supported by the generator")); } diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 9834b64..3b9d2fd 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -1385,8 +1385,8 @@ bool cmGlobalXCodeGenerator::CreateXCodeTarget( if (gtgt->HaveCxx20ModuleSources()) { gtgt->Makefile->IssueMessage( MessageType::FATAL_ERROR, - cmStrCat("The \"", gtgt->GetName(), - "\" target contains C++ module sources which are not " + cmStrCat("The target named \"", gtgt->GetName(), + "\" contains C++ sources that export modules which is not " "supported by the generator")); } diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 5e3bf61..caa5e67 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -207,9 +207,9 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules() if (this->GeneratorTarget->HaveCxx20ModuleSources()) { this->Makefile->IssueMessage( MessageType::FATAL_ERROR, - cmStrCat("The \"", this->GeneratorTarget->GetName(), - "\" target contains C++ module sources which are not supported " - "by the generator")); + cmStrCat("The target named \"", this->GeneratorTarget->GetName(), + "\" contains C++ sources that export modules which is not " + "supported by the generator")); } // -- Write the custom commands for this target diff --git a/Source/cmStandardLevelResolver.cxx b/Source/cmStandardLevelResolver.cxx index f6e8bc6..de42bc6 100644 --- a/Source/cmStandardLevelResolver.cxx +++ b/Source/cmStandardLevelResolver.cxx @@ -13,7 +13,9 @@ #include <vector> #include <cm/iterator> +#include <cm/string_view> #include <cmext/algorithm> +#include <cmext/string_view> #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" @@ -71,6 +73,8 @@ struct StandardLevelComputer assert(this->Levels.size() == this->LevelsAsStrings.size()); } + // Note that the logic here is shadowed in `GetEffectiveStandard`; if one is + // changed, the other needs changed as well. std::string GetCompileOptionDef(cmMakefile* makefile, cmGeneratorTarget const* target, std::string const& config) const @@ -107,7 +111,7 @@ struct StandardLevelComputer if (cmp0128 == cmPolicies::NEW) { // Add extension flag if compiler's default doesn't match. if (ext != defaultExt) { - return cmStrCat("CMAKE_", this->Language, *defaultStd, "_", type, + return cmStrCat("CMAKE_", this->Language, *defaultStd, '_', type, "_COMPILE_OPTION"); } } else { @@ -130,7 +134,7 @@ struct StandardLevelComputer cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0128), "\nFor compatibility with older versions of CMake, " "compiler extensions won't be ", - state, ".")); + state, '.')); } } @@ -144,7 +148,7 @@ struct StandardLevelComputer if (target->GetLanguageStandardRequired(this->Language)) { std::string option_flag = cmStrCat( - "CMAKE_", this->Language, *standardProp, "_", type, "_COMPILE_OPTION"); + "CMAKE_", this->Language, *standardProp, '_', type, "_COMPILE_OPTION"); cmValue opt = target->Target->GetMakefile()->GetDefinition(option_flag); if (!opt) { @@ -155,8 +159,8 @@ struct StandardLevelComputer << this->Language << *standardProp << "\" " << (ext ? "(with compiler extensions)" : "") << ". But the current compiler \"" - << makefile->GetSafeDefinition("CMAKE_" + this->Language + - "_COMPILER_ID") + << makefile->GetSafeDefinition( + cmStrCat("CMAKE_", this->Language, "_COMPILER_ID")) << "\" does not support this, or " "CMake does not know the flags to enable it."; @@ -185,7 +189,7 @@ struct StandardLevelComputer } std::string standardStr(*standardProp); - if (this->Language == "CUDA" && standardStr == "98") { + if (this->Language == "CUDA"_s && standardStr == "98"_s) { standardStr = "03"; } @@ -194,7 +198,7 @@ struct StandardLevelComputer if (stdIt == cm::cend(stds)) { std::string e = cmStrCat(this->Language, "_STANDARD is set to invalid value '", - standardStr, "'"); + standardStr, '\''); makefile->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e, target->GetBacktrace()); return std::string{}; @@ -205,7 +209,7 @@ struct StandardLevelComputer if (defaultStdIt == cm::cend(stds)) { std::string e = cmStrCat("CMAKE_", this->Language, "_STANDARD_DEFAULT is set to invalid value '", - *defaultStd, "'"); + *defaultStd, '\''); makefile->IssueMessage(MessageType::INTERNAL_ERROR, e); return std::string{}; } @@ -216,7 +220,7 @@ struct StandardLevelComputer (cmp0128 == cmPolicies::NEW && (stdIt < defaultStdIt || ext != defaultExt))) { auto offset = std::distance(cm::cbegin(stds), stdIt); - return cmStrCat("CMAKE_", this->Language, stdsStrings[offset], "_", type, + return cmStrCat("CMAKE_", this->Language, stdsStrings[offset], '_', type, "_COMPILE_OPTION"); } @@ -226,7 +230,7 @@ struct StandardLevelComputer for (; defaultStdIt < stdIt; --stdIt) { auto offset = std::distance(cm::cbegin(stds), stdIt); std::string option_flag = - cmStrCat("CMAKE_", this->Language, stdsStrings[offset], "_", type, + cmStrCat("CMAKE_", this->Language, stdsStrings[offset], '_', type, "_COMPILE_OPTION"); if (target->Target->GetMakefile()->GetDefinition(option_flag)) { return option_flag; @@ -236,6 +240,105 @@ struct StandardLevelComputer return std::string{}; } + std::string GetEffectiveStandard(cmMakefile* makefile, + cmGeneratorTarget const* target, + std::string const& config) const + { + const auto& stds = this->Levels; + const auto& stdsStrings = this->LevelsAsStrings; + + cmValue defaultStd = makefile->GetDefinition( + cmStrCat("CMAKE_", this->Language, "_STANDARD_DEFAULT")); + if (!cmNonempty(defaultStd)) { + // this compiler has no notion of language standard levels + return std::string{}; + } + + cmPolicies::PolicyStatus const cmp0128{ makefile->GetPolicyStatus( + cmPolicies::CMP0128) }; + bool const defaultExt{ cmIsOn(*makefile->GetDefinition( + cmStrCat("CMAKE_", this->Language, "_EXTENSIONS_DEFAULT"))) }; + bool ext = true; + + if (cmp0128 == cmPolicies::NEW) { + ext = defaultExt; + } + + if (cmValue extPropValue = target->GetLanguageExtensions(this->Language)) { + ext = cmIsOn(*extPropValue); + } + + std::string const type{ ext ? "EXTENSION" : "STANDARD" }; + + cmValue standardProp = target->GetLanguageStandard(this->Language, config); + if (!standardProp) { + if (cmp0128 == cmPolicies::NEW) { + // Add extension flag if compiler's default doesn't match. + if (ext != defaultExt) { + return *defaultStd; + } + } else { + if (ext) { + return *defaultStd; + } + } + return std::string{}; + } + + if (target->GetLanguageStandardRequired(this->Language)) { + return *standardProp; + } + + // If the request matches the compiler's defaults we don't need to add + // anything. + if (*standardProp == *defaultStd && ext == defaultExt) { + if (cmp0128 == cmPolicies::NEW) { + return std::string{}; + } + } + + std::string standardStr(*standardProp); + if (this->Language == "CUDA"_s && standardStr == "98"_s) { + standardStr = "03"; + } + + auto stdIt = + std::find(cm::cbegin(stds), cm::cend(stds), ParseStd(standardStr)); + if (stdIt == cm::cend(stds)) { + return std::string{}; + } + + auto defaultStdIt = + std::find(cm::cbegin(stds), cm::cend(stds), ParseStd(*defaultStd)); + if (defaultStdIt == cm::cend(stds)) { + return std::string{}; + } + + // If the standard requested is older than the compiler's default or the + // extension mode doesn't match then we need to use a flag. + if ((cmp0128 != cmPolicies::NEW && stdIt <= defaultStdIt) || + (cmp0128 == cmPolicies::NEW && + (stdIt < defaultStdIt || ext != defaultExt))) { + auto offset = std::distance(cm::cbegin(stds), stdIt); + return stdsStrings[offset]; + } + + // The compiler's default is at least as new as the requested standard, + // and the requested standard is not required. Decay to the newest + // standard for which a flag is defined. + for (; defaultStdIt < stdIt; --stdIt) { + auto offset = std::distance(cm::cbegin(stds), stdIt); + std::string option_flag = + cmStrCat("CMAKE_", this->Language, stdsStrings[offset], '_', type, + "_COMPILE_OPTION"); + if (target->Target->GetMakefile()->GetDefinition(option_flag)) { + return stdsStrings[offset]; + } + } + + return std::string{}; + } + bool GetNewRequiredStandard(cmMakefile* makefile, std::string const& targetName, const std::string& feature, @@ -418,6 +521,18 @@ std::string cmStandardLevelResolver::GetCompileOptionDef( return mapping->second.GetCompileOptionDef(this->Makefile, target, config); } +std::string cmStandardLevelResolver::GetEffectiveStandard( + cmGeneratorTarget const* target, std::string const& lang, + std::string const& config) const +{ + const auto& mapping = StandardComputerMapping.find(lang); + if (mapping == cm::cend(StandardComputerMapping)) { + return std::string{}; + } + + return mapping->second.GetEffectiveStandard(this->Makefile, target, config); +} + bool cmStandardLevelResolver::AddRequiredTargetFeature( cmTarget* target, const std::string& feature, std::string* error) const { @@ -474,11 +589,12 @@ bool cmStandardLevelResolver::CheckCompileFeaturesAvailable( std::ostringstream e; e << "The compiler feature \"" << feature << "\" is not known to " << lang << " compiler\n\"" - << this->Makefile->GetSafeDefinition("CMAKE_" + lang + "_COMPILER_ID") + << this->Makefile->GetSafeDefinition( + cmStrCat("CMAKE_", lang, "_COMPILER_ID")) << "\"\nversion " - << this->Makefile->GetSafeDefinition("CMAKE_" + lang + - "_COMPILER_VERSION") - << "."; + << this->Makefile->GetSafeDefinition( + cmStrCat("CMAKE_", lang, "_COMPILER_VERSION")) + << '.'; if (error) { *error = e.str(); } else { @@ -561,8 +677,8 @@ cmValue cmStandardLevelResolver::CompileFeaturesAvailable( return nullptr; } - cmValue featuresKnown = - this->Makefile->GetDefinition("CMAKE_" + lang + "_COMPILE_FEATURES"); + cmValue featuresKnown = this->Makefile->GetDefinition( + cmStrCat("CMAKE_", lang, "_COMPILE_FEATURES")); if (!cmNonempty(featuresKnown)) { std::ostringstream e; @@ -572,11 +688,12 @@ cmValue cmStandardLevelResolver::CompileFeaturesAvailable( e << "No"; } e << " known features for " << lang << " compiler\n\"" - << this->Makefile->GetSafeDefinition("CMAKE_" + lang + "_COMPILER_ID") + << this->Makefile->GetSafeDefinition( + cmStrCat("CMAKE_", lang, "_COMPILER_ID")) << "\"\nversion " - << this->Makefile->GetSafeDefinition("CMAKE_" + lang + - "_COMPILER_VERSION") - << "."; + << this->Makefile->GetSafeDefinition( + cmStrCat("CMAKE_", lang, "_COMPILER_VERSION")) + << '.'; if (error) { *error = e.str(); } else { diff --git a/Source/cmStandardLevelResolver.h b/Source/cmStandardLevelResolver.h index 4226456..03adf3f 100644 --- a/Source/cmStandardLevelResolver.h +++ b/Source/cmStandardLevelResolver.h @@ -22,6 +22,9 @@ public: std::string GetCompileOptionDef(cmGeneratorTarget const* target, std::string const& lang, std::string const& config) const; + std::string GetEffectiveStandard(cmGeneratorTarget const* target, + std::string const& lang, + std::string const& config) const; bool AddRequiredTargetFeature(cmTarget* target, const std::string& feature, std::string* error = nullptr) const; diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 1bd4c57..7ca23a3 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -366,9 +366,9 @@ void cmVisualStudio10TargetGenerator::Generate() !this->GlobalGenerator->SupportsCxxModuleDyndep()) { this->Makefile->IssueMessage( MessageType::FATAL_ERROR, - cmStrCat("The \"", this->GeneratorTarget->GetName(), - "\" target contains C++ module sources which are not supported " - "by the generator")); + cmStrCat("The target named \"", this->GeneratorTarget->GetName(), + "\" contains C++ sources that export modules which is not " + "supported by the generator")); } this->ProjectType = computeProjectType(this->GeneratorTarget); diff --git a/Tests/RunCMake/CXXModules/NoCXX-stderr.txt b/Tests/RunCMake/CXXModules/NoCXX-stderr.txt index aa7f406..102d497 100644 --- a/Tests/RunCMake/CXXModules/NoCXX-stderr.txt +++ b/Tests/RunCMake/CXXModules/NoCXX-stderr.txt @@ -6,15 +6,15 @@ Call Stack \(most recent call first\): This warning is for project developers. Use -Wno-dev to suppress it. CMake Error in CMakeLists.txt: - The "nocxx" target has C\+\+ module sources but the "CXX" language has not - been enabled + The target named "nocxx" has C\+\+ sources that export modules but the "CXX" + language has not been enabled ( CMake Error in CMakeLists.txt: -( The "nocxx" target has C\+\+ module sources but the "CXX" language has not - been enabled -| The "nocxx" target contains C\+\+ module sources which are not supported by - the generator +( The target named "nocxx" has C\+\+ sources that export modules but the "CXX" + language has not been enabled +| The target named "nocxx" contains C\+\+ sources that export modules which is + not supported by the generator ) )* CMake Generate step failed. Build files cannot be regenerated correctly. diff --git a/Tests/RunCMake/CXXModules/NoCXX20-stderr.txt b/Tests/RunCMake/CXXModules/NoCXX20-stderr.txt index 95d73b1..dd25689 100644 --- a/Tests/RunCMake/CXXModules/NoCXX20-stderr.txt +++ b/Tests/RunCMake/CXXModules/NoCXX20-stderr.txt @@ -6,15 +6,17 @@ Call Stack \(most recent call first\): This warning is for project developers. Use -Wno-dev to suppress it. CMake Error in CMakeLists.txt: - The "nocxx20" target has C\+\+ module sources but is not using at least - "cxx_std_20" + The target named "nocxx20" has C\+\+ sources that export modules but does not + include "cxx_std_20" \(or newer\) among its `target_compile_features`; found + "cxx_std_17" ( CMake Error in CMakeLists.txt: -( The "nocxx20" target has C\+\+ module sources but is not using at least - "cxx_std_20" -| The "nocxx20" target contains C\+\+ module sources which are not supported by - the generator +( The target named "nocxx20" has C\+\+ sources that export modules but does not + include "cxx_std_20" \(or newer\) among its `target_compile_features`; found + "cxx_std_17" +| The target named "nocxx20" contains C\+\+ sources that export modules which + is not supported by the generator ) )* CMake Generate step failed. Build files cannot be regenerated correctly. diff --git a/Tests/RunCMake/CXXModules/NoCXX20ModuleFlag-stderr.txt b/Tests/RunCMake/CXXModules/NoCXX20ModuleFlag-stderr.txt index aa99af0..c2dc0b6 100644 --- a/Tests/RunCMake/CXXModules/NoCXX20ModuleFlag-stderr.txt +++ b/Tests/RunCMake/CXXModules/NoCXX20ModuleFlag-stderr.txt @@ -6,15 +6,15 @@ Call Stack \(most recent call first\): This warning is for project developers. Use -Wno-dev to suppress it. CMake Error in CMakeLists.txt: - The "noexperimentalflag" target has C\+\+ module sources but its experimental - support has not been requested + The target named "noexperimentalflag" has C\+\+ sources that export modules + but its experimental support has not been requested ( CMake Error in CMakeLists.txt: -( The "noexperimentalflag" target has C\+\+ module sources but its experimental - support has not been requested -| The "noexperimentalflag" target contains C\+\+ module sources which are not - supported by the generator +( The target named "noexperimentalflag" has C\+\+ sources that export modules + but its experimental support has not been requested +| The target named "noexperimentalflag" contains C\+\+ sources that export + modules which is not supported by the generator ) )* CMake Generate step failed. Build files cannot be regenerated correctly. diff --git a/Tests/RunCMake/CXXModules/NoDyndepSupport-stderr.txt b/Tests/RunCMake/CXXModules/NoDyndepSupport-stderr.txt index b63d291..c82a35a 100644 --- a/Tests/RunCMake/CXXModules/NoDyndepSupport-stderr.txt +++ b/Tests/RunCMake/CXXModules/NoDyndepSupport-stderr.txt @@ -13,13 +13,13 @@ This warning is for project developers. Use -Wno-dev to suppress it. due to lack of required features. Ninja 1.11 or higher is required. |CMake Error in CMakeLists.txt: - The "nodyndep" target contains C\+\+ module sources which are not supported - by the generator + The target named "nodyndep" contains C\+\+ sources that export modules which + is not supported by the generator ( CMake Error in CMakeLists.txt: - The "nodyndep" target contains C\+\+ module sources which are not supported - by the generator + The target named "nodyndep" contains C\+\+ sources that export modules which + is not supported by the generator )*) CMake Generate step failed. Build files cannot be regenerated correctly. |