summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
authorStephen Kelly <steveire@gmail.com>2014-05-15 09:32:30 (GMT)
committerStephen Kelly <steveire@gmail.com>2014-05-21 15:22:32 (GMT)
commit0dfe395e3cb1a720c4853087db554a6827feaadb (patch)
tree83d9cbe0ee9843bc4aa0012d9a7064a3522ba018 /Source
parentaa8a6fcee8c67b0516efcd745fb1d7a66d249096 (diff)
downloadCMake-0dfe395e3cb1a720c4853087db554a6827feaadb.zip
CMake-0dfe395e3cb1a720c4853087db554a6827feaadb.tar.gz
CMake-0dfe395e3cb1a720c4853087db554a6827feaadb.tar.bz2
Features: Add COMPILE_FEATURES generator expression.
Allow setting build properties based on the features available for a target. The availability of features is determined at generate-time by evaluating the link implementation. Ensure that the <LANG>_STANDARD determined while evaluating COMPILE_FEATURES in the link implementation is not lower than that provided by the INTERFACE of the link implementation. This is similar to handling of transitive properties such as POSITION_INDEPENDENT_CODE.
Diffstat (limited to 'Source')
-rw-r--r--Source/cmGeneratorExpression.cxx17
-rw-r--r--Source/cmGeneratorExpression.h5
-rw-r--r--Source/cmGeneratorExpressionEvaluator.cxx89
-rw-r--r--Source/cmGeneratorExpressionEvaluator.h2
-rw-r--r--Source/cmLocalGenerator.cxx25
-rw-r--r--Source/cmMakefile.cxx22
-rw-r--r--Source/cmMakefile.h4
-rw-r--r--Source/cmTarget.cxx1
-rw-r--r--Source/cmTarget.h7
9 files changed, 172 insertions, 0 deletions
diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx
index d09e950..d53bdd7 100644
--- a/Source/cmGeneratorExpression.cxx
+++ b/Source/cmGeneratorExpression.cxx
@@ -110,6 +110,9 @@ const char *cmCompiledGeneratorExpression::Evaluate(
break;
}
}
+
+ this->MaxLanguageStandard = context.MaxLanguageStandard;
+
if (!context.HadError)
{
this->HadContextSensitiveCondition = context.HadContextSensitiveCondition;
@@ -465,3 +468,17 @@ bool cmGeneratorExpression::IsValidTargetName(const std::string &input)
return targetNameValidator.find(input.c_str());
}
+
+//----------------------------------------------------------------------------
+void
+cmCompiledGeneratorExpression::GetMaxLanguageStandard(cmTarget const* tgt,
+ std::map<std::string, std::string>& mapping)
+{
+ typedef std::map<cmTarget const*,
+ std::map<std::string, std::string> > MapType;
+ MapType::const_iterator it = this->MaxLanguageStandard.find(tgt);
+ if (it != this->MaxLanguageStandard.end())
+ {
+ mapping = it->second;
+ }
+}
diff --git a/Source/cmGeneratorExpression.h b/Source/cmGeneratorExpression.h
index da64515..ef5360e 100644
--- a/Source/cmGeneratorExpression.h
+++ b/Source/cmGeneratorExpression.h
@@ -117,6 +117,9 @@ public:
this->EvaluateForBuildsystem = eval;
}
+ void GetMaxLanguageStandard(cmTarget const* tgt,
+ std::map<std::string, std::string>& mapping);
+
private:
cmCompiledGeneratorExpression(cmListFileBacktrace const& backtrace,
const std::string& input);
@@ -134,6 +137,8 @@ private:
mutable std::set<cmTarget*> DependTargets;
mutable std::set<cmTarget const*> AllTargetsSeen;
mutable std::set<std::string> SeenTargetProperties;
+ mutable std::map<cmTarget const*, std::map<std::string, std::string> >
+ MaxLanguageStandard;
mutable std::string Output;
mutable bool HadContextSensitiveCondition;
bool EvaluateForBuildsystem;
diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx
index a513921..0b357f6 100644
--- a/Source/cmGeneratorExpressionEvaluator.cxx
+++ b/Source/cmGeneratorExpressionEvaluator.cxx
@@ -1314,6 +1314,94 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode
} targetObjectsNode;
//----------------------------------------------------------------------------
+static const struct CompileFeaturesNode : public cmGeneratorExpressionNode
+{
+ CompileFeaturesNode() {}
+
+ virtual int NumExpectedParameters() const { return OneOrMoreParameters; }
+
+ std::string Evaluate(const std::vector<std::string> &parameters,
+ cmGeneratorExpressionContext *context,
+ const GeneratorExpressionContent *content,
+ cmGeneratorExpressionDAGChecker *dagChecker) const
+ {
+ cmTarget const* target = context->HeadTarget;
+ if (!target)
+ {
+ reportError(context, content->GetOriginalExpression(),
+ "$<COMPILE_FEATURE> may only be used with binary targets. It may "
+ "not be used with add_custom_command or add_custom_target.");
+ return std::string();
+ }
+
+ typedef std::map<std::string, std::vector<std::string> > LangMap;
+ static LangMap availableFeatures;
+
+ LangMap testedFeatures;
+
+ for (std::vector<std::string>::const_iterator it = parameters.begin();
+ it != parameters.end(); ++it)
+ {
+ std::string error;
+ std::string lang;
+ if (!context->Makefile->CompileFeatureKnown(context->HeadTarget,
+ *it, lang, &error))
+ {
+ reportError(context, content->GetOriginalExpression(), error);
+ return std::string();
+ }
+ testedFeatures[lang].push_back(*it);
+
+ if (availableFeatures.find(lang) == availableFeatures.end())
+ {
+ const char* featuresKnown
+ = context->Makefile->CompileFeaturesAvailable(lang, &error);
+ if (!featuresKnown)
+ {
+ reportError(context, content->GetOriginalExpression(), error);
+ return std::string();
+ }
+ cmSystemTools::ExpandListArgument(featuresKnown,
+ availableFeatures[lang]);
+ }
+ }
+
+ bool evalLL = dagChecker && dagChecker->EvaluatingLinkLibraries();
+
+ std::string result;
+
+ for (LangMap::const_iterator lit = testedFeatures.begin();
+ lit != testedFeatures.end(); ++lit)
+ {
+ for (std::vector<std::string>::const_iterator it = lit->second.begin();
+ it != lit->second.end(); ++it)
+ {
+ if (!context->Makefile->HaveFeatureAvailable(target,
+ lit->first, *it))
+ {
+ if (evalLL)
+ {
+ const char* l = target->GetProperty(lit->first + "_STANDARD");
+ if (!l)
+ {
+ l = context->Makefile
+ ->GetDefinition("CMAKE_" + lit->first + "_STANDARD_DEFAULT");
+ }
+ assert(l);
+ context->MaxLanguageStandard[target][lit->first] = l;
+ }
+ else
+ {
+ return "0";
+ }
+ }
+ }
+ }
+ return "1";
+ }
+} compileFeaturesNode;
+
+//----------------------------------------------------------------------------
static const char* targetPolicyWhitelist[] = {
0
#define TARGET_POLICY_STRING(POLICY) \
@@ -1647,6 +1735,7 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier)
nodeMap["C_COMPILER_VERSION"] = &cCompilerVersionNode;
nodeMap["CXX_COMPILER_VERSION"] = &cxxCompilerVersionNode;
nodeMap["PLATFORM_ID"] = &platformIdNode;
+ nodeMap["COMPILE_FEATURES"] = &compileFeaturesNode;
nodeMap["CONFIGURATION"] = &configurationNode;
nodeMap["CONFIG"] = &configurationTestNode;
nodeMap["TARGET_FILE"] = &targetFileNode;
diff --git a/Source/cmGeneratorExpressionEvaluator.h b/Source/cmGeneratorExpressionEvaluator.h
index 54a2548..eb76d7f 100644
--- a/Source/cmGeneratorExpressionEvaluator.h
+++ b/Source/cmGeneratorExpressionEvaluator.h
@@ -26,6 +26,8 @@ struct cmGeneratorExpressionContext
std::set<cmTarget*> DependTargets;
std::set<cmTarget const*> AllTargets;
std::set<std::string> SeenTargetProperties;
+ std::map<cmTarget const*, std::map<std::string, std::string> >
+ MaxLanguageStandard;
cmMakefile *Makefile;
std::string Config;
cmTarget const* HeadTarget; // The target whose property is being evaluated.
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index a6ad714..5d58265 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -1484,6 +1484,31 @@ void cmLocalGenerator::AddCompileOptions(
return;
}
}
+
+ for(std::map<std::string, std::string>::const_iterator it
+ = target->GetMaxLanguageStandards().begin();
+ it != target->GetMaxLanguageStandards().end(); ++it)
+ {
+ const char* standard = target->GetProperty(it->first + "_STANDARD");
+ if(!standard)
+ {
+ continue;
+ }
+ if (this->Makefile->IsLaterStandard(it->first, standard, it->second))
+ {
+ cmOStringStream e;
+ e << "The COMPILE_FEATURES property of target \""
+ << target->GetName() << "\" was evaluated when computing the link "
+ "implementation, and the \"" << it->first << "_STANDARD\" was \""
+ << it->second << "\" for that computation. Computing the "
+ "COMPILE_FEATURES based on the link implementation resulted in a "
+ "higher \"" << it->first << "_STANDARD\" \"" << standard << "\". "
+ "This is not permitted. The COMPILE_FEATURES may not both depend on "
+ "and be depended on by the link implementation." << std::endl;
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return;
+ }
+ }
this->AddCompilerRequirementFlag(flags, target, lang);
}
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 9d7b3c6..9f33b92 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -5187,6 +5187,28 @@ HaveCFeatureAvailable(cmTarget const* target, const std::string& feature) const
}
//----------------------------------------------------------------------------
+bool cmMakefile::IsLaterStandard(std::string const& lang,
+ std::string const& lhs,
+ std::string const& rhs)
+{
+ if (lang == "C")
+ {
+ const char * const *rhsIt = std::find_if(cmArrayBegin(C_STANDARDS),
+ cmArrayEnd(C_STANDARDS),
+ cmStrCmp(rhs));
+
+ return std::find_if(rhsIt, cmArrayEnd(C_STANDARDS),
+ cmStrCmp(lhs)) != cmArrayEnd(C_STANDARDS);
+ }
+ const char * const *rhsIt = std::find_if(cmArrayBegin(CXX_STANDARDS),
+ cmArrayEnd(CXX_STANDARDS),
+ cmStrCmp(rhs));
+
+ return std::find_if(rhsIt, cmArrayEnd(CXX_STANDARDS),
+ cmStrCmp(lhs)) != cmArrayEnd(CXX_STANDARDS);
+}
+
+//----------------------------------------------------------------------------
bool cmMakefile::HaveCxxFeatureAvailable(cmTarget const* target,
const std::string& feature) const
{
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index b2c3c4d..11904a6 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -898,6 +898,10 @@ public:
bool HaveFeatureAvailable(cmTarget const* target, std::string const& lang,
const std::string& feature) const;
+ bool IsLaterStandard(std::string const& lang,
+ std::string const& lhs,
+ std::string const& rhs);
+
void ClearMatches();
void StoreMatches(cmsys::RegularExpression& re);
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 86842a4..63db20f 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -1229,6 +1229,7 @@ void cmTarget::GetDirectLinkLibraries(const std::string& config,
this->LinkImplicitNullProperties.insert(*it);
}
}
+ cge->GetMaxLanguageStandard(this, this->MaxLanguageStandards);
}
}
diff --git a/Source/cmTarget.h b/Source/cmTarget.h
index bee6b34..45d1bd6 100644
--- a/Source/cmTarget.h
+++ b/Source/cmTarget.h
@@ -587,6 +587,12 @@ public:
const std::string &report,
const std::string &compatibilityType) const;
+ std::map<std::string, std::string> const&
+ GetMaxLanguageStandards() const
+ {
+ return this->MaxLanguageStandards;
+ }
+
private:
bool HandleLocationPropertyPolicy(cmMakefile* context) const;
@@ -718,6 +724,7 @@ private:
mutable bool DebugSourcesDone;
mutable bool DebugCompileFeaturesDone;
mutable std::set<std::string> LinkImplicitNullProperties;
+ mutable std::map<std::string, std::string> MaxLanguageStandards;
bool BuildInterfaceIncludesAppended;
// Cache target output paths for each configuration.