Handle INTERFACE properties transitively for includes and defines.
Contextually, the behavior is as if the properties content from another target is included in the string and then the result is evaluated.
This commit is contained in:
parent
f5b1980fb2
commit
894f52f32d
|
@ -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();
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -719,6 +719,28 @@ void cmTarget::DefineProperties(cmake *cm)
|
|||
"If set, this property completely overrides the generic property "
|
||||
"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.",
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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")
|
||||
|
|
Loading…
Reference in New Issue