[Cmake-commits] CMake branch, next, updated. v3.0.0-rc5-3289-gcd27123

Stephen Kelly steveire at gmail.com
Wed May 21 11:22:51 EDT 2014


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "CMake".

The branch, next has been updated
       via  cd27123d257999660aac9269887af2d7a3482022 (commit)
       via  0dfe395e3cb1a720c4853087db554a6827feaadb (commit)
      from  d1cfc53414307c7c8988a1bee606326f63c17325 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=cd27123d257999660aac9269887af2d7a3482022
commit cd27123d257999660aac9269887af2d7a3482022
Merge: d1cfc53 0dfe395
Author:     Stephen Kelly <steveire at gmail.com>
AuthorDate: Wed May 21 11:22:50 2014 -0400
Commit:     CMake Topic Stage <kwrobot at kitware.com>
CommitDate: Wed May 21 11:22:50 2014 -0400

    Merge topic 'COMPILE_FEATURES-genex' into next
    
    0dfe395e Features: Add COMPILE_FEATURES generator expression.


http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=0dfe395e3cb1a720c4853087db554a6827feaadb
commit 0dfe395e3cb1a720c4853087db554a6827feaadb
Author:     Stephen Kelly <steveire at gmail.com>
AuthorDate: Thu May 15 11:32:30 2014 +0200
Commit:     Stephen Kelly <steveire at gmail.com>
CommitDate: Wed May 21 17:22:32 2014 +0200

    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.

diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst
index dfda8dc..9184580 100644
--- a/Help/manual/cmake-generator-expressions.7.rst
+++ b/Help/manual/cmake-generator-expressions.7.rst
@@ -83,6 +83,12 @@ otherwise expands to nothing.
   else ``0``.  If the policy was not set, the warning message for the policy
   will be emitted. This generator expression only works for a subset of
   policies.
+``$<COMPILE_FEATURES:feature[,feature]...>``
+  ``1`` if all of the ``feature`` features are available for the 'head'
+  target, and ``0`` otherwise. If this expression is used while evaluating
+  the link implementation of a target and if any dependency transitively
+  increases the required :prop_tgt:`C_STANDARD` or :prop_tgt:`CXX_STANDARD`
+  for the 'head' target, an error is reported.
 
 Informational Expressions
 =========================
diff --git a/Help/release/dev/compile-language-features.rst b/Help/release/dev/compile-language-features.rst
index fe72e39..d10e22b 100644
--- a/Help/release/dev/compile-language-features.rst
+++ b/Help/release/dev/compile-language-features.rst
@@ -22,3 +22,7 @@ target-language-features
 * New :command:`target_compile_features` command allows populating the
   :prop_tgt:`COMPILE_FEATURES` target property, just like any other
   build variable.
+
+* New ``COMPILE_FEATURES``
+  :manual:`generator expression <cmake-generator-expressions(7)>` allows
+  setting build properties based on available compiler features.
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.
diff --git a/Tests/CompileFeatures/CMakeLists.txt b/Tests/CompileFeatures/CMakeLists.txt
index 0e1e6c9..7a8a975 100644
--- a/Tests/CompileFeatures/CMakeLists.txt
+++ b/Tests/CompileFeatures/CMakeLists.txt
@@ -83,3 +83,17 @@ set_property(TARGET iface
 )
 add_executable(IfaceCompileFeatures main.cpp)
 target_link_libraries(IfaceCompileFeatures iface)
+
+add_executable(CompileFeaturesGenex genex_test.cpp)
+set_property(TARGET CompileFeaturesGenex PROPERTY CXX_STANDARD 11)
+target_compile_definitions(CompileFeaturesGenex PRIVATE HAVE_OVERRIDE_CONTROL=$<COMPILE_FEATURES:cxx_final,cxx_override>)
+
+add_executable(CompileFeaturesGenex2 genex_test.cpp)
+target_compile_features(CompileFeaturesGenex2 PRIVATE cxx_constexpr)
+target_compile_definitions(CompileFeaturesGenex2 PRIVATE HAVE_OVERRIDE_CONTROL=$<COMPILE_FEATURES:cxx_final,cxx_override>)
+
+add_library(noexcept_iface INTERFACE)
+target_compile_features(noexcept_iface INTERFACE cxx_noexcept)
+add_executable(CompileFeaturesGenex3 genex_test.cpp)
+target_link_libraries(CompileFeaturesGenex3 PRIVATE noexcept_iface)
+target_compile_definitions(CompileFeaturesGenex3 PRIVATE HAVE_OVERRIDE_CONTROL=$<COMPILE_FEATURES:cxx_final,cxx_override>)
diff --git a/Tests/CompileFeatures/genex_test.cpp b/Tests/CompileFeatures/genex_test.cpp
new file mode 100644
index 0000000..ca38883
--- /dev/null
+++ b/Tests/CompileFeatures/genex_test.cpp
@@ -0,0 +1,21 @@
+
+#if !HAVE_OVERRIDE_CONTROL
+#error "Expect override control feature"
+#else
+
+struct A
+{
+  virtual int getA() { return 7; }
+};
+
+struct B final : A
+{
+  int getA() override { return 42; }
+};
+
+#endif
+
+int main()
+{
+
+}
diff --git a/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycle-result.txt b/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycle-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycle-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycle-stderr.txt b/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycle-stderr.txt
new file mode 100644
index 0000000..a584d7d
--- /dev/null
+++ b/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycle-stderr.txt
@@ -0,0 +1,7 @@
+CMake Error in CMakeLists.txt:
+  The COMPILE_FEATURES property of target "empty1" was evaluated when
+  computing the link implementation, and the "CXX_STANDARD" was "98" for that
+  computation.  Computing the COMPILE_FEATURES based on the link
+  implementation resulted in a higher "CXX_STANDARD" "11".  This is not
+  permitted.  The COMPILE_FEATURES may not both depend on and be depended on
+  by the link implementation.
diff --git a/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycle.cmake b/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycle.cmake
new file mode 100644
index 0000000..9d56bc0
--- /dev/null
+++ b/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycle.cmake
@@ -0,0 +1,15 @@
+
+add_library(empty1 empty.cpp)
+
+add_library(empty2 INTERFACE)
+add_library(empty3 INTERFACE)
+target_compile_features(empty3 INTERFACE cxx_constexpr)
+
+target_link_libraries(empty1
+  # When starting, $<COMPILE_FEATURES:cxx_final> is '0', so 'freeze' the
+  # CXX_STANDARD at 98 during computation.
+  $<$<COMPILE_FEATURES:cxx_final>:empty2>
+  # This would add cxx_constexpr, but that would require CXX_STANDARD = 11,
+  # which is not allowed after freeze.  Report an error.
+  empty3
+)
diff --git a/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycleSolved-result.txt b/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycleSolved-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycleSolved-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycleSolved-stderr.txt b/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycleSolved-stderr.txt
new file mode 100644
index 0000000..10f3293
--- /dev/null
+++ b/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycleSolved-stderr.txt
@@ -0,0 +1 @@
+^$
diff --git a/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycleSolved.cmake b/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycleSolved.cmake
new file mode 100644
index 0000000..0df548b
--- /dev/null
+++ b/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycleSolved.cmake
@@ -0,0 +1,14 @@
+
+add_library(empty1 empty.cpp)
+
+add_library(empty2 INTERFACE)
+add_library(empty3 INTERFACE)
+target_compile_features(empty3 INTERFACE cxx_constexpr)
+
+target_link_libraries(empty1
+  $<$<COMPILE_FEATURES:cxx_final>:empty2>
+  empty3
+)
+# This, or populating the COMPILE_FEATURES property with a feature in the
+# same standard as cxx_final, solves the cycle above.
+set_property(TARGET empty1 PROPERTY CXX_STANDARD 11)
diff --git a/Tests/RunCMake/CompileFeatures/NonValidTarget1-result.txt b/Tests/RunCMake/CompileFeatures/NonValidTarget1-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CompileFeatures/NonValidTarget1-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CompileFeatures/NonValidTarget1-stderr.txt b/Tests/RunCMake/CompileFeatures/NonValidTarget1-stderr.txt
new file mode 100644
index 0000000..7f3b43b
--- /dev/null
+++ b/Tests/RunCMake/CompileFeatures/NonValidTarget1-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget1.cmake:[0-9]+ \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<COMPILE_FEATURES:cxx_final>
+
+  \$<COMPILE_FEATURE> may only be used with binary targets.  It may not be
+  used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/CompileFeatures/NonValidTarget1.cmake b/Tests/RunCMake/CompileFeatures/NonValidTarget1.cmake
new file mode 100644
index 0000000..c6707c1
--- /dev/null
+++ b/Tests/RunCMake/CompileFeatures/NonValidTarget1.cmake
@@ -0,0 +1,17 @@
+
+set(genexvar $<COMPILE_FEATURES:cxx_final>)
+
+if (HAVE_FINAL)
+  set(expected_result 1)
+else()
+  set(expected_result 0)
+endif()
+
+add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/copied_file${HAVE_FINAL}.cpp"
+  COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/empty.cpp" "${CMAKE_CURRENT_BINARY_DIR}/copied_file${genexvar}.cpp"
+)
+
+add_library(empty "${CMAKE_CURRENT_BINARY_DIR}/copied_file${genexvar}.cpp")
+if (HAVE_FINAL)
+  target_compile_features(empty PRIVATE cxx_final)
+endif()
diff --git a/Tests/RunCMake/CompileFeatures/NonValidTarget2-result.txt b/Tests/RunCMake/CompileFeatures/NonValidTarget2-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CompileFeatures/NonValidTarget2-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CompileFeatures/NonValidTarget2-stderr.txt b/Tests/RunCMake/CompileFeatures/NonValidTarget2-stderr.txt
new file mode 100644
index 0000000..635150c
--- /dev/null
+++ b/Tests/RunCMake/CompileFeatures/NonValidTarget2-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget2.cmake:4 \(add_custom_target\):
+  Error evaluating generator expression:
+
+    \$<COMPILE_FEATURES:cxx_final>
+
+  \$<COMPILE_FEATURE> may only be used with binary targets.  It may not be
+  used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/CompileFeatures/NonValidTarget2.cmake b/Tests/RunCMake/CompileFeatures/NonValidTarget2.cmake
new file mode 100644
index 0000000..eb84692
--- /dev/null
+++ b/Tests/RunCMake/CompileFeatures/NonValidTarget2.cmake
@@ -0,0 +1,8 @@
+
+set(genexvar $<COMPILE_FEATURES:cxx_final>)
+
+add_custom_target(copy_target
+  COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/empty.cpp" "${CMAKE_CURRENT_BINARY_DIR}/copied_file${genexvar}.txt"
+)
+
+add_library(empty "${CMAKE_CURRENT_BINARY_DIR}/copied_file${genexvar}.cpp")
diff --git a/Tests/RunCMake/CompileFeatures/RunCMakeTest.cmake b/Tests/RunCMake/CompileFeatures/RunCMakeTest.cmake
index a23d44f..1892a5c 100644
--- a/Tests/RunCMake/CompileFeatures/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CompileFeatures/RunCMakeTest.cmake
@@ -26,6 +26,16 @@ endif()
 if (NOT CXX_FEATURES)
   run_cmake(NoSupportedCxxFeatures)
   run_cmake(NoSupportedCxxFeaturesGenex)
+else()
+  run_cmake(LinkImplementationFeatureCycle)
+  run_cmake(LinkImplementationFeatureCycleSolved)
+
+  if (";${CXX_FEATURES};" MATCHES ";cxx_final;")
+    set(RunCMake_TEST_OPTIONS "-DHAVE_FINAL=1")
+  endif()
+  run_cmake(NonValidTarget1)
+  run_cmake(NonValidTarget2)
+  unset(RunCMake_TEST_OPTIONS)
 endif()
 
 foreach(standard 98 11)

-----------------------------------------------------------------------

Summary of changes:


hooks/post-receive
-- 
CMake


More information about the Cmake-commits mailing list