ENH: Add library dependency analysis.
This commit is contained in:
parent
d53458de9a
commit
1f8df8585e
|
@ -162,6 +162,14 @@ IF(BUILD_TESTING)
|
|||
${CMake_BINARY_DIR}/Tests/Wrapping/bin
|
||||
TestDriverTest subdir/test3)
|
||||
|
||||
ADD_TEST(dependency ${CMake_BINARY_DIR}/Source/cmaketest
|
||||
${CMake_SOURCE_DIR}/Tests/Dependency
|
||||
${CMake_BINARY_DIR}/Tests/Dependency
|
||||
exec
|
||||
${CMake_BINARY_DIR}/Tests/Dependency/Exec
|
||||
Dependency)
|
||||
|
||||
ENDIF (DART_ROOT)
|
||||
ENDIF(BUILD_TESTING)
|
||||
|
||||
|
||||
|
|
|
@ -653,8 +653,8 @@ void cmDSPWriter::WriteDSPHeader(std::ostream& fout, const char *libName,
|
|||
libMultiLineOptions += " \n";
|
||||
}
|
||||
}
|
||||
std::vector<std::string>::iterator i;
|
||||
std::vector<std::string>& libdirs = m_Makefile->GetLinkDirectories();
|
||||
std::vector<std::string>::const_iterator i;
|
||||
const std::vector<std::string>& libdirs = target.GetLinkDirectories();
|
||||
for(i = libdirs.begin(); i != libdirs.end(); ++i)
|
||||
{
|
||||
std::string path = *i;
|
||||
|
|
|
@ -169,8 +169,7 @@ void cmDSWWriter::WriteDSWFile(std::ostream& fout)
|
|||
}
|
||||
else
|
||||
{
|
||||
l->second.GetLinkLibraries().push_back(
|
||||
cmTarget::LinkLibraries::value_type(al->first, cmTarget::GENERAL));
|
||||
l->second.AddLinkLibrary(al->first, cmTarget::GENERAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -240,9 +240,7 @@ void cmMSDotNETGenerator::WriteSLNFile(std::ostream& fout)
|
|||
}
|
||||
else
|
||||
{
|
||||
l->second.GetLinkLibraries().push_back(
|
||||
cmTarget::LinkLibraries::value_type(al->first,
|
||||
cmTarget::GENERAL));
|
||||
l->second.AddLinkLibrary(al->first,cmTarget::GENERAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -907,7 +905,7 @@ void cmMSDotNETGenerator::OutputModuleDefinitionFile(std::ostream& fout,
|
|||
void cmMSDotNETGenerator::OutputLibraryDirectories(std::ostream& fout,
|
||||
const char*,
|
||||
const char*,
|
||||
const cmTarget &)
|
||||
const cmTarget &tgt)
|
||||
{
|
||||
bool hasone = false;
|
||||
if(m_LibraryOutputPath.size())
|
||||
|
@ -922,8 +920,8 @@ void cmMSDotNETGenerator::OutputLibraryDirectories(std::ostream& fout,
|
|||
}
|
||||
|
||||
std::set<std::string> pathEmitted;
|
||||
std::vector<std::string>::iterator i;
|
||||
std::vector<std::string>& libdirs = m_Makefile->GetLinkDirectories();
|
||||
std::vector<std::string>::const_iterator i;
|
||||
const std::vector<std::string>& libdirs = tgt.GetLinkDirectories();
|
||||
for(i = libdirs.begin(); i != libdirs.end(); ++i)
|
||||
{
|
||||
std::string lpath = *i;
|
||||
|
|
|
@ -429,6 +429,8 @@ void cmMakefile::GenerateMakefile()
|
|||
{
|
||||
l->second.GenerateSourceFilesFromSourceLists(*this);
|
||||
l->second.MergeLibraries(m_LinkLibraries);
|
||||
l->second.MergeDirectories(m_LinkDirectories);
|
||||
l->second.AnalyzeLibDependencies(*this);
|
||||
}
|
||||
// now do the generation
|
||||
m_MakefileGenerator->GenerateMakefile();
|
||||
|
@ -521,9 +523,7 @@ void cmMakefile::AddLinkLibraryForTarget(const char *target,
|
|||
{
|
||||
if (m_Targets.find(target) != m_Targets.end())
|
||||
{
|
||||
m_Targets[target].GetLinkLibraries().
|
||||
push_back(
|
||||
std::pair<std::string, cmTarget::LinkLibraryType>(lib,llt));
|
||||
m_Targets[target].AddLinkLibrary( *this, target, lib, llt );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -695,6 +695,15 @@ void cmMakefile::AddLibrary(const char* lname, int shared,
|
|||
"Whether a library is static, shared or module.",
|
||||
cmCacheManager::INTERNAL);
|
||||
}
|
||||
|
||||
// Clear its dependencies. Otherwise, dependencies might persist
|
||||
// over changes in CMakeLists.txt, making the information stale and
|
||||
// hence useless.
|
||||
std::string depname = lname;
|
||||
depname += "_LIB_DEPENDS";
|
||||
cmCacheManager::GetInstance()->
|
||||
AddCacheEntry(depname.c_str(), "",
|
||||
"Dependencies for target", cmCacheManager::INTERNAL);
|
||||
}
|
||||
|
||||
void cmMakefile::AddExecutable(const char *exeName,
|
||||
|
@ -861,7 +870,7 @@ void cmMakefile::ExpandVariables()
|
|||
}
|
||||
}
|
||||
|
||||
bool cmMakefile::IsOn(const char* name)
|
||||
bool cmMakefile::IsOn(const char* name) const
|
||||
{
|
||||
const char* value = this->GetDefinition(name);
|
||||
return cmSystemTools::IsOn(value);
|
||||
|
|
|
@ -390,14 +390,6 @@ public:
|
|||
return m_IncludeDirectories;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of link directories in the build.
|
||||
*/
|
||||
std::vector<std::string>& GetLinkDirectories()
|
||||
{
|
||||
return m_LinkDirectories;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of source files in this makefile.
|
||||
*/
|
||||
|
@ -440,7 +432,7 @@ public:
|
|||
/** Test a boolean cache entry to see if it is true or false,
|
||||
* returns false if no entry defined.
|
||||
*/
|
||||
bool IsOn(const char* name);
|
||||
bool IsOn(const char* name) const;
|
||||
|
||||
/**
|
||||
* Get a list of preprocessor define flags.
|
||||
|
|
|
@ -578,8 +578,8 @@ void cmNMakeMakefileGenerator::OutputLinkLibraries(std::ostream& fout,
|
|||
|
||||
if (lib_path_opt.size())
|
||||
{
|
||||
std::vector<std::string>& libdirs = m_Makefile->GetLinkDirectories();
|
||||
for(std::vector<std::string>::iterator libDir = libdirs.begin();
|
||||
const std::vector<std::string>& libdirs = tgt.GetLinkDirectories();
|
||||
for(std::vector<std::string>::const_iterator libDir = libdirs.begin();
|
||||
libDir != libdirs.end(); ++libDir)
|
||||
{
|
||||
std::string libpath = ShortPath(libDir->c_str());
|
||||
|
|
|
@ -17,6 +17,10 @@
|
|||
#include "cmTarget.h"
|
||||
#include "cmMakefile.h"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
|
||||
void cmTarget::GenerateSourceFilesFromSourceLists( cmMakefile &mf)
|
||||
{
|
||||
// this is only done for non install targets
|
||||
|
@ -65,14 +69,46 @@ void cmTarget::GenerateSourceFilesFromSourceLists( cmMakefile &mf)
|
|||
|
||||
void cmTarget::MergeLibraries(const LinkLibraries &ll)
|
||||
{
|
||||
typedef std::vector<std::pair<std::string,LinkLibraryType> > LinkLibraries;
|
||||
|
||||
LinkLibraries::const_iterator p = ll.begin();
|
||||
for (;p != ll.end(); ++p)
|
||||
{
|
||||
m_LinkLibraries.push_back(*p);
|
||||
m_LinkLibraries.insert( m_LinkLibraries.end(), ll.begin(), ll.end() );
|
||||
}
|
||||
|
||||
void cmTarget::MergeDirectories(const std::vector<std::string> &ld)
|
||||
{
|
||||
m_LinkDirectories.insert( m_LinkDirectories.end(), ld.begin(), ld.end() );
|
||||
}
|
||||
|
||||
|
||||
void cmTarget::AddLinkLibrary(const std::string& lib,
|
||||
LinkLibraryType llt)
|
||||
{
|
||||
m_LinkLibraries.push_back( std::pair<std::string, cmTarget::LinkLibraryType>(lib,llt) );
|
||||
}
|
||||
|
||||
void cmTarget::AddLinkLibrary(cmMakefile& mf,
|
||||
const char *target, const char* lib,
|
||||
LinkLibraryType llt)
|
||||
{
|
||||
m_LinkLibraries.push_back( std::pair<std::string, cmTarget::LinkLibraryType>(lib,llt) );
|
||||
|
||||
// Add the explicit dependency information for this target. This is
|
||||
// simply a set of libraries separated by ";". There should always
|
||||
// be a trailing ";". These library names are not canonical, in that
|
||||
// they may be "-framework x", "-ly", "/path/libz.a", etc.
|
||||
std::string cache_name( target );
|
||||
cache_name += "_LIB_DEPENDS";
|
||||
std::string dependencies;
|
||||
const char* old_val = mf.GetDefinition( cache_name.c_str() );
|
||||
if( old_val )
|
||||
{
|
||||
dependencies += old_val;
|
||||
}
|
||||
if( dependencies.find( lib ) == std::string::npos )
|
||||
{
|
||||
dependencies += lib;
|
||||
dependencies += ";";
|
||||
}
|
||||
mf.AddCacheDefinition( cache_name.c_str(), dependencies.c_str(),
|
||||
"Dependencies for the target", cmCacheManager::INTERNAL );
|
||||
}
|
||||
|
||||
bool cmTarget::HasCxx() const
|
||||
|
@ -87,3 +123,264 @@ bool cmTarget::HasCxx() const
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cmTarget::AnalyzeLibDependencies( const cmMakefile& mf )
|
||||
{
|
||||
typedef std::map< std::string, std::pair<std::string,LinkLibraryType> > LibMap;
|
||||
typedef std::vector< std::string > LinkLine;
|
||||
|
||||
// Maps the canonical names to the full objects of m_LinkLibraries.
|
||||
LibMap lib_map;
|
||||
|
||||
// The list canonical names in the order they were orginally
|
||||
// specified on the link line (m_LinkLibraries).
|
||||
LinkLine lib_order;
|
||||
|
||||
// The dependency maps.
|
||||
DependencyMap dep_map, dep_map_implicit;
|
||||
|
||||
LinkLibraries::iterator lib;
|
||||
for(lib = m_LinkLibraries.begin(); lib != m_LinkLibraries.end(); ++lib)
|
||||
{
|
||||
// skip zero size library entries, this may happen
|
||||
// if a variable expands to nothing.
|
||||
if (lib->first.size() == 0) continue;
|
||||
|
||||
std::string cname = CanonicalLibraryName(lib->first);
|
||||
lib_map[ cname ] = *lib;
|
||||
lib_order.push_back( cname );
|
||||
}
|
||||
|
||||
// First, get the explicit dependencies for those libraries that
|
||||
// have specified them
|
||||
for( LibMap::iterator i = lib_map.begin(); i != lib_map.end(); ++i )
|
||||
{
|
||||
GatherDependencies( mf, i->first, dep_map );
|
||||
}
|
||||
|
||||
// For the rest, get implicit dependencies. A library x depends
|
||||
// implicitly on a library y if x appears before y on the link
|
||||
// line. However, x does not implicitly depend on y if y
|
||||
// *explicitly* depends on x [*1]--such cyclic dependencies must be
|
||||
// explicitly specified. Note that implicit dependency cycles can
|
||||
// still occur: "-lx -ly -lx" will generate a implicit dependency
|
||||
// cycle provided that neither x nor y have explicit dependencies.
|
||||
//
|
||||
// [*1] This prevents external libraries from depending on libraries
|
||||
// generated by this project.
|
||||
|
||||
for( LibMap::iterator i = lib_map.begin(); i != lib_map.end(); ++i )
|
||||
{
|
||||
if( dep_map.find( i->first ) == dep_map.end() )
|
||||
{
|
||||
LinkLine::iterator pos = std::find( lib_order.begin(), lib_order.end(), i->first );
|
||||
for( ; pos != lib_order.end(); ++pos )
|
||||
{
|
||||
std::set<std::string> visited;
|
||||
if( !DependsOn( *pos, i->first, dep_map, visited ) )
|
||||
{
|
||||
dep_map_implicit[ i->first ].insert( *pos );
|
||||
}
|
||||
}
|
||||
dep_map_implicit[ i->first ].erase( i->first ); // cannot depend on itself
|
||||
}
|
||||
}
|
||||
|
||||
// Combine all the depedency information
|
||||
// dep_map.insert( dep_map_implicit.begin(), dep_map_implicit.end() );
|
||||
// doesn't work under MSVC++.
|
||||
for( DependencyMap::iterator i = dep_map_implicit.begin();
|
||||
i != dep_map_implicit.end(); ++i )
|
||||
{
|
||||
dep_map[ i->first ] = i->second;
|
||||
}
|
||||
|
||||
// Create a new link line order.
|
||||
std::set<std::string> done, visited;
|
||||
std::vector<std::string> link_line;
|
||||
for( LibMap::iterator i = lib_map.begin(); i != lib_map.end(); ++i )
|
||||
{
|
||||
Emit( i->first, dep_map, done, visited, link_line );
|
||||
}
|
||||
|
||||
|
||||
// If LIBRARY_OUTPUT_PATH is not set, then we must add search paths
|
||||
// for all the new libraries added by the dependency analysis.
|
||||
const char* libOutPath = mf.GetDefinition("LIBRARY_OUTPUT_PATH");
|
||||
bool addLibDirs = (libOutPath==0 || strcmp(libOutPath,"")==0);
|
||||
|
||||
m_LinkLibraries.clear();
|
||||
for( std::vector<std::string>::reverse_iterator i = link_line.rbegin();
|
||||
i != link_line.rend(); ++i )
|
||||
{
|
||||
// Some of the libraries in the new link line may not have been in
|
||||
// the orginal link line, but were added by the dependency
|
||||
// analysis. For these libraries, we assume the GENERAL type and
|
||||
// add the name of the library.
|
||||
if( lib_map.find(*i) == lib_map.end() )
|
||||
{
|
||||
if( addLibDirs )
|
||||
{
|
||||
const char* libpath = mf.GetDefinition( i->c_str() );
|
||||
if( libpath )
|
||||
{
|
||||
// Don't add a link directory that is already present.
|
||||
if(std::find(m_LinkDirectories.begin(),
|
||||
m_LinkDirectories.end(), libpath) == m_LinkDirectories.end())
|
||||
{
|
||||
m_LinkDirectories.push_back(libpath);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_LinkLibraries.push_back( std::make_pair(*i,GENERAL) );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_LinkLibraries.push_back( lib_map[ *i ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string cmTarget::CanonicalLibraryName( const std::string& lib ) const
|
||||
{
|
||||
cmRegularExpression reg("((^[ \t]*\\-l)|(^[ \t]*\\-framework[ \t]*))(.+)");
|
||||
if(lib.find('/') != std::string::npos
|
||||
&& !reg.find(lib))
|
||||
{
|
||||
std::string dir, file;
|
||||
cmSystemTools::SplitProgramPath(lib.c_str(),
|
||||
dir, file);
|
||||
cmRegularExpression libname("lib(.*)(\\.so|\\.sl|\\.a|\\.dylib).*");
|
||||
cmRegularExpression libname_noprefix("(.*)(\\.so|\\.sl|\\.a|\\.dylib|\\.lib).*");
|
||||
if(libname.find(file))
|
||||
{
|
||||
return libname.match(1);
|
||||
}
|
||||
else if(libname_noprefix.find(file))
|
||||
{
|
||||
return libname_noprefix.match(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
return file;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!reg.find(lib))
|
||||
{
|
||||
return lib;
|
||||
}
|
||||
else
|
||||
{
|
||||
return reg.match(4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void cmTarget::Emit( const std::string& lib,
|
||||
const DependencyMap& dep_map,
|
||||
std::set<std::string>& emitted,
|
||||
std::set<std::string>& visited,
|
||||
std::vector<std::string>& link_line ) const
|
||||
{
|
||||
// It's already been emitted
|
||||
if( emitted.find(lib) != emitted.end() )
|
||||
return;
|
||||
|
||||
// If this library hasn't been visited before, then emit all its
|
||||
// dependencies before emitting the library itself. If it has been
|
||||
// visited before, then there is a dependency cycle. Just emit the
|
||||
// library itself, and let the recursion that got us here deal with
|
||||
// emitting the dependencies for the library.
|
||||
|
||||
if( visited.insert(lib).second )
|
||||
{
|
||||
if( dep_map.find(lib) != dep_map.end() ) // does it have dependencies?
|
||||
{
|
||||
const std::set<std::string>& dep_on = dep_map.find( lib )->second;
|
||||
std::set<std::string>::const_iterator i;
|
||||
for( i = dep_on.begin(); i != dep_on.end(); ++i )
|
||||
{
|
||||
Emit( *i, dep_map, emitted, visited, link_line );
|
||||
}
|
||||
}
|
||||
}
|
||||
link_line.push_back( lib );
|
||||
emitted.insert(lib);
|
||||
}
|
||||
|
||||
|
||||
void cmTarget::GatherDependencies( const cmMakefile& mf,
|
||||
const std::string& lib,
|
||||
DependencyMap& dep_map ) const
|
||||
{
|
||||
// If the library is already in the dependency map, then it has
|
||||
// already been fully processed.
|
||||
if( dep_map.find(lib) != dep_map.end() )
|
||||
return;
|
||||
|
||||
const char* deps = mf.GetDefinition( (lib+"_LIB_DEPENDS").c_str() );
|
||||
if( deps )
|
||||
{
|
||||
// Make sure this library is in the map, even if it has an empty
|
||||
// set of dependencies. This distinguishes the case of explicitly
|
||||
// no dependencies with that of unspecified dependencies.
|
||||
dep_map[lib];
|
||||
|
||||
// Parse the dependency information, which is simply a set of
|
||||
// libraries separated by ";". There is always a trailing ";".
|
||||
std::string depline = deps;
|
||||
std::string::size_type start = 0;
|
||||
std::string::size_type end;
|
||||
end = depline.find( ";", start );
|
||||
while( end != std::string::npos )
|
||||
{
|
||||
std::string l = depline.substr( start, end-start );
|
||||
if( l.size() != 0 )
|
||||
{
|
||||
const std::string cname = CanonicalLibraryName(l);
|
||||
dep_map[ lib ].insert( cname );
|
||||
GatherDependencies( mf, cname, dep_map );
|
||||
}
|
||||
start = end+1; // skip the ;
|
||||
end = depline.find( ";", start );
|
||||
}
|
||||
dep_map[lib].erase(lib); // cannot depend on itself
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool cmTarget::DependsOn( const std::string& lib1, const std::string& lib2,
|
||||
const DependencyMap& dep_map,
|
||||
std::set<std::string>& visited ) const
|
||||
{
|
||||
if( !visited.insert( lib1 ).second )
|
||||
return false; // already visited here
|
||||
|
||||
if( lib1 == lib2 )
|
||||
return false;
|
||||
|
||||
if( dep_map.find(lib1) == dep_map.end() )
|
||||
return false; // lib1 doesn't have any dependencies
|
||||
|
||||
const std::set<std::string>& dep_set = dep_map.find(lib1)->second;
|
||||
|
||||
if( dep_set.end() != dep_set.find( lib2 ) )
|
||||
return true; // lib1 doesn't directly depend on lib2.
|
||||
|
||||
// Do a recursive check: does lib1 depend on x which depends on lib2?
|
||||
for( std::set<std::string>::const_iterator itr = dep_set.begin();
|
||||
itr != dep_set.end(); ++itr )
|
||||
{
|
||||
if( DependsOn( *itr, lib2, dep_map, visited ) )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -79,7 +79,8 @@ public:
|
|||
enum LinkLibraryType {GENERAL, DEBUG, OPTIMIZED};
|
||||
typedef std::vector<std::pair<std::string,LinkLibraryType> > LinkLibraries;
|
||||
const LinkLibraries &GetLinkLibraries() const {return m_LinkLibraries;}
|
||||
LinkLibraries &GetLinkLibraries() {return m_LinkLibraries;}
|
||||
|
||||
const std::vector<std::string>& GetLinkDirectories() const {return m_LinkDirectories;}
|
||||
|
||||
/**
|
||||
* Set the path where this target should be installed. This is relative to
|
||||
|
@ -88,11 +89,23 @@ public:
|
|||
std::string GetInstallPath() const {return m_InstallPath;}
|
||||
void SetInstallPath(const char *name) {m_InstallPath = name;}
|
||||
|
||||
void AddLinkLibrary(cmMakefile& mf,
|
||||
const char *target, const char* lib,
|
||||
LinkLibraryType llt);
|
||||
|
||||
void AddLinkLibrary(const std::string& lib,
|
||||
LinkLibraryType llt);
|
||||
|
||||
/**
|
||||
* Merge Link Libraries into this targets current list
|
||||
*/
|
||||
void MergeLibraries(const LinkLibraries &ll);
|
||||
|
||||
/**
|
||||
* Merge Link Directories into this targets current list
|
||||
*/
|
||||
void MergeDirectories(const std::vector<std::string> &ld);
|
||||
|
||||
/**
|
||||
* Generate the SourceFilesList from the SourceLists. This should only be
|
||||
* done once to be safe.
|
||||
|
@ -107,12 +120,59 @@ public:
|
|||
///! Get the utilities used by this target
|
||||
std::set<std::string>const& GetUtilities() const { return m_Utilities; }
|
||||
|
||||
void AnalyzeLibDependencies( const cmMakefile& mf );
|
||||
|
||||
private:
|
||||
/**
|
||||
* This map holds the dependency graph. map[x] returns a set of
|
||||
* direct dependencies of x.
|
||||
*/
|
||||
typedef std::map< std::string, std::set< std::string > > DependencyMap;
|
||||
|
||||
/**
|
||||
* For each library in the link line, return a canonical name. The
|
||||
* orginal library names have complicated forms, such as "x",
|
||||
* "libx.so", "/full/path/libx.a", "-lx", and "-framework x".
|
||||
*/
|
||||
std::string CanonicalLibraryName( const std::string& lib ) const;
|
||||
|
||||
/**
|
||||
* Emits the library \param lib and all its dependencies into
|
||||
* link_line. \param emitted keeps track of the libraries that have
|
||||
* been emitted to avoid duplicates--it is more efficient than
|
||||
* searching link_line. \param visited is used detect cycles. Note
|
||||
* that \param link_line is in reverse order, in that the
|
||||
* dependencies of a library are listed before the library itself.
|
||||
*/
|
||||
void Emit( const std::string& lib,
|
||||
const DependencyMap& dep_map,
|
||||
std::set<std::string>& emitted,
|
||||
std::set<std::string>& visited,
|
||||
std::vector<std::string>& link_line ) const;
|
||||
|
||||
/**
|
||||
* Finds the explicit dependencies for \param lib, if they have been
|
||||
* specified, and inserts them into \param dep_map.
|
||||
*/
|
||||
void GatherDependencies( const cmMakefile& mf, const std::string& lib,
|
||||
DependencyMap& dep_map ) const;
|
||||
|
||||
/**
|
||||
* Returns true if lib1 depends on lib2 according to \param
|
||||
* dep_map. \param visited is used to prevent infinite loops when
|
||||
* cycles are present.
|
||||
*/
|
||||
bool DependsOn( const std::string& lib1, const std::string& lib2,
|
||||
const DependencyMap& dep_map,
|
||||
std::set<std::string>& visited ) const;
|
||||
|
||||
private:
|
||||
std::vector<cmCustomCommand> m_CustomCommands;
|
||||
std::vector<std::string> m_SourceLists;
|
||||
TargetType m_TargetType;
|
||||
std::vector<cmSourceFile*> m_SourceFiles;
|
||||
LinkLibraries m_LinkLibraries;
|
||||
std::vector<std::string> m_LinkDirectories;
|
||||
bool m_InAll;
|
||||
std::string m_InstallPath;
|
||||
std::set<std::string> m_Utilities;
|
||||
|
|
|
@ -480,8 +480,8 @@ void cmUnixMakefileGenerator::OutputLinkLibraries(std::ostream& fout,
|
|||
|
||||
// collect all the flags needed for linking libraries
|
||||
std::string linkLibs;
|
||||
std::vector<std::string>& libdirs = m_Makefile->GetLinkDirectories();
|
||||
for(std::vector<std::string>::iterator libDir = libdirs.begin();
|
||||
const std::vector<std::string>& libdirs = tgt.GetLinkDirectories();
|
||||
for(std::vector<std::string>::const_iterator libDir = libdirs.begin();
|
||||
libDir != libdirs.end(); ++libDir)
|
||||
{
|
||||
std::string libpath = this->ConvertToOutputPath(libDir->c_str());
|
||||
|
@ -564,11 +564,6 @@ void cmUnixMakefileGenerator::OutputLinkLibraries(std::ostream& fout,
|
|||
|
||||
linkLibs += librariesLinked;
|
||||
|
||||
if(!targetLibrary)
|
||||
{
|
||||
// For executables, add these a second time so order does not matter
|
||||
linkLibs += librariesLinked;
|
||||
}
|
||||
fout << linkLibs;
|
||||
|
||||
if(outputRuntime && runtimeDirs.size()>0)
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
PROJECT( Dependency )
|
||||
|
||||
SET( LIBRARY_OUTPUT_PATH ${Dependency_BINARY_DIR}/Lib )
|
||||
SET( CMAKE_ANALYZE_LIB_DEPENDS "ON" )
|
||||
|
||||
# There is one executable that depends on eight libraries. The
|
||||
# system has the following dependency graph:
|
||||
#
|
||||
# +----------- NoDepC <---- EXECUTABLE
|
||||
# | | |
|
||||
# V | |
|
||||
# | |
|
||||
# NoDepA <----- NoDepB <-------+ |
|
||||
# |
|
||||
# ^ |
|
||||
# | |
|
||||
# One <------ Four -----> Two <----- Five <---+
|
||||
# |
|
||||
# ^ ^ |
|
||||
# | | |
|
||||
# +--------- Three <-------+
|
||||
#
|
||||
# NoDepA:
|
||||
# NoDepB: NoDepA
|
||||
# NoDepC: NoDepA
|
||||
# One:
|
||||
# Two: Three
|
||||
# Three: One Four
|
||||
# Four: One Two A
|
||||
# Five: Two
|
||||
# Exec: NoDepB NoDepC Five
|
||||
#
|
||||
# The libraries One,...,Five have their dependencies explicitly
|
||||
# encoded. The libraries NoDepA,...,NoDepC do not.
|
||||
|
||||
SUBDIRS( NoDepA NoDepB NoDepC )
|
||||
SUBDIRS( One Two Three Four Five )
|
||||
SUBDIRS( Exec )
|
|
@ -0,0 +1,6 @@
|
|||
ADD_EXECUTABLE( exec ExecMain.c )
|
||||
|
||||
# This executable directly depends on NoDepB, NoDepC and Five. However,
|
||||
# since NoDepB and NoDepC do not have explicit dependency information,
|
||||
# and they depend on NoDepA, we have to manually specify that dependency.
|
||||
LINK_LIBRARIES( NoDepB NoDepC NoDepA Five )
|
|
@ -0,0 +1,16 @@
|
|||
#include <stdio.h>
|
||||
|
||||
void NoDepBFunction();
|
||||
void NoDepCFunction();
|
||||
void FiveFunction();
|
||||
|
||||
int main( )
|
||||
{
|
||||
FiveFunction();
|
||||
NoDepBFunction();
|
||||
NoDepCFunction();
|
||||
|
||||
printf("Dependency test executable ran successfully.\n");
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
ADD_LIBRARY( Five FiveSrc.c )
|
||||
TARGET_LINK_LIBRARIES( Five Two )
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
void TwoFunction();
|
||||
|
||||
void FiveFunction()
|
||||
{
|
||||
TwoFunction();
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
ADD_LIBRARY( Four FourSrc.c )
|
||||
TARGET_LINK_LIBRARIES( Four One Two NoDepA )
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
void NoDepAFunction();
|
||||
void OneFunction();
|
||||
void TwoFunction();
|
||||
|
||||
void FourFunction()
|
||||
{
|
||||
static int count = 0;
|
||||
if( count == 0 ) {
|
||||
++count;
|
||||
TwoFunction();
|
||||
}
|
||||
OneFunction();
|
||||
NoDepAFunction();
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
ADD_LIBRARY( NoDepA NoDepASrc.c )
|
|
@ -0,0 +1,3 @@
|
|||
void NoDepAFunction()
|
||||
{
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
ADD_LIBRARY( NoDepB NoDepBSrc.c )
|
||||
# This library depends on NoDepA, but the
|
||||
# dependency is not explicitly specified.
|
|
@ -0,0 +1,6 @@
|
|||
void NoDepAFunction();
|
||||
|
||||
void NoDepBFunction()
|
||||
{
|
||||
NoDepAFunction();
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
ADD_LIBRARY( NoDepC NoDepCSrc.c )
|
||||
# This library depends on NoDepA, but the
|
||||
# dependency is not explicitly specified.
|
|
@ -0,0 +1,6 @@
|
|||
void NoDepAFunction();
|
||||
|
||||
void NoDepCFunction()
|
||||
{
|
||||
NoDepAFunction();
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
ADD_LIBRARY( One OneSrc.c )
|
||||
# This library has no dependencies
|
||||
TARGET_LINK_LIBRARIES( One "" )
|
|
@ -0,0 +1,3 @@
|
|||
void OneFunction()
|
||||
{
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
ADD_LIBRARY( Three ThreeSrc.c )
|
||||
TARGET_LINK_LIBRARIES( Three One Four )
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
void OneFunction();
|
||||
void FourFunction();
|
||||
|
||||
void ThreeFunction()
|
||||
{
|
||||
static int count = 0;
|
||||
if( count == 0 ) {
|
||||
++count;
|
||||
FourFunction();
|
||||
}
|
||||
OneFunction();
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
ADD_LIBRARY( Two TwoSrc.c )
|
||||
TARGET_LINK_LIBRARIES( Two Three )
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
void ThreeFunction();
|
||||
|
||||
void TwoFunction()
|
||||
{
|
||||
static int count = 0;
|
||||
if( count == 0 ) {
|
||||
++count;
|
||||
ThreeFunction();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue