cmTarget: Add COMPILE_FEATURES target property.
Use the contents of it to upgrade the CXX_STANDARD target property, if appropriate. This will have the effect of adding the -std=c++11 compile flag or other language specification on GNU when that is needed for the feature.
This commit is contained in:
parent
faeddf64f2
commit
03355d6b5b
|
@ -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
|
||||
|
|
|
@ -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.
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue