BUG: Correct some of the dependency analysis code.

- Make sure the original link line is untouched
- Avoid duplicating the link line when supporting version < 1.4
- Make sure the cyclic dependencies and such are output correctly in
  complicated cases.
- Avoid outputing dependencies that are already satisfied on the original
  link line when possible.
This commit is contained in:
Amitha Perera 2002-05-10 13:35:42 -04:00
parent 6b08b83d89
commit 0e6b39e52f
18 changed files with 219 additions and 74 deletions

View File

@ -177,6 +177,34 @@ IF(BUILD_TESTING)
${CMake_BINARY_DIR}/Tests/Dependency/WOLibOut/Exec ${CMake_BINARY_DIR}/Tests/Dependency/WOLibOut/Exec
Dependency) Dependency)
ADD_TEST(dependency2 ${CMake_BINARY_DIR}/Source/cmaketest
${CMake_SOURCE_DIR}/Tests/Dependency
${CMake_BINARY_DIR}/Tests/Dependency/WithLibOut
exec2
${CMake_BINARY_DIR}/Tests/Dependency/WithLibOut/Exec2
Dependency CMAKE_ARGS -DLIBRARY_OUTPUT_PATH:PATH=${CMake_BINARY_DIR}/Tests/Dependency/WithLibOut/Lib)
ADD_TEST(dependency3 ${CMake_BINARY_DIR}/Source/cmaketest
${CMake_SOURCE_DIR}/Tests/Dependency
${CMake_BINARY_DIR}/Tests/Dependency/WithLibOut
exec3
${CMake_BINARY_DIR}/Tests/Dependency/WithLibOut/Exec3
Dependency CMAKE_ARGS -DLIBRARY_OUTPUT_PATH:PATH=${CMake_BINARY_DIR}/Tests/Dependency/WithLibOut/Lib)
ADD_TEST(dependency4 ${CMake_BINARY_DIR}/Source/cmaketest
${CMake_SOURCE_DIR}/Tests/Dependency
${CMake_BINARY_DIR}/Tests/Dependency/WithLibOut
exec4
${CMake_BINARY_DIR}/Tests/Dependency/WithLibOut/Exec4
Dependency CMAKE_ARGS -DLIBRARY_OUTPUT_PATH:PATH=${CMake_BINARY_DIR}/Tests/Dependency/WithLibOut/Lib)
ADD_TEST(linkline ${CMake_BINARY_DIR}/Source/cmaketest
${CMake_SOURCE_DIR}/Tests/LinkLine
${CMake_BINARY_DIR}/Tests/LinkLine
Exec
${CMake_BINARY_DIR}/Tests/LinkLine
LinkLine)
ENDIF (DART_ROOT) ENDIF (DART_ROOT)
ENDIF(BUILD_TESTING) ENDIF(BUILD_TESTING)

View File

@ -19,7 +19,7 @@
#include <map> #include <map>
#include <set> #include <set>
#include <cassert>
void cmTarget::GenerateSourceFilesFromSourceLists( cmMakefile &mf) void cmTarget::GenerateSourceFilesFromSourceLists( cmMakefile &mf)
@ -73,15 +73,17 @@ void cmTarget::MergeLinkLibraries( cmMakefile& mf,
const char *selfname, const char *selfname,
const LinkLibraries& libs ) const LinkLibraries& libs )
{ {
for( LinkLibraries::const_iterator i = libs.begin(); // Only add on libraries we haven't added on before.
i != libs.end(); ++i ) // Assumption: the global link libraries could only grow, never shrink
{ assert( libs.size() >= m_PrevLinkedLibraries.size() );
if(m_PrevLinkedLibraries.insert(i->first).second) LinkLibraries::const_iterator i = libs.begin();
i += m_PrevLinkedLibraries.size();
for( ; i != libs.end(); ++i )
{ {
// We call this so that the dependencies get written to the cache // We call this so that the dependencies get written to the cache
this->AddLinkLibrary( mf, selfname, i->first.c_str(), i->second ); this->AddLinkLibrary( mf, selfname, i->first.c_str(), i->second );
} }
} m_PrevLinkedLibraries = libs;
} }
void cmTarget::AddLinkDirectory(const char* d) void cmTarget::AddLinkDirectory(const char* d)
@ -231,8 +233,8 @@ cmTarget::AnalyzeLibDependencies( const cmMakefile& mf )
// 3. Create the new link line by simply emitting any dependencies that are // 3. Create the new link line by simply emitting any dependencies that are
// missing. Start from the back and keep adding. // missing. Start from the back and keep adding.
LinkLibraries newLinkLibraries = m_LinkLibraries;
std::set<cmStdString> done, visited; std::set<cmStdString> done, visited;
std::vector<std::string> newLinkLibraries;
for(LinkLibraries::reverse_iterator lib = m_LinkLibraries.rbegin(); for(LinkLibraries::reverse_iterator lib = m_LinkLibraries.rbegin();
lib != m_LinkLibraries.rend(); ++lib) lib != m_LinkLibraries.rend(); ++lib)
{ {
@ -240,21 +242,26 @@ cmTarget::AnalyzeLibDependencies( const cmMakefile& mf )
// if a variable expands to nothing. // if a variable expands to nothing.
if (lib->first.size() == 0) continue; if (lib->first.size() == 0) continue;
std::vector<std::string> link_line; // Emit all the dependencies that are not already satisfied on the
Emit( lib->first, dep_map, done, visited, link_line ); // original link line.
if( link_line.size() == 0 ) if( dep_map.find(lib->first) != dep_map.end() ) // does it have dependencies?
{ {
// everything for this library is already on the link line, but since const std::set<cmStdString>& dep_on = dep_map.find( lib->first )->second;
// we are not going to touch the user's link line, we will output the std::set<cmStdString>::iterator i;
// library anyway. for( i = dep_on.begin(); i != dep_on.end(); ++i )
newLinkLibraries.push_back( *lib ); {
if( satisfied[lib->first].end() == satisfied[lib->first].find( *i ) )
{
Emit( *i, dep_map, done, visited, newLinkLibraries );
} }
else }
{ }
for( std::vector<std::string>::reverse_iterator k = link_line.rbegin(); }
k != link_line.rend(); ++k )
{ // 4. Add the new libraries to the link line.
if( satisfied[lib->first].insert( *k ).second )
for( std::vector<std::string>::reverse_iterator k = newLinkLibraries.rbegin();
k != newLinkLibraries.rend(); ++k )
{ {
if( addLibDirs ) if( addLibDirs )
{ {
@ -284,12 +291,8 @@ cmTarget::AnalyzeLibDependencies( const cmMakefile& mf )
llt = cmTarget::OPTIMIZED; llt = cmTarget::OPTIMIZED;
} }
} }
newLinkLibraries.push_back( std::make_pair(*k,llt) ); m_LinkLibraries.push_back( std::make_pair(*k,llt) );
} }
}
}
}
m_LinkLibraries = newLinkLibraries;
} }

View File

@ -169,7 +169,7 @@ private:
TargetType m_TargetType; TargetType m_TargetType;
std::vector<cmSourceFile*> m_SourceFiles; std::vector<cmSourceFile*> m_SourceFiles;
LinkLibraries m_LinkLibraries; LinkLibraries m_LinkLibraries;
std::set<cmStdString> m_PrevLinkedLibraries; LinkLibraries m_PrevLinkedLibraries;
std::vector<std::string> m_LinkDirectories; std::vector<std::string> m_LinkDirectories;
bool m_InAll; bool m_InAll;
std::string m_InstallPath; std::string m_InstallPath;

View File

@ -3,23 +3,6 @@ PROJECT( Dependency )
# There is one executable that depends on eight libraries. The # There is one executable that depends on eight libraries. The
# system has the following dependency graph: # system has the following dependency graph:
# #
# +----------- NoDepC <---- EXECUTABLE ---+
# | | | |
# V | | |
# | | |
# NoDepA <----- NoDepB <-------+ | |
# | |
# ^ | V
# | |
# One <------ Four -----> Two <----- Five <---|----- SixB
# | | |
# ^ ^ ^ | ^ ^ | |
# | | +-----+ | \ | | |
# | | | | \ | | |
# +--------- Three <------+ --- SixA <----+ |
# | |
# | |
# +---------------------------------+
# NoDepA: # NoDepA:
# NoDepB: NoDepA # NoDepB: NoDepA
# NoDepC: NoDepA # NoDepC: NoDepA
@ -30,14 +13,20 @@ PROJECT( Dependency )
# Five: Two # Five: Two
# SixA: Two Five # SixA: Two Five
# SixB: Four Five # SixB: Four Five
# Exec: NoDepB NoDepC SixA SixB # Seven: Two
# Eight: Seven
# #
# The libraries One,...,Five have their dependencies explicitly # Exec: NoDepB NoDepC SixA SixB
# Exec2: Eight Five
# Exec3: Eight Five
# Exec4: Five Two
#
# The libraries One,...,Eight have their dependencies explicitly
# encoded. The libraries NoDepA,...,NoDepC do not. # encoded. The libraries NoDepA,...,NoDepC do not.
# #
# Although SixB does not depend on Two, there is a dependency listed # Although SixB does not depend on Two, there is a dependency listed
# in the corresponding CMakeLists.txt just because of commands used. # in the corresponding CMakeLists.txt just because of commands used.
SUBDIRS( NoDepA NoDepB NoDepC ) SUBDIRS( NoDepA NoDepB NoDepC )
SUBDIRS( One Two Three Four Five Six ) SUBDIRS( One Two Three Four Five Six Seven Eight )
SUBDIRS( Exec ) SUBDIRS( Exec Exec2 Exec3 Exec4 )

View File

@ -0,0 +1,3 @@
ADD_LIBRARY( Eight EightSrc.c )
TARGET_LINK_LIBRARIES( Eight Seven )

View File

@ -0,0 +1,6 @@
void SevenFunction();
void EightFunction()
{
SevenFunction();
}

View File

@ -0,0 +1,12 @@
# Here, Eight depends on Seven, which has the same dependencies as Five.
# If the dependencies of Five are emitted, and then we attempt to emit the
# dependencies of Seven, then we find that they have already been done. So:
# Original line: Eight Five
# Add deps of Five: Eight Five Two ... NoDepA
# Now, we must make sure that Seven gets inserted between Five and Two, and
# not at the end. Unfortunately, if we get it wrong, the test will only
# fail on a platform where the link order makes a difference.
LINK_LIBRARIES( Eight Five )
ADD_EXECUTABLE( exec2 ExecMain.c )

View File

@ -0,0 +1,14 @@
#include <stdio.h>
void FiveFunction();
void EightFunction();
int main( )
{
FiveFunction();
EightFunction();
printf("Dependency test executable ran successfully.\n");
return 0;
}

View File

@ -0,0 +1,6 @@
# Here, Five already has it's immediate dependency, Two satisfied. We must
# make sure Two gets output anyway, because Eight indirectly depends on it.
LINK_LIBRARIES( Five Two Eight Five )
ADD_EXECUTABLE( exec3 ExecMain.c )

View File

@ -0,0 +1,14 @@
#include <stdio.h>
void FiveFunction();
void EightFunction();
int main( )
{
FiveFunction();
EightFunction();
printf("Dependency test executable ran successfully.\n");
return 0;
}

View File

@ -0,0 +1,6 @@
# Even though Five's dependency on Two is explicitly satisfied, Two
# must be emitted again in order to satisfy a cyclic dependency on Three.
LINK_LIBRARIES( Five Two Five )
ADD_EXECUTABLE( exec4 ExecMain.c )

View File

@ -0,0 +1,14 @@
#include <stdio.h>
void FiveFunction();
void TwoFunction();
int main( )
{
FiveFunction();
TwoFunction();
printf("Dependency test executable ran successfully.\n");
return 0;
}

View File

@ -0,0 +1,3 @@
ADD_LIBRARY( Seven SevenSrc.c )
TARGET_LINK_LIBRARIES( Seven Two )

View File

@ -0,0 +1,6 @@
void TwoFunction();
void SevenFunction()
{
TwoFunction();
}

View File

@ -0,0 +1,12 @@
PROJECT( LinkLine )
# Makes sure that the library order as specified by the user are
# unchanged by dependency analysis, etc. libOne and libTwo are
# dependent on each other. The link line should be -lOne -lTwo -lOne.
ADD_LIBRARY( One One.c )
ADD_LIBRARY( Two Two.c )
LINK_LIBRARIES( One Two )
ADD_EXECUTABLE( Exec Exec.c )
LINK_LIBRARIES( One )

9
Tests/LinkLine/Exec.c Normal file
View File

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

10
Tests/LinkLine/One.c Normal file
View File

@ -0,0 +1,10 @@
void TwoFunc();
void OneFunc()
{
static int i = 0;
++i;
if( i==1 ) {
TwoFunc();
}
}

10
Tests/LinkLine/Two.c Normal file
View File

@ -0,0 +1,10 @@
void OneFunc();
void TwoFunc()
{
static int i = 0;
++i;
if( i==1 ) {
OneFunc();
}
}