diff options
author | Stephen Kelly <steveire@gmail.com> | 2012-09-23 11:16:44 (GMT) |
---|---|---|
committer | Stephen Kelly <steveire@gmail.com> | 2013-01-05 00:05:08 (GMT) |
commit | b2f1700bc7caf12c3f28890ebe183ae09c90d7dc (patch) | |
tree | fc7c8f8378d213183caaa5c5fbd381ae579431c3 | |
parent | 95b74cafed4ba7ce572dc03b11e72d902f4df7ca (diff) | |
download | CMake-b2f1700bc7caf12c3f28890ebe183ae09c90d7dc.zip CMake-b2f1700bc7caf12c3f28890ebe183ae09c90d7dc.tar.gz CMake-b2f1700bc7caf12c3f28890ebe183ae09c90d7dc.tar.bz2 |
GenEx: Add expressions to specify build- or install-only values
This is for specifying INCLUDE_DIRECTORIES relevant to the build-location
or the install location for example:
set_property(TARGET foo PROPERTY
INTERFACE_INCLUDE_DIRECTORIES
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR};${CMAKE_CURRENT_SOURCE_DIR}>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include>"
)
A 'bar' target can then use:
set_property(TARGET bar PROPERTY
INCLUDE_DIRECTORIES
"$<TARGET_PROPERTY:foo,INTERFACE_INCLUDE_DIRECTORIES>"
)
and it will work whether foo is in the same project, or an imported target
from an installation location, or an imported target from a build location
generated by the export() command.
Because the generator expressions are only evaluated at build-time, these
new expressions are equivalent to the ZeroNode and OneNode.
The GeneratorExpression test is split into parts. Some shells can't run
the custom command as it is getting too long.
-rw-r--r-- | Source/cmDocumentGeneratorExpressions.h | 6 | ||||
-rw-r--r-- | Source/cmGeneratorExpression.cxx | 88 | ||||
-rw-r--r-- | Source/cmGeneratorExpression.h | 4 | ||||
-rw-r--r-- | Source/cmGeneratorExpressionEvaluator.cxx | 10 | ||||
-rw-r--r-- | Tests/GeneratorExpression/CMakeLists.txt | 15 | ||||
-rw-r--r-- | Tests/GeneratorExpression/check-common.cmake | 5 | ||||
-rw-r--r-- | Tests/GeneratorExpression/check-part1.cmake (renamed from Tests/GeneratorExpression/check.cmake) | 28 | ||||
-rw-r--r-- | Tests/GeneratorExpression/check-part2.cmake | 26 |
8 files changed, 144 insertions, 38 deletions
diff --git a/Source/cmDocumentGeneratorExpressions.h b/Source/cmDocumentGeneratorExpressions.h index 445fd0e..1927012 100644 --- a/Source/cmDocumentGeneratorExpressions.h +++ b/Source/cmDocumentGeneratorExpressions.h @@ -26,6 +26,12 @@ "strings which contain a '>' for example.\n" \ " $<COMMA> = A literal ','. Used to compare " \ "strings which contain a ',' for example.\n" \ + " $<INSTALL_INTERFACE:...> = content of \"...\" when the property " \ + "is exported using install(EXPORT), and empty otherwise.\n" \ + " $<BUILD_INTERFACE:...> = content of \"...\" when the property " \ + "is exported using export(), or when the target is used by another " \ + "target in the same buildsystem. Expands to the empty string " \ + "otherwise.\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" \ diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx index 3fd4a5f..841fbb7 100644 --- a/Source/cmGeneratorExpression.cxx +++ b/Source/cmGeneratorExpression.cxx @@ -123,15 +123,9 @@ cmCompiledGeneratorExpression::~cmCompiledGeneratorExpression() } } -std::string cmGeneratorExpression::Preprocess(const std::string &input, - PreprocessContext context) +//---------------------------------------------------------------------------- +static std::string stripAllGeneratorExpressions(const std::string &input) { - if (context != StripAllGeneratorExpressions) - { - assert(!"cmGeneratorExpression::Preprocess called with invalid args"); - return std::string(); - } - std::string result; std::string::size_type pos = 0; std::string::size_type lastPos = pos; @@ -170,3 +164,81 @@ std::string cmGeneratorExpression::Preprocess(const std::string &input, result += input.substr(lastPos); return result; } + +//---------------------------------------------------------------------------- +static std::string stripExportInterface(const std::string &input, + cmGeneratorExpression::PreprocessContext context) +{ + std::string result; + + std::string::size_type pos = 0; + std::string::size_type lastPos = pos; + while((pos = input.find("$<BUILD_INTERFACE:", lastPos)) != input.npos + || (pos = input.find("$<INSTALL_INTERFACE:", lastPos)) != input.npos) + { + result += input.substr(lastPos, pos - lastPos); + const bool gotInstallInterface = input[pos + 2] == 'I'; + pos += gotInstallInterface ? sizeof("$<INSTALL_INTERFACE:") - 1 + : sizeof("$<BUILD_INTERFACE:") - 1; + int nestingLevel = 1; + const char *c = input.c_str() + pos; + const char * const cStart = c; + for ( ; *c; ++c) + { + if(c[0] == '$' && c[1] == '<') + { + ++nestingLevel; + ++c; + continue; + } + if(c[0] == '>') + { + --nestingLevel; + if (nestingLevel != 0) + { + continue; + } + if(context == cmGeneratorExpression::BuildInterface + && !gotInstallInterface) + { + result += input.substr(pos, c - cStart); + } + else if(context == cmGeneratorExpression::InstallInterface + && gotInstallInterface) + { + result += input.substr(pos, c - cStart); + } + break; + } + } + const std::string::size_type traversed = (c - cStart) + 1; + if (!*c) + { + result += std::string(gotInstallInterface ? "$<INSTALL_INTERFACE:" + : "$<BUILD_INTERFACE:") + + input.substr(pos, traversed); + } + pos += traversed; + lastPos = pos; + } + result += input.substr(lastPos); + + return result; +} + +//---------------------------------------------------------------------------- +std::string cmGeneratorExpression::Preprocess(const std::string &input, + PreprocessContext context) +{ + if (context == StripAllGeneratorExpressions) + { + return stripAllGeneratorExpressions(input); + } + else if (context == BuildInterface || context == InstallInterface) + { + return stripExportInterface(input, context); + } + + assert(!"cmGeneratorExpression::Preprocess called with invalid args"); + return std::string(); +} diff --git a/Source/cmGeneratorExpression.h b/Source/cmGeneratorExpression.h index 15e637c..99056a5 100644 --- a/Source/cmGeneratorExpression.h +++ b/Source/cmGeneratorExpression.h @@ -51,7 +51,9 @@ public: cmsys::auto_ptr<cmCompiledGeneratorExpression> Parse(const char* input); enum PreprocessContext { - StripAllGeneratorExpressions + StripAllGeneratorExpressions, + BuildInterface, + InstallInterface }; static std::string Preprocess(const std::string &input, diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx index 3b7cfc0..e20e203 100644 --- a/Source/cmGeneratorExpressionEvaluator.cxx +++ b/Source/cmGeneratorExpressionEvaluator.cxx @@ -96,6 +96,12 @@ static const struct OneNode : public cmGeneratorExpressionNode } oneNode; //---------------------------------------------------------------------------- +static const struct OneNode buildInterfaceNode; + +//---------------------------------------------------------------------------- +static const struct ZeroNode installInterfaceNode; + +//---------------------------------------------------------------------------- #define BOOLEAN_OP_NODE(OPNAME, OP, SUCCESS_VALUE, FAILURE_VALUE) \ static const struct OP ## Node : public cmGeneratorExpressionNode \ { \ @@ -593,6 +599,10 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier) return &commaNode; else if (identifier == "TARGET_PROPERTY") return &targetPropertyNode; + else if (identifier == "BUILD_INTERFACE") + return &buildInterfaceNode; + else if (identifier == "INSTALL_INTERFACE") + return &installInterfaceNode; return 0; } diff --git a/Tests/GeneratorExpression/CMakeLists.txt b/Tests/GeneratorExpression/CMakeLists.txt index 3a92d81..db6fb74 100644 --- a/Tests/GeneratorExpression/CMakeLists.txt +++ b/Tests/GeneratorExpression/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required (VERSION 2.8.8) project(GeneratorExpression NONE) -add_custom_target(check ALL +add_custom_target(check-part1 ALL COMMAND ${CMAKE_COMMAND} -Dtest_0=$<0:nothing> -Dtest_0_with_comma=$<0:-Wl,--no-undefined> @@ -57,6 +57,13 @@ add_custom_target(check ALL -Dtest_colons_3=$<1:Qt5::Core> -Dtest_colons_4=$<1:C:\\CMake> -Dtest_colons_5=$<1:C:/CMake> + -P ${CMAKE_CURRENT_SOURCE_DIR}/check-part1.cmake + COMMAND ${CMAKE_COMMAND} -E echo "check done (part 1 of 2)" + VERBATIM + ) + +add_custom_target(check-part2 ALL + COMMAND ${CMAKE_COMMAND} -Dtest_incomplete_1=$< -Dtest_incomplete_2=$<something -Dtest_incomplete_3=$<something: @@ -78,7 +85,9 @@ add_custom_target(check ALL -Dtest_incomplete_19=$<1:some,thing$<ANGLE-R> -Dtest_incomplete_20=$<CONFIGURATION$<ANGLE-R> -Dtest_incomplete_21=$<BOOL:something$<ANGLE-R> - -P ${CMAKE_CURRENT_SOURCE_DIR}/check.cmake - COMMAND ${CMAKE_COMMAND} -E echo "check done" + -Dtest_build_interface=$<BUILD_INTERFACE:build> + -Dtest_install_interface=$<INSTALL_INTERFACE:install> + -P ${CMAKE_CURRENT_SOURCE_DIR}/check-part2.cmake + COMMAND ${CMAKE_COMMAND} -E echo "check done (part 2 of 2)" VERBATIM ) diff --git a/Tests/GeneratorExpression/check-common.cmake b/Tests/GeneratorExpression/check-common.cmake new file mode 100644 index 0000000..8ffebd7 --- /dev/null +++ b/Tests/GeneratorExpression/check-common.cmake @@ -0,0 +1,5 @@ +macro(check var val) + if(NOT "${${var}}" STREQUAL "${val}") + message(SEND_ERROR "${var} is \"${${var}}\", not \"${val}\"") + endif() +endmacro() diff --git a/Tests/GeneratorExpression/check.cmake b/Tests/GeneratorExpression/check-part1.cmake index af436de..7abfa82 100644 --- a/Tests/GeneratorExpression/check.cmake +++ b/Tests/GeneratorExpression/check-part1.cmake @@ -1,8 +1,5 @@ -macro(check var val) - if(NOT "${${var}}" STREQUAL "${val}") - message(SEND_ERROR "${var} is \"${${var}}\", not \"${val}\"") - endif() -endmacro() + +include(${CMAKE_CURRENT_LIST_DIR}/check-common.cmake) message(STATUS "config=[${config}]") check(test_0 "") @@ -57,24 +54,3 @@ check(test_colons_2 "::") check(test_colons_3 "Qt5::Core") check(test_colons_4 "C:\\\\CMake") check(test_colons_5 "C:/CMake") -check(test_incomplete_1 "$<") -check(test_incomplete_2 "$<something") -check(test_incomplete_3 "$<something:") -check(test_incomplete_4 "$<something:,") -check(test_incomplete_5 "$something:,>") -check(test_incomplete_6 "<something:,>") -check(test_incomplete_7 "$<something::") -check(test_incomplete_8 "$<something:,") -check(test_incomplete_9 "$<something:,,") -check(test_incomplete_10 "$<something:,:") -check(test_incomplete_11 "$<something,,") -check(test_incomplete_12 "$<,,") -check(test_incomplete_13 "$<somespecialthing") -check(test_incomplete_14 "$<>") -check(test_incomplete_15 "$<some$<thing") -check(test_incomplete_16 "$<BOOL:something") -check(test_incomplete_17 "some$thing") -check(test_incomplete_18 "$<1:some,thing") -check(test_incomplete_19 "$<1:some,thing>") -check(test_incomplete_20 "$<CONFIGURATION>") -check(test_incomplete_21 "$<BOOL:something>") diff --git a/Tests/GeneratorExpression/check-part2.cmake b/Tests/GeneratorExpression/check-part2.cmake new file mode 100644 index 0000000..149a658 --- /dev/null +++ b/Tests/GeneratorExpression/check-part2.cmake @@ -0,0 +1,26 @@ + +include(${CMAKE_CURRENT_LIST_DIR}/check-common.cmake) + +check(test_incomplete_1 "$<") +check(test_incomplete_2 "$<something") +check(test_incomplete_3 "$<something:") +check(test_incomplete_4 "$<something:,") +check(test_incomplete_5 "$something:,>") +check(test_incomplete_6 "<something:,>") +check(test_incomplete_7 "$<something::") +check(test_incomplete_8 "$<something:,") +check(test_incomplete_9 "$<something:,,") +check(test_incomplete_10 "$<something:,:") +check(test_incomplete_11 "$<something,,") +check(test_incomplete_12 "$<,,") +check(test_incomplete_13 "$<somespecialthing") +check(test_incomplete_14 "$<>") +check(test_incomplete_15 "$<some$<thing") +check(test_incomplete_16 "$<BOOL:something") +check(test_incomplete_17 "some$thing") +check(test_incomplete_18 "$<1:some,thing") +check(test_incomplete_19 "$<1:some,thing>") +check(test_incomplete_20 "$<CONFIGURATION>") +check(test_incomplete_21 "$<BOOL:something>") +check(test_build_interface "build") +check(test_install_interface "") |