Commit 32410140 authored by Stephen Kelly's avatar Stephen Kelly Committed by Brad King
Browse files

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.
parent a7ba4520
......@@ -74,4 +74,12 @@
"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
......@@ -45,6 +45,11 @@ void reportError(cmGeneratorExpressionContext *context,
//----------------------------------------------------------------------------
struct cmGeneratorExpressionNode
{
enum {
DynamicParameters = 0,
OneOrMoreParameters = -1,
ZeroOrMoreParameters = -2
};
virtual ~cmGeneratorExpressionNode() {}
virtual bool GeneratesContent() const { return true; }
......@@ -110,8 +115,7 @@ static const struct ZeroNode installInterfaceNode;
static const struct OP ## Node : public cmGeneratorExpressionNode \
{ \
OP ## Node () {} \
/* We let -1 carry the meaning 'at least one' */ \
virtual int NumExpectedParameters() const { return -1; } \
virtual int NumExpectedParameters() const { return OneOrMoreParameters; } \
\
std::string Evaluate(const std::vector<std::string> &parameters, \
cmGeneratorExpressionContext *context, \
......@@ -306,6 +310,60 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
}
} 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
{
......@@ -347,7 +405,7 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
TargetPropertyNode() {}
// 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,
cmGeneratorExpressionContext *context,
......@@ -961,6 +1019,8 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier)
return &configurationNode;
else if (identifier == "CONFIG")
return &configurationTestNode;
else if (identifier == "LINK_LANGUAGE")
return &linkLanguageNode;
else if (identifier == "TARGET_FILE")
return &targetFileNode;
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)
{
......@@ -1213,7 +1274,8 @@ std::string GeneratorExpressionContent::EvaluateParameters(
return std::string();
}
if (numExpected == -1 && parameters.empty())
if (numExpected == cmGeneratorExpressionNode::OneOrMoreParameters
&& parameters.empty())
{
reportError(context, this->GetOriginalExpression(), "$<" + identifier
+ "> expression requires at least one parameter.");
......
......@@ -277,6 +277,7 @@ void cmTarget::DefineProperties(cmake *cm)
"Contents of COMPILE_DEFINITIONS may use \"generator expressions\" with "
"the syntax \"$<...>\". "
CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS
CM_DOCUMENT_LANGUAGE_GENERATOR_EXPRESSIONS
CM_DOCUMENT_COMPILE_DEFINITIONS_DISCLAIMER);
cm->DefineProperty
......@@ -605,7 +606,8 @@ void cmTarget::DefineProperties(cmake *cm)
"See also the include_directories command.\n"
"Contents of INCLUDE_DIRECTORIES may use \"generator expressions\" with "
"the syntax \"$<...>\". "
CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS);
CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS
CM_DOCUMENT_LANGUAGE_GENERATOR_EXPRESSIONS);
cm->DefineProperty
("INSTALL_NAME_DIR", cmProperty::TARGET,
......@@ -802,7 +804,8 @@ void cmTarget::DefineProperties(cmake *cm)
"as $<TARGET_PROPERTY:foo,INTERFACE_INCLUDE_DIRECTORIES> to use the "
"include directories specified in the interface of 'foo'."
"\n"
CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS);
CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS
CM_DOCUMENT_LANGUAGE_GENERATOR_EXPRESSIONS);
cm->DefineProperty
("INTERFACE_COMPILE_DEFINITIONS", cmProperty::TARGET,
......@@ -813,7 +816,8 @@ void cmTarget::DefineProperties(cmake *cm)
"as $<TARGET_PROPERTY:foo,INTERFACE_COMPILE_DEFINITIONS> to use the "
"compile definitions specified in the interface of 'foo'."
"\n"
CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS);
CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS
CM_DOCUMENT_LANGUAGE_GENERATOR_EXPRESSIONS);
cm->DefineProperty
("LINK_INTERFACE_MULTIPLICITY", cmProperty::TARGET,
......
......@@ -70,6 +70,7 @@ public:
"Arguments to target_compile_definitions may use \"generator "
"expressions\" with the syntax \"$<...>\". "
CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS
CM_DOCUMENT_LANGUAGE_GENERATOR_EXPRESSIONS
;
}
......
......@@ -75,6 +75,7 @@ public:
"Arguments to target_include_directories may use \"generator "
"expressions\" with the syntax \"$<...>\". "
CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS
CM_DOCUMENT_LANGUAGE_GENERATOR_EXPRESSIONS
;
}
......
#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;
}
......@@ -56,6 +56,21 @@ enum {
#error Expect PREFIX_DEF2
#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
#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
void someFunc(void)
{
}
#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;
}
......@@ -19,9 +19,29 @@ set_property(TARGET target_prop_executable APPEND PROPERTY COMPILE_DEFINITIONS
LETTER_LIST3=\"$<JOIN:A;B;C;D,,->\"
LETTER_LIST4=\"$<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
BUILD_IS_DEBUG=$<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>"
)
......@@ -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")
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/>"
)
#include "common.h"
int main(void)
{
return 0;
}
......@@ -11,6 +11,7 @@
#include "list.h"
#include "target.h"
#include "prefix_foo_bar_bat.h"
#include "common.h"
int main(int, char**)
{
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment