From 5412deded1073e9a217c771ae24e8c5a8a581a96 Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Tue, 22 Oct 2013 01:40:47 +0200 Subject: 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. --- Help/manual/cmake-properties.7.rst | 1 + Help/prop_tgt/INTERFACE_COMPILE_FEATURES.rst | 14 +++ Help/variable/CMAKE_DEBUG_TARGET_PROPERTIES.rst | 2 +- Source/cmGeneratorExpressionDAGChecker.h | 3 +- Source/cmLocalGenerator.cxx | 2 +- Source/cmTarget.cxx | 121 +++++++++++++++++++-- Source/cmTarget.h | 4 +- Tests/CompileFeatures/CMakeLists.txt | 7 ++ .../NotAFeatureTransitive-result.txt | 1 + .../NotAFeatureTransitive-stderr.txt | 2 + .../CompileFeatures/NotAFeatureTransitive.cmake | 6 + .../NotAFeature_OriginDebug-result.txt | 1 + .../NotAFeature_OriginDebug-stderr.txt | 11 ++ .../CompileFeatures/NotAFeature_OriginDebug.cmake | 4 + .../NotAFeature_OriginDebugGenex-result.txt | 1 + .../NotAFeature_OriginDebugGenex-stderr.txt | 11 ++ .../NotAFeature_OriginDebugGenex.cmake | 4 + .../NotAFeature_OriginDebugTransitive-result.txt | 1 + .../NotAFeature_OriginDebugTransitive-stderr.txt | 11 ++ .../NotAFeature_OriginDebugTransitive.cmake | 6 + Tests/RunCMake/CompileFeatures/RunCMakeTest.cmake | 4 + 21 files changed, 203 insertions(+), 14 deletions(-) create mode 100644 Help/prop_tgt/INTERFACE_COMPILE_FEATURES.rst create mode 100644 Tests/RunCMake/CompileFeatures/NotAFeatureTransitive-result.txt create mode 100644 Tests/RunCMake/CompileFeatures/NotAFeatureTransitive-stderr.txt create mode 100644 Tests/RunCMake/CompileFeatures/NotAFeatureTransitive.cmake create mode 100644 Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebug-result.txt create mode 100644 Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebug-stderr.txt create mode 100644 Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebug.cmake create mode 100644 Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugGenex-result.txt create mode 100644 Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugGenex-stderr.txt create mode 100644 Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugGenex.cmake create mode 100644 Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugTransitive-result.txt create mode 100644 Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugTransitive-stderr.txt create mode 100644 Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugTransitive.cmake diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index 30413ae..a82522d 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -151,6 +151,7 @@ Properties on Targets /prop_tgt/INSTALL_RPATH_USE_LINK_PATH /prop_tgt/INTERFACE_AUTOUIC_OPTIONS /prop_tgt/INTERFACE_COMPILE_DEFINITIONS + /prop_tgt/INTERFACE_COMPILE_FEATURES /prop_tgt/INTERFACE_COMPILE_OPTIONS /prop_tgt/INTERFACE_INCLUDE_DIRECTORIES /prop_tgt/INTERFACE_LINK_LIBRARIES diff --git a/Help/prop_tgt/INTERFACE_COMPILE_FEATURES.rst b/Help/prop_tgt/INTERFACE_COMPILE_FEATURES.rst new file mode 100644 index 0000000..a98e362 --- /dev/null +++ b/Help/prop_tgt/INTERFACE_COMPILE_FEATURES.rst @@ -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 ``$`` +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. diff --git a/Help/variable/CMAKE_DEBUG_TARGET_PROPERTIES.rst b/Help/variable/CMAKE_DEBUG_TARGET_PROPERTIES.rst index edd8fa1..e200b86 100644 --- a/Help/variable/CMAKE_DEBUG_TARGET_PROPERTIES.rst +++ b/Help/variable/CMAKE_DEBUG_TARGET_PROPERTIES.rst @@ -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 only be used when evaluating the :prop_tgt:`INCLUDE_DIRECTORIES`, :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 listed in :prop_tgt:`COMPATIBLE_INTERFACE_STRING` and other ``COMPATIBLE_INTERFACE_`` properties. It outputs an origin for each entry in the target property. diff --git a/Source/cmGeneratorExpressionDAGChecker.h b/Source/cmGeneratorExpressionDAGChecker.h index b3147f7..7217a56 100644 --- a/Source/cmGeneratorExpressionDAGChecker.h +++ b/Source/cmGeneratorExpressionDAGChecker.h @@ -26,7 +26,8 @@ SELECT(F, EvaluatingCompileDefinitions, COMPILE_DEFINITIONS) \ SELECT(F, EvaluatingCompileOptions, COMPILE_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) \ CM_FOR_EACH_TRANSITIVE_PROPERTY_IMPL(F, CM_SELECT_BOTH) diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index f581806..528b1dc 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -1460,7 +1460,7 @@ void cmLocalGenerator::AddCompileOptions( } } std::vector features; - target->GetCompileFeatures(features); + target->GetCompileFeatures(features, config); for(std::vector::const_iterator it = features.begin(); it != features.end(); ++it) { diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 09e3339..1d4d84c 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -166,11 +166,14 @@ public: CachedLinkInterfaceCompileDefinitionsEntries; mutable std::map > CachedLinkInterfaceSourcesEntries; + mutable std::map > + CachedLinkInterfaceCompileFeaturesEntries; mutable std::map CacheLinkInterfaceIncludeDirectoriesDone; mutable std::map CacheLinkInterfaceCompileDefinitionsDone; mutable std::map CacheLinkInterfaceCompileOptionsDone; mutable std::map CacheLinkInterfaceSourcesDone; + mutable std::map CacheLinkInterfaceCompileFeaturesDone; }; //---------------------------------------------------------------------------- @@ -205,6 +208,7 @@ cmTargetInternals::~cmTargetInternals() { deleteAndClear(this->CachedLinkInterfaceIncludeDirectoriesEntries); deleteAndClear(this->CachedLinkInterfaceCompileOptionsEntries); + deleteAndClear(this->CachedLinkInterfaceCompileFeaturesEntries); deleteAndClear(this->CachedLinkInterfaceCompileDefinitionsEntries); deleteAndClear(this->CachedLinkInterfaceSourcesEntries); } @@ -228,6 +232,7 @@ cmTarget::cmTarget() this->BuildInterfaceIncludesAppended = false; this->DebugIncludesDone = false; this->DebugCompileOptionsDone = false; + this->DebugCompileFeaturesDone = false; this->DebugCompileDefinitionsDone = false; this->DebugSourcesDone = false; } @@ -2617,18 +2622,114 @@ void cmTarget::GetCompileDefinitions(std::vector &list, } //---------------------------------------------------------------------------- -void cmTarget::GetCompileFeatures(std::vector &features) const +static void processCompileFeatures(cmTarget const* tgt, + const std::vector &entries, + std::vector &options, + std::set &uniqueOptions, + cmGeneratorExpressionDAGChecker *dagChecker, + const std::string& config, bool debugOptions) { - assert(this->GetType() != INTERFACE_LIBRARY); - for(std::vector::const_iterator - si = this->Internal->CompileFeaturesEntries.begin(); - si != this->Internal->CompileFeaturesEntries.end(); ++si) + processCompileOptionsInternal(tgt, entries, options, uniqueOptions, + dagChecker, config, debugOptions, "features"); +} + +//---------------------------------------------------------------------------- +void cmTarget::GetCompileFeatures(std::vector &result, + const std::string& config) const +{ + std::set uniqueFeatures; + cmListFileBacktrace lfbt; + + cmGeneratorExpressionDAGChecker dagChecker(lfbt, + this->GetName(), + "COMPILE_FEATURES", + 0, 0); + + std::vector debugProperties; + const char *debugProp = + this->Makefile->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES"); + if (debugProp) { - cmSystemTools::ExpandListArgument((*si)->ge->Evaluate(this->Makefile, - "", - false, - this), - features); + cmSystemTools::ExpandListArgument(debugProp, debugProperties); + } + + bool debugFeatures = !this->DebugCompileFeaturesDone + && 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::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 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 = "$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 = "$<$Value + ">:" + featureGenex + ">"; + } + cmGeneratorExpression ge(it->Backtrace); + cmsys::auto_ptr 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; } } diff --git a/Source/cmTarget.h b/Source/cmTarget.h index fe3ea2b..8984649 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -545,7 +545,8 @@ public: const std::string& config) const; void GetAutoUicOptions(std::vector &result, const std::string& config) const; - void GetCompileFeatures(std::vector &features) const; + void GetCompileFeatures(std::vector &features, + const std::string& config) const; bool IsNullImpliedByLinkLibraries(const std::string &p) const; bool IsLinkInterfaceDependentBoolProperty(const std::string &p, @@ -712,6 +713,7 @@ private: mutable bool DebugCompileOptionsDone; mutable bool DebugCompileDefinitionsDone; mutable bool DebugSourcesDone; + mutable bool DebugCompileFeaturesDone; mutable std::set LinkImplicitNullProperties; bool BuildInterfaceIncludesAppended; diff --git a/Tests/CompileFeatures/CMakeLists.txt b/Tests/CompileFeatures/CMakeLists.txt index 2114f94..bceb6bb 100644 --- a/Tests/CompileFeatures/CMakeLists.txt +++ b/Tests/CompileFeatures/CMakeLists.txt @@ -27,3 +27,10 @@ add_executable(GenexCompileFeatures main.cpp) set_property(TARGET GenexCompileFeatures 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) diff --git a/Tests/RunCMake/CompileFeatures/NotAFeatureTransitive-result.txt b/Tests/RunCMake/CompileFeatures/NotAFeatureTransitive-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CompileFeatures/NotAFeatureTransitive-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CompileFeatures/NotAFeatureTransitive-stderr.txt b/Tests/RunCMake/CompileFeatures/NotAFeatureTransitive-stderr.txt new file mode 100644 index 0000000..ff60e50 --- /dev/null +++ b/Tests/RunCMake/CompileFeatures/NotAFeatureTransitive-stderr.txt @@ -0,0 +1,2 @@ +CMake Error in CMakeLists.txt: + Specified unknown feature "not_a_feature" for target "somelib". diff --git a/Tests/RunCMake/CompileFeatures/NotAFeatureTransitive.cmake b/Tests/RunCMake/CompileFeatures/NotAFeatureTransitive.cmake new file mode 100644 index 0000000..7311aec --- /dev/null +++ b/Tests/RunCMake/CompileFeatures/NotAFeatureTransitive.cmake @@ -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) diff --git a/Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebug-result.txt b/Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebug-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebug-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebug-stderr.txt b/Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebug-stderr.txt new file mode 100644 index 0000000..60a8e51 --- /dev/null +++ b/Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebug-stderr.txt @@ -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". diff --git a/Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebug.cmake b/Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebug.cmake new file mode 100644 index 0000000..350c2ea --- /dev/null +++ b/Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebug.cmake @@ -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") diff --git a/Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugGenex-result.txt b/Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugGenex-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugGenex-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugGenex-stderr.txt b/Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugGenex-stderr.txt new file mode 100644 index 0000000..08e20a8 --- /dev/null +++ b/Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugGenex-stderr.txt @@ -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". diff --git a/Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugGenex.cmake b/Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugGenex.cmake new file mode 100644 index 0000000..2122981 --- /dev/null +++ b/Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugGenex.cmake @@ -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>") diff --git a/Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugTransitive-result.txt b/Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugTransitive-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugTransitive-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugTransitive-stderr.txt b/Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugTransitive-stderr.txt new file mode 100644 index 0000000..23c3305 --- /dev/null +++ b/Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugTransitive-stderr.txt @@ -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". diff --git a/Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugTransitive.cmake b/Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugTransitive.cmake new file mode 100644 index 0000000..05d0073 --- /dev/null +++ b/Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugTransitive.cmake @@ -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) diff --git a/Tests/RunCMake/CompileFeatures/RunCMakeTest.cmake b/Tests/RunCMake/CompileFeatures/RunCMakeTest.cmake index da9477d..a059900 100644 --- a/Tests/RunCMake/CompileFeatures/RunCMakeTest.cmake +++ b/Tests/RunCMake/CompileFeatures/RunCMakeTest.cmake @@ -2,3 +2,7 @@ include(RunCMake) run_cmake(NotAFeature) run_cmake(NotAFeatureGenex) +run_cmake(NotAFeatureTransitive) +run_cmake(NotAFeature_OriginDebug) +run_cmake(NotAFeature_OriginDebugGenex) +run_cmake(NotAFeature_OriginDebugTransitive) -- cgit v0.12