Kaynağa Gözat

Add the $<TARGET_POLICY> expression

This new expression allows checking how a policy was set when a target
was created.  That information is only recorded for a subset of policies,
so a whitelist is used.
Stephen Kelly 13 yıl önce
ebeveyn
işleme
6c8d8afe34

+ 4 - 0
Source/cmDocumentGeneratorExpressions.h

@@ -50,6 +50,10 @@
   "  $<TARGET_PROPERTY:tgt,prop>   = The value of the property prop\n"  \
   "on the target tgt. Note that tgt is not added as a dependency of\n"  \
   "the target this expression is evaluated on.\n"                       \
+  "  $<TARGET_POLICY:pol>          = '1' if the policy was NEW when "   \
+  "the 'head' target was created, 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.\n"         \
   "Boolean expressions:\n"                                              \
   "  $<AND:?[,?]...>           = '1' if all '?' are '1', else '0'\n"    \
   "  $<OR:?[,?]...>            = '0' if all '?' are '0', else '1'\n"    \

+ 98 - 0
Source/cmGeneratorExpressionEvaluator.cxx

@@ -487,6 +487,102 @@ static const struct TargetNameNode : public cmGeneratorExpressionNode
 
 } targetNameNode;
 
+//----------------------------------------------------------------------------
+static const char* targetPolicyWhitelist[] = {
+    "CMP0003"
+  , "CMP0004"
+  , "CMP0008"
+};
+
+cmPolicies::PolicyStatus statusForTarget(cmTarget *tgt, const char *policy)
+{
+#define RETURN_POLICY(POLICY) \
+  if (strcmp(policy, #POLICY) == 0) \
+  { \
+    return tgt->GetPolicyStatus ## POLICY (); \
+  } \
+
+  RETURN_POLICY(CMP0003)
+  RETURN_POLICY(CMP0004)
+  RETURN_POLICY(CMP0008)
+
+#undef RETURN_POLICY
+
+  assert("!Unreachable code. Not a valid policy");
+  return cmPolicies::WARN;
+}
+
+cmPolicies::PolicyID policyForString(const char *policy_id)
+{
+#define RETURN_POLICY_ID(POLICY_ID) \
+  if (strcmp(policy_id, #POLICY_ID) == 0) \
+  { \
+    return cmPolicies:: POLICY_ID; \
+  } \
+
+  RETURN_POLICY_ID(CMP0003)
+  RETURN_POLICY_ID(CMP0004)
+  RETURN_POLICY_ID(CMP0008)
+
+#undef RETURN_POLICY_ID
+
+  assert("!Unreachable code. Not a valid policy");
+  return cmPolicies::CMP0002;
+}
+
+//----------------------------------------------------------------------------
+static const struct TargetPolicyNode : public cmGeneratorExpressionNode
+{
+  TargetPolicyNode() {}
+
+  virtual int NumExpectedParameters() const { return 1; }
+
+  std::string Evaluate(const std::vector<std::string> &parameters,
+                       cmGeneratorExpressionContext *context ,
+                       const GeneratorExpressionContent *content,
+                       cmGeneratorExpressionDAGChecker *) const
+  {
+    if (!context->HeadTarget)
+      {
+      reportError(context, content->GetOriginalExpression(),
+          "$<TARGET_POLICY:prop> may only be used with targets.  It may not "
+          "be used with add_custom_command.");
+      return std::string();
+      }
+    for (size_t i = 0;
+         i < (sizeof(targetPolicyWhitelist) /
+              sizeof(*targetPolicyWhitelist));
+         ++i)
+      {
+      const char *policy = targetPolicyWhitelist[i];
+      if (parameters.front() == policy)
+        {
+        cmMakefile *mf = context->HeadTarget->GetMakefile();
+        switch(statusForTarget(context->HeadTarget, policy))
+          {
+          case cmPolicies::WARN:
+            mf->IssueMessage(cmake::AUTHOR_WARNING,
+                             mf->GetPolicies()->
+                             GetPolicyWarning(policyForString(policy)));
+          case cmPolicies::REQUIRED_IF_USED:
+          case cmPolicies::REQUIRED_ALWAYS:
+          case cmPolicies::OLD:
+            return "0";
+          case cmPolicies::NEW:
+            return "1";
+          }
+        }
+      }
+    reportError(context, content->GetOriginalExpression(),
+      "$<TARGET_POLICY:prop> may only be used with a limited number of "
+      "policies.  Currently it may be used with policies CMP0003, CMP0004 "
+      "and CMP0008."
+      );
+    return std::string();
+  }
+
+} targetPolicyNode;
+
 //----------------------------------------------------------------------------
 template<bool linker, bool soname>
 struct TargetFilesystemArtifactResultCreator
@@ -714,6 +810,8 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier)
     return &targetPropertyNode;
   else if (identifier == "TARGET_NAME")
     return &targetNameNode;
+  else if (identifier == "TARGET_POLICY")
+    return &targetPolicyNode;
   else if (identifier == "BUILD_INTERFACE")
     return &buildInterfaceNode;
   else if (identifier == "INSTALL_INTERFACE")

+ 1 - 0
Tests/RunCMake/CMP0004/CMP0004-NEW-result.txt

@@ -0,0 +1 @@
+1

+ 2 - 0
Tests/RunCMake/CMP0004/CMP0004-NEW-stderr.txt

@@ -0,0 +1,2 @@
+  Target "foo" links to item " bar " which has leading or trailing
+  whitespace.  This is now an error according to policy CMP0004.

+ 9 - 0
Tests/RunCMake/CMP0004/CMP0004-NEW.cmake

@@ -0,0 +1,9 @@
+
+cmake_minimum_required(VERSION 2.8)
+
+cmake_policy(SET CMP0004 NEW)
+
+add_library(foo SHARED empty.cpp)
+add_library(bar SHARED empty.cpp)
+
+target_link_libraries(foo "$<1: bar >")

+ 1 - 0
Tests/RunCMake/CMP0004/CMP0004-OLD-result.txt

@@ -0,0 +1 @@
+1

+ 2 - 0
Tests/RunCMake/CMP0004/CMP0004-OLD-stderr.txt

@@ -0,0 +1,2 @@
+  Target "bat" links to item " bar " which has leading or trailing
+  whitespace.  This is now an error according to policy CMP0004.

+ 21 - 0
Tests/RunCMake/CMP0004/CMP0004-OLD.cmake

@@ -0,0 +1,21 @@
+
+cmake_minimum_required(VERSION 2.8)
+
+cmake_policy(SET CMP0004 OLD)
+
+add_library(foo SHARED empty.cpp)
+add_library(bar SHARED empty.cpp)
+add_library(bing SHARED empty.cpp)
+add_library(bung SHARED empty.cpp)
+
+cmake_policy(SET CMP0004 NEW)
+
+add_library(bat SHARED empty.cpp)
+
+target_link_libraries(foo "$<1: bar >")
+target_link_libraries(bing "$<$<NOT:$<TARGET_POLICY:CMP0004>>: bar >")
+target_link_libraries(bung "$<$<TARGET_POLICY:CMP0004>: bar >")
+
+# The line below causes the error because the policy is NEW when bat
+# is created.
+target_link_libraries(bat "$<1: bar >")

+ 0 - 0
Tests/RunCMake/CMP0004/CMP0004-WARN-stderr.txt


+ 1 - 0
Tests/RunCMake/CMP0004/CMP0004-policy-genex-result.txt

@@ -0,0 +1 @@
+1

+ 2 - 0
Tests/RunCMake/CMP0004/CMP0004-policy-genex-stderr.txt

@@ -0,0 +1,2 @@
+  Target "foo" links to item " bat " which has leading or trailing
+  whitespace.  This is now an error according to policy CMP0004.

+ 14 - 0
Tests/RunCMake/CMP0004/CMP0004-policy-genex.cmake

@@ -0,0 +1,14 @@
+
+cmake_minimum_required(VERSION 2.8)
+
+cmake_policy(SET CMP0004 NEW)
+
+add_library(foo SHARED empty.cpp)
+add_library(bar SHARED empty.cpp)
+add_library(bat SHARED empty.cpp)
+
+# The negation here avoids the error.
+target_link_libraries(foo "$<$<NOT:$<TARGET_POLICY:CMP0004>>: bar >")
+
+# The below line causes the error.
+target_link_libraries(foo "$<$<TARGET_POLICY:CMP0004>: bat >")

+ 3 - 0
Tests/RunCMake/CMP0004/CMakeLists.txt

@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)

+ 5 - 0
Tests/RunCMake/CMP0004/RunCMakeTest.cmake

@@ -0,0 +1,5 @@
+include(RunCMake)
+
+run_cmake(CMP0004-OLD)
+run_cmake(CMP0004-NEW)
+run_cmake(CMP0004-policy-genex)

+ 0 - 0
Tests/RunCMake/CMP0004/empty.cpp


+ 1 - 0
Tests/RunCMake/CMakeLists.txt

@@ -59,6 +59,7 @@ add_RunCMake_test(find_package)
 add_RunCMake_test(include)
 add_RunCMake_test(include_directories)
 add_RunCMake_test(list)
+add_RunCMake_test(CMP0004)
 
 if("${CMAKE_TEST_GENERATOR}" MATCHES "Visual Studio [^6]")
   add_RunCMake_test(include_external_msproject)