[Cmake-commits] CMake branch, next, updated. v3.0.0-rc5-3234-gfe7e36a

Stephen Kelly steveire at gmail.com
Tue May 20 10:30:14 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  fe7e36a8b3e98a1d0575f4e27952d50783ada53d (commit)
       via  bb1c0b63f20db47cd151c9fe483402dbbb798bbb (commit)
       via  9939cb53edbaca8476a23a7b8e9eb50b251f58ca (commit)
       via  b6dedf034e33dfafcb804c01691a080701ee680a (commit)
       via  8dd129dfbb8f8aeefa333a0bfa5f44d835b6913e (commit)
       via  6b9b2fff61777b7d18f6c550119103dd3357d6c4 (commit)
      from  8519fd6ab067c0853f99f7f63ba76c56469503df (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=fe7e36a8b3e98a1d0575f4e27952d50783ada53d
commit fe7e36a8b3e98a1d0575f4e27952d50783ada53d
Merge: 8519fd6 bb1c0b6
Author:     Stephen Kelly <steveire at gmail.com>
AuthorDate: Tue May 20 10:30:12 2014 -0400
Commit:     CMake Topic Stage <kwrobot at kitware.com>
CommitDate: Tue May 20 10:30:12 2014 -0400

    Merge topic 'COMPILE_FEATURES-genex' into next
    
    bb1c0b63 Features: Add COMPILE_FEATURES generator expression.
    9939cb53 cmMakefile: Add methods for checking availability of a feature.
    b6dedf03 cmMakefile: Extract CheckNeeded{C,Cxx}Language methods.
    8dd129df cmMakefile: Extract CompileFeaturesAvailable method.
    6b9b2fff cmMakefile: Extract CompileFeatureKnown method.


http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=bb1c0b63f20db47cd151c9fe483402dbbb798bbb
commit bb1c0b63f20db47cd151c9fe483402dbbb798bbb
Author:     Stephen Kelly <steveire at gmail.com>
AuthorDate: Thu May 15 11:32:30 2014 +0200
Commit:     Stephen Kelly <steveire at gmail.com>
CommitDate: Tue May 20 16:28:52 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 73e68b6..c86af67 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/CMakeLists.txt b/Tests/CMakeLists.txt
index 5014ef3..912aa8d 100644
--- a/Tests/CMakeLists.txt
+++ b/Tests/CMakeLists.txt
@@ -198,6 +198,7 @@ if(BUILD_TESTING)
   ADD_TEST_MACRO(SystemInformation SystemInformation)
   ADD_TEST_MACRO(MathTest MathTest)
   ADD_TEST_MACRO(CompileFeatures CompileFeatures)
+  ADD_TEST_MACRO(CompileFeaturesGenex CompileFeaturesGenex)
   ADD_TEST_MACRO(CMakeCommands.target_compile_features target_compile_features)
 
   # assume no resources building to test
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/RunCMakeTest.cmake b/Tests/RunCMake/CompileFeatures/RunCMakeTest.cmake
index a23d44f..8ae51be 100644
--- a/Tests/RunCMake/CompileFeatures/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CompileFeatures/RunCMakeTest.cmake
@@ -26,6 +26,9 @@ endif()
 if (NOT CXX_FEATURES)
   run_cmake(NoSupportedCxxFeatures)
   run_cmake(NoSupportedCxxFeaturesGenex)
+else()
+  run_cmake(LinkImplementationFeatureCycle)
+  run_cmake(LinkImplementationFeatureCycleSolved)
 endif()
 
 foreach(standard 98 11)

http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=9939cb53edbaca8476a23a7b8e9eb50b251f58ca
commit 9939cb53edbaca8476a23a7b8e9eb50b251f58ca
Author:     Stephen Kelly <steveire at gmail.com>
AuthorDate: Thu May 15 11:54:24 2014 +0200
Commit:     Stephen Kelly <steveire at gmail.com>
CommitDate: Tue May 20 16:11:35 2014 +0200

    cmMakefile: Add methods for checking availability of a feature.

diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 7bcbeb8..73e68b6 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -5121,6 +5121,118 @@ CompileFeaturesAvailable(const std::string& lang, std::string *error) const
 }
 
 //----------------------------------------------------------------------------
+bool cmMakefile::HaveFeatureAvailable(cmTarget const* target,
+                                      std::string const& lang,
+                                      const std::string& feature) const
+{
+  return lang == "C"
+      ? this->HaveCFeatureAvailable(target, feature)
+      : this->HaveCxxFeatureAvailable(target, feature);
+}
+
+//----------------------------------------------------------------------------
+bool cmMakefile::
+HaveCFeatureAvailable(cmTarget const* target, const std::string& feature) const
+{
+  bool needC90 = false;
+  bool needC99 = false;
+  bool needC11 = false;
+
+  this->CheckNeededCLanguage(feature, needC90, needC99, needC11);
+
+  const char *existingCStandard = target->GetProperty("C_STANDARD");
+  if (!existingCStandard)
+    {
+    existingCStandard = this->GetDefinition("CMAKE_C_STANDARD_DEFAULT");
+    }
+
+  if (std::find_if(cmArrayBegin(C_STANDARDS), cmArrayEnd(C_STANDARDS),
+                cmStrCmp(existingCStandard)) == cmArrayEnd(C_STANDARDS))
+    {
+    cmOStringStream e;
+    e << "The C_STANDARD property on target \"" << target->GetName()
+      << "\" contained an invalid value: \"" << existingCStandard << "\".";
+    this->IssueMessage(cmake::FATAL_ERROR, e.str().c_str());
+    return false;
+    }
+
+  const char * const *existingCIt = existingCStandard
+                                    ? std::find_if(cmArrayBegin(C_STANDARDS),
+                                      cmArrayEnd(C_STANDARDS),
+                                      cmStrCmp(existingCStandard))
+                                    : cmArrayEnd(C_STANDARDS);
+
+  if (needC11 && existingCStandard && existingCIt <
+                                    std::find_if(cmArrayBegin(C_STANDARDS),
+                                      cmArrayEnd(C_STANDARDS),
+                                      cmStrCmp("11")))
+    {
+    return false;
+    }
+  else if(needC99 && existingCStandard && existingCIt <
+                                    std::find_if(cmArrayBegin(C_STANDARDS),
+                                      cmArrayEnd(C_STANDARDS),
+                                      cmStrCmp("99")))
+    {
+    return false;
+    }
+  else if(needC90 && existingCStandard && existingCIt <
+                                    std::find_if(cmArrayBegin(C_STANDARDS),
+                                      cmArrayEnd(C_STANDARDS),
+                                      cmStrCmp("90")))
+    {
+    return false;
+    }
+  return true;
+}
+
+//----------------------------------------------------------------------------
+bool cmMakefile::
+HaveCxxFeatureAvailable(cmTarget const* target, const std::string& feature) const
+{
+  bool needCxx98 = false;
+  bool needCxx11 = false;
+  this->CheckNeededCxxLanguage(feature, needCxx98, needCxx11);
+
+  const char *existingCxxStandard = target->GetProperty("CXX_STANDARD");
+  if (!existingCxxStandard)
+    {
+    existingCxxStandard = this->GetDefinition("CMAKE_CXX_STANDARD_DEFAULT");
+    }
+
+  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);
+
+  if (needCxx11 && existingCxxIt < std::find_if(cmArrayBegin(CXX_STANDARDS),
+                                      cmArrayEnd(CXX_STANDARDS),
+                                      cmStrCmp("11")))
+    {
+    return false;
+    }
+  else if(needCxx98 && existingCxxIt <
+                                    std::find_if(cmArrayBegin(CXX_STANDARDS),
+                                      cmArrayEnd(CXX_STANDARDS),
+                                      cmStrCmp("98")))
+    {
+    return false;
+    }
+  return true;
+}
+
+//----------------------------------------------------------------------------
 void cmMakefile::CheckNeededCxxLanguage(const std::string& feature,
                                         bool& needCxx98,
                                         bool& needCxx11) const
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index 40e44a5..b2c3c4d 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -895,6 +895,9 @@ public:
   const char* CompileFeaturesAvailable(const std::string& lang,
                                        std::string *error) const;
 
+  bool HaveFeatureAvailable(cmTarget const* target, std::string const& lang,
+                            const std::string& feature) const;
+
   void ClearMatches();
   void StoreMatches(cmsys::RegularExpression& re);
 
@@ -1115,6 +1118,11 @@ private:
                             bool& needC99, bool& needC11) const;
   void CheckNeededCxxLanguage(const std::string& feature, bool& needCxx98,
                               bool& needCxx11) const;
+
+  bool HaveCFeatureAvailable(cmTarget const* target,
+                             const std::string& feature) const;
+  bool HaveCxxFeatureAvailable(cmTarget const* target,
+                               const std::string& feature) const;
 };
 
 //----------------------------------------------------------------------------

http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=b6dedf034e33dfafcb804c01691a080701ee680a
commit b6dedf034e33dfafcb804c01691a080701ee680a
Author:     Stephen Kelly <steveire at gmail.com>
AuthorDate: Thu May 15 11:49:02 2014 +0200
Commit:     Stephen Kelly <steveire at gmail.com>
CommitDate: Tue May 20 16:11:35 2014 +0200

    cmMakefile: Extract CheckNeeded{C,Cxx}Language methods.

diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 4317fbe..7bcbeb8 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -5121,13 +5121,10 @@ CompileFeaturesAvailable(const std::string& lang, std::string *error) const
 }
 
 //----------------------------------------------------------------------------
-bool cmMakefile::
-AddRequiredTargetCxxFeature(cmTarget *target,
-                            const std::string& feature) const
+void cmMakefile::CheckNeededCxxLanguage(const std::string& feature,
+                                        bool& needCxx98,
+                                        bool& needCxx11) const
 {
-  bool needCxx98 = false;
-  bool needCxx11 = false;
-
   if (const char *propCxx98 =
           this->GetDefinition("CMAKE_CXX98_COMPILE_FEATURES"))
     {
@@ -5142,6 +5139,17 @@ AddRequiredTargetCxxFeature(cmTarget *target,
     cmSystemTools::ExpandListArgument(propCxx11, props);
     needCxx11 = std::find(props.begin(), props.end(), feature) != props.end();
     }
+}
+
+//----------------------------------------------------------------------------
+bool cmMakefile::
+AddRequiredTargetCxxFeature(cmTarget *target,
+                            const std::string& feature) const
+{
+  bool needCxx98 = false;
+  bool needCxx11 = false;
+
+  this->CheckNeededCxxLanguage(feature, needCxx98, needCxx11);
 
   const char *existingCxxStandard = target->GetProperty("CXX_STANDARD");
   if (existingCxxStandard)
@@ -5192,13 +5200,11 @@ AddRequiredTargetCxxFeature(cmTarget *target,
 }
 
 //----------------------------------------------------------------------------
-bool cmMakefile::
-AddRequiredTargetCFeature(cmTarget *target, const std::string& feature) const
+void cmMakefile::CheckNeededCLanguage(const std::string& feature,
+                                        bool& needC90,
+                                        bool& needC99,
+                                        bool& needC11) const
 {
-  bool needC90 = false;
-  bool needC99 = false;
-  bool needC11 = false;
-
   if (const char *propC90 =
           this->GetDefinition("CMAKE_C90_COMPILE_FEATURES"))
     {
@@ -5220,6 +5226,17 @@ AddRequiredTargetCFeature(cmTarget *target, const std::string& feature) const
     cmSystemTools::ExpandListArgument(propC11, props);
     needC11 = std::find(props.begin(), props.end(), feature) != props.end();
     }
+}
+
+//----------------------------------------------------------------------------
+bool cmMakefile::
+AddRequiredTargetCFeature(cmTarget *target, const std::string& feature) const
+{
+  bool needC90 = false;
+  bool needC99 = false;
+  bool needC11 = false;
+
+  this->CheckNeededCLanguage(feature, needC90, needC99, needC11);
 
   const char *existingCStandard = target->GetProperty("C_STANDARD");
   if (existingCStandard)
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index be384e6..40e44a5 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -1110,6 +1110,11 @@ private:
 
   bool AddRequiredTargetCxxFeature(cmTarget *target,
                                    const std::string& feature) const;
+
+  void CheckNeededCLanguage(const std::string& feature, bool& needC90,
+                            bool& needC99, bool& needC11) const;
+  void CheckNeededCxxLanguage(const std::string& feature, bool& needCxx98,
+                              bool& needCxx11) const;
 };
 
 //----------------------------------------------------------------------------

http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=8dd129dfbb8f8aeefa333a0bfa5f44d835b6913e
commit 8dd129dfbb8f8aeefa333a0bfa5f44d835b6913e
Author:     Stephen Kelly <steveire at gmail.com>
AuthorDate: Thu May 15 11:33:20 2014 +0200
Commit:     Stephen Kelly <steveire at gmail.com>
CommitDate: Tue May 20 16:11:34 2014 +0200

    cmMakefile: Extract CompileFeaturesAvailable method.

diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 1905489..4317fbe 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -5011,37 +5011,14 @@ AddRequiredTargetFeature(cmTarget *target, const std::string& feature,
     return false;
     }
 
-  const char* featuresKnown =
-    this->GetDefinition("CMAKE_" + lang + "_COMPILE_FEATURES");
-
-  if (!featuresKnown || !*featuresKnown)
+  const char* features = this->CompileFeaturesAvailable(lang, error);
+  if (!features)
     {
-    cmOStringStream e;
-    if (error)
-      {
-      e << "no";
-      }
-    else
-      {
-      e << "No";
-      }
-    e << " known features for " << lang << " compiler\n\""
-      << this->GetDefinition("CMAKE_" + lang + "_COMPILER_ID")
-      << "\"\nversion "
-      << this->GetDefinition("CMAKE_" + lang + "_COMPILER_VERSION") << ".";
-    if (error)
-      {
-      *error = e.str();
-      }
-    else
-      {
-      this->IssueMessage(cmake::FATAL_ERROR, e.str());
-      }
     return false;
     }
 
   std::vector<std::string> availableFeatures;
-  cmSystemTools::ExpandListArgument(featuresKnown, availableFeatures);
+  cmSystemTools::ExpandListArgument(features, availableFeatures);
   if (std::find(availableFeatures.begin(),
                 availableFeatures.end(),
                 feature) == availableFeatures.end())
@@ -5109,6 +5086,41 @@ CompileFeatureKnown(cmTarget const* target, const std::string& feature,
 }
 
 //----------------------------------------------------------------------------
+const char* cmMakefile::
+CompileFeaturesAvailable(const std::string& lang, std::string *error) const
+{
+  const char* featuresKnown =
+    this->GetDefinition("CMAKE_" + lang + "_COMPILE_FEATURES");
+
+  if (!featuresKnown || !*featuresKnown)
+    {
+    cmOStringStream e;
+    if (error)
+      {
+      e << "no";
+      }
+    else
+      {
+      e << "No";
+      }
+    e << " known features for " << lang << " compiler\n\""
+      << this->GetDefinition("CMAKE_" + lang + "_COMPILER_ID")
+      << "\"\nversion "
+      << this->GetDefinition("CMAKE_" + lang + "_COMPILER_VERSION") << ".";
+    if (error)
+      {
+      *error = e.str();
+      }
+    else
+      {
+      this->IssueMessage(cmake::FATAL_ERROR, e.str());
+      }
+    return 0;
+    }
+  return featuresKnown;
+}
+
+//----------------------------------------------------------------------------
 bool cmMakefile::
 AddRequiredTargetCxxFeature(cmTarget *target,
                             const std::string& feature) const
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index 1a7bf20..be384e6 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -892,6 +892,9 @@ public:
   bool CompileFeatureKnown(cmTarget const* target, const std::string& feature,
                            std::string& lang, std::string *error) const;
 
+  const char* CompileFeaturesAvailable(const std::string& lang,
+                                       std::string *error) const;
+
   void ClearMatches();
   void StoreMatches(cmsys::RegularExpression& re);
 

http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=6b9b2fff61777b7d18f6c550119103dd3357d6c4
commit 6b9b2fff61777b7d18f6c550119103dd3357d6c4
Author:     Stephen Kelly <steveire at gmail.com>
AuthorDate: Thu May 15 11:33:20 2014 +0200
Commit:     Stephen Kelly <steveire at gmail.com>
CommitDate: Tue May 20 16:11:34 2014 +0200

    cmMakefile: Extract CompileFeatureKnown method.

diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 42dedc9..1905489 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -5004,38 +5004,13 @@ AddRequiredTargetFeature(cmTarget *target, const std::string& feature,
     target->AppendProperty("COMPILE_FEATURES", feature.c_str());
     return true;
     }
-  bool isCFeature = std::find_if(cmArrayBegin(C_FEATURES) + 1,
-              cmArrayEnd(C_FEATURES), cmStrCmp(feature))
-              != cmArrayEnd(C_FEATURES);
-  bool isCxxFeature = std::find_if(cmArrayBegin(CXX_FEATURES) + 1,
-              cmArrayEnd(CXX_FEATURES), cmStrCmp(feature))
-              != cmArrayEnd(CXX_FEATURES);
-  if (!isCFeature && !isCxxFeature)
+
+  std::string lang;
+  if (!this->CompileFeatureKnown(target, feature, lang, error))
     {
-    cmOStringStream e;
-    if (error)
-      {
-      e << "specified";
-      }
-    else
-      {
-      e << "Specified";
-      }
-    e << " unknown feature \"" << feature << "\" for "
-      "target \"" << target->GetName() << "\".";
-    if (error)
-      {
-      *error = e.str();
-      }
-    else
-      {
-      this->IssueMessage(cmake::FATAL_ERROR, e.str());
-      }
     return false;
     }
 
-  std::string lang = isCFeature ? "C" : "CXX";
-
   const char* featuresKnown =
     this->GetDefinition("CMAKE_" + lang + "_COMPILE_FEATURES");
 
@@ -5083,13 +5058,58 @@ AddRequiredTargetFeature(cmTarget *target, const std::string& feature,
 
   target->AppendProperty("COMPILE_FEATURES", feature.c_str());
 
-  return isCFeature
+  return lang == "C"
       ? this->AddRequiredTargetCFeature(target, feature)
       : this->AddRequiredTargetCxxFeature(target, feature);
 }
 
 //----------------------------------------------------------------------------
 bool cmMakefile::
+CompileFeatureKnown(cmTarget const* target, const std::string& feature,
+                    std::string& lang, std::string *error) const
+{
+  assert(cmGeneratorExpression::Find(feature) == std::string::npos);
+
+  bool isCFeature = std::find_if(cmArrayBegin(C_FEATURES) + 1,
+              cmArrayEnd(C_FEATURES), cmStrCmp(feature))
+              != cmArrayEnd(C_FEATURES);
+  if (isCFeature)
+    {
+    lang = "C";
+    return true;
+    }
+  bool isCxxFeature = std::find_if(cmArrayBegin(CXX_FEATURES) + 1,
+              cmArrayEnd(CXX_FEATURES), cmStrCmp(feature))
+              != cmArrayEnd(CXX_FEATURES);
+  if (isCxxFeature)
+    {
+    lang = "CXX";
+    return true;
+    }
+  cmOStringStream e;
+  if (error)
+    {
+    e << "specified";
+    }
+  else
+    {
+    e << "Specified";
+    }
+  e << " unknown feature \"" << feature << "\" for "
+    "target \"" << target->GetName() << "\".";
+  if (error)
+    {
+    *error = e.str();
+    }
+  else
+    {
+    this->IssueMessage(cmake::FATAL_ERROR, e.str());
+    }
+  return false;
+}
+
+//----------------------------------------------------------------------------
+bool cmMakefile::
 AddRequiredTargetCxxFeature(cmTarget *target,
                             const std::string& feature) const
 {
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index 90e2e19..1a7bf20 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -889,6 +889,9 @@ public:
                                 const std::string& feature,
                                 std::string *error = 0) const;
 
+  bool CompileFeatureKnown(cmTarget const* target, const std::string& feature,
+                           std::string& lang, std::string *error) const;
+
   void ClearMatches();
   void StoreMatches(cmsys::RegularExpression& re);
 

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

Summary of changes:
 Help/manual/cmake-generator-expressions.7.rst      |    6 +
 Help/release/dev/compile-language-features.rst     |    4 +
 Source/cmGeneratorExpression.cxx                   |   17 ++
 Source/cmGeneratorExpression.h                     |    5 +
 Source/cmGeneratorExpressionEvaluator.cxx          |   89 +++++++
 Source/cmGeneratorExpressionEvaluator.h            |    2 +
 Source/cmLocalGenerator.cxx                        |   25 ++
 Source/cmMakefile.cxx                              |  277 ++++++++++++++++----
 Source/cmMakefile.h                                |   23 ++
 Source/cmTarget.cxx                                |    1 +
 Source/cmTarget.h                                  |    7 +
 Tests/CMakeLists.txt                               |    1 +
 Tests/CompileFeatures/CMakeLists.txt               |   14 +
 Tests/CompileFeatures/genex_test.cpp               |   21 ++
 .../LinkImplementationFeatureCycle-result.txt}     |    0
 .../LinkImplementationFeatureCycle-stderr.txt      |    7 +
 .../LinkImplementationFeatureCycle.cmake           |   15 ++
 ...inkImplementationFeatureCycleSolved-result.txt} |    0
 ...inkImplementationFeatureCycleSolved-stderr.txt} |    0
 .../LinkImplementationFeatureCycleSolved.cmake     |   14 +
 Tests/RunCMake/CompileFeatures/RunCMakeTest.cmake  |    3 +
 21 files changed, 484 insertions(+), 47 deletions(-)
 create mode 100644 Tests/CompileFeatures/genex_test.cpp
 copy Tests/RunCMake/{CMP0004/CMP0004-NEW-result.txt => CompileFeatures/LinkImplementationFeatureCycle-result.txt} (100%)
 create mode 100644 Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycle-stderr.txt
 create mode 100644 Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycle.cmake
 copy Tests/RunCMake/{CMP0022/CMP0022-WARN-empty-old-result.txt => CompileFeatures/LinkImplementationFeatureCycleSolved-result.txt} (100%)
 copy Tests/RunCMake/{CMP0022/CMP0022-NOWARN-exe-stderr.txt => CompileFeatures/LinkImplementationFeatureCycleSolved-stderr.txt} (100%)
 create mode 100644 Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycleSolved.cmake


hooks/post-receive
-- 
CMake


More information about the Cmake-commits mailing list