Commit 47a8db5b authored by Stephen Kelly's avatar Stephen Kelly

Add generator expressions for compiler versions.

New generator expressions allow retrieval of the version per language,
as well as equality comparison.
parent d221eac8
......@@ -54,6 +54,13 @@
"else '0'.\n" \
" $<VERSION_EQUAL:v1,v2> = '1' if v1 is the same version as v2, " \
"else '0'.\n" \
" $<C_COMPILER_VERSION> = The version of the C compiler used.\n" \
" $<C_COMPILER_VERSION:ver> = '1' if the version of the C " \
"compiler matches ver, otherwise '0'.\n" \
" $<CXX_COMPILER_VERSION> = The version of the CXX compiler " \
"used.\n" \
" $<CXX_COMPILER_VERSION:ver> = '1' if the version of the CXX " \
"compiler matches ver, otherwise '0'.\n" \
" $<TARGET_FILE:tgt> = main file (.exe, .so.1.2, .a)\n" \
" $<TARGET_LINKER_FILE:tgt> = file used to link (.a, .lib, .so)\n" \
" $<TARGET_SONAME_FILE:tgt> = file with soname (.so.3)\n" \
......
......@@ -341,6 +341,102 @@ static const struct CXXCompilerIdNode : public CompilerIdNode
}
} cxxCompilerIdNode;
//----------------------------------------------------------------------------
struct CompilerVersionNode : public cmGeneratorExpressionNode
{
CompilerVersionNode() {}
virtual int NumExpectedParameters() const { return ZeroOrMoreParameters; }
std::string EvaluateWithLanguage(const std::vector<std::string> &parameters,
cmGeneratorExpressionContext *context,
const GeneratorExpressionContent *content,
cmGeneratorExpressionDAGChecker *,
const std::string &lang) const
{
const char *compilerVersion = context->Makefile ?
context->Makefile->GetSafeDefinition((
"CMAKE_" + lang + "_COMPILER_VERSION").c_str()) : "";
if (parameters.size() == 0)
{
return compilerVersion ? compilerVersion : "";
}
cmsys::RegularExpression compilerIdValidator;
compilerIdValidator.compile("^[0-9\\.]*$");
if (!compilerIdValidator.find(parameters.begin()->c_str()))
{
reportError(context, content->GetOriginalExpression(),
"Expression syntax not recognized.");
return std::string();
}
if (!compilerVersion)
{
return parameters.front().empty() ? "1" : "0";
}
return cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL,
parameters.begin()->c_str(),
compilerVersion) ? "1" : "0";
}
};
//----------------------------------------------------------------------------
static const struct CCompilerVersionNode : public CompilerVersionNode
{
CCompilerVersionNode() {}
std::string Evaluate(const std::vector<std::string> &parameters,
cmGeneratorExpressionContext *context,
const GeneratorExpressionContent *content,
cmGeneratorExpressionDAGChecker *dagChecker) const
{
if (parameters.size() != 0 && parameters.size() != 1)
{
reportError(context, content->GetOriginalExpression(),
"$<C_COMPILER_VERSION> expression requires one or two parameters");
return std::string();
}
if (!context->HeadTarget)
{
reportError(context, content->GetOriginalExpression(),
"$<C_COMPILER_VERSION> may only be used with targets. It may not "
"be used with add_custom_command.");
}
return this->EvaluateWithLanguage(parameters, context, content,
dagChecker, "C");
}
} cCompilerVersionNode;
//----------------------------------------------------------------------------
static const struct CxxCompilerVersionNode : public CompilerVersionNode
{
CxxCompilerVersionNode() {}
std::string Evaluate(const std::vector<std::string> &parameters,
cmGeneratorExpressionContext *context,
const GeneratorExpressionContent *content,
cmGeneratorExpressionDAGChecker *dagChecker) const
{
if (parameters.size() != 0 && parameters.size() != 1)
{
reportError(context, content->GetOriginalExpression(),
"$<CXX_COMPILER_VERSION> expression requires one or two "
"parameters");
return std::string();
}
if (!context->HeadTarget)
{
reportError(context, content->GetOriginalExpression(),
"$<CXX_COMPILER_VERSION> may only be used with targets. It may "
"not be used with add_custom_command.");
}
return this->EvaluateWithLanguage(parameters, context, content,
dagChecker, "CXX");
}
} cxxCompilerVersionNode;
//----------------------------------------------------------------------------
static const struct VersionGreaterNode : public cmGeneratorExpressionNode
{
......@@ -1247,6 +1343,10 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier)
return &versionLessNode;
else if (identifier == "VERSION_EQUAL")
return &versionEqualNode;
else if (identifier == "C_COMPILER_VERSION")
return &cCompilerVersionNode;
else if (identifier == "CXX_COMPILER_VERSION")
return &cxxCompilerVersionNode;
else if (identifier == "CONFIGURATION")
return &configurationNode;
else if (identifier == "CONFIG")
......
......@@ -5,11 +5,23 @@ project(CompileOptions)
add_library(testlib other.cpp)
add_executable(CompileOptions main.cpp)
macro(get_compiler_test_genex lst lang)
list(APPEND ${lst} -DTEST_${lang}_COMPILER_VERSION="$<${lang}_COMPILER_VERSION>")
list(APPEND ${lst} -DTEST_${lang}_COMPILER_VERSION_EQUALITY=$<${lang}_COMPILER_VERSION:${CMAKE_${lang}_COMPILER_VERSION}>)
endmacro()
get_compiler_test_genex(c_tests C)
get_compiler_test_genex(cxx_tests CXX)
set_property(TARGET CompileOptions PROPERTY COMPILE_OPTIONS
"-DTEST_DEFINE"
"-DNEEDS_ESCAPE=\"E$CAPE\""
"$<$<CXX_COMPILER_ID:GNU>:-DTEST_DEFINE_GNU>"
${c_tests}
${cxx_tests}
)
target_link_libraries(CompileOptions testlib)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
......@@ -18,3 +30,9 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
"DO_GNU_TESTS"
)
endif()
target_compile_definitions(CompileOptions
PRIVATE
"EXPECTED_C_COMPILER_VERSION=\"${CMAKE_C_COMPILER_VERSION}\""
"EXPECTED_CXX_COMPILER_VERSION=\"${CMAKE_CXX_COMPILER_VERSION}\""
)
......@@ -16,5 +16,9 @@
int main()
{
return strcmp(NEEDS_ESCAPE, "E$CAPE") == 0 ? 0 : 1;
return (strcmp(NEEDS_ESCAPE, "E$CAPE") == 0
&& strcmp(EXPECTED_C_COMPILER_VERSION, TEST_C_COMPILER_VERSION) == 0
&& strcmp(EXPECTED_CXX_COMPILER_VERSION, TEST_CXX_COMPILER_VERSION) == 0
&& TEST_C_COMPILER_VERSION_EQUALITY == 1
&& TEST_CXX_COMPILER_VERSION_EQUALITY == 1) ? 0 : 1;
}
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