|
|
@@ -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"
|
|
|
@@ -4681,7 +4682,33 @@ bool cmMakefile::AddRequiredTargetFeature(cmTarget* target,
|
|
|
}
|
|
|
|
|
|
std::string lang;
|
|
|
- if (!this->CompileFeatureKnown(target, 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 <LANG>_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;
|
|
|
}
|
|
|
|
|
|
@@ -4707,18 +4734,10 @@ 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(cmTarget const* target,
|
|
|
+bool cmMakefile::CompileFeatureKnown(const std::string& targetName,
|
|
|
const std::string& feature,
|
|
|
std::string& lang,
|
|
|
std::string* error) const
|
|
|
@@ -4755,7 +4774,7 @@ bool cmMakefile::CompileFeatureKnown(cmTarget const* target,
|
|
|
e << " unknown feature \"" << feature
|
|
|
<< "\" for "
|
|
|
"target \""
|
|
|
- << target->GetName() << "\".";
|
|
|
+ << targetName << "\".";
|
|
|
if (error) {
|
|
|
*error = e.str();
|
|
|
} else {
|
|
|
@@ -4810,22 +4829,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"));
|
|
|
@@ -4854,7 +4901,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;
|
|
|
}
|
|
|
@@ -4917,9 +4964,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"));
|
|
|
@@ -4949,8 +4997,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;
|
|
|
}
|
|
|
@@ -5017,6 +5064,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;
|
|
|
@@ -5026,8 +5096,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"));
|
|
|
@@ -5042,7 +5111,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;
|
|
|
@@ -5068,16 +5137,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"));
|
|
|
@@ -5108,8 +5178,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;
|
|
|
}
|
|
|
@@ -5176,6 +5245,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;
|
|
|
@@ -5185,8 +5276,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"));
|
|
|
@@ -5201,7 +5291,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;
|
|
|
@@ -5227,7 +5317,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;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -5260,13 +5350,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"));
|
|
|
@@ -5278,7 +5391,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;
|
|
|
@@ -5315,11 +5428,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;
|
|
|
}
|