diff options
-rw-r--r-- | Source/cmExportBuildFileGenerator.cxx | 15 | ||||
-rw-r--r-- | Source/cmExportInstallFileGenerator.cxx | 17 | ||||
-rw-r--r-- | Source/cmGeneratorExpressionEvaluator.cxx | 30 | ||||
-rw-r--r-- | Source/cmTarget.cxx | 22 | ||||
-rw-r--r-- | Tests/ExportImport/Export/CMakeLists.txt | 75 | ||||
-rw-r--r-- | Tests/ExportImport/Export/testLibDepends.c | 16 | ||||
-rw-r--r-- | Tests/ExportImport/Import/A/CMakeLists.txt | 15 | ||||
-rw-r--r-- | Tests/ExportImport/Import/A/deps_iface.cpp | 24 | ||||
-rw-r--r-- | Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt | 31 |
9 files changed, 243 insertions, 2 deletions
diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index 3e9a9fd..9533319 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -52,6 +52,8 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) this->GenerateExpectedTargetsCode(os, expectedTargets); } + std::vector<std::string> missingTargets; + // Create all the imported targets. for(std::vector<cmTarget*>::const_iterator tei = allTargets.begin(); @@ -59,8 +61,21 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) { cmTarget* te = *tei; this->GenerateImportTargetCode(os, te); + + ImportPropertyMap properties; + + this->PopulateInterfaceProperty("INTERFACE_INCLUDE_DIRECTORIES", te, + cmGeneratorExpression::BuildInterface, + properties, missingTargets); + this->PopulateInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS", te, + cmGeneratorExpression::BuildInterface, + properties, missingTargets); + + this->GenerateInterfaceProperties(te, os, properties); } + this->GenerateMissingTargetsCheckCode(os, missingTargets); + // Generate import file content for each configuration. for(std::vector<std::string>::const_iterator ci = this->Configurations.begin(); diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index 2b7937e..bc953c9 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -69,6 +69,8 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) this->GenerateExpectedTargetsCode(os, expectedTargets); } + std::vector<std::string> missingTargets; + // Create all the imported targets. for(std::vector<cmTarget*>::const_iterator tei = allTargets.begin(); @@ -76,8 +78,23 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) { cmTarget* te = *tei; this->GenerateImportTargetCode(os, te); + + ImportPropertyMap properties; + + this->PopulateInterfaceProperty("INTERFACE_INCLUDE_DIRECTORIES", + te, + cmGeneratorExpression::InstallInterface, + properties, missingTargets); + this->PopulateInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS", + te, + cmGeneratorExpression::InstallInterface, + properties, missingTargets); + + this->GenerateInterfaceProperties(te, os, properties); } + this->GenerateMissingTargetsCheckCode(os, missingTargets); + // Now load per-configuration properties for them. os << "# Load information for each installed configuration.\n" << "GET_FILENAME_COMPONENT(_DIR \"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n" diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx index 4b44ebe..b7ce155 100644 --- a/Source/cmGeneratorExpressionEvaluator.cxx +++ b/Source/cmGeneratorExpressionEvaluator.cxx @@ -286,6 +286,13 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode } } configurationTestNode; + +//---------------------------------------------------------------------------- +static const char* targetPropertyTransitiveWhitelist[] = { + "INTERFACE_INCLUDE_DIRECTORIES" + , "INTERFACE_COMPILE_DEFINITIONS" +}; + //---------------------------------------------------------------------------- static const struct TargetPropertyNode : public cmGeneratorExpressionNode { @@ -394,7 +401,28 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode } const char *prop = target->GetProperty(propertyName.c_str()); - return prop ? prop : ""; + if (!prop) + { + return std::string(); + } + + for (size_t i = 0; + i < (sizeof(targetPropertyTransitiveWhitelist) / + sizeof(*targetPropertyTransitiveWhitelist)); + ++i) + { + if (targetPropertyTransitiveWhitelist[i] == propertyName) + { + cmGeneratorExpression ge(context->Backtrace); + return ge.Parse(prop)->Evaluate(context->Makefile, + context->Config, + context->Quiet, + context->HeadTarget, + target, + &dagChecker); + } + } + return prop; } } targetPropertyNode; diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index d60979c..ca53a39 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -720,6 +720,28 @@ void cmTarget::DefineProperties(cmake *cm) "for the named configuration."); cm->DefineProperty + ("INTERFACE_INCLUDE_DIRECTORIES", cmProperty::TARGET, + "List of public include directories for a library.", + "Targets may populate this property to publish the include directories " + "required to compile against the headers for the target. Consuming " + "targets can add entries to their own INCLUDE_DIRECTORIES property such " + "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->DefineProperty + ("INTERFACE_COMPILE_DEFINITIONS", cmProperty::TARGET, + "List of public compile definitions for a library.", + "Targets may populate this property to publish the compile definitions " + "required to compile against the headers for the target. Consuming " + "targets can add entries to their own COMPILE_DEFINITIONS property such " + "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->DefineProperty ("LINK_INTERFACE_MULTIPLICITY", cmProperty::TARGET, "Repetition count for STATIC libraries with cyclic dependencies.", "When linking to a STATIC library target with cyclic dependencies the " diff --git a/Tests/ExportImport/Export/CMakeLists.txt b/Tests/ExportImport/Export/CMakeLists.txt index e19ab88..569845a 100644 --- a/Tests/ExportImport/Export/CMakeLists.txt +++ b/Tests/ExportImport/Export/CMakeLists.txt @@ -90,9 +90,82 @@ set_property(TARGET testLibCycleA PROPERTY LINK_INTERFACE_MULTIPLICITY 3) # Test exporting dependent libraries into different exports add_library(testLibRequired testLibRequired.c) add_library(testLibDepends testLibDepends.c) +set_property(TARGET testLibDepends APPEND PROPERTY + INCLUDE_DIRECTORIES + $<TARGET_PROPERTY:testLibRequired,INTERFACE_INCLUDE_DIRECTORIES> +) +set_property(TARGET testLibDepends APPEND PROPERTY + COMPILE_DEFINITIONS + $<TARGET_PROPERTY:testLibRequired,INTERFACE_COMPILE_DEFINITIONS> +) +set_property(TARGET testLibDepends APPEND PROPERTY + INTERFACE_INCLUDE_DIRECTORIES + $<TARGET_PROPERTY:testLibRequired,INTERFACE_INCLUDE_DIRECTORIES> +) +set_property(TARGET testLibDepends APPEND PROPERTY + INTERFACE_COMPILE_DEFINITIONS + $<TARGET_PROPERTY:testLibRequired,INTERFACE_COMPILE_DEFINITIONS> +) target_link_libraries(testLibDepends testLibRequired) -install(TARGETS testLibRequired EXPORT RequiredExp DESTINATION lib ) +macro(add_include_lib _libName) + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${_libName}.c" "// no content\n") + add_library(${_libName} "${CMAKE_CURRENT_BINARY_DIR}/${_libName}.c") + file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${_libName}") + set_property(TARGET ${_libName} APPEND PROPERTY + INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/${_libName}") + if (NOT "${ARGV1}" STREQUAL "NO_HEADER") + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${_libName}/${_libName}.h" "// no content\n") + endif() +endmacro() + +add_include_lib(testLibIncludeRequired1) +add_include_lib(testLibIncludeRequired2) +add_include_lib(testLibIncludeRequired3 NO_HEADER) +# Generate testLibIncludeRequired4 in the testLibIncludeRequired3 directory +# with an error. If the includes from testLibIncludeRequired3 appear first, +# the error will be hit. +# Below, the '3' library appears before the '4' library +# but we are testing that the INSTALL_INTERFACE causes it not to be used +# at build time. +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/testLibIncludeRequired3/testLibIncludeRequired4.h" "#error Should not be included\n") +add_include_lib(testLibIncludeRequired4) +add_include_lib(testLibIncludeRequired5 NO_HEADER) +# Generate testLibIncludeRequired6 in the testLibIncludeRequired5 directory +# with an error. If the includes from testLibIncludeRequired5 appear first, +# the error will be hit. +# Below, the '5' library appears before the '6' library +# but we are testing that when the installed IMPORTED target is used, from +# the Import side of this unit test, the '6' include from the '5' directory +# will not be used because it is in the BUILD_INTERFACE only. +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/testLibIncludeRequired5/testLibIncludeRequired6.h" "#error Should not be included\n") +add_include_lib(testLibIncludeRequired6) + +set_property(TARGET testLibRequired APPEND PROPERTY + INTERFACE_INCLUDE_DIRECTORIES + $<TARGET_PROPERTY:testLibIncludeRequired1,INTERFACE_INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:$<1:$<TARGET_NAME:testLibIncludeRequired2>>,INTERFACE_INCLUDE_DIRECTORIES> + $<INSTALL_INTERFACE:$<TARGET_PROPERTY:testLibIncludeRequired3,INTERFACE_INCLUDE_DIRECTORIES>> + $<BUILD_INTERFACE:$<TARGET_PROPERTY:testLibIncludeRequired4,INTERFACE_INCLUDE_DIRECTORIES>> + $<BUILD_INTERFACE:$<TARGET_PROPERTY:testLibIncludeRequired5,INTERFACE_INCLUDE_DIRECTORIES>> + $<INSTALL_INTERFACE:$<TARGET_PROPERTY:testLibIncludeRequired6,INTERFACE_INCLUDE_DIRECTORIES>> +) + +set_property(TARGET testLibRequired APPEND PROPERTY + INTERFACE_COMPILE_DEFINITIONS + testLibRequired_IFACE_DEFINE + $<BUILD_INTERFACE:BuildOnly_DEFINE> + $<INSTALL_INTERFACE:InstallOnly_DEFINE> +) + +install(TARGETS testLibRequired + testLibIncludeRequired1 + testLibIncludeRequired2 + testLibIncludeRequired3 + testLibIncludeRequired4 + testLibIncludeRequired5 + testLibIncludeRequired6 + EXPORT RequiredExp DESTINATION lib ) install(EXPORT RequiredExp NAMESPACE Req:: FILE testLibRequiredConfig.cmake DESTINATION lib/cmake/testLibRequired) install(TARGETS testLibDepends EXPORT DependsExp DESTINATION lib ) diff --git a/Tests/ExportImport/Export/testLibDepends.c b/Tests/ExportImport/Export/testLibDepends.c index 2849b33..fb5a002 100644 --- a/Tests/ExportImport/Export/testLibDepends.c +++ b/Tests/ExportImport/Export/testLibDepends.c @@ -1,4 +1,20 @@ +#include "testLibIncludeRequired1.h" +#include "testLibIncludeRequired2.h" +#include "testLibIncludeRequired4.h" + +#ifndef testLibRequired_IFACE_DEFINE +#error Expected testLibRequired_IFACE_DEFINE +#endif + +#ifndef BuildOnly_DEFINE +#error Expected BuildOnly_DEFINE +#endif + +#ifdef InstallOnly_DEFINE +#error Unexpected InstallOnly_DEFINE +#endif + extern int testLibRequired(void); int testLibDepends(void) { return testLibRequired(); } diff --git a/Tests/ExportImport/Import/A/CMakeLists.txt b/Tests/ExportImport/Import/A/CMakeLists.txt index 8841792..b77562e 100644 --- a/Tests/ExportImport/Import/A/CMakeLists.txt +++ b/Tests/ExportImport/Import/A/CMakeLists.txt @@ -152,3 +152,18 @@ check_function_exists(testLib1 HAVE_TESTLIB1_FUNCTION) if (NOT HAVE_TESTLIB1_FUNCTION) message(SEND_ERROR "Using imported target testLib2 in check_function_exists() failed !") endif() + +#----------------------------------------------------------------------------- +# Test that dependent imported targets have usable +# INTERFACE_COMPILE_DEFINITIONS and INTERFACE_INCLUDE_DIRECTORIES + +add_library(deps_iface deps_iface.cpp) +target_link_libraries(deps_iface testLibsDepends) +set_property(TARGET deps_iface APPEND PROPERTY + COMPILE_DEFINITIONS + $<TARGET_PROPERTY:testLibDepends,INTERFACE_COMPILE_DEFINITIONS> +) +set_property(TARGET deps_iface APPEND PROPERTY + INCLUDE_DIRECTORIES + $<TARGET_PROPERTY:testLibDepends,INTERFACE_INCLUDE_DIRECTORIES> +) diff --git a/Tests/ExportImport/Import/A/deps_iface.cpp b/Tests/ExportImport/Import/A/deps_iface.cpp new file mode 100644 index 0000000..7190b92 --- /dev/null +++ b/Tests/ExportImport/Import/A/deps_iface.cpp @@ -0,0 +1,24 @@ + +#include "testLibIncludeRequired1.h" +#include "testLibIncludeRequired2.h" +#include "testLibIncludeRequired6.h" + +#ifndef testLibRequired_IFACE_DEFINE +#error Expected testLibRequired_IFACE_DEFINE +#endif + +#ifdef BuildOnly_DEFINE +#error Unexpected BuildOnly_DEFINE +#endif + +#ifndef InstallOnly_DEFINE +#error Expected InstallOnly_DEFINE +#endif + +extern int testLibDepends(void); + + +int main(int,char **) +{ + return testLibDepends(); +} diff --git a/Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt b/Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt index 7cb1b42..63a5492 100644 --- a/Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt +++ b/Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt @@ -37,6 +37,37 @@ include_directories("sing$<1:/ting>") include_directories("$<1:${CMAKE_CURRENT_BINARY_DIR}/arguments;${CMAKE_CURRENT_BINARY_DIR}/list>") +create_header(fee) +create_header(fiy) +create_header(foh) +create_header(fum) + +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/lib1.cpp" "#include \"fee.h\"\n") +add_library(lib1 "${CMAKE_CURRENT_BINARY_DIR}/lib1.cpp") +set_property(TARGET lib1 APPEND PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/fee") +set_property(TARGET lib1 APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/fiy") +set_property(TARGET lib1 APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES "$<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,EXECUTABLE>:${CMAKE_CURRENT_BINARY_DIR}/foh>") + +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/lib2.cpp" "#include \"fiy.h\"\n") +add_library(lib2 "${CMAKE_CURRENT_BINARY_DIR}/lib2.cpp") +set_property(TARGET lib2 APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/fum;$<TARGET_PROPERTY:lib1,INTERFACE_INCLUDE_DIRECTORIES>") +set_property(TARGET lib2 APPEND PROPERTY INCLUDE_DIRECTORIES "$<TARGET_PROPERTY:lib1,INTERFACE_INCLUDE_DIRECTORIES>") + +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main3.cpp" "#include \"fiy.h\"\n#include \"foh.h\"\n#include \"fum.h\"\nint main(int,char**) { return 0; }\n") +add_executable(exe3 "${CMAKE_CURRENT_BINARY_DIR}/main3.cpp") +set_property(TARGET exe3 APPEND PROPERTY INCLUDE_DIRECTORIES "$<TARGET_PROPERTY:lib2,INTERFACE_INCLUDE_DIRECTORIES>") + +# Test cycles +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/lib3.cpp" "#include \"fiy.h\"\n#include \"foh.h\"\n") +add_library(lib3 "${CMAKE_CURRENT_BINARY_DIR}/lib3.cpp") +set_property(TARGET lib3 APPEND PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/fiy;$<TARGET_PROPERTY:lib4,INTERFACE_INCLUDE_DIRECTORIES>") +set_property(TARGET lib3 APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/fiy;$<TARGET_PROPERTY:lib4,INTERFACE_INCLUDE_DIRECTORIES>") + +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/lib4.cpp" "#include \"fiy.h\"\n#include \"foh.h\"\n") +add_library(lib4 "${CMAKE_CURRENT_BINARY_DIR}/lib4.cpp") +set_property(TARGET lib4 APPEND PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/foh;$<TARGET_PROPERTY:lib3,INTERFACE_INCLUDE_DIRECTORIES>") +set_property(TARGET lib4 APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/foh;$<TARGET_PROPERTY:lib3,INTERFACE_INCLUDE_DIRECTORIES>") + add_library(somelib::withcolons UNKNOWN IMPORTED) set_property(TARGET somelib::withcolons PROPERTY IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/target") set_property(TARGET somelib::withcolons PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/target") |