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.
This commit is contained in:
Stephen Kelly 2013-01-16 16:42:39 +01:00
parent 1800f702a0
commit 6c8d8afe34
16 changed files with 164 additions and 0 deletions

View File

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

View File

@ -487,6 +487,102 @@ static const struct TargetNameNode : public cmGeneratorExpressionNode
} targetNameNode; } 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> template<bool linker, bool soname>
struct TargetFilesystemArtifactResultCreator struct TargetFilesystemArtifactResultCreator
@ -714,6 +810,8 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier)
return &targetPropertyNode; return &targetPropertyNode;
else if (identifier == "TARGET_NAME") else if (identifier == "TARGET_NAME")
return &targetNameNode; return &targetNameNode;
else if (identifier == "TARGET_POLICY")
return &targetPolicyNode;
else if (identifier == "BUILD_INTERFACE") else if (identifier == "BUILD_INTERFACE")
return &buildInterfaceNode; return &buildInterfaceNode;
else if (identifier == "INSTALL_INTERFACE") else if (identifier == "INSTALL_INTERFACE")

View File

@ -0,0 +1 @@
1

View File

@ -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.

View File

@ -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 >")

View File

@ -0,0 +1 @@
1

View File

@ -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.

View File

@ -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 >")

View File

@ -0,0 +1 @@
1

View File

@ -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.

View File

@ -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 >")

View File

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

View File

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

View File

View File

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