Allow generator expressions in LINK_INTERFACE_LIBRARIES.
The Config and IMPORTED_ variants may also contain generator expressions. If 'the implementation is the interface', then the result of evaluating the expressions at generate time is used to populate the IMPORTED_LINK_INTERFACE_LIBRARIES property. 1) In the case of non-static libraries, this is fine because the user still has the option to populate the LINK_INTERFACE_LIBRARIES with generator expressions if that is what is wanted. 2) In the case of static libraries, this prevents a footgun, enforcing that the interface and the implementation are really the same. Otherwise, the LINK_LIBRARIES could contain a generator expression which is evaluated with a different context at build time, and when used as an imported target. That would mean that the result of evaluating the INTERFACE_LINK_LIBRARIES property for a static library would not necessarily be the 'link implementation'. For example: add_library(libone STATIC libone.cpp) add_library(libtwo STATIC libtwo.cpp) add_library(libthree STATIC libthree.cpp) target_link_libraries(libtwo $<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,STATIC_LIBRARY>:libone>) target_link_libraries(libthree libtwo) If the LINK_LIBRARIES content was simply copied to the IMPORTED_LINK_INTERFACE_LIBRARIES, then libthree links to libone, but executables linking to libthree will not link to libone. 3) As the 'implementation is the interface' concept is to be deprecated in the future anyway, this should be fine.
This commit is contained in:
parent
94aeaf72c7
commit
77d2646784
|
@ -359,9 +359,47 @@ cmExportFileGenerator
|
|||
{
|
||||
return;
|
||||
}
|
||||
this->SetImportLinkProperty(suffix, target,
|
||||
"IMPORTED_LINK_INTERFACE_LIBRARIES",
|
||||
iface->Libraries, properties, missingTargets);
|
||||
|
||||
if (iface->ImplementationIsInterface)
|
||||
{
|
||||
this->SetImportLinkProperty(suffix, target,
|
||||
"IMPORTED_LINK_INTERFACE_LIBRARIES",
|
||||
iface->Libraries, properties, missingTargets);
|
||||
return;
|
||||
}
|
||||
|
||||
const char *propContent;
|
||||
|
||||
if (const char *prop_suffixed = target->GetProperty(
|
||||
("LINK_INTERFACE_LIBRARIES" + suffix).c_str()))
|
||||
{
|
||||
propContent = prop_suffixed;
|
||||
}
|
||||
else if (const char *prop = target->GetProperty(
|
||||
"LINK_INTERFACE_LIBRARIES"))
|
||||
{
|
||||
propContent = prop;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!*propContent)
|
||||
{
|
||||
properties["IMPORTED_LINK_INTERFACE_LIBRARIES" + suffix] = "";
|
||||
return;
|
||||
}
|
||||
|
||||
std::string prepro = cmGeneratorExpression::Preprocess(propContent,
|
||||
preprocessRule);
|
||||
if (!prepro.empty())
|
||||
{
|
||||
this->ResolveTargetsInGeneratorExpressions(prepro, target,
|
||||
missingTargets,
|
||||
ReplaceFreeTargets);
|
||||
properties["IMPORTED_LINK_INTERFACE_LIBRARIES" + suffix] = prepro;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
|
|
@ -4896,16 +4896,30 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config,
|
|||
{
|
||||
std::string linkProp = "IMPORTED_LINK_INTERFACE_LIBRARIES";
|
||||
linkProp += suffix;
|
||||
if(const char* config_libs = this->GetProperty(linkProp.c_str()))
|
||||
|
||||
const char *propertyLibs = this->GetProperty(linkProp.c_str());
|
||||
|
||||
if(!propertyLibs)
|
||||
{
|
||||
cmSystemTools::ExpandListArgument(config_libs,
|
||||
info.LinkInterface.Libraries);
|
||||
linkProp = "IMPORTED_LINK_INTERFACE_LIBRARIES";
|
||||
propertyLibs = this->GetProperty(linkProp.c_str());
|
||||
}
|
||||
else if(const char* libs =
|
||||
this->GetProperty("IMPORTED_LINK_INTERFACE_LIBRARIES"))
|
||||
if(propertyLibs)
|
||||
{
|
||||
cmSystemTools::ExpandListArgument(libs,
|
||||
info.LinkInterface.Libraries);
|
||||
cmListFileBacktrace lfbt;
|
||||
cmGeneratorExpression ge(lfbt);
|
||||
|
||||
cmGeneratorExpressionDAGChecker dagChecker(lfbt,
|
||||
this->GetName(),
|
||||
linkProp, 0, 0);
|
||||
cmSystemTools::ExpandListArgument(ge.Parse(propertyLibs)
|
||||
->Evaluate(this->Makefile,
|
||||
desired_config.c_str(),
|
||||
false,
|
||||
headTarget,
|
||||
this,
|
||||
&dagChecker),
|
||||
info.LinkInterface.Libraries);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5019,18 +5033,20 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface,
|
|||
// An explicit list of interface libraries may be set for shared
|
||||
// libraries and executables that export symbols.
|
||||
const char* explicitLibraries = 0;
|
||||
std::string linkIfaceProp;
|
||||
if(this->GetType() == cmTarget::SHARED_LIBRARY ||
|
||||
this->IsExecutableWithExports())
|
||||
{
|
||||
// Lookup the per-configuration property.
|
||||
std::string propName = "LINK_INTERFACE_LIBRARIES";
|
||||
propName += suffix;
|
||||
explicitLibraries = this->GetProperty(propName.c_str());
|
||||
linkIfaceProp = "LINK_INTERFACE_LIBRARIES";
|
||||
linkIfaceProp += suffix;
|
||||
explicitLibraries = this->GetProperty(linkIfaceProp.c_str());
|
||||
|
||||
// If not set, try the generic property.
|
||||
if(!explicitLibraries)
|
||||
{
|
||||
explicitLibraries = this->GetProperty("LINK_INTERFACE_LIBRARIES");
|
||||
linkIfaceProp = "LINK_INTERFACE_LIBRARIES";
|
||||
explicitLibraries = this->GetProperty(linkIfaceProp.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5048,7 +5064,16 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface,
|
|||
if(explicitLibraries)
|
||||
{
|
||||
// The interface libraries have been explicitly set.
|
||||
cmSystemTools::ExpandListArgument(explicitLibraries, iface.Libraries);
|
||||
cmListFileBacktrace lfbt;
|
||||
cmGeneratorExpression ge(lfbt);
|
||||
cmGeneratorExpressionDAGChecker dagChecker(lfbt, this->GetName(),
|
||||
linkIfaceProp, 0, 0);
|
||||
cmSystemTools::ExpandListArgument(ge.Parse(explicitLibraries)->Evaluate(
|
||||
this->Makefile,
|
||||
config,
|
||||
false,
|
||||
headTarget,
|
||||
this, &dagChecker), iface.Libraries);
|
||||
|
||||
if(this->GetType() == cmTarget::SHARED_LIBRARY)
|
||||
{
|
||||
|
@ -5091,6 +5116,7 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface,
|
|||
// The link implementation is the default link interface.
|
||||
LinkImplementation const* impl = this->GetLinkImplementation(config,
|
||||
headTarget);
|
||||
iface.ImplementationIsInterface = true;
|
||||
iface.Libraries = impl->Libraries;
|
||||
iface.WrongConfigLibraries = impl->WrongConfigLibraries;
|
||||
if(this->GetType() == cmTarget::STATIC_LIBRARY)
|
||||
|
|
|
@ -258,7 +258,9 @@ public:
|
|||
// Needed only for OLD behavior of CMP0003.
|
||||
std::vector<std::string> WrongConfigLibraries;
|
||||
|
||||
LinkInterface(): Multiplicity(0) {}
|
||||
bool ImplementationIsInterface;
|
||||
|
||||
LinkInterface(): Multiplicity(0), ImplementationIsInterface(false) {}
|
||||
};
|
||||
|
||||
/** Get the link interface for the given configuration. Returns 0
|
||||
|
|
|
@ -80,3 +80,13 @@ assert_property(targetA LINK_INTERFACE_LIBRARIES "")
|
|||
add_library(depIfaceOnly SHARED EXCLUDE_FROM_ALL depIfaceOnly.cpp)
|
||||
generate_export_header(depIfaceOnly)
|
||||
set_property(TARGET depB APPEND PROPERTY LINK_INTERFACE_LIBRARIES depIfaceOnly)
|
||||
|
||||
add_library(depD SHARED depD.cpp)
|
||||
generate_export_header(depD)
|
||||
set_property(TARGET depD APPEND PROPERTY
|
||||
LINK_INTERFACE_LIBRARIES
|
||||
$<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,EXECUTABLE>:depA>
|
||||
)
|
||||
|
||||
add_executable(targetB targetB.cpp)
|
||||
target_link_libraries(targetB depD)
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
#include "depD.h"
|
||||
|
||||
int DepD::foo()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
DepA DepD::getA()
|
||||
{
|
||||
DepA a;
|
||||
return a;
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
#include "depd_export.h"
|
||||
|
||||
#include "depA.h"
|
||||
|
||||
struct DEPD_EXPORT DepD
|
||||
{
|
||||
int foo();
|
||||
|
||||
DepA getA();
|
||||
};
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
#include "depD.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
DepD d;
|
||||
DepA a = d.getA();
|
||||
|
||||
return d.foo() + a.foo();
|
||||
}
|
|
@ -158,6 +158,36 @@ set_property(TARGET testLibRequired APPEND PROPERTY
|
|||
$<INSTALL_INTERFACE:InstallOnly_DEFINE>
|
||||
)
|
||||
|
||||
include(GenerateExportHeader)
|
||||
|
||||
add_library(testSharedLibRequired SHARED testSharedLibRequired.cpp)
|
||||
generate_export_header(testSharedLibRequired)
|
||||
set_property(TARGET testSharedLibRequired APPEND PROPERTY
|
||||
INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
)
|
||||
set_property(TARGET testSharedLibRequired APPEND PROPERTY
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
)
|
||||
|
||||
add_library(testSharedLibDepends SHARED testSharedLibDepends.cpp)
|
||||
set_property(TARGET testSharedLibDepends APPEND PROPERTY
|
||||
INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
)
|
||||
generate_export_header(testSharedLibDepends)
|
||||
|
||||
set_property(TARGET testSharedLibDepends APPEND PROPERTY
|
||||
INTERFACE_INCLUDE_DIRECTORIES
|
||||
$<TARGET_PROPERTY:testSharedLibRequired,INTERFACE_INCLUDE_DIRECTORIES>
|
||||
)
|
||||
set_property(TARGET testSharedLibDepends APPEND PROPERTY
|
||||
LINK_INTERFACE_LIBRARIES
|
||||
$<1:$<TARGET_NAME:testSharedLibRequired>>
|
||||
)
|
||||
|
||||
# LINK_PRIVATE because the LINK_INTERFACE_LIBRARIES is specified above.
|
||||
target_link_libraries(testSharedLibDepends LINK_PRIVATE testSharedLibRequired)
|
||||
|
||||
install(TARGETS testLibRequired
|
||||
testLibIncludeRequired1
|
||||
testLibIncludeRequired2
|
||||
|
@ -165,10 +195,11 @@ install(TARGETS testLibRequired
|
|||
testLibIncludeRequired4
|
||||
testLibIncludeRequired5
|
||||
testLibIncludeRequired6
|
||||
testSharedLibRequired
|
||||
EXPORT RequiredExp DESTINATION lib )
|
||||
install(EXPORT RequiredExp NAMESPACE Req:: FILE testLibRequiredConfig.cmake DESTINATION lib/cmake/testLibRequired)
|
||||
|
||||
install(TARGETS testLibDepends EXPORT DependsExp DESTINATION lib )
|
||||
install(TARGETS testLibDepends testSharedLibDepends EXPORT DependsExp DESTINATION lib )
|
||||
install(EXPORT DependsExp FILE testLibDependsConfig.cmake DESTINATION lib/cmake/testLibDepends)
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
#include "testSharedLibDepends.h"
|
||||
|
||||
int TestSharedLibDepends::foo()
|
||||
{
|
||||
TestSharedLibRequired req;
|
||||
return req.foo();
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
#ifndef TESTSHAREDLIBDEPENDS_H
|
||||
#define TESTSHAREDLIBDEPENDS_H
|
||||
|
||||
#include "testsharedlibdepends_export.h"
|
||||
|
||||
#include "testSharedLibRequired.h"
|
||||
|
||||
struct TESTSHAREDLIBDEPENDS_EXPORT TestSharedLibDepends
|
||||
{
|
||||
int foo();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,7 @@
|
|||
|
||||
#include "testSharedLibRequired.h"
|
||||
|
||||
int TestSharedLibRequired::foo()
|
||||
{
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
#ifndef TESTSHAREDLIBREQUIRED_H
|
||||
#define TESTSHAREDLIBREQUIRED_H
|
||||
|
||||
#include "testsharedlibrequired_export.h"
|
||||
|
||||
struct TESTSHAREDLIBREQUIRED_EXPORT TestSharedLibRequired
|
||||
{
|
||||
int foo();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -167,3 +167,14 @@ set_property(TARGET deps_iface APPEND PROPERTY
|
|||
INCLUDE_DIRECTORIES
|
||||
$<TARGET_PROPERTY:testLibDepends,INTERFACE_INCLUDE_DIRECTORIES>
|
||||
)
|
||||
|
||||
add_executable(deps_shared_iface deps_shared_iface.cpp)
|
||||
target_link_libraries(deps_shared_iface testSharedLibDepends)
|
||||
set_property(TARGET deps_shared_iface APPEND PROPERTY
|
||||
COMPILE_DEFINITIONS
|
||||
$<TARGET_PROPERTY:testSharedLibDepends,INTERFACE_COMPILE_DEFINITIONS>
|
||||
)
|
||||
set_property(TARGET deps_shared_iface APPEND PROPERTY
|
||||
INCLUDE_DIRECTORIES
|
||||
$<TARGET_PROPERTY:testSharedLibDepends,INTERFACE_INCLUDE_DIRECTORIES>
|
||||
)
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
|
||||
#include "testSharedLibDepends.h"
|
||||
|
||||
int main(int,char **)
|
||||
{
|
||||
TestSharedLibDepends dep;
|
||||
TestSharedLibRequired req;
|
||||
|
||||
return dep.foo() + req.foo();
|
||||
}
|
Loading…
Reference in New Issue