Tolerate cycles in shared library link interfaces (#12647)

Since commit 183b9509 (Follow all dependencies of shared library private
dependencies, 2011-12-14) we honor LINK_INTERFACE_LIBRARIES when
following dependent shared libraries.  The link interface properties may
form a cycle if set incorrectly by a project.  Furthermore, the property
LINK_DEPENDENT_LIBRARIES may form a cycle if set incorrectly by hand
(though CMake should never generate one).  In either case, do not follow
the cycle forever when following the dependent shared library closure.
We only need to add dependency edges to the constraint graph once.

Add "LinkInterfaceLoop" test to cover this case.
This commit is contained in:
Brad King 2012-01-12 10:22:00 -05:00
parent 9a20abf04a
commit 8e756d2b9b
6 changed files with 55 additions and 3 deletions

View File

@ -358,7 +358,7 @@ void cmComputeLinkDepends::FollowLinkEntry(BFSEntry const& qe)
this->AddLinkEntries(depender_index, iface->Libraries); this->AddLinkEntries(depender_index, iface->Libraries);
// Handle dependent shared libraries. // Handle dependent shared libraries.
this->QueueSharedDependencies(depender_index, iface->SharedDeps); this->FollowSharedDeps(depender_index, iface);
// Support for CMP0003. // Support for CMP0003.
for(std::vector<std::string>::const_iterator for(std::vector<std::string>::const_iterator
@ -376,6 +376,23 @@ void cmComputeLinkDepends::FollowLinkEntry(BFSEntry const& qe)
} }
} }
//----------------------------------------------------------------------------
void
cmComputeLinkDepends
::FollowSharedDeps(int depender_index, cmTarget::LinkInterface const* iface,
bool follow_interface)
{
// Follow dependencies if we have not followed them already.
if(this->SharedDepFollowed.insert(depender_index).second)
{
if(follow_interface)
{
this->QueueSharedDependencies(depender_index, iface->Libraries);
}
this->QueueSharedDependencies(depender_index, iface->SharedDeps);
}
}
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void void
cmComputeLinkDepends cmComputeLinkDepends
@ -430,8 +447,7 @@ void cmComputeLinkDepends::HandleSharedDependency(SharedDepEntry const& dep)
entry.Target->GetLinkInterface(this->Config)) entry.Target->GetLinkInterface(this->Config))
{ {
// Follow public and private dependencies transitively. // Follow public and private dependencies transitively.
this->QueueSharedDependencies(index, iface->Libraries); this->FollowSharedDeps(index, iface, true);
this->QueueSharedDependencies(index, iface->SharedDeps);
} }
} }
} }

View File

@ -105,6 +105,10 @@ private:
int DependerIndex; int DependerIndex;
}; };
std::queue<SharedDepEntry> SharedDepQueue; std::queue<SharedDepEntry> SharedDepQueue;
std::set<int> SharedDepFollowed;
void FollowSharedDeps(int depender_index,
cmTarget::LinkInterface const* iface,
bool follow_interface = false);
void QueueSharedDependencies(int depender_index, void QueueSharedDependencies(int depender_index,
std::vector<std::string> const& deps); std::vector<std::string> const& deps);
void HandleSharedDependency(SharedDepEntry const& dep); void HandleSharedDependency(SharedDepEntry const& dep);

View File

@ -7,3 +7,6 @@ macro(add_CMakeOnly_test test)
-P ${CMAKE_CURRENT_BINARY_DIR}/Test.cmake -P ${CMAKE_CURRENT_BINARY_DIR}/Test.cmake
) )
endmacro() endmacro()
add_CMakeOnly_test(LinkInterfaceLoop)
set_property(TEST CMakeOnly.LinkInterfaceLoop PROPERTY TIMEOUT 90)

View File

@ -0,0 +1,27 @@
cmake_minimum_required (VERSION 2.8)
project(LinkInterfaceLoop C)
# Add a shared library that incorrectly names itself as a
# dependency, thus forming a cycle.
add_library(A SHARED IMPORTED)
set_target_properties(A PROPERTIES
IMPORTED_LINK_DEPENDENT_LIBRARIES A
IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/dirA/A"
)
# Add a shared library that incorrectly names itself in
# its link interface, thus forming a cycle.
add_library(B SHARED IMPORTED)
set_target_properties(B PROPERTIES
IMPORTED_LINK_INTERFACE_LIBRARIES B
IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/dirB/B"
)
# Add a shared library with an empty link interface
# that depends on two shared libraries.
add_library(C SHARED lib.c)
set_property(TARGET C PROPERTY LINK_INTERFACE_LIBRARIES "")
target_link_libraries(C B A)
add_executable(main main.c)
target_link_libraries(main C)

View File

@ -0,0 +1 @@
int lib(void) { return 0; }

View File

@ -0,0 +1 @@
int main(void) { return 0; }