/*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: $RCSfile$ Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) 2002 Insight Consortium. All rights reserved. See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "cmTarget.h" #include "cmMakefile.h" #include #include void cmTarget::GenerateSourceFilesFromSourceLists( cmMakefile &mf) { // this is only done for non install targets if ((this->m_TargetType == cmTarget::INSTALL_FILES) || (this->m_TargetType == cmTarget::INSTALL_PROGRAMS)) { return; } // for each src lists add the classes for (std::vector::const_iterator s = m_SourceLists.begin(); s != m_SourceLists.end(); ++s) { // replace any variables std::string temps = *s; mf.ExpandVariablesInString(temps); // look for a srclist if (mf.GetSources().find(temps) != mf.GetSources().end()) { const std::vector &clsList = mf.GetSources().find(temps)->second; // if we ahave a limited build list, use it m_SourceFiles.insert(m_SourceFiles.end(), clsList.begin(), clsList.end()); } // if one wasn't found then assume it is a single class else { cmSourceFile file; file.SetIsAnAbstractClass(false); file.SetName(temps.c_str(), mf.GetCurrentDirectory(), mf.GetSourceExtensions(), mf.GetHeaderExtensions()); m_SourceFiles.push_back(mf.AddSource(file)); } } // expand any link library variables whle we are at it LinkLibraries::iterator p = m_LinkLibraries.begin(); for (;p != m_LinkLibraries.end(); ++p) { mf.ExpandVariablesInString(p->first); } } void cmTarget::AddLinkLibrary(const std::string& lib, LinkLibraryType llt) { m_LinkLibraries.push_back( std::pair(lib,llt) ); } void cmTarget::AddLinkLibrary(cmMakefile& mf, const char *target, const char* lib, LinkLibraryType llt) { m_LinkLibraries.push_back( std::pair(lib,llt) ); mf.AddDependencyToCache( target, lib ); } bool cmTarget::HasCxx() const { for(std::vector::const_iterator i = m_SourceFiles.begin(); i != m_SourceFiles.end(); ++i) { if((*i)->GetSourceExtension() != "c") { return true; } } return false; } void cmTarget::AnalyzeLibDependencies( const cmMakefile& mf ) { typedef std::map< std::string, std::pair > 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 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 done, visited; std::vector 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::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& emitted, std::set& visited, std::vector& 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& dep_on = dep_map.find( lib )->second; std::set::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 && strcmp(deps,"") != 0 ) { // 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& 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& 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::const_iterator itr = dep_set.begin(); itr != dep_set.end(); ++itr ) { if( DependsOn( *itr, lib2, dep_map, visited ) ) return true; } return false; }