summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Help/manual/cmake-properties.7.rst1
-rw-r--r--Help/prop_tgt/COMPILE_FEATURES.rst7
-rw-r--r--Help/release/dev/compile-language-features.rst6
-rw-r--r--Source/cmLocalGenerator.cxx13
-rw-r--r--Source/cmMakefile.cxx113
-rw-r--r--Source/cmMakefile.h4
-rw-r--r--Source/cmTarget.cxx40
7 files changed, 184 insertions, 0 deletions
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index 9ea50de..30413ae 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -98,6 +98,7 @@ Properties on Targets
/prop_tgt/COMPATIBLE_INTERFACE_STRING
/prop_tgt/COMPILE_DEFINITIONS_CONFIG
/prop_tgt/COMPILE_DEFINITIONS
+ /prop_tgt/COMPILE_FEATURES
/prop_tgt/COMPILE_FLAGS
/prop_tgt/COMPILE_OPTIONS
/prop_tgt/COMPILE_PDB_NAME
diff --git a/Help/prop_tgt/COMPILE_FEATURES.rst b/Help/prop_tgt/COMPILE_FEATURES.rst
new file mode 100644
index 0000000..b2c6145
--- /dev/null
+++ b/Help/prop_tgt/COMPILE_FEATURES.rst
@@ -0,0 +1,7 @@
+COMPILE_FEATURES
+----------------
+
+Compiler features enabled for this target.
+
+The list of features in this property are a subset of the features listed
+in the :variable:`CMAKE_CXX_COMPILE_FEATURES` variable.
diff --git a/Help/release/dev/compile-language-features.rst b/Help/release/dev/compile-language-features.rst
index f03e1a3..74fe209 100644
--- a/Help/release/dev/compile-language-features.rst
+++ b/Help/release/dev/compile-language-features.rst
@@ -6,3 +6,9 @@ target-language-features
compile options such as ``-std=c++11`` or ``-std=gnu++11``. The
:variable:`CMAKE_CXX_STANDARD` and :variable:`CMAKE_CXX_EXTENSIONS`
variables may be set to initialize the target properties.
+
+* New :prop_tgt:`COMPILE_FEATURES` target property may contain a list
+ of features required to compile a target. CMake uses this
+ information to ensure that the compiler in use is capable of building
+ the target, and to add any necessary compile flags to support language
+ features.
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index 779a2b8..0f8e7dc 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -1459,6 +1459,19 @@ void cmLocalGenerator::AddCompileOptions(
this->AppendFlagEscape(flags, *i);
}
}
+ if (const char* featureProp = target->GetProperty("COMPILE_FEATURES"))
+ {
+ std::vector<std::string> features;
+ cmSystemTools::ExpandListArgument(featureProp, features);
+ for(std::vector<std::string>::const_iterator it = features.begin();
+ it != features.end(); ++it)
+ {
+ if (!this->Makefile->AddRequiredTargetFeature(target, *it))
+ {
+ return;
+ }
+ }
+ }
this->AddCompilerRequirementFlag(flags, target, lang);
}
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 1328974..64163de 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -41,6 +41,8 @@
#include <ctype.h> // for isspace
#include <assert.h>
+#define FOR_EACH_CXX_FEATURE(F)
+
class cmMakefile::Internals
{
public:
@@ -4494,3 +4496,114 @@ void cmMakefile::RecordPolicies(cmPolicies::PolicyMap& pm)
pm[pid] = this->GetPolicyStatus(pid);
}
}
+
+#define FEATURE_STRING(F) , #F
+
+static const char * const CXX_FEATURES[] = {
+ 0
+ FOR_EACH_CXX_FEATURE(FEATURE_STRING)
+};
+
+static const char * const CXX_STANDARDS[] = {
+ "98"
+ , "11"
+};
+
+//----------------------------------------------------------------------------
+bool cmMakefile::
+AddRequiredTargetFeature(cmTarget *target, const std::string& feature,
+ std::string *error) const
+{
+ bool isCxxFeature = std::find_if(cmArrayBegin(CXX_FEATURES) + 1,
+ cmArrayEnd(CXX_FEATURES), cmStrCmp(feature))
+ != cmArrayEnd(CXX_FEATURES);
+ if (!isCxxFeature)
+ {
+ cmOStringStream e;
+ e << "specified unknown feature \"" << feature << "\" specified for "
+ "target \"" << target->GetName() << "\".";
+ if (error)
+ {
+ *error = e.str();
+ }
+ else
+ {
+ this->IssueMessage(cmake::FATAL_ERROR, e.str());
+ }
+ return false;
+ }
+
+ std::string lang = "CXX";
+
+ const char* featuresKnown =
+ this->GetDefinition("CMAKE_" + lang + "_COMPILE_FEATURES");
+
+ if (!featuresKnown || !*featuresKnown)
+ {
+ // We know of no features for the compiler at all.
+ return true;
+ }
+
+ std::vector<std::string> availableFeatures;
+ cmSystemTools::ExpandListArgument(featuresKnown, availableFeatures);
+ if (std::find(availableFeatures.begin(),
+ availableFeatures.end(),
+ feature) == availableFeatures.end())
+ {
+ cmOStringStream e;
+ e << "The compiler feature \"" << feature
+ << "\" is not known to compiler\n\""
+ << this->GetDefinition("CMAKE_" + lang + "_COMPILER_ID")
+ << "\"\nversion "
+ << this->GetDefinition("CMAKE_" + lang + "_COMPILER_VERSION") << ".";
+ this->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return false;
+ }
+
+ target->AppendProperty("COMPILE_FEATURES", feature.c_str());
+
+ bool needCxx11 = false;
+
+ if (const char *propCxx11 =
+ this->GetDefinition("CMAKE_CXX11_COMPILE_FEATURES"))
+ {
+ std::vector<std::string> props;
+ cmSystemTools::ExpandListArgument(propCxx11, props);
+ needCxx11 = std::find(props.begin(), props.end(), feature) != props.end();
+ }
+
+ const char *existingCxxStandard = target->GetProperty("CXX_STANDARD");
+ if (existingCxxStandard)
+ {
+ if (std::find_if(cmArrayBegin(CXX_STANDARDS), cmArrayEnd(CXX_STANDARDS),
+ cmStrCmp(existingCxxStandard)) == cmArrayEnd(CXX_STANDARDS))
+ {
+ cmOStringStream e;
+ e << "The CXX_STANDARD property on target \"" << target->GetName()
+ << "\" contained an invalid value: \"" << existingCxxStandard << "\".";
+ this->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return false;
+ }
+ }
+ const char * const *existingCxxIt = existingCxxStandard
+ ? std::find_if(cmArrayBegin(CXX_STANDARDS),
+ cmArrayEnd(CXX_STANDARDS),
+ cmStrCmp(existingCxxStandard))
+ : cmArrayEnd(CXX_STANDARDS);
+
+ bool setCxx11 = needCxx11 && !existingCxxStandard;
+
+ if (needCxx11 && existingCxxStandard && existingCxxIt <
+ std::find_if(cmArrayBegin(CXX_STANDARDS),
+ cmArrayEnd(CXX_STANDARDS),
+ cmStrCmp("11")))
+ {
+ setCxx11 = true;
+ }
+
+ if (setCxx11)
+ {
+ target->SetProperty("CXX_STANDARD", "11");
+ }
+ return true;
+}
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index 7695d6e..3bccb63 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -885,6 +885,10 @@ public:
bool PolicyOptionalWarningEnabled(std::string const& var);
+ bool AddRequiredTargetFeature(cmTarget *target,
+ const std::string& feature,
+ std::string *error = 0) const;
+
protected:
// add link libraries and directories to the target
void AddGlobalLinkInformation(const std::string& name, cmTarget& target);
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 53c0205..6f53009 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -153,6 +153,7 @@ public:
};
std::vector<TargetPropertyEntry*> IncludeDirectoriesEntries;
std::vector<TargetPropertyEntry*> CompileOptionsEntries;
+ std::vector<TargetPropertyEntry*> CompileFeaturesEntries;
std::vector<TargetPropertyEntry*> CompileDefinitionsEntries;
std::vector<TargetPropertyEntry*> SourceEntries;
std::vector<cmValueWithOrigin> LinkImplementationPropertyEntries;
@@ -1722,6 +1723,17 @@ void cmTarget::SetProperty(const std::string& prop, const char* value)
new cmTargetInternals::TargetPropertyEntry(cge));
return;
}
+ if(prop == "COMPILE_FEATURES")
+ {
+ cmListFileBacktrace lfbt;
+ this->Makefile->GetBacktrace(lfbt);
+ cmGeneratorExpression ge(lfbt);
+ deleteAndClear(this->Internal->CompileFeaturesEntries);
+ cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(value);
+ this->Internal->CompileFeaturesEntries.push_back(
+ new cmTargetInternals::TargetPropertyEntry(cge));
+ return;
+ }
if(prop == "COMPILE_DEFINITIONS")
{
cmListFileBacktrace lfbt;
@@ -1812,6 +1824,15 @@ void cmTarget::AppendProperty(const std::string& prop, const char* value,
new cmTargetInternals::TargetPropertyEntry(ge.Parse(value)));
return;
}
+ if(prop == "COMPILE_FEATURES")
+ {
+ cmListFileBacktrace lfbt;
+ this->Makefile->GetBacktrace(lfbt);
+ cmGeneratorExpression ge(lfbt);
+ this->Internal->CompileFeaturesEntries.push_back(
+ new cmTargetInternals::TargetPropertyEntry(ge.Parse(value)));
+ return;
+ }
if(prop == "COMPILE_DEFINITIONS")
{
cmListFileBacktrace lfbt;
@@ -3109,6 +3130,24 @@ const char *cmTarget::GetProperty(const std::string& prop,
}
return output.c_str();
}
+ if(prop == "COMPILE_FEATURES")
+ {
+ static std::string output;
+ output = "";
+ std::string sep;
+ typedef cmTargetInternals::TargetPropertyEntry
+ TargetPropertyEntry;
+ for (std::vector<TargetPropertyEntry*>::const_iterator
+ it = this->Internal->CompileFeaturesEntries.begin(),
+ end = this->Internal->CompileFeaturesEntries.end();
+ it != end; ++it)
+ {
+ output += sep;
+ output += (*it)->ge->GetInput();
+ sep = ";";
+ }
+ return output.c_str();
+ }
if(prop == "COMPILE_DEFINITIONS")
{
static std::string output;
@@ -6886,6 +6925,7 @@ cmTargetInternalPointer::~cmTargetInternalPointer()
{
deleteAndClear(this->Pointer->IncludeDirectoriesEntries);
deleteAndClear(this->Pointer->CompileOptionsEntries);
+ deleteAndClear(this->Pointer->CompileFeaturesEntries);
deleteAndClear(this->Pointer->CompileDefinitionsEntries);
deleteAndClear(this->Pointer->SourceEntries);
delete this->Pointer;