From 0892c798f795c6072ce882552384187db86797f0 Mon Sep 17 00:00:00 2001 From: Justin Goshi Date: Thu, 11 Jun 2020 12:27:46 -0700 Subject: cmMakefile: Change CompileFeatureKnown to take target name instead of target The implementation needs only the target name. --- Source/cmGeneratorExpressionNode.cxx | 2 +- Source/cmMakefile.cxx | 6 +++--- Source/cmMakefile.h | 5 +++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index e4fb67e..6254c5b 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -1708,7 +1708,7 @@ static const struct CompileFeaturesNode : public cmGeneratorExpressionNode std::string error; std::string lang; if (!context->LG->GetMakefile()->CompileFeatureKnown( - context->HeadTarget->Target, p, lang, &error)) { + context->HeadTarget->Target->GetName(), p, lang, &error)) { reportError(context, content->GetOriginalExpression(), error); return std::string(); } diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 5c3063b..cf84b94 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -4673,7 +4673,7 @@ bool cmMakefile::AddRequiredTargetFeature(cmTarget* target, } std::string lang; - if (!this->CompileFeatureKnown(target, feature, lang, error)) { + if (!this->CompileFeatureKnown(target->GetName(), feature, lang, error)) { return false; } @@ -4710,7 +4710,7 @@ bool cmMakefile::AddRequiredTargetFeature(cmTarget* target, return this->AddRequiredTargetCxxFeature(target, feature, lang, error); } -bool cmMakefile::CompileFeatureKnown(cmTarget const* target, +bool cmMakefile::CompileFeatureKnown(const std::string& targetName, const std::string& feature, std::string& lang, std::string* error) const @@ -4747,7 +4747,7 @@ bool cmMakefile::CompileFeatureKnown(cmTarget const* target, e << " unknown feature \"" << feature << "\" for " "target \"" - << target->GetName() << "\"."; + << targetName << "\"."; if (error) { *error = e.str(); } else { diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 45d7109..368676f 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -928,8 +928,9 @@ public: bool AddRequiredTargetFeature(cmTarget* target, const std::string& feature, std::string* error = nullptr) const; - bool CompileFeatureKnown(cmTarget const* target, const std::string& feature, - std::string& lang, std::string* error) const; + bool CompileFeatureKnown(const std::string& targetName, + const std::string& feature, std::string& lang, + std::string* error) const; const char* CompileFeaturesAvailable(const std::string& lang, std::string* error) const; -- cgit v0.12 From 742ff97f809410055b22405a6b5728e72c458683 Mon Sep 17 00:00:00 2001 From: Justin Goshi Date: Thu, 11 Jun 2020 13:06:02 -0700 Subject: Refactor language standard computation Instead of mutating the configure-time cmTarget's properties at generate time, compute and store it in a cmGeneratorTarget field. --- Source/cmGeneratorExpressionNode.cxx | 4 +- Source/cmGeneratorTarget.cxx | 97 ++++++++++++++++- Source/cmGeneratorTarget.h | 17 +++ Source/cmGlobalGenerator.cxx | 10 +- Source/cmLocalGenerator.cxx | 52 ++-------- Source/cmLocalGenerator.h | 3 +- Source/cmMakefile.cxx | 195 +++++++++++++++++++++++++++-------- Source/cmMakefile.h | 54 ++++++++-- 8 files changed, 330 insertions(+), 102 deletions(-) diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index 6254c5b..3e0c21c 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -1742,9 +1742,9 @@ static const struct CompileFeaturesNode : public cmGeneratorExpressionNode continue; } if (!context->LG->GetMakefile()->HaveStandardAvailable( - target->Target, lit.first, it)) { + target, lit.first, context->Config, it)) { if (evalLL) { - cmProp l = target->GetProperty(lit.first + "_STANDARD"); + cmProp l = target->GetLanguageStandard(lit.first, context->Config); if (!l) { l = standardDefault; } diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index f2011ee..1f66a9f 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -947,6 +947,45 @@ bool cmGeneratorTarget::HasExplicitObjectName(cmSourceFile const* file) const return it != this->ExplicitObjectName.end(); } +cmProp cmGeneratorTarget::GetLanguageStandard(std::string const& lang, + std::string const& config) const +{ + std::string key = cmStrCat(cmSystemTools::UpperCase(config), '-', lang); + auto langStandardIter = this->LanguageStandardMap.find(key); + if (langStandardIter != this->LanguageStandardMap.end()) { + return &langStandardIter->second; + } + + return this->Target->GetProperty(cmStrCat(lang, "_STANDARD")); +} + +cmProp cmGeneratorTarget::GetLanguageStandardProperty(std::string const& lang, + const char* suffix) const +{ + cmProp propertyValue = this->Target->GetProperty(cmStrCat(lang, suffix)); + if (propertyValue == nullptr) { + // Check if we should use the value set by another language. + if (lang == "OBJC") { + propertyValue = this->GetLanguageStandardProperty("C", suffix); + } else if (lang == "OBJCXX" || lang == "CUDA") { + propertyValue = this->GetLanguageStandardProperty("CXX", suffix); + } + } + return propertyValue; +} + +cmProp cmGeneratorTarget::GetLanguageExtensions(std::string const& lang) const +{ + return this->GetLanguageStandardProperty(lang, "_EXTENSIONS"); +} + +bool cmGeneratorTarget::GetLanguageStandardRequired( + std::string const& lang) const +{ + cmProp p = this->GetLanguageStandardProperty(lang, "_STANDARD_REQUIRED"); + return p && cmIsOn(*p); +} + void cmGeneratorTarget::GetModuleDefinitionSources( std::vector& data, const std::string& config) const { @@ -4408,12 +4447,68 @@ void cmGeneratorTarget::ComputeTargetManifest(const std::string& config) const bool cmGeneratorTarget::ComputeCompileFeatures(std::string const& config) const { + // Compute the language standard based on the compile features. std::vector> features = this->GetCompileFeatures(config); for (BT const& f : features) { - if (!this->Makefile->AddRequiredTargetFeature(this->Target, f.Value)) { + std::string lang; + if (!this->Makefile->CompileFeatureKnown(this->Target->GetName(), f.Value, + lang, nullptr)) { return false; } + + std::string key = cmStrCat(cmSystemTools::UpperCase(config), '-', lang); + cmProp currentLanguageStandard = this->GetLanguageStandard(lang, config); + + std::string newRequiredStandard; + if (!this->Makefile->GetNewRequiredStandard( + this->Target->GetName(), f.Value, currentLanguageStandard, + newRequiredStandard)) { + return false; + } + + if (!newRequiredStandard.empty()) { + this->LanguageStandardMap[key] = newRequiredStandard; + } } + + return true; +} + +bool cmGeneratorTarget::ComputeCompileFeatures( + std::string const& config, std::set const& languagePairs) const +{ + for (const auto& language : languagePairs) { + cmProp generatorTargetLanguageStandard = + this->GetLanguageStandard(language.first, config); + if (!generatorTargetLanguageStandard) { + // If the standard isn't explicitly set we copy it over from the + // specified paired language. + std::string key = + cmStrCat(cmSystemTools::UpperCase(config), '-', language.first); + cmProp standardToCopy = + this->GetLanguageStandard(language.second, config); + if (standardToCopy != nullptr) { + this->LanguageStandardMap[key] = *standardToCopy; + generatorTargetLanguageStandard = &this->LanguageStandardMap[key]; + } else { + cmProp defaultStandard = this->Makefile->GetDef( + cmStrCat("CMAKE_", language.second, "_STANDARD_DEFAULT")); + if (defaultStandard != nullptr) { + this->LanguageStandardMap[key] = *defaultStandard; + generatorTargetLanguageStandard = &this->LanguageStandardMap[key]; + } + } + + // Custom updates for the CUDA standard. + if (generatorTargetLanguageStandard != nullptr && + language.first == "CUDA") { + if (*generatorTargetLanguageStandard == "98") { + this->LanguageStandardMap[key] = "03"; + } + } + } + } + return true; } diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 3aedbf5..a71e64c 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -148,6 +148,13 @@ public: bool HasExplicitObjectName(cmSourceFile const* file) const; void AddExplicitObjectName(cmSourceFile const* sf); + cmProp GetLanguageStandard(std::string const& lang, + std::string const& config) const; + + cmProp GetLanguageExtensions(std::string const& lang) const; + + bool GetLanguageStandardRequired(std::string const& lang) const; + void GetModuleDefinitionSources(std::vector&, const std::string& config) const; void GetExternalObjects(std::vector&, @@ -515,6 +522,11 @@ public: bool ComputeCompileFeatures(std::string const& config) const; + using LanguagePair = std::pair; + bool ComputeCompileFeatures( + std::string const& config, + std::set const& languagePairs) const; + /** * Trace through the source files in this target and add al source files * that they depend on, used by all generators @@ -1038,6 +1050,11 @@ private: bool GetRPATH(const std::string& config, const std::string& prop, std::string& rpath) const; + mutable std::map LanguageStandardMap; + + cmProp GetLanguageStandardProperty(std::string const& lang, + const char* suffix) const; + public: const std::vector& GetLinkImplementationClosure( const std::string& config) const; diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 1ed5e8b..4b4ffda 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -1442,12 +1442,10 @@ bool cmGlobalGenerator::Compute() localGen->AddHelperCommands(); } - // Finalize the set of compile features for each target. - // FIXME: This turns into calls to cmMakefile::AddRequiredTargetFeature - // which actually modifies the _STANDARD target property - // on the original cmTarget instance. It accumulates features - // across all configurations. Some refactoring is needed to - // compute a per-config resulta purely during generation. + // Perform up-front computation in order to handle errors (such as unknown + // features) at this point. While processing the compile features we also + // calculate and cache the language standard required by the compile + // features. for (const auto& localGen : this->LocalGenerators) { if (!localGen->ComputeTargetCompileFeatures()) { return false; diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index f748822..5c09208 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -803,39 +803,8 @@ bool cmLocalGenerator::ComputeTargetCompileFeatures() // Now that C/C++ _STANDARD values have been computed // set the values to ObjC/ObjCXX _STANDARD variables if (target->GetType() != cmStateEnums::INTERFACE_LIBRARY) { - auto copyStandardToObjLang = [&](LanguagePair const& lang) -> bool { - if (!target->GetProperty(cmStrCat(lang.first, "_STANDARD"))) { - cmProp standard = - target->GetProperty(cmStrCat(lang.second, "_STANDARD")); - if (!standard) { - standard = this->Makefile->GetDef( - cmStrCat("CMAKE_", lang.second, "_STANDARD_DEFAULT")); - } - target->Target->SetProperty(cmStrCat(lang.first, "_STANDARD"), - standard ? standard->c_str() : nullptr); - return true; - } - return false; - }; - auto copyPropertyToObjLang = [&](LanguagePair const& lang, - const char* property) { - if (!target->GetProperty(cmStrCat(lang.first, property)) && - target->GetProperty(cmStrCat(lang.second, property))) { - cmProp p = target->GetProperty(cmStrCat(lang.second, property)); - target->Target->SetProperty(cmStrCat(lang.first, property), - p ? p->c_str() : nullptr); - } - }; - for (auto const& lang : pairedLanguages) { - if (copyStandardToObjLang(lang)) { - copyPropertyToObjLang(lang, "_STANDARD_REQUIRED"); - copyPropertyToObjLang(lang, "_EXTENSIONS"); - } - } - if (cmProp standard = target->GetProperty("CUDA_STANDARD")) { - if (*standard == "98") { - target->Target->SetProperty("CUDA_STANDARD", "03"); - } + for (std::string const& c : configNames) { + target->ComputeCompileFeatures(c, inferredEnabledLanguages); } } } @@ -1026,7 +995,7 @@ void cmLocalGenerator::AddCompileOptions(std::vector>& flags, } for (auto const& it : target->GetMaxLanguageStandards()) { - cmProp standard = target->GetProperty(it.first + "_STANDARD"); + cmProp standard = target->GetLanguageStandard(it.first, config); if (!standard) { continue; } @@ -1050,7 +1019,7 @@ void cmLocalGenerator::AddCompileOptions(std::vector>& flags, } std::string compReqFlag; - this->AddCompilerRequirementFlag(compReqFlag, target, lang); + this->AddCompilerRequirementFlag(compReqFlag, target, lang, config); if (!compReqFlag.empty()) { flags.emplace_back(std::move(compReqFlag)); } @@ -2045,7 +2014,7 @@ void cmLocalGenerator::AddLanguageFlagsForLinking( // when linking in order to use the matching standard library. // FIXME: If CMake gains an abstraction for standard library // selection, this will have to be reconciled with it. - this->AddCompilerRequirementFlag(flags, target, lang); + this->AddCompilerRequirementFlag(flags, target, lang, config); } this->AddLanguageFlags(flags, target, lang, config); @@ -2188,7 +2157,8 @@ void cmLocalGenerator::AddSharedFlags(std::string& flags, } void cmLocalGenerator::AddCompilerRequirementFlag( - std::string& flags, cmGeneratorTarget const* target, const std::string& lang) + std::string& flags, cmGeneratorTarget const* target, const std::string& lang, + const std::string& config) { if (lang.empty()) { return; @@ -2199,15 +2169,13 @@ void cmLocalGenerator::AddCompilerRequirementFlag( // This compiler has no notion of language standard levels. return; } - std::string extProp = lang + "_EXTENSIONS"; bool ext = true; - if (cmProp extPropValue = target->GetProperty(extProp)) { + if (cmProp extPropValue = target->GetLanguageExtensions(lang)) { if (cmIsOff(*extPropValue)) { ext = false; } } - std::string stdProp = lang + "_STANDARD"; - cmProp standardProp = target->GetProperty(stdProp); + cmProp standardProp = target->GetLanguageStandard(lang, config); if (!standardProp) { if (ext) { // No language standard is specified and extensions are not disabled. @@ -2227,7 +2195,7 @@ void cmLocalGenerator::AddCompilerRequirementFlag( std::string const type = ext ? "EXTENSION" : "STANDARD"; - if (target->GetPropertyAsBool(lang + "_STANDARD_REQUIRED")) { + if (target->GetLanguageStandardRequired(lang)) { std::string option_flag = "CMAKE_" + lang + *standardProp + "_" + type + "_COMPILE_OPTION"; diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index f2d9145..f4781d6 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -123,7 +123,8 @@ public: const std::string& config); void AddCompilerRequirementFlag(std::string& flags, cmGeneratorTarget const* target, - const std::string& lang); + const std::string& lang, + const std::string& config); //! Append flags to a string. virtual void AppendFlags(std::string& flags, const std::string& newFlags) const; diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index cf84b94..f3da7a0 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -39,6 +39,7 @@ #include "cmGeneratedFileStream.h" #include "cmGeneratorExpression.h" #include "cmGeneratorExpressionEvaluationFile.h" +#include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmInstallGenerator.h" // IWYU pragma: keep #include "cmInstallSubdirectoryGenerator.h" @@ -4673,7 +4674,33 @@ bool cmMakefile::AddRequiredTargetFeature(cmTarget* target, } std::string lang; - if (!this->CompileFeatureKnown(target->GetName(), feature, lang, error)) { + if (!this->CheckCompileFeaturesAvailable(target->GetName(), feature, lang, + error)) { + return false; + } + + target->AppendProperty("COMPILE_FEATURES", feature); + + // FIXME: Add a policy to avoid updating the _STANDARD target + // property due to COMPILE_FEATURES. The language standard selection + // should be done purely at generate time based on whatever the project + // code put in these properties explicitly. That is mostly true now, + // but for compatibility we need to continue updating the property here. + if (lang == "C" || lang == "OBJC") { + return this->AddRequiredTargetCFeature(target, feature, lang, error); + } + if (lang == "CUDA") { + return this->AddRequiredTargetCudaFeature(target, feature, lang, error); + } + return this->AddRequiredTargetCxxFeature(target, feature, lang, error); +} + +bool cmMakefile::CheckCompileFeaturesAvailable(const std::string& targetName, + const std::string& feature, + std::string& lang, + std::string* error) const +{ + if (!this->CompileFeatureKnown(targetName, feature, lang, error)) { return false; } @@ -4699,15 +4726,7 @@ bool cmMakefile::AddRequiredTargetFeature(cmTarget* target, return false; } - target->AppendProperty("COMPILE_FEATURES", feature); - - if (lang == "C" || lang == "OBJC") { - return this->AddRequiredTargetCFeature(target, feature, lang, error); - } - if (lang == "CUDA") { - return this->AddRequiredTargetCudaFeature(target, feature, lang, error); - } - return this->AddRequiredTargetCxxFeature(target, feature, lang, error); + return true; } bool cmMakefile::CompileFeatureKnown(const std::string& targetName, @@ -4802,22 +4821,50 @@ const char* cmMakefile::CompileFeaturesAvailable(const std::string& lang, return featuresKnown; } -bool cmMakefile::HaveStandardAvailable(cmTarget const* target, +bool cmMakefile::GetNewRequiredStandard(const std::string& targetName, + const std::string& feature, + cmProp currentLangStandardValue, + std::string& newRequiredStandard, + std::string* error) const +{ + std::string lang; + if (!this->CheckCompileFeaturesAvailable(targetName, feature, lang, error)) { + return false; + } + + if (lang == "C" || lang == "OBJC") { + return this->GetNewRequiredCStandard(targetName, feature, lang, + currentLangStandardValue, + newRequiredStandard, error); + } + if (lang == "CUDA") { + return this->GetNewRequiredCudaStandard(targetName, feature, lang, + currentLangStandardValue, + newRequiredStandard, error); + } + return this->GetNewRequiredCxxStandard(targetName, feature, lang, + currentLangStandardValue, + newRequiredStandard, error); +} + +bool cmMakefile::HaveStandardAvailable(cmGeneratorTarget const* target, std::string const& lang, + std::string const& config, const std::string& feature) const { if (lang == "C" || lang == "OBJC") { - return this->HaveCStandardAvailable(target, feature, lang); + return this->HaveCStandardAvailable(target, lang, config, feature); } if (lang == "CUDA") { - return this->HaveCudaStandardAvailable(target, feature, lang); + return this->HaveCudaStandardAvailable(target, lang, config, feature); } - return this->HaveCxxStandardAvailable(target, feature, lang); + return this->HaveCxxStandardAvailable(target, lang, config, feature); } -bool cmMakefile::HaveCStandardAvailable(cmTarget const* target, - const std::string& feature, - std::string const& lang) const +bool cmMakefile::HaveCStandardAvailable(cmGeneratorTarget const* target, + std::string const& lang, + std::string const& config, + const std::string& feature) const { cmProp defaultCStandard = this->GetDef(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT")); @@ -4846,7 +4893,7 @@ bool cmMakefile::HaveCStandardAvailable(cmTarget const* target, this->CheckNeededCLanguage(feature, lang, needC90, needC99, needC11); - cmProp existingCStandard = target->GetProperty(cmStrCat(lang, "_STANDARD")); + cmProp existingCStandard = target->GetLanguageStandard(lang, config); if (!existingCStandard) { existingCStandard = defaultCStandard; } @@ -4909,9 +4956,10 @@ bool cmMakefile::IsLaterStandard(std::string const& lang, cm::cend(CXX_STANDARDS); } -bool cmMakefile::HaveCxxStandardAvailable(cmTarget const* target, - const std::string& feature, - std::string const& lang) const +bool cmMakefile::HaveCxxStandardAvailable(cmGeneratorTarget const* target, + std::string const& lang, + std::string const& config, + const std::string& feature) const { cmProp defaultCxxStandard = this->GetDef(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT")); @@ -4941,8 +4989,7 @@ bool cmMakefile::HaveCxxStandardAvailable(cmTarget const* target, this->CheckNeededCxxLanguage(feature, lang, needCxx98, needCxx11, needCxx14, needCxx17, needCxx20); - cmProp existingCxxStandard = - target->GetProperty(cmStrCat(lang, "_STANDARD")); + cmProp existingCxxStandard = target->GetLanguageStandard(lang, config); if (!existingCxxStandard) { existingCxxStandard = defaultCxxStandard; } @@ -5009,6 +5056,29 @@ bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target, std::string const& lang, std::string* error) const { + std::string newRequiredStandard; + if (this->GetNewRequiredCxxStandard( + target->GetName(), feature, lang, + target->GetProperty(cmStrCat(lang, "_STANDARD")), newRequiredStandard, + error)) { + if (!newRequiredStandard.empty()) { + target->SetProperty(cmStrCat(lang, "_STANDARD"), newRequiredStandard); + } + return true; + } + + return false; +} + +bool cmMakefile::GetNewRequiredCxxStandard(const std::string& targetName, + const std::string& feature, + std::string const& lang, + cmProp currentLangStandardValue, + std::string& newRequiredStandard, + std::string* error) const +{ + newRequiredStandard.clear(); + bool needCxx98 = false; bool needCxx11 = false; bool needCxx14 = false; @@ -5018,8 +5088,7 @@ bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target, this->CheckNeededCxxLanguage(feature, lang, needCxx98, needCxx11, needCxx14, needCxx17, needCxx20); - cmProp existingCxxStandard = - target->GetProperty(cmStrCat(lang, "_STANDARD")); + cmProp existingCxxStandard = currentLangStandardValue; if (existingCxxStandard == nullptr) { cmProp defaultCxxStandard = this->GetDef(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT")); @@ -5034,7 +5103,7 @@ bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target, cmStrCmp(*existingCxxStandard)); if (existingCxxLevel == cm::cend(CXX_STANDARDS)) { const std::string e = cmStrCat( - "The ", lang, "_STANDARD property on target \"", target->GetName(), + "The ", lang, "_STANDARD property on target \"", targetName, "\" contained an invalid value: \"", *existingCxxStandard, "\"."); if (error) { *error = e; @@ -5060,16 +5129,17 @@ bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target, // Ensure the C++ language level is high enough to support // the needed C++ features. if (!existingCxxLevel || existingCxxLevel < needCxxLevel) { - target->SetProperty(cmStrCat(lang, "_STANDARD"), *needCxxLevel); + newRequiredStandard = *needCxxLevel; } } return true; } -bool cmMakefile::HaveCudaStandardAvailable(cmTarget const* target, - const std::string& feature, - std::string const& lang) const +bool cmMakefile::HaveCudaStandardAvailable(cmGeneratorTarget const* target, + std::string const& lang, + std::string const& config, + const std::string& feature) const { cmProp defaultCudaStandard = this->GetDef(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT")); @@ -5100,8 +5170,7 @@ bool cmMakefile::HaveCudaStandardAvailable(cmTarget const* target, this->CheckNeededCudaLanguage(feature, lang, needCuda03, needCuda11, needCuda14, needCuda17, needCuda20); - cmProp existingCudaStandard = - target->GetProperty(cmStrCat(lang, "_STANDARD")); + cmProp existingCudaStandard = target->GetLanguageStandard(lang, config); if (!existingCudaStandard) { existingCudaStandard = defaultCudaStandard; } @@ -5168,6 +5237,28 @@ bool cmMakefile::AddRequiredTargetCudaFeature(cmTarget* target, std::string const& lang, std::string* error) const { + std::string newRequiredStandard; + if (this->GetNewRequiredCudaStandard( + target->GetName(), feature, lang, + target->GetProperty(cmStrCat(lang, "_STANDARD")), newRequiredStandard, + error)) { + if (!newRequiredStandard.empty()) { + target->SetProperty(cmStrCat(lang, "_STANDARD"), newRequiredStandard); + } + return true; + } + return false; +} + +bool cmMakefile::GetNewRequiredCudaStandard(const std::string& targetName, + const std::string& feature, + std::string const& lang, + cmProp currentLangStandardValue, + std::string& newRequiredStandard, + std::string* error) const +{ + newRequiredStandard.clear(); + bool needCuda03 = false; bool needCuda11 = false; bool needCuda14 = false; @@ -5177,8 +5268,7 @@ bool cmMakefile::AddRequiredTargetCudaFeature(cmTarget* target, this->CheckNeededCudaLanguage(feature, lang, needCuda03, needCuda11, needCuda14, needCuda17, needCuda20); - cmProp existingCudaStandard = - target->GetProperty(cmStrCat(lang, "_STANDARD")); + cmProp existingCudaStandard = currentLangStandardValue; if (existingCudaStandard == nullptr) { cmProp defaultCudaStandard = this->GetDef(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT")); @@ -5193,7 +5283,7 @@ bool cmMakefile::AddRequiredTargetCudaFeature(cmTarget* target, cmStrCmp(*existingCudaStandard)); if (existingCudaLevel == cm::cend(CUDA_STANDARDS)) { const std::string e = cmStrCat( - "The ", lang, "_STANDARD property on target \"", target->GetName(), + "The ", lang, "_STANDARD property on target \"", targetName, "\" contained an invalid value: \"", *existingCudaStandard, "\"."); if (error) { *error = e; @@ -5219,7 +5309,7 @@ bool cmMakefile::AddRequiredTargetCudaFeature(cmTarget* target, // Ensure the CUDA language level is high enough to support // the needed CUDA features. if (!existingCudaLevel || existingCudaLevel < needCudaLevel) { - target->SetProperty("CUDA_STANDARD", *needCudaLevel); + newRequiredStandard = *needCudaLevel; } } @@ -5252,13 +5342,36 @@ bool cmMakefile::AddRequiredTargetCFeature(cmTarget* target, std::string const& lang, std::string* error) const { + std::string newRequiredStandard; + if (this->GetNewRequiredCStandard( + target->GetName(), feature, lang, + target->GetProperty(cmStrCat(lang, "_STANDARD")), newRequiredStandard, + error)) { + if (!newRequiredStandard.empty()) { + target->SetProperty(cmStrCat(lang, "_STANDARD"), newRequiredStandard); + } + return true; + } + + return false; +} + +bool cmMakefile::GetNewRequiredCStandard(const std::string& targetName, + const std::string& feature, + std::string const& lang, + cmProp currentLangStandardValue, + std::string& newRequiredStandard, + std::string* error) const +{ + newRequiredStandard.clear(); + bool needC90 = false; bool needC99 = false; bool needC11 = false; this->CheckNeededCLanguage(feature, lang, needC90, needC99, needC11); - cmProp existingCStandard = target->GetProperty(cmStrCat(lang, "_STANDARD")); + cmProp existingCStandard = currentLangStandardValue; if (existingCStandard == nullptr) { cmProp defaultCStandard = this->GetDef(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT")); @@ -5270,7 +5383,7 @@ bool cmMakefile::AddRequiredTargetCFeature(cmTarget* target, if (std::find_if(cm::cbegin(C_STANDARDS), cm::cend(C_STANDARDS), cmStrCmp(*existingCStandard)) == cm::cend(C_STANDARDS)) { const std::string e = cmStrCat( - "The ", lang, "_STANDARD property on target \"", target->GetName(), + "The ", lang, "_STANDARD property on target \"", targetName, "\" contained an invalid value: \"", *existingCStandard, "\"."); if (error) { *error = e; @@ -5307,11 +5420,11 @@ bool cmMakefile::AddRequiredTargetCFeature(cmTarget* target, } if (setC11) { - target->SetProperty(cmStrCat(lang, "_STANDARD"), "11"); + newRequiredStandard = "11"; } else if (setC99) { - target->SetProperty(cmStrCat(lang, "_STANDARD"), "99"); + newRequiredStandard = "99"; } else if (setC90) { - target->SetProperty(cmStrCat(lang, "_STANDARD"), "90"); + newRequiredStandard = "90"; } return true; } diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 368676f..332554e 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -47,6 +47,7 @@ class cmExpandedCommandArgument; class cmExportBuildFileGenerator; class cmFunctionBlocker; class cmGeneratorExpressionEvaluationFile; +class cmGeneratorTarget; class cmGlobalGenerator; class cmImplicitDependsList; class cmInstallGenerator; @@ -935,7 +936,15 @@ public: const char* CompileFeaturesAvailable(const std::string& lang, std::string* error) const; - bool HaveStandardAvailable(cmTarget const* target, std::string const& lang, + bool GetNewRequiredStandard(const std::string& targetName, + const std::string& feature, + cmProp currentLangStandardValue, + std::string& newRequiredStandard, + std::string* error = nullptr) const; + + bool HaveStandardAvailable(cmGeneratorTarget const* target, + std::string const& lang, + std::string const& config, const std::string& feature) const; bool IsLaterStandard(std::string const& lang, std::string const& lhs, @@ -1175,6 +1184,11 @@ private: std::string const& lang, std::string* error = nullptr) const; + bool CheckCompileFeaturesAvailable(const std::string& targetName, + const std::string& feature, + std::string& lang, + std::string* error) const; + void CheckNeededCLanguage(const std::string& feature, std::string const& lang, bool& needC90, bool& needC99, bool& needC11) const; @@ -1187,15 +1201,37 @@ private: bool& needCuda11, bool& needCuda14, bool& needCuda17, bool& needCuda20) const; - bool HaveCStandardAvailable(cmTarget const* target, - const std::string& feature, - std::string const& lang) const; - bool HaveCxxStandardAvailable(cmTarget const* target, - const std::string& feature, - std::string const& lang) const; - bool HaveCudaStandardAvailable(cmTarget const* target, + bool GetNewRequiredCStandard(const std::string& targetName, + const std::string& feature, + std::string const& lang, + cmProp currentLangStandardValue, + std::string& newRequiredStandard, + std::string* error = nullptr) const; + bool GetNewRequiredCxxStandard(const std::string& targetName, const std::string& feature, - std::string const& lang) const; + std::string const& lang, + cmProp currentLangStandardValue, + std::string& newRequiredStandard, + std::string* error = nullptr) const; + bool GetNewRequiredCudaStandard(const std::string& targetName, + const std::string& feature, + std::string const& lang, + cmProp currentLangStandardValue, + std::string& newRequiredStandard, + std::string* error = nullptr) const; + + bool HaveCStandardAvailable(cmGeneratorTarget const* target, + std::string const& lang, + std::string const& config, + const std::string& feature) const; + bool HaveCxxStandardAvailable(cmGeneratorTarget const* target, + std::string const& lang, + std::string const& config, + const std::string& feature) const; + bool HaveCudaStandardAvailable(cmGeneratorTarget const* target, + std::string const& lang, + std::string const& config, + const std::string& feature) const; void CheckForUnusedVariables() const; -- cgit v0.12