Fix link line order when shared libraries are de-duplicated

Since commit v3.1.0-rc1~227^2~1 (De-duplicate shared library targets in
generated link lines, 2014-07-30) we de-duplicate shared library targets
on the link line.  However, some toolchains will fail linking if an
executable is linking to a shared library that is not used directly and
a static library that depends on the shared one.  The linker may not
keep the reference to the shared library the first time and then the
symbols needed by the static library may not be found.

Fix this by reversing the direction of the for loop that removes the
duplicate shared libraries, in order to ensure that the last occurrence
of the library is left instead of the first one.

Extend Tests/Dependency with a case covering this behavior.  Create an
executable that links to a shared library and a static library but only
needs the shared library as a dependency of the static library.

Co-Author: Brad King <brad.king@kitware.com>
This commit is contained in:
Daniele E. Domenichelli 2014-11-09 17:35:20 +01:00 committed by Brad King
parent 06c3b7a822
commit 4db31095e5
6 changed files with 46 additions and 4 deletions

View File

@ -263,21 +263,26 @@ cmComputeLinkDepends::Compute()
this->OrderLinkEntires(); this->OrderLinkEntires();
// Compute the final set of link entries. // Compute the final set of link entries.
// Iterate in reverse order so we can keep only the last occurrence
// of a shared library.
std::set<int> emmitted; std::set<int> emmitted;
for(std::vector<int>::const_iterator li = this->FinalLinkOrder.begin(); for(std::vector<int>::const_reverse_iterator
li != this->FinalLinkOrder.end(); ++li) li = this->FinalLinkOrder.rbegin(),
le = this->FinalLinkOrder.rend();
li != le; ++li)
{ {
int i = *li; int i = *li;
LinkEntry const& e = this->EntryList[i]; LinkEntry const& e = this->EntryList[i];
cmTarget const* t = e.Target; cmTarget const* t = e.Target;
// Entries that we know the linker will re-use for symbols // Entries that we know the linker will re-use do not need to be repeated.
// needed by later entries do not need to be repeated.
bool uniquify = t && t->GetType() == cmTarget::SHARED_LIBRARY; bool uniquify = t && t->GetType() == cmTarget::SHARED_LIBRARY;
if(!uniquify || emmitted.insert(i).second) if(!uniquify || emmitted.insert(i).second)
{ {
this->FinalLinkEntries.push_back(e); this->FinalLinkEntries.push_back(e);
} }
} }
// Reverse the resulting order since we iterated in reverse.
std::reverse(this->FinalLinkEntries.begin(), this->FinalLinkEntries.end());
// Display the final set. // Display the final set.
if(this->DebugMode) if(this->DebugMode)

View File

@ -51,3 +51,4 @@ add_subdirectory(Case1)
add_subdirectory(Case2) add_subdirectory(Case2)
add_subdirectory(Case3) add_subdirectory(Case3)
add_subdirectory(Case4) add_subdirectory(Case4)
add_subdirectory(Case5)

View File

@ -0,0 +1,8 @@
project(CASE5 C)
add_library(case5Foo SHARED foo.c)
add_library(case5Bar STATIC bar.c)
target_link_libraries(case5Bar case5Foo)
add_executable(case5 main.c)
target_link_libraries(case5 case5Foo case5Bar)

View File

@ -0,0 +1,12 @@
#ifdef _WIN32
__declspec(dllimport)
#endif
void foo(void);
#include <stdio.h>
void bar(void)
{
foo();
printf("bar()\n");
}

View File

@ -0,0 +1,9 @@
#include <stdio.h>
#ifdef _WIN32
__declspec(dllexport)
#endif
void foo(void)
{
printf("foo()\n");
}

View File

@ -0,0 +1,7 @@
void bar(void);
int main(int argc, char *argv[])
{
bar();
return 0;
}