cmTarget: Transitively evaluate compiler features.
Extend the interface of the target_compile_features command with PUBLIC and INTERFACE keywords. Populate the INTERFACE_COMPILER_FEATURES target property if they are set. Consume the INTERFACE_COMPILER_FEATURES target property from linked dependent targets to determine the final required compiler features and the compile flag, if needed. Use the same pattern of origin-debugging which is used for other build properties.
This commit is contained in:
parent
baff44345c
commit
5412deded1
@ -151,6 +151,7 @@ Properties on Targets
|
|||||||
/prop_tgt/INSTALL_RPATH_USE_LINK_PATH
|
/prop_tgt/INSTALL_RPATH_USE_LINK_PATH
|
||||||
/prop_tgt/INTERFACE_AUTOUIC_OPTIONS
|
/prop_tgt/INTERFACE_AUTOUIC_OPTIONS
|
||||||
/prop_tgt/INTERFACE_COMPILE_DEFINITIONS
|
/prop_tgt/INTERFACE_COMPILE_DEFINITIONS
|
||||||
|
/prop_tgt/INTERFACE_COMPILE_FEATURES
|
||||||
/prop_tgt/INTERFACE_COMPILE_OPTIONS
|
/prop_tgt/INTERFACE_COMPILE_OPTIONS
|
||||||
/prop_tgt/INTERFACE_INCLUDE_DIRECTORIES
|
/prop_tgt/INTERFACE_INCLUDE_DIRECTORIES
|
||||||
/prop_tgt/INTERFACE_LINK_LIBRARIES
|
/prop_tgt/INTERFACE_LINK_LIBRARIES
|
||||||
|
14
Help/prop_tgt/INTERFACE_COMPILE_FEATURES.rst
Normal file
14
Help/prop_tgt/INTERFACE_COMPILE_FEATURES.rst
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
INTERFACE_COMPILE_FEATURES
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
List of public compile requirements for a library.
|
||||||
|
|
||||||
|
Targets may populate this property to publish the compiler features
|
||||||
|
required to compile against the headers for the target. Consuming
|
||||||
|
targets can add entries to their own :prop_tgt:`COMPILE_FEATURES`
|
||||||
|
property such as ``$<TARGET_PROPERTY:foo,INTERFACE_COMPILE_FEATURES>``
|
||||||
|
to require the features specified in the interface of ``foo``.
|
||||||
|
|
||||||
|
Contents of ``INTERFACE_COMPILE_FEATURES`` may use "generator expressions"
|
||||||
|
with the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
|
||||||
|
manual for available expressions.
|
@ -7,7 +7,7 @@ This variable can be populated with a list of properties to generate
|
|||||||
debug output for when evaluating target properties. Currently it can
|
debug output for when evaluating target properties. Currently it can
|
||||||
only be used when evaluating the :prop_tgt:`INCLUDE_DIRECTORIES`,
|
only be used when evaluating the :prop_tgt:`INCLUDE_DIRECTORIES`,
|
||||||
:prop_tgt:`COMPILE_DEFINITIONS`, :prop_tgt:`COMPILE_OPTIONS`,
|
:prop_tgt:`COMPILE_DEFINITIONS`, :prop_tgt:`COMPILE_OPTIONS`,
|
||||||
:prop_tgt:`AUTOUIC_OPTIONS`, :prop_tgt:`SOURCES`,
|
:prop_tgt:`AUTOUIC_OPTIONS`, :prop_tgt:`SOURCES`, :prop_tgt:`COMPILE_FEATURES`,
|
||||||
:prop_tgt:`POSITION_INDEPENDENT_CODE` target properties and any other property
|
:prop_tgt:`POSITION_INDEPENDENT_CODE` target properties and any other property
|
||||||
listed in :prop_tgt:`COMPATIBLE_INTERFACE_STRING` and other ``COMPATIBLE_INTERFACE_``
|
listed in :prop_tgt:`COMPATIBLE_INTERFACE_STRING` and other ``COMPATIBLE_INTERFACE_``
|
||||||
properties. It outputs an origin for each entry in the target property.
|
properties. It outputs an origin for each entry in the target property.
|
||||||
|
@ -26,7 +26,8 @@
|
|||||||
SELECT(F, EvaluatingCompileDefinitions, COMPILE_DEFINITIONS) \
|
SELECT(F, EvaluatingCompileDefinitions, COMPILE_DEFINITIONS) \
|
||||||
SELECT(F, EvaluatingCompileOptions, COMPILE_OPTIONS) \
|
SELECT(F, EvaluatingCompileOptions, COMPILE_OPTIONS) \
|
||||||
SELECT(F, EvaluatingAutoUicOptions, AUTOUIC_OPTIONS) \
|
SELECT(F, EvaluatingAutoUicOptions, AUTOUIC_OPTIONS) \
|
||||||
SELECT(F, EvaluatingSources, SOURCES)
|
SELECT(F, EvaluatingSources, SOURCES) \
|
||||||
|
SELECT(F, EvaluatingCompileFeatures, COMPILE_FEATURES)
|
||||||
|
|
||||||
#define CM_FOR_EACH_TRANSITIVE_PROPERTY(F) \
|
#define CM_FOR_EACH_TRANSITIVE_PROPERTY(F) \
|
||||||
CM_FOR_EACH_TRANSITIVE_PROPERTY_IMPL(F, CM_SELECT_BOTH)
|
CM_FOR_EACH_TRANSITIVE_PROPERTY_IMPL(F, CM_SELECT_BOTH)
|
||||||
|
@ -1460,7 +1460,7 @@ void cmLocalGenerator::AddCompileOptions(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::vector<std::string> features;
|
std::vector<std::string> features;
|
||||||
target->GetCompileFeatures(features);
|
target->GetCompileFeatures(features, config);
|
||||||
for(std::vector<std::string>::const_iterator it = features.begin();
|
for(std::vector<std::string>::const_iterator it = features.begin();
|
||||||
it != features.end(); ++it)
|
it != features.end(); ++it)
|
||||||
{
|
{
|
||||||
|
@ -166,11 +166,14 @@ public:
|
|||||||
CachedLinkInterfaceCompileDefinitionsEntries;
|
CachedLinkInterfaceCompileDefinitionsEntries;
|
||||||
mutable std::map<std::string, std::vector<TargetPropertyEntry*> >
|
mutable std::map<std::string, std::vector<TargetPropertyEntry*> >
|
||||||
CachedLinkInterfaceSourcesEntries;
|
CachedLinkInterfaceSourcesEntries;
|
||||||
|
mutable std::map<std::string, std::vector<TargetPropertyEntry*> >
|
||||||
|
CachedLinkInterfaceCompileFeaturesEntries;
|
||||||
|
|
||||||
mutable std::map<std::string, bool> CacheLinkInterfaceIncludeDirectoriesDone;
|
mutable std::map<std::string, bool> CacheLinkInterfaceIncludeDirectoriesDone;
|
||||||
mutable std::map<std::string, bool> CacheLinkInterfaceCompileDefinitionsDone;
|
mutable std::map<std::string, bool> CacheLinkInterfaceCompileDefinitionsDone;
|
||||||
mutable std::map<std::string, bool> CacheLinkInterfaceCompileOptionsDone;
|
mutable std::map<std::string, bool> CacheLinkInterfaceCompileOptionsDone;
|
||||||
mutable std::map<std::string, bool> CacheLinkInterfaceSourcesDone;
|
mutable std::map<std::string, bool> CacheLinkInterfaceSourcesDone;
|
||||||
|
mutable std::map<std::string, bool> CacheLinkInterfaceCompileFeaturesDone;
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@ -205,6 +208,7 @@ cmTargetInternals::~cmTargetInternals()
|
|||||||
{
|
{
|
||||||
deleteAndClear(this->CachedLinkInterfaceIncludeDirectoriesEntries);
|
deleteAndClear(this->CachedLinkInterfaceIncludeDirectoriesEntries);
|
||||||
deleteAndClear(this->CachedLinkInterfaceCompileOptionsEntries);
|
deleteAndClear(this->CachedLinkInterfaceCompileOptionsEntries);
|
||||||
|
deleteAndClear(this->CachedLinkInterfaceCompileFeaturesEntries);
|
||||||
deleteAndClear(this->CachedLinkInterfaceCompileDefinitionsEntries);
|
deleteAndClear(this->CachedLinkInterfaceCompileDefinitionsEntries);
|
||||||
deleteAndClear(this->CachedLinkInterfaceSourcesEntries);
|
deleteAndClear(this->CachedLinkInterfaceSourcesEntries);
|
||||||
}
|
}
|
||||||
@ -228,6 +232,7 @@ cmTarget::cmTarget()
|
|||||||
this->BuildInterfaceIncludesAppended = false;
|
this->BuildInterfaceIncludesAppended = false;
|
||||||
this->DebugIncludesDone = false;
|
this->DebugIncludesDone = false;
|
||||||
this->DebugCompileOptionsDone = false;
|
this->DebugCompileOptionsDone = false;
|
||||||
|
this->DebugCompileFeaturesDone = false;
|
||||||
this->DebugCompileDefinitionsDone = false;
|
this->DebugCompileDefinitionsDone = false;
|
||||||
this->DebugSourcesDone = false;
|
this->DebugSourcesDone = false;
|
||||||
}
|
}
|
||||||
@ -2617,18 +2622,114 @@ void cmTarget::GetCompileDefinitions(std::vector<std::string> &list,
|
|||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void cmTarget::GetCompileFeatures(std::vector<std::string> &features) const
|
static void processCompileFeatures(cmTarget const* tgt,
|
||||||
|
const std::vector<cmTargetInternals::TargetPropertyEntry*> &entries,
|
||||||
|
std::vector<std::string> &options,
|
||||||
|
std::set<std::string> &uniqueOptions,
|
||||||
|
cmGeneratorExpressionDAGChecker *dagChecker,
|
||||||
|
const std::string& config, bool debugOptions)
|
||||||
{
|
{
|
||||||
assert(this->GetType() != INTERFACE_LIBRARY);
|
processCompileOptionsInternal(tgt, entries, options, uniqueOptions,
|
||||||
for(std::vector<cmTargetInternals::TargetPropertyEntry*>::const_iterator
|
dagChecker, config, debugOptions, "features");
|
||||||
si = this->Internal->CompileFeaturesEntries.begin();
|
}
|
||||||
si != this->Internal->CompileFeaturesEntries.end(); ++si)
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void cmTarget::GetCompileFeatures(std::vector<std::string> &result,
|
||||||
|
const std::string& config) const
|
||||||
|
{
|
||||||
|
std::set<std::string> uniqueFeatures;
|
||||||
|
cmListFileBacktrace lfbt;
|
||||||
|
|
||||||
|
cmGeneratorExpressionDAGChecker dagChecker(lfbt,
|
||||||
|
this->GetName(),
|
||||||
|
"COMPILE_FEATURES",
|
||||||
|
0, 0);
|
||||||
|
|
||||||
|
std::vector<std::string> debugProperties;
|
||||||
|
const char *debugProp =
|
||||||
|
this->Makefile->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES");
|
||||||
|
if (debugProp)
|
||||||
{
|
{
|
||||||
cmSystemTools::ExpandListArgument((*si)->ge->Evaluate(this->Makefile,
|
cmSystemTools::ExpandListArgument(debugProp, debugProperties);
|
||||||
"",
|
}
|
||||||
false,
|
|
||||||
this),
|
bool debugFeatures = !this->DebugCompileFeaturesDone
|
||||||
features);
|
&& std::find(debugProperties.begin(),
|
||||||
|
debugProperties.end(),
|
||||||
|
"COMPILE_FEATURES")
|
||||||
|
!= debugProperties.end();
|
||||||
|
|
||||||
|
if (this->Makefile->IsGeneratingBuildSystem())
|
||||||
|
{
|
||||||
|
this->DebugCompileFeaturesDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
processCompileFeatures(this,
|
||||||
|
this->Internal->CompileFeaturesEntries,
|
||||||
|
result,
|
||||||
|
uniqueFeatures,
|
||||||
|
&dagChecker,
|
||||||
|
config,
|
||||||
|
debugFeatures);
|
||||||
|
|
||||||
|
if (!this->Internal->CacheLinkInterfaceCompileFeaturesDone[config])
|
||||||
|
{
|
||||||
|
for (std::vector<cmValueWithOrigin>::const_iterator
|
||||||
|
it = this->Internal->LinkImplementationPropertyEntries.begin(),
|
||||||
|
end = this->Internal->LinkImplementationPropertyEntries.end();
|
||||||
|
it != end; ++it)
|
||||||
|
{
|
||||||
|
if (!cmGeneratorExpression::IsValidTargetName(it->Value)
|
||||||
|
&& cmGeneratorExpression::Find(it->Value) == std::string::npos)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
cmGeneratorExpression ge(lfbt);
|
||||||
|
cmsys::auto_ptr<cmCompiledGeneratorExpression> cge =
|
||||||
|
ge.Parse(it->Value);
|
||||||
|
std::string targetResult = cge->Evaluate(this->Makefile, config,
|
||||||
|
false, this, 0, 0);
|
||||||
|
if (!this->Makefile->FindTargetToUse(targetResult))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::string featureGenex = "$<TARGET_PROPERTY:" +
|
||||||
|
it->Value + ",INTERFACE_COMPILE_FEATURES>";
|
||||||
|
if (cmGeneratorExpression::Find(it->Value) != std::string::npos)
|
||||||
|
{
|
||||||
|
// Because it->Value is a generator expression, ensure that it
|
||||||
|
// evaluates to the non-empty string before being used in the
|
||||||
|
// TARGET_PROPERTY expression.
|
||||||
|
featureGenex = "$<$<BOOL:" + it->Value + ">:" + featureGenex + ">";
|
||||||
|
}
|
||||||
|
cmGeneratorExpression ge(it->Backtrace);
|
||||||
|
cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(
|
||||||
|
featureGenex);
|
||||||
|
|
||||||
|
this->Internal
|
||||||
|
->CachedLinkInterfaceCompileFeaturesEntries[config].push_back(
|
||||||
|
new cmTargetInternals::TargetPropertyEntry(cge,
|
||||||
|
it->Value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
processCompileFeatures(this,
|
||||||
|
this->Internal->CachedLinkInterfaceCompileFeaturesEntries[config],
|
||||||
|
result,
|
||||||
|
uniqueFeatures,
|
||||||
|
&dagChecker,
|
||||||
|
config,
|
||||||
|
debugFeatures);
|
||||||
|
|
||||||
|
if (!this->Makefile->IsGeneratingBuildSystem())
|
||||||
|
{
|
||||||
|
deleteAndClear(this->Internal->CachedLinkInterfaceCompileFeaturesEntries);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->Internal->CacheLinkInterfaceCompileFeaturesDone[config] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -545,7 +545,8 @@ public:
|
|||||||
const std::string& config) const;
|
const std::string& config) const;
|
||||||
void GetAutoUicOptions(std::vector<std::string> &result,
|
void GetAutoUicOptions(std::vector<std::string> &result,
|
||||||
const std::string& config) const;
|
const std::string& config) const;
|
||||||
void GetCompileFeatures(std::vector<std::string> &features) const;
|
void GetCompileFeatures(std::vector<std::string> &features,
|
||||||
|
const std::string& config) const;
|
||||||
|
|
||||||
bool IsNullImpliedByLinkLibraries(const std::string &p) const;
|
bool IsNullImpliedByLinkLibraries(const std::string &p) const;
|
||||||
bool IsLinkInterfaceDependentBoolProperty(const std::string &p,
|
bool IsLinkInterfaceDependentBoolProperty(const std::string &p,
|
||||||
@ -712,6 +713,7 @@ private:
|
|||||||
mutable bool DebugCompileOptionsDone;
|
mutable bool DebugCompileOptionsDone;
|
||||||
mutable bool DebugCompileDefinitionsDone;
|
mutable bool DebugCompileDefinitionsDone;
|
||||||
mutable bool DebugSourcesDone;
|
mutable bool DebugSourcesDone;
|
||||||
|
mutable bool DebugCompileFeaturesDone;
|
||||||
mutable std::set<std::string> LinkImplicitNullProperties;
|
mutable std::set<std::string> LinkImplicitNullProperties;
|
||||||
bool BuildInterfaceIncludesAppended;
|
bool BuildInterfaceIncludesAppended;
|
||||||
|
|
||||||
|
@ -27,3 +27,10 @@ add_executable(GenexCompileFeatures main.cpp)
|
|||||||
set_property(TARGET GenexCompileFeatures
|
set_property(TARGET GenexCompileFeatures
|
||||||
PROPERTY COMPILE_FEATURES "$<1:cxx_auto_type>;$<0:not_a_feature>"
|
PROPERTY COMPILE_FEATURES "$<1:cxx_auto_type>;$<0:not_a_feature>"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_library(iface INTERFACE)
|
||||||
|
set_property(TARGET iface
|
||||||
|
PROPERTY INTERFACE_COMPILE_FEATURES "cxx_auto_type"
|
||||||
|
)
|
||||||
|
add_executable(IfaceCompileFeatures main.cpp)
|
||||||
|
target_link_libraries(IfaceCompileFeatures iface)
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
1
|
@ -0,0 +1,2 @@
|
|||||||
|
CMake Error in CMakeLists.txt:
|
||||||
|
Specified unknown feature "not_a_feature" for target "somelib".
|
@ -0,0 +1,6 @@
|
|||||||
|
|
||||||
|
add_library(iface INTERFACE)
|
||||||
|
set_property(TARGET iface PROPERTY INTERFACE_COMPILE_FEATURES "not_a_feature")
|
||||||
|
|
||||||
|
add_library(somelib STATIC empty.cpp)
|
||||||
|
target_link_libraries(somelib iface)
|
@ -0,0 +1 @@
|
|||||||
|
1
|
@ -0,0 +1,11 @@
|
|||||||
|
CMake Debug Log at NotAFeature_OriginDebug.cmake:4 \(set_property\):
|
||||||
|
Used compile features for target somelib:
|
||||||
|
|
||||||
|
\* not_a_feature
|
||||||
|
|
||||||
|
Call Stack \(most recent call first\):
|
||||||
|
CMakeLists.txt:3 \(include\)
|
||||||
|
|
||||||
|
|
||||||
|
CMake Error in CMakeLists.txt:
|
||||||
|
Specified unknown feature "not_a_feature" for target "somelib".
|
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
set(CMAKE_DEBUG_TARGET_PROPERTIES COMPILE_FEATURES)
|
||||||
|
add_library(somelib STATIC empty.cpp)
|
||||||
|
set_property(TARGET somelib PROPERTY COMPILE_FEATURES "not_a_feature")
|
@ -0,0 +1 @@
|
|||||||
|
1
|
@ -0,0 +1,11 @@
|
|||||||
|
CMake Debug Log at NotAFeature_OriginDebugGenex.cmake:4 \(set_property\):
|
||||||
|
Used compile features for target somelib:
|
||||||
|
|
||||||
|
\* not_a_feature
|
||||||
|
|
||||||
|
Call Stack \(most recent call first\):
|
||||||
|
CMakeLists.txt:3 \(include\)
|
||||||
|
|
||||||
|
|
||||||
|
CMake Error in CMakeLists.txt:
|
||||||
|
Specified unknown feature "not_a_feature" for target "somelib".
|
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
set(CMAKE_DEBUG_TARGET_PROPERTIES COMPILE_FEATURES)
|
||||||
|
add_library(somelib STATIC empty.cpp)
|
||||||
|
set_property(TARGET somelib PROPERTY COMPILE_FEATURES "$<1:not_a_feature>")
|
@ -0,0 +1 @@
|
|||||||
|
1
|
@ -0,0 +1,11 @@
|
|||||||
|
CMake Debug Log at NotAFeature_OriginDebugTransitive.cmake:6 \(target_link_libraries\):
|
||||||
|
Used compile features for target somelib:
|
||||||
|
|
||||||
|
\* not_a_feature
|
||||||
|
|
||||||
|
Call Stack \(most recent call first\):
|
||||||
|
CMakeLists.txt:3 \(include\)
|
||||||
|
|
||||||
|
|
||||||
|
CMake Error in CMakeLists.txt:
|
||||||
|
Specified unknown feature "not_a_feature" for target "somelib".
|
@ -0,0 +1,6 @@
|
|||||||
|
|
||||||
|
set(CMAKE_DEBUG_TARGET_PROPERTIES COMPILE_FEATURES)
|
||||||
|
add_library(iface INTERFACE)
|
||||||
|
set_property(TARGET iface PROPERTY INTERFACE_COMPILE_FEATURES "not_a_feature")
|
||||||
|
add_library(somelib STATIC empty.cpp)
|
||||||
|
target_link_libraries(somelib iface)
|
@ -2,3 +2,7 @@ include(RunCMake)
|
|||||||
|
|
||||||
run_cmake(NotAFeature)
|
run_cmake(NotAFeature)
|
||||||
run_cmake(NotAFeatureGenex)
|
run_cmake(NotAFeatureGenex)
|
||||||
|
run_cmake(NotAFeatureTransitive)
|
||||||
|
run_cmake(NotAFeature_OriginDebug)
|
||||||
|
run_cmake(NotAFeature_OriginDebugGenex)
|
||||||
|
run_cmake(NotAFeature_OriginDebugTransitive)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user