2005-02-24 21:16:41 +03:00
# include "cmOrderLinkDirectories.h"
# include "cmSystemTools.h"
# include "cmsys/RegularExpression.hxx"
2005-04-08 20:46:56 +04:00
# include <ctype.h>
2005-02-24 21:16:41 +03:00
2005-03-04 02:46:52 +03:00
//-------------------------------------------------------------------
cmOrderLinkDirectories : : cmOrderLinkDirectories ( )
{
m_Debug = false ;
}
2005-02-24 21:16:41 +03:00
//-------------------------------------------------------------------
bool cmOrderLinkDirectories : : LibraryInDirectory ( const char * dir ,
2005-02-24 23:36:56 +03:00
const char * libIn )
2005-02-24 21:16:41 +03:00
{
cmStdString path = dir ;
path + = " / " ;
2005-02-24 23:36:56 +03:00
path + = libIn ;
2005-02-24 21:16:41 +03:00
// first look for the library as given
if ( cmSystemTools : : FileExists ( path . c_str ( ) ) )
{
return true ;
}
// next remove the extension (.a, .so ) and look for the library
// under a different name as the linker can do either
2005-02-24 23:36:56 +03:00
if ( m_RemoveLibraryExtension . find ( libIn ) )
2005-02-24 21:16:41 +03:00
{
cmStdString lib = m_RemoveLibraryExtension . match ( 1 ) ;
cmStdString ext = m_RemoveLibraryExtension . match ( 2 ) ;
for ( std : : vector < cmStdString > : : iterator i = m_LinkExtensions . begin ( ) ;
i ! = m_LinkExtensions . end ( ) ; + + i )
{
if ( ext ! = * i )
{
path = dir ;
path + = " / " ;
path + = lib + * i ;
if ( cmSystemTools : : FileExists ( path . c_str ( ) ) )
{
return true ;
}
}
}
}
return false ;
}
//-------------------------------------------------------------------
void cmOrderLinkDirectories : : FindLibrariesInSeachPaths ( )
{
for ( std : : set < cmStdString > : : iterator dir = m_LinkPathSet . begin ( ) ;
dir ! = m_LinkPathSet . end ( ) ; + + dir )
{
for ( std : : map < cmStdString , Library > : : iterator lib
= m_FullPathLibraries . begin ( ) ;
lib ! = m_FullPathLibraries . end ( ) ; + + lib )
{
if ( lib - > second . Path ! = * dir )
{
2005-03-04 02:16:00 +03:00
if ( this - > LibraryInDirectory ( dir - > c_str ( ) , lib - > second . File . c_str ( ) ) )
2005-02-24 21:16:41 +03:00
{
m_LibraryToDirectories [ lib - > second . FullPath ] . push_back ( * dir ) ;
}
}
}
}
}
//-------------------------------------------------------------------
void cmOrderLinkDirectories : : FindIndividualLibraryOrders ( )
{
for ( std : : vector < Library > : : iterator lib = m_MultiDirectoryLibraries . begin ( ) ;
lib ! = m_MultiDirectoryLibraries . end ( ) ; + + lib )
{
std : : vector < cmStdString > & dirs = m_LibraryToDirectories [ lib - > FullPath ] ;
m_DirectoryToAfterList [ lib - > Path ] = dirs ;
}
}
2005-04-08 20:46:56 +04:00
//-------------------------------------------------------------------
std : : string cmOrderLinkDirectories : : NoCaseExpression ( const char * str )
{
std : : string ret ;
const char * s = str ;
while ( * s )
{
if ( * s = = ' . ' )
{
ret + = * s ;
}
else
{
ret + = " [ " ;
ret + = tolower ( * s ) ;
ret + = toupper ( * s ) ;
ret + = " ] " ;
}
s + + ;
}
return ret ;
}
2005-02-24 21:16:41 +03:00
//-------------------------------------------------------------------
void cmOrderLinkDirectories : : CreateRegularExpressions ( )
{
cmStdString libext = " ( " ;
bool first = true ;
for ( std : : vector < cmStdString > : : iterator i = m_LinkExtensions . begin ( ) ;
i ! = m_LinkExtensions . end ( ) ; + + i )
{
if ( ! first )
{
libext + = " | " ;
}
first = false ;
libext + = " \\ " ;
2005-04-08 20:46:56 +04:00
# ifndef _WIN32
2005-02-24 21:16:41 +03:00
libext + = * i ;
2005-04-08 20:46:56 +04:00
# else
libext + = this - > NoCaseExpression ( i - > c_str ( ) ) ;
# endif
2005-02-24 21:16:41 +03:00
}
libext + = " ).* " ;
cmStdString reg ( " (.*) " ) ;
reg + = libext ;
m_RemoveLibraryExtension . compile ( reg . c_str ( ) ) ;
reg = " ^lib([^/]*) " ;
reg + = libext ;
m_ExtractBaseLibraryName . compile ( reg . c_str ( ) ) ;
reg = " ([^/]*) " ;
reg + = libext ;
m_ExtractBaseLibraryNameNoPrefix . compile ( reg . c_str ( ) ) ;
}
//-------------------------------------------------------------------
void cmOrderLinkDirectories : : PrepareLinkTargets ( )
{
for ( std : : vector < cmStdString > : : iterator i = m_LinkItems . begin ( ) ;
i ! = m_LinkItems . end ( ) ; + + i )
{
// separate the library name from libfoo.a or foo.a
if ( m_ExtractBaseLibraryName . find ( * i ) )
{
* i = m_ExtractBaseLibraryName . match ( 1 ) ;
}
else if ( m_ExtractBaseLibraryNameNoPrefix . find ( * i ) )
{
* i = m_ExtractBaseLibraryNameNoPrefix . match ( 1 ) ;
}
}
}
//-------------------------------------------------------------------
2005-03-04 02:16:00 +03:00
bool cmOrderLinkDirectories : : FindPathNotInDirectoryToAfterList (
cmStdString & path )
2005-02-24 21:16:41 +03:00
{
2005-03-04 02:16:00 +03:00
for ( std : : map < cmStdString , std : : vector < cmStdString > > : : iterator i
= m_DirectoryToAfterList . begin ( ) ;
i ! = m_DirectoryToAfterList . end ( ) ; + + i )
2005-02-24 21:16:41 +03:00
{
2005-03-04 02:16:00 +03:00
const cmStdString & p = i - > first ;
bool found = false ;
for ( std : : map < cmStdString , std : : vector < cmStdString > > : : iterator j
= m_DirectoryToAfterList . begin ( ) ; j ! = m_DirectoryToAfterList . end ( )
& & ! found ; + + j )
2005-03-03 01:49:11 +03:00
{
2005-03-04 02:16:00 +03:00
if ( j ! = i )
{
found = ( std : : find ( j - > second . begin ( ) , j - > second . end ( ) , p ) ! = j - > second . end ( ) ) ;
}
2005-03-03 01:49:11 +03:00
}
2005-03-04 02:16:00 +03:00
if ( ! found )
2005-03-03 01:49:11 +03:00
{
2005-03-04 02:16:00 +03:00
path = p ;
m_DirectoryToAfterList . erase ( i ) ;
return true ;
2005-03-03 01:49:11 +03:00
}
2005-03-04 02:16:00 +03:00
}
path = " " ;
return false ;
2005-03-03 02:56:46 +03:00
}
2005-03-04 02:16:00 +03:00
2005-03-03 02:56:46 +03:00
//-------------------------------------------------------------------
void cmOrderLinkDirectories : : OrderPaths ( std : : vector < cmStdString > &
orderedPaths )
{
2005-03-04 02:16:00 +03:00
cmStdString path ;
// This is a topological sort implementation
// One at a time find paths that are not in any other paths after list
// and put them into the orderedPaths vector in that order
// FindPathNotInDirectoryToAfterList removes the path from the
// m_DirectoryToAfterList once it is found
while ( this - > FindPathNotInDirectoryToAfterList ( path ) )
{
orderedPaths . push_back ( path ) ;
}
// at this point if there are still paths in m_DirectoryToAfterList
// then there is a cycle and we are stuck
if ( m_DirectoryToAfterList . size ( ) )
{
for ( std : : map < cmStdString , std : : vector < cmStdString > > : : iterator i
= m_DirectoryToAfterList . begin ( ) ;
i ! = m_DirectoryToAfterList . end ( ) ; + + i )
{
m_ImposibleDirectories . insert ( i - > first ) ;
// still put it in the path list in the order we find them
orderedPaths . push_back ( i - > first ) ;
}
}
2005-02-24 21:16:41 +03:00
}
//-------------------------------------------------------------------
void cmOrderLinkDirectories : : SetLinkInformation ( const cmTarget & target ,
cmTarget : : LinkLibraryType
linktype ,
const char * targetLibrary )
{
// collect the search paths from the target into paths set
const std : : vector < std : : string > & searchPaths = target . GetLinkDirectories ( ) ;
2005-03-04 02:16:00 +03:00
std : : vector < cmStdString > empty ;
2005-02-24 21:16:41 +03:00
for ( std : : vector < std : : string > : : const_iterator p = searchPaths . begin ( ) ;
p ! = searchPaths . end ( ) ; + + p )
{
2005-03-04 02:16:00 +03:00
m_DirectoryToAfterList [ * p ] = empty ;
2005-02-24 21:16:41 +03:00
m_LinkPathSet . insert ( * p ) ;
}
// collect the link items from the target and put it into libs
const cmTarget : : LinkLibraries & tlibs = target . GetLinkLibraries ( ) ;
std : : vector < cmStdString > libs ;
for ( cmTarget : : LinkLibraries : : const_iterator lib = tlibs . begin ( ) ;
lib ! = tlibs . end ( ) ; + + lib )
{
// skip zero size library entries, this may happen
// if a variable expands to nothing.
if ( lib - > first . size ( ) = = 0 )
{
continue ;
}
// Don't link the library against itself!
if ( targetLibrary & & ( lib - > first = = targetLibrary ) )
{
continue ;
}
// use the correct lib for the current configuration
if ( lib - > second = = cmTarget : : DEBUG & & linktype ! = cmTarget : : DEBUG )
{
continue ;
}
if ( lib - > second = = cmTarget : : OPTIMIZED & &
linktype ! = cmTarget : : OPTIMIZED )
{
continue ;
}
m_RawLinkItems . push_back ( lib - > first ) ;
}
}
//-------------------------------------------------------------------
bool cmOrderLinkDirectories : : DetermineLibraryPathOrder ( )
{
// set up all the regular expressions
this - > CreateRegularExpressions ( ) ;
std : : vector < cmStdString > finalOrderPaths ;
// find all libs that are full paths
Library aLib ;
cmStdString dir ;
cmStdString file ;
2005-03-04 02:16:00 +03:00
std : : vector < cmStdString > empty ;
2005-02-24 21:16:41 +03:00
for ( unsigned int i = 0 ; i < m_RawLinkItems . size ( ) ; + + i )
{
if ( cmSystemTools : : FileIsFullPath ( m_RawLinkItems [ i ] . c_str ( ) ) )
{
cmSystemTools : : SplitProgramPath ( m_RawLinkItems [ i ] . c_str ( ) ,
dir , file ) ;
2005-03-04 02:16:00 +03:00
m_DirectoryToAfterList [ dir ] = empty ;
2005-02-24 21:16:41 +03:00
m_LinkPathSet . insert ( dir ) ;
aLib . FullPath = m_RawLinkItems [ i ] ;
aLib . File = file ;
aLib . Path = dir ;
m_FullPathLibraries [ aLib . FullPath ] = aLib ;
m_LinkItems . push_back ( file ) ;
}
else
{
m_LinkItems . push_back ( m_RawLinkItems [ i ] ) ;
}
}
this - > FindLibrariesInSeachPaths ( ) ;
for ( std : : map < cmStdString , std : : vector < cmStdString > > : : iterator lib =
m_LibraryToDirectories . begin ( ) ; lib ! = m_LibraryToDirectories . end ( ) ;
+ + lib )
{
if ( lib - > second . size ( ) > 0 )
{
m_MultiDirectoryLibraries . push_back ( m_FullPathLibraries [ lib - > first ] ) ;
}
else
{
m_SingleDirectoryLibraries . push_back ( m_FullPathLibraries [ lib - > first ] ) ;
}
}
this - > FindIndividualLibraryOrders ( ) ;
m_SortedSearchPaths . clear ( ) ;
2005-03-04 02:46:52 +03:00
if ( m_Debug )
{
this - > PrintMap ( " m_LibraryToDirectories " , m_LibraryToDirectories ) ;
this - > PrintMap ( " m_DirectoryToAfterList " , m_DirectoryToAfterList ) ;
}
2005-03-04 02:16:00 +03:00
this - > OrderPaths ( m_SortedSearchPaths ) ;
2005-02-24 21:16:41 +03:00
// now turn libfoo.a into foo and foo.a into foo
// This will prepare the link items for -litem
this - > PrepareLinkTargets ( ) ;
if ( m_ImposibleDirectories . size ( ) )
{
2005-02-26 01:45:12 +03:00
cmSystemTools : : Message ( this - > GetWarnings ( ) . c_str ( ) ) ;
2005-02-24 21:16:41 +03:00
return false ;
}
return true ;
}
std : : string cmOrderLinkDirectories : : GetWarnings ( )
{
std : : string warning = " It is impossible to order the linker search path in such a way that libraries specified as full paths will be picked by the linker. \n Directories and libraries involvied are: \n " ;
for ( std : : set < cmStdString > : : iterator i = m_ImposibleDirectories . begin ( ) ;
i ! = m_ImposibleDirectories . end ( ) ; + + i )
{
warning + = " Directory: " ;
warning + = * i ;
2005-03-04 02:16:00 +03:00
warning + = " contains: \n " ;
2005-02-24 21:16:41 +03:00
std : : map < cmStdString , std : : vector < cmStdString > > : : iterator j ;
for ( j = m_LibraryToDirectories . begin ( ) ;
j ! = m_LibraryToDirectories . end ( ) ; + + j )
{
if ( std : : find ( j - > second . begin ( ) , j - > second . end ( ) , * i )
! = j - > second . end ( ) )
{
warning + = " Library: " ;
warning + = j - > first ;
warning + = " \n " ;
}
}
2005-03-04 02:16:00 +03:00
warning + = " \n " ;
2005-02-24 21:16:41 +03:00
}
warning + = " \n " ;
return warning ;
}
2005-02-24 21:26:39 +03:00
//-------------------------------------------------------------------
void
cmOrderLinkDirectories : : PrintMap ( const char * name ,
std : : map < cmStdString , std : : vector < cmStdString > > & m )
{
2005-03-04 02:46:52 +03:00
std : : cout < < name < < " \n " ;
2005-02-24 21:26:39 +03:00
for ( std : : map < cmStdString , std : : vector < cmStdString > > : : iterator i =
m . begin ( ) ; i ! = m . end ( ) ;
+ + i )
{
2005-03-04 02:46:52 +03:00
std : : cout < < i - > first < < " : " ;
2005-02-24 21:26:39 +03:00
for ( std : : vector < cmStdString > : : iterator l = i - > second . begin ( ) ;
l ! = i - > second . end ( ) ; + + l )
{
2005-03-04 02:46:52 +03:00
std : : cout < < * l < < " " ;
2005-02-24 21:26:39 +03:00
}
2005-03-04 02:46:52 +03:00
std : : cout < < " \n " ;
2005-02-24 21:26:39 +03:00
}
}
2005-02-26 01:45:12 +03:00
void cmOrderLinkDirectories : : GetFullPathLibraries ( std : : vector < cmStdString > &
libs )
{
for ( std : : map < cmStdString , Library > : : iterator i = m_FullPathLibraries . begin ( ) ;
i ! = m_FullPathLibraries . end ( ) ; + + i )
{
libs . push_back ( i - > first ) ;
}
}