diff options
author | Brad King <brad.king@kitware.com> | 2023-08-25 15:27:10 (GMT) |
---|---|---|
committer | Kitware Robot <kwrobot@kitware.com> | 2023-08-25 15:27:27 (GMT) |
commit | 863891adb232cd89830080c702361444f496b4fe (patch) | |
tree | 4a7c0cb3b7a33d3cf2cfe85f0d5075f7455605ae /Source | |
parent | 5ae0030e90df07e56dc16b0210bd334650dcc9d4 (diff) | |
parent | 571b5e1f2c5569cd555377423930f8d61d5d2e99 (diff) | |
download | CMake-863891adb232cd89830080c702361444f496b4fe.zip CMake-863891adb232cd89830080c702361444f496b4fe.tar.gz CMake-863891adb232cd89830080c702361444f496b4fe.tar.bz2 |
Merge topic 'modules-better-messages'
571b5e1f2c cxxmodules: improve error messages for C++ module setup
8b4d32c18b cmStandardLevelResolver: add query for the effective standard level
17ddc4ac76 cmStandardLevelResolver: compare with static string literals
6f1dae2b01 cmStandardLevelResolver: use `cmStrCat` where possible
0d45d40e13 cmStandardLevelResolver: use character literals where possible
Acked-by: Kitware Robot <kwrobot@kitware.com>
Tested-by: buildbot <buildbot@kitware.com>
Merge-request: !8755
Diffstat (limited to 'Source')
-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 |
7 files changed, 170 insertions, 41 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); |