Add $<LINK_LANGUAGE> generator expression

They can't be used when evaluating link libraries, but they can be
used for include directories and compile definitions. Later they can
be used for compile options.
This commit is contained in:
Stephen Kelly 2013-05-16 15:52:25 +02:00 committed by Brad King
parent a7ba4520c7
commit 32410140a7
13 changed files with 200 additions and 8 deletions

View File

@ -74,4 +74,12 @@
"the target on which the generator expression is evaluated.\n" \ "the target on which the generator expression is evaluated.\n" \
"" ""
#define CM_DOCUMENT_LANGUAGE_GENERATOR_EXPRESSIONS \
"Language related expressions:\n" \
" $<LINK_LANGUAGE> = The link language of the target " \
"being generated.\n" \
" $<LINK_LANGUAGE:lang> = '1' if the link language of the " \
"target being generated matches lang, else '0'.\n" \
""
#endif #endif

View File

@ -45,6 +45,11 @@ void reportError(cmGeneratorExpressionContext *context,
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
struct cmGeneratorExpressionNode struct cmGeneratorExpressionNode
{ {
enum {
DynamicParameters = 0,
OneOrMoreParameters = -1,
ZeroOrMoreParameters = -2
};
virtual ~cmGeneratorExpressionNode() {} virtual ~cmGeneratorExpressionNode() {}
virtual bool GeneratesContent() const { return true; } virtual bool GeneratesContent() const { return true; }
@ -110,8 +115,7 @@ static const struct ZeroNode installInterfaceNode;
static const struct OP ## Node : public cmGeneratorExpressionNode \ static const struct OP ## Node : public cmGeneratorExpressionNode \
{ \ { \
OP ## Node () {} \ OP ## Node () {} \
/* We let -1 carry the meaning 'at least one' */ \ virtual int NumExpectedParameters() const { return OneOrMoreParameters; } \
virtual int NumExpectedParameters() const { return -1; } \
\ \
std::string Evaluate(const std::vector<std::string> &parameters, \ std::string Evaluate(const std::vector<std::string> &parameters, \
cmGeneratorExpressionContext *context, \ cmGeneratorExpressionContext *context, \
@ -306,6 +310,60 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
} }
} configurationTestNode; } configurationTestNode;
//----------------------------------------------------------------------------
static const struct LinkLanguageNode : public cmGeneratorExpressionNode
{
LinkLanguageNode() {}
virtual int NumExpectedParameters() const { return ZeroOrMoreParameters; }
std::string Evaluate(const std::vector<std::string> &parameters,
cmGeneratorExpressionContext *context,
const GeneratorExpressionContent *content,
cmGeneratorExpressionDAGChecker *) const
{
if (parameters.size() != 0 && parameters.size() != 1)
{
reportError(context, content->GetOriginalExpression(),
"$<LINK_LANGUAGE> expression requires one or two parameters");
return std::string();
}
cmTarget* target = context->HeadTarget;
if (!target)
{
reportError(context, content->GetOriginalExpression(),
"$<LINK_LANGUAGE> may only be used with targets. It may not "
"be used with add_custom_command.");
}
const char *lang = target->GetLinkerLanguage(context->Config);
if (parameters.size() == 0)
{
return lang ? lang : "";
}
else
{
cmsys::RegularExpression langValidator;
langValidator.compile("^[A-Za-z0-9_]*$");
if (!langValidator.find(parameters.begin()->c_str()))
{
reportError(context, content->GetOriginalExpression(),
"Expression syntax not recognized.");
return std::string();
}
if (!lang)
{
return parameters.front().empty() ? "1" : "0";
}
if (strcmp(parameters.begin()->c_str(), lang) == 0)
{
return "1";
}
return "0";
}
}
} linkLanguageNode;
static const struct JoinNode : public cmGeneratorExpressionNode static const struct JoinNode : public cmGeneratorExpressionNode
{ {
@ -347,7 +405,7 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
TargetPropertyNode() {} TargetPropertyNode() {}
// This node handles errors on parameter count itself. // This node handles errors on parameter count itself.
virtual int NumExpectedParameters() const { return -1; } virtual int NumExpectedParameters() const { return OneOrMoreParameters; }
std::string Evaluate(const std::vector<std::string> &parameters, std::string Evaluate(const std::vector<std::string> &parameters,
cmGeneratorExpressionContext *context, cmGeneratorExpressionContext *context,
@ -961,6 +1019,8 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier)
return &configurationNode; return &configurationNode;
else if (identifier == "CONFIG") else if (identifier == "CONFIG")
return &configurationTestNode; return &configurationTestNode;
else if (identifier == "LINK_LANGUAGE")
return &linkLanguageNode;
else if (identifier == "TARGET_FILE") else if (identifier == "TARGET_FILE")
return &targetFileNode; return &targetFileNode;
else if (identifier == "TARGET_LINKER_FILE") else if (identifier == "TARGET_LINKER_FILE")
@ -1188,7 +1248,8 @@ std::string GeneratorExpressionContent::EvaluateParameters(
} }
} }
if ((numExpected != -1 && (unsigned int)numExpected != parameters.size())) if ((numExpected > cmGeneratorExpressionNode::DynamicParameters
&& (unsigned int)numExpected != parameters.size()))
{ {
if (numExpected == 0) if (numExpected == 0)
{ {
@ -1213,7 +1274,8 @@ std::string GeneratorExpressionContent::EvaluateParameters(
return std::string(); return std::string();
} }
if (numExpected == -1 && parameters.empty()) if (numExpected == cmGeneratorExpressionNode::OneOrMoreParameters
&& parameters.empty())
{ {
reportError(context, this->GetOriginalExpression(), "$<" + identifier reportError(context, this->GetOriginalExpression(), "$<" + identifier
+ "> expression requires at least one parameter."); + "> expression requires at least one parameter.");

View File

@ -277,6 +277,7 @@ void cmTarget::DefineProperties(cmake *cm)
"Contents of COMPILE_DEFINITIONS may use \"generator expressions\" with " "Contents of COMPILE_DEFINITIONS may use \"generator expressions\" with "
"the syntax \"$<...>\". " "the syntax \"$<...>\". "
CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS
CM_DOCUMENT_LANGUAGE_GENERATOR_EXPRESSIONS
CM_DOCUMENT_COMPILE_DEFINITIONS_DISCLAIMER); CM_DOCUMENT_COMPILE_DEFINITIONS_DISCLAIMER);
cm->DefineProperty cm->DefineProperty
@ -605,7 +606,8 @@ void cmTarget::DefineProperties(cmake *cm)
"See also the include_directories command.\n" "See also the include_directories command.\n"
"Contents of INCLUDE_DIRECTORIES may use \"generator expressions\" with " "Contents of INCLUDE_DIRECTORIES may use \"generator expressions\" with "
"the syntax \"$<...>\". " "the syntax \"$<...>\". "
CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS); CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS
CM_DOCUMENT_LANGUAGE_GENERATOR_EXPRESSIONS);
cm->DefineProperty cm->DefineProperty
("INSTALL_NAME_DIR", cmProperty::TARGET, ("INSTALL_NAME_DIR", cmProperty::TARGET,
@ -802,7 +804,8 @@ void cmTarget::DefineProperties(cmake *cm)
"as $<TARGET_PROPERTY:foo,INTERFACE_INCLUDE_DIRECTORIES> to use the " "as $<TARGET_PROPERTY:foo,INTERFACE_INCLUDE_DIRECTORIES> to use the "
"include directories specified in the interface of 'foo'." "include directories specified in the interface of 'foo'."
"\n" "\n"
CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS); CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS
CM_DOCUMENT_LANGUAGE_GENERATOR_EXPRESSIONS);
cm->DefineProperty cm->DefineProperty
("INTERFACE_COMPILE_DEFINITIONS", cmProperty::TARGET, ("INTERFACE_COMPILE_DEFINITIONS", cmProperty::TARGET,
@ -813,7 +816,8 @@ void cmTarget::DefineProperties(cmake *cm)
"as $<TARGET_PROPERTY:foo,INTERFACE_COMPILE_DEFINITIONS> to use the " "as $<TARGET_PROPERTY:foo,INTERFACE_COMPILE_DEFINITIONS> to use the "
"compile definitions specified in the interface of 'foo'." "compile definitions specified in the interface of 'foo'."
"\n" "\n"
CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS); CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS
CM_DOCUMENT_LANGUAGE_GENERATOR_EXPRESSIONS);
cm->DefineProperty cm->DefineProperty
("LINK_INTERFACE_MULTIPLICITY", cmProperty::TARGET, ("LINK_INTERFACE_MULTIPLICITY", cmProperty::TARGET,

View File

@ -70,6 +70,7 @@ public:
"Arguments to target_compile_definitions may use \"generator " "Arguments to target_compile_definitions may use \"generator "
"expressions\" with the syntax \"$<...>\". " "expressions\" with the syntax \"$<...>\". "
CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS
CM_DOCUMENT_LANGUAGE_GENERATOR_EXPRESSIONS
; ;
} }

View File

@ -75,6 +75,7 @@ public:
"Arguments to target_include_directories may use \"generator " "Arguments to target_include_directories may use \"generator "
"expressions\" with the syntax \"$<...>\". " "expressions\" with the syntax \"$<...>\". "
CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS
CM_DOCUMENT_LANGUAGE_GENERATOR_EXPRESSIONS
; ;
} }

View File

@ -0,0 +1,19 @@
#ifndef LINK_C_DEFINE
#error Expected LINK_C_DEFINE
#endif
#ifndef LINK_LANGUAGE_IS_C
#error Expected LINK_LANGUAGE_IS_C
#endif
#ifdef LINK_CXX_DEFINE
#error Unexpected LINK_CXX_DEFINE
#endif
#ifdef LINK_LANGUAGE_IS_CXX
#error Unexpected LINK_LANGUAGE_IS_CXX
#endif
int main(void)
{
return 0;
}

View File

@ -56,6 +56,21 @@ enum {
#error Expect PREFIX_DEF2 #error Expect PREFIX_DEF2
#endif #endif
#ifndef LINK_CXX_DEFINE
#error Expected LINK_CXX_DEFINE
#endif
#ifndef LINK_LANGUAGE_IS_CXX
#error Expected LINK_LANGUAGE_IS_CXX
#endif
#ifdef LINK_C_DEFINE
#error Unexpected LINK_C_DEFINE
#endif
#ifdef LINK_LANGUAGE_IS_C
#error Unexpected LINK_LANGUAGE_IS_C
#endif
// TEST_GENERATOR_EXPRESSIONS // TEST_GENERATOR_EXPRESSIONS
#endif #endif

View File

@ -0,0 +1,19 @@
#ifndef LINK_CXX_DEFINE
#error Expected LINK_CXX_DEFINE
#endif
#ifndef LINK_LANGUAGE_IS_CXX
#error Expected LINK_LANGUAGE_IS_CXX
#endif
#ifdef LINK_C_DEFINE
#error Unexpected LINK_C_DEFINE
#endif
#ifdef LINK_LANGUAGE_IS_C
#error Unexpected LINK_LANGUAGE_IS_C
#endif
void someFunc(void)
{
}

View File

@ -0,0 +1,19 @@
#ifndef LINK_CXX_DEFINE
#error Expected LINK_CXX_DEFINE
#endif
#ifndef LINK_LANGUAGE_IS_CXX
#error Expected LINK_LANGUAGE_IS_CXX
#endif
#ifdef LINK_C_DEFINE
#error Unexpected LINK_C_DEFINE
#endif
#ifdef LINK_LANGUAGE_IS_C
#error Unexpected LINK_LANGUAGE_IS_C
#endif
int main(int argc, char **argv)
{
return 0;
}

View File

@ -19,9 +19,29 @@ set_property(TARGET target_prop_executable APPEND PROPERTY COMPILE_DEFINITIONS
LETTER_LIST3=\"$<JOIN:A;B;C;D,,->\" LETTER_LIST3=\"$<JOIN:A;B;C;D,,->\"
LETTER_LIST4=\"$<JOIN:A;B;C;D,-,->\" LETTER_LIST4=\"$<JOIN:A;B;C;D,-,->\"
LETTER_LIST5=\"$<JOIN:A;B;C;D,-,>\" LETTER_LIST5=\"$<JOIN:A;B;C;D,-,>\"
"$<$<LINK_LANGUAGE:CXX>:LINK_CXX_DEFINE>"
"$<$<LINK_LANGUAGE:C>:LINK_C_DEFINE>"
"LINK_LANGUAGE_IS_$<LINK_LANGUAGE>"
) )
set_property(TARGET target_prop_executable APPEND PROPERTY COMPILE_DEFINITIONS set_property(TARGET target_prop_executable APPEND PROPERTY COMPILE_DEFINITIONS
BUILD_IS_DEBUG=$<CONFIG:Debug> BUILD_IS_DEBUG=$<CONFIG:Debug>
BUILD_IS_NOT_DEBUG=$<NOT:$<CONFIG:Debug>> BUILD_IS_NOT_DEBUG=$<NOT:$<CONFIG:Debug>>
) )
add_executable(target_prop_c_executable ../compiletest.c)
set_property(TARGET target_prop_c_executable APPEND PROPERTY COMPILE_DEFINITIONS
"$<$<LINK_LANGUAGE:CXX>:LINK_CXX_DEFINE>"
"$<$<LINK_LANGUAGE:C>:LINK_C_DEFINE>"
"LINK_LANGUAGE_IS_$<LINK_LANGUAGE>"
)
# Resulting link language will be CXX
add_executable(target_prop_mixed_executable ../compiletest_mixed_c.c ../compiletest_mixed_cxx.cpp)
set_property(TARGET target_prop_mixed_executable APPEND PROPERTY COMPILE_DEFINITIONS
"$<$<LINK_LANGUAGE:CXX>:LINK_CXX_DEFINE>"
"$<$<LINK_LANGUAGE:C>:LINK_C_DEFINE>"
"LINK_LANGUAGE_IS_$<LINK_LANGUAGE>"
)

View File

@ -128,3 +128,19 @@ file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/prefix_foo/prefix_bar/prefix_ba
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/prefix_foo/prefix_bar/prefix_bat/prefix_foo_bar_bat.h" "// prefix_foo_bar_bat.h\n") file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/prefix_foo/prefix_bar/prefix_bat/prefix_foo_bar_bat.h" "// prefix_foo_bar_bat.h\n")
target_include_directories(TargetIncludeDirectories PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/prefix_$<JOIN:foo;bar;bat,/prefix_>") target_include_directories(TargetIncludeDirectories PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/prefix_$<JOIN:foo;bar;bat,/prefix_>")
# Test that the language generator expressions work
set_property(TARGET TargetIncludeDirectories
APPEND PROPERTY INCLUDE_DIRECTORIES
"$<$<LINK_LANGUAGE:C>:${CMAKE_CURRENT_BINARY_DIR}/bad>"
"$<$<LINK_LANGUAGE:CXX>:${CMAKE_CURRENT_BINARY_DIR}/good>"
"$<$<STREQUAL:$<LINK_LANGUAGE>,CXX>:${CMAKE_CURRENT_BINARY_DIR}/othergood/>"
)
add_executable(TargetIncludeDirectories_C main.c)
set_property(TARGET TargetIncludeDirectories_C
APPEND PROPERTY INCLUDE_DIRECTORIES
"$<$<LINK_LANGUAGE:CXX>:${CMAKE_CURRENT_BINARY_DIR}/bad>"
"$<$<LINK_LANGUAGE:C>:${CMAKE_CURRENT_BINARY_DIR}/good>"
"$<$<STREQUAL:$<LINK_LANGUAGE>,C>:${CMAKE_CURRENT_BINARY_DIR}/othergood/>"
)

View File

@ -0,0 +1,7 @@
#include "common.h"
int main(void)
{
return 0;
}

View File

@ -11,6 +11,7 @@
#include "list.h" #include "list.h"
#include "target.h" #include "target.h"
#include "prefix_foo_bar_bat.h" #include "prefix_foo_bar_bat.h"
#include "common.h"
int main(int, char**) int main(int, char**)
{ {