|
|
@@ -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
|
|
|
@@ -59,20 +63,52 @@ void cmTarget::GenerateSourceFilesFromSourceLists( cmMakefile &mf)
|
|
|
LinkLibraries::iterator p = m_LinkLibraries.begin();
|
|
|
for (;p != m_LinkLibraries.end(); ++p)
|
|
|
{
|
|
|
- mf.ExpandVariablesInString(p->first);
|
|
|
+ mf.ExpandVariablesInString(p->first);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void cmTarget::MergeLibraries(const LinkLibraries &ll)
|
|
|
{
|
|
|
- typedef std::vector<std::pair<std::string,LinkLibraryType> > LinkLibraries;
|
|
|
+ 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() );
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
- LinkLibraries::const_iterator p = ll.begin();
|
|
|
- for (;p != ll.end(); ++p)
|
|
|
+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 )
|
|
|
{
|
|
|
- m_LinkLibraries.push_back(*p);
|
|
|
+ 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;
|
|
|
+}
|