Merge topic 'policy-CMP0022-fixes-for-master'

b51696f CMP0022: Update target_link_libraries plain signature documentation
25b7f87 Merge branch 'policy-CMP0022-fixes' into policy-CMP0022-fixes-for-master
0a561a0 CMP0022: Warn about a given target at most once
23d21b7 Do not export INTERFACE_LINK_LIBRARIES from non-linkable targets
ef10b87 CMP0022: Plain target_link_libraries must populate link interface
0e06788 CMP0022: Add test for target_link_libraries plain signature
c0f4a61 CMP0022: Add unit test for null pointer check and message.
4b0cfa7 Merge branch 'output-CMP0022-entries' into policy-CMP0022-fixes
This commit is contained in:
Brad King 2013-11-04 07:54:20 -05:00 committed by CMake Topic Stage
commit b4a1f442bb
23 changed files with 242 additions and 162 deletions

View File

@ -32,13 +32,16 @@ per-configuration rules by creating and linking to IMPORTED library
targets. See the IMPORTED mode of the add_library command for more
information.
Library dependencies are transitive by default. When this target is
linked into another target then the libraries linked to this target
will appear on the link line for the other target too. See the
INTERFACE_LINK_LIBRARIES target property to override the set of
transitive link dependencies for a target. Calls to other signatures
of this command may set the property making any libraries linked
exclusively by this signature private.
Library dependencies are transitive by default with this signature.
When this target is linked into another target then the libraries
linked to this target will appear on the link line for the other
target too. This transitive "link interface" is stored in the
INTERFACE_LINK_LIBRARIES target property when policy CMP0022 is set to
NEW and may be overridden by setting the property directly.
(When CMP0022 is not set to NEW, transitive linking is builtin but may
be overridden by the LINK_INTERFACE_LIBRARIES property. Calls to other
signatures of this command may set the property making any libraries
linked exclusively by this signature private.)
CMake will also propagate "usage requirements" from linked library
targets. Usage requirements affect compilation of sources in the

View File

@ -191,6 +191,10 @@ bool cmExportFileGenerator::PopulateInterfaceLinkLibrariesProperty(
ImportPropertyMap &properties,
std::vector<std::string> &missingTargets)
{
if(!target->IsLinkable())
{
return false;
}
const char *input = target->GetProperty("INTERFACE_LINK_LIBRARIES");
if (input)
{
@ -654,6 +658,7 @@ cmExportFileGenerator
if (iface->ImplementationIsInterface)
{
// Policy CMP0022 must not be NEW.
this->SetImportLinkProperty(suffix, target,
"IMPORTED_LINK_INTERFACE_LIBRARIES",
iface->Libraries, properties, missingTargets);

View File

@ -81,10 +81,12 @@ class cmTargetInternals
public:
cmTargetInternals()
{
this->PolicyWarnedCMP0022 = false;
this->SourceFileFlagsConstructed = false;
}
cmTargetInternals(cmTargetInternals const&)
{
this->PolicyWarnedCMP0022 = false;
this->SourceFileFlagsConstructed = false;
}
~cmTargetInternals();
@ -104,6 +106,7 @@ public:
typedef std::map<TargetConfigPair, OptionalLinkInterface>
LinkInterfaceMapType;
LinkInterfaceMapType LinkInterfaceMap;
bool PolicyWarnedCMP0022;
typedef std::map<cmStdString, cmTarget::OutputInfo> OutputInfoMapType;
OutputInfoMapType OutputInfoMap;
@ -685,21 +688,10 @@ void cmTarget::MergeLinkLibraries( cmMakefile& mf,
i += this->PrevLinkedLibraries.size();
for( ; i != libs.end(); ++i )
{
const char *lib = i->first.c_str();
// We call this so that the dependencies get written to the cache
this->AddLinkLibrary( mf, selfname, lib, i->second );
if (this->GetType() == cmTarget::STATIC_LIBRARY)
{
std::string configLib = this->GetDebugGeneratorExpressions(lib,
i->second);
if (cmGeneratorExpression::IsValidTargetName(lib)
|| cmGeneratorExpression::Find(lib) != std::string::npos)
{
configLib = "$<LINK_ONLY:" + configLib + ">";
}
this->AppendProperty("INTERFACE_LINK_LIBRARIES", configLib.c_str());
}
// This is equivalent to the target_link_libraries plain signature.
this->AddLinkLibrary( mf, selfname, i->first.c_str(), i->second );
this->AppendProperty("INTERFACE_LINK_LIBRARIES",
this->GetDebugGeneratorExpressions(i->first.c_str(), i->second).c_str());
}
this->PrevLinkedLibraries = libs;
}
@ -5030,12 +5022,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;
const char* newExplicitLibraries =
this->GetProperty("INTERFACE_LINK_LIBRARIES");
std::string linkIfaceProp;
if(this->GetType() == cmTarget::SHARED_LIBRARY ||
this->IsExecutableWithExports())
if(this->PolicyStatusCMP0022 != cmPolicies::OLD &&
this->PolicyStatusCMP0022 != cmPolicies::WARN)
{
// CMP0022 NEW behavior is to use INTERFACE_LINK_LIBRARIES.
linkIfaceProp = "INTERFACE_LINK_LIBRARIES";
explicitLibraries = this->GetProperty(linkIfaceProp.c_str());
}
else if(this->GetType() == cmTarget::SHARED_LIBRARY ||
this->IsExecutableWithExports())
{
// CMP0022 OLD behavior is to use LINK_INTERFACE_LIBRARIES if set on a
// shared lib or executable.
// Lookup the per-configuration property.
linkIfaceProp = "LINK_INTERFACE_LIBRARIES";
linkIfaceProp += suffix;
@ -5047,126 +5047,33 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface,
linkIfaceProp = "LINK_INTERFACE_LIBRARIES";
explicitLibraries = this->GetProperty(linkIfaceProp.c_str());
}
if (newExplicitLibraries
&& (!explicitLibraries ||
(explicitLibraries
&& strcmp(newExplicitLibraries, explicitLibraries) != 0)))
{
switch(this->GetPolicyStatusCMP0022())
{
case cmPolicies::WARN:
{
cmOStringStream w;
w << (this->Makefile->GetPolicies()
->GetPolicyWarning(cmPolicies::CMP0022)) << "\n"
<< "Target \"" << this->GetName() << "\" has a "
"INTERFACE_LINK_LIBRARIES property which differs from its "
<< linkIfaceProp << " properties."
"\n"
"INTERFACE_LINK_LIBRARIES:\n "
<< newExplicitLibraries
<< "\n"
<< linkIfaceProp << ":\n "
<< (explicitLibraries ? explicitLibraries : "(empty)") << "\n";
this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, w.str());
}
// Fall through
case cmPolicies::OLD:
break;
case cmPolicies::REQUIRED_IF_USED:
case cmPolicies::REQUIRED_ALWAYS:
case cmPolicies::NEW:
explicitLibraries = newExplicitLibraries;
linkIfaceProp = "INTERFACE_LINK_LIBRARIES";
break;
}
}
}
else if(this->GetType() == cmTarget::STATIC_LIBRARY)
{
if (newExplicitLibraries)
{
cmListFileBacktrace lfbt;
cmGeneratorExpression ge(lfbt);
cmGeneratorExpressionDAGChecker dagChecker(lfbt, this->GetName(),
"INTERFACE_LINK_LIBRARIES", 0, 0);
std::vector<std::string> ifaceLibs;
cmSystemTools::ExpandListArgument(
ge.Parse(newExplicitLibraries)->Evaluate(
this->Makefile,
config,
false,
headTarget,
this, &dagChecker), ifaceLibs);
LinkImplementation const* impl = this->GetLinkImplementation(config,
headTarget);
if (ifaceLibs != impl->Libraries)
{
switch(this->GetPolicyStatusCMP0022())
{
case cmPolicies::WARN:
{
std::string oldLibraries;
std::string newLibraries;
const char *sep = "";
for(std::vector<std::string>::const_iterator it
= impl->Libraries.begin(); it != impl->Libraries.end(); ++it)
{
oldLibraries += sep;
oldLibraries += *it;
sep = ";";
}
sep = "";
for(std::vector<std::string>::const_iterator it
= ifaceLibs.begin(); it != ifaceLibs.end(); ++it)
{
newLibraries += sep;
newLibraries += *it;
sep = ";";
}
cmOStringStream w;
w << (this->Makefile->GetPolicies()
->GetPolicyWarning(cmPolicies::CMP0022)) << "\n"
<< "Static library target \"" << this->GetName() << "\" has a "
"INTERFACE_LINK_LIBRARIES property. This should be preferred "
"as the source of the link interface for this library. "
"Ignoring the property and using the link implementation "
"as the link interface instead."
"\n"
"INTERFACE_LINK_LIBRARIES:\n "
<< newLibraries
<< "\n"
<< "Link implementation:\n "
<< oldLibraries << "\n";
this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, w.str());
}
// Fall through
case cmPolicies::OLD:
break;
case cmPolicies::REQUIRED_IF_USED:
case cmPolicies::REQUIRED_ALWAYS:
case cmPolicies::NEW:
explicitLibraries = newExplicitLibraries;
linkIfaceProp = "INTERFACE_LINK_LIBRARIES";
break;
}
}
else
{
iface.Libraries = impl->Libraries;
if(this->LinkLanguagePropagatesToDependents())
{
// Targets using this archive need its language runtime libraries.
iface.Languages = impl->Languages;
}
}
}
}
else if (this->GetType() == cmTarget::INTERFACE_LIBRARY)
if(explicitLibraries && this->PolicyStatusCMP0022 == cmPolicies::WARN &&
!this->Internal->PolicyWarnedCMP0022)
{
explicitLibraries = newExplicitLibraries;
linkIfaceProp = "INTERFACE_LINK_LIBRARIES";
// Compare the explicitly set old link interface properties to the
// preferred new link interface property one and warn if different.
const char* newExplicitLibraries =
this->GetProperty("INTERFACE_LINK_LIBRARIES");
if (newExplicitLibraries
&& strcmp(newExplicitLibraries, explicitLibraries) != 0)
{
cmOStringStream w;
w <<
(this->Makefile->GetPolicies()
->GetPolicyWarning(cmPolicies::CMP0022)) << "\n"
"Target \"" << this->GetName() << "\" has an "
"INTERFACE_LINK_LIBRARIES property which differs from its " <<
linkIfaceProp << " properties."
"\n"
"INTERFACE_LINK_LIBRARIES:\n"
" " << newExplicitLibraries << "\n" <<
linkIfaceProp << ":\n"
" " << (explicitLibraries ? explicitLibraries : "(empty)") << "\n";
this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, w.str());
this->Internal->PolicyWarnedCMP0022 = true;
}
}
// There is no implicit link interface for executables or modules
@ -5235,11 +5142,12 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface,
}
}
}
else if (this->GetPolicyStatusCMP0022() == cmPolicies::WARN
|| this->GetPolicyStatusCMP0022() == cmPolicies::OLD)
// The implementation shouldn't be the interface if CMP0022 is NEW. That
// way, the LINK_LIBRARIES property can be set directly without having to
// empty the INTERFACE_LINK_LIBRARIES
else if (this->PolicyStatusCMP0022 == cmPolicies::WARN
|| this->PolicyStatusCMP0022 == cmPolicies::OLD)
// If CMP0022 is NEW then the plain tll signature sets the
// INTERFACE_LINK_LIBRARIES, so if we get here then the project
// cleared the property explicitly and we should not fall back
// to the link implementation.
{
// The link implementation is the default link interface.
LinkImplementation const* impl = this->GetLinkImplementation(config,
@ -5252,6 +5160,70 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface,
// Targets using this archive need its language runtime libraries.
iface.Languages = impl->Languages;
}
if(this->PolicyStatusCMP0022 == cmPolicies::WARN &&
!this->Internal->PolicyWarnedCMP0022)
{
// Compare the link implementation fallback link interface to the
// preferred new link interface property and warn if different.
cmListFileBacktrace lfbt;
cmGeneratorExpression ge(lfbt);
cmGeneratorExpressionDAGChecker dagChecker(lfbt, this->GetName(),
"INTERFACE_LINK_LIBRARIES", 0, 0);
std::vector<std::string> ifaceLibs;
const char* newExplicitLibraries =
this->GetProperty("INTERFACE_LINK_LIBRARIES");
cmSystemTools::ExpandListArgument(
ge.Parse(newExplicitLibraries)->Evaluate(this->Makefile,
config,
false,
headTarget,
this, &dagChecker),
ifaceLibs);
if (ifaceLibs != impl->Libraries)
{
std::string oldLibraries;
std::string newLibraries;
const char *sep = "";
for(std::vector<std::string>::const_iterator it
= impl->Libraries.begin(); it != impl->Libraries.end(); ++it)
{
oldLibraries += sep;
oldLibraries += *it;
sep = ";";
}
sep = "";
for(std::vector<std::string>::const_iterator it
= ifaceLibs.begin(); it != ifaceLibs.end(); ++it)
{
newLibraries += sep;
newLibraries += *it;
sep = ";";
}
if(oldLibraries.empty())
{ oldLibraries = "(empty)"; }
if(newLibraries.empty())
{ newLibraries = "(empty)"; }
cmOStringStream w;
w <<
(this->Makefile->GetPolicies()
->GetPolicyWarning(cmPolicies::CMP0022)) << "\n"
"Target \"" << this->GetName() << "\" has an "
"INTERFACE_LINK_LIBRARIES property. "
"This should be preferred as the source of the link interface "
"for this library but because CMP0022 is not set CMake is "
"ignoring the property and using the link implementation "
"as the link interface instead."
"\n"
"INTERFACE_LINK_LIBRARIES:\n"
" " << newLibraries << "\n"
"Link implementation:\n"
" " << oldLibraries << "\n";
this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, w.str());
this->Internal->PolicyWarnedCMP0022 = true;
}
}
}
if(this->GetType() == cmTarget::STATIC_LIBRARY)

View File

@ -390,8 +390,14 @@ cmTargetLinkLibrariesCommand::HandleLibrary(const char* lib,
{
this->Makefile
->AddLinkLibraryForTarget(this->Target->GetName(), lib, llt);
if (this->CurrentProcessingState != ProcessingKeywordPublicInterface
&& this->CurrentProcessingState != ProcessingPlainPublicInterface)
if(this->CurrentProcessingState == ProcessingLinkLibraries)
{
this->Target->AppendProperty("INTERFACE_LINK_LIBRARIES",
this->Target->GetDebugGeneratorExpressions(lib, llt).c_str());
return true;
}
else if(this->CurrentProcessingState != ProcessingKeywordPublicInterface
&& this->CurrentProcessingState != ProcessingPlainPublicInterface)
{
if (this->Target->GetType() == cmTarget::STATIC_LIBRARY)
{

View File

@ -28,3 +28,10 @@ endif()
add_executable(staticlib_exe staticlib_exe.cpp)
target_link_libraries(staticlib_exe staticlib1)
add_library(onlyplainlib1 SHARED onlyplainlib1.cpp)
add_library(onlyplainlib2 SHARED onlyplainlib2.cpp)
target_link_libraries(onlyplainlib2 onlyplainlib1)
add_executable(onlyplainlib_user onlyplainlib_user.cpp)
target_link_libraries(onlyplainlib_user onlyplainlib2)

View File

@ -0,0 +1,13 @@
#include "onlyplainlib1.h"
OnlyPlainLib1::OnlyPlainLib1()
: result(0)
{
}
int OnlyPlainLib1::GetResult()
{
return result;
}

View File

@ -0,0 +1,14 @@
struct
#ifdef _WIN32
__declspec(dllexport)
#endif
OnlyPlainLib1
{
OnlyPlainLib1();
int GetResult();
private:
int result;
};

View File

@ -0,0 +1,8 @@
#include "onlyplainlib2.h"
OnlyPlainLib1 onlyPlainLib2()
{
OnlyPlainLib1 opl1;
return opl1;
}

View File

@ -0,0 +1,7 @@
#include "onlyplainlib1.h"
#ifdef _WIN32
__declspec(dllexport)
#endif
OnlyPlainLib1 onlyPlainLib2();

View File

@ -0,0 +1,7 @@
#include "onlyplainlib2.h"
int main(int argc, char **argv)
{
return onlyPlainLib2().GetResult();
}

View File

@ -0,0 +1 @@
^$

View File

@ -0,0 +1,7 @@
enable_language(CXX)
add_library(testLib empty_vs6_1.cpp)
add_executable(testExe empty_vs6_2.cpp)
target_link_libraries(testExe testLib)
export(TARGETS testExe FILE "${CMAKE_CURRENT_BINARY_DIR}/cmp0022NOWARN-exe.cmake")

View File

@ -0,0 +1 @@
^$

View File

@ -0,0 +1,8 @@
enable_language(CXX)
add_library(foo SHARED empty_vs6_1.cpp)
add_library(bar SHARED empty_vs6_2.cpp)
target_link_libraries(bar foo)
add_executable(zot empty.cpp)
target_link_libraries(zot bar)

View File

@ -3,14 +3,16 @@ CMake Warning \(dev\) in CMakeLists.txt:
interface. Run "cmake --help-policy CMP0022" for policy details. Use the
cmake_policy command to set the policy and suppress this warning.
Target "bar" has a INTERFACE_LINK_LIBRARIES property which differs from its
LINK_INTERFACE_LIBRARIES properties.
Target "bar" has an INTERFACE_LINK_LIBRARIES property. This should be
preferred as the source of the link interface for this library but because
CMP0022 is not set CMake is ignoring the property and using the link
implementation as the link interface instead.
INTERFACE_LINK_LIBRARIES:
foo
LINK_INTERFACE_LIBRARIES:
Link implementation:
\(empty\)

View File

@ -3,10 +3,10 @@ CMake Warning \(dev\) in CMakeLists.txt:
interface. Run "cmake --help-policy CMP0022" for policy details. Use the
cmake_policy command to set the policy and suppress this warning.
Static library target "bar" has a INTERFACE_LINK_LIBRARIES property. This
should be preferred as the source of the link interface for this library.
Ignoring the property and using the link implementation as the link
interface instead.
Target "bar" has an INTERFACE_LINK_LIBRARIES property. This should be
preferred as the source of the link interface for this library but because
CMP0022 is not set CMake is ignoring the property and using the link
implementation as the link interface instead.
INTERFACE_LINK_LIBRARIES:

View File

@ -1,10 +1,10 @@
CMake Warning \(dev\) in CMakeLists.txt:
^CMake Warning \(dev\) in CMakeLists.txt:
Policy CMP0022 is not set: INTERFACE_LINK_LIBRARIES defines the link
interface. Run "cmake --help-policy CMP0022" for policy details. Use the
cmake_policy command to set the policy and suppress this warning.
Target "bar" has a INTERFACE_LINK_LIBRARIES property which differs from its
LINK_INTERFACE_LIBRARIES properties.
Target "bar" has an INTERFACE_LINK_LIBRARIES property which differs from
its LINK_INTERFACE_LIBRARIES properties.
INTERFACE_LINK_LIBRARIES:

View File

@ -3,8 +3,8 @@ CMake Warning \(dev\) in CMakeLists.txt:
interface. Run "cmake --help-policy CMP0022" for policy details. Use the
cmake_policy command to set the policy and suppress this warning.
Target "bar" has a INTERFACE_LINK_LIBRARIES property which differs from its
LINK_INTERFACE_LIBRARIES properties.
Target "bar" has an INTERFACE_LINK_LIBRARIES property which differs from
its LINK_INTERFACE_LIBRARIES properties.
INTERFACE_LINK_LIBRARIES:

View File

@ -9,3 +9,8 @@ set_property(TARGET bar PROPERTY LINK_INTERFACE_LIBRARIES bat)
add_library(user empty.cpp)
target_link_libraries(user bar)
# Use "bar" again with a different "head" target to check
# that the warning does not appear again.
add_library(user2 empty_vs6_3.cpp)
target_link_libraries(user2 bar)

View File

@ -0,0 +1 @@
^$

View File

@ -0,0 +1,9 @@
enable_language(CXX)
cmake_policy(SET CMP0022 NEW)
add_library(testLib empty_vs6_1.cpp)
add_executable(testExe empty_vs6_2.cpp)
target_link_libraries(testExe testLib)
export(TARGETS testExe FILE "${CMAKE_CURRENT_BINARY_DIR}/cmp0022NEW-exe.cmake")

View File

@ -4,7 +4,10 @@ run_cmake(CMP0022-WARN)
run_cmake(CMP0022-WARN-tll)
run_cmake(CMP0022-WARN-static)
run_cmake(CMP0022-WARN-empty-old)
run_cmake(CMP0022-NOWARN-exe)
run_cmake(CMP0022-NOWARN-shared)
run_cmake(CMP0022-NOWARN-static)
run_cmake(CMP0022-NOWARN-static-link_libraries)
run_cmake(CMP0022-export)
run_cmake(CMP0022-export-exe)
run_cmake(CMP0022-install-export)

View File

@ -0,0 +1 @@
#include "empty.cpp"