ENH: add a new library path ordering algorithm to make sure -L paths will pick the correct libraries if possible
This commit is contained in:
parent
9c4997bf06
commit
ff812580eb
|
@ -44,6 +44,7 @@ SET(SRCS
|
|||
cmMakeDepend.h
|
||||
cmMakefile.cxx
|
||||
cmMakefile.h
|
||||
cmOrderLinkDirectories.cxx
|
||||
cmSourceFile.cxx
|
||||
cmSourceFile.h
|
||||
cmSourceGroup.cxx
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "cmMakefile.h"
|
||||
#include "cmGeneratedFileStream.h"
|
||||
#include "cmSourceFile.h"
|
||||
#include "cmOrderLinkDirectories.h"
|
||||
|
||||
cmLocalGenerator::cmLocalGenerator()
|
||||
{
|
||||
|
@ -1077,6 +1078,16 @@ void cmLocalGenerator::GetTargetFlags(std::string& linkLibs,
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
cmLocalGenerator::DetermineLibraryPathOrder(const cmTarget& target,
|
||||
std::vector<std::string>&
|
||||
linkPaths,
|
||||
std::vector<std::string>&
|
||||
linkLibs)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the linking rules on a command line. For executables,
|
||||
* targetLibrary should be a NULL pointer. For libraries, it should point
|
||||
|
@ -1088,7 +1099,6 @@ void cmLocalGenerator::OutputLinkLibraries(std::ostream& fout,
|
|||
{
|
||||
// Try to emit each search path once
|
||||
std::set<cmStdString> emitted;
|
||||
|
||||
// Embed runtime search paths if possible and if required.
|
||||
bool outputRuntime = true;
|
||||
std::string runtimeFlag;
|
||||
|
@ -1097,12 +1107,21 @@ void cmLocalGenerator::OutputLinkLibraries(std::ostream& fout,
|
|||
|
||||
std::string buildType = m_Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
|
||||
buildType = cmSystemTools::UpperCase(buildType);
|
||||
|
||||
cmTarget::LinkLibraryType cmakeBuildType = cmTarget::GENERAL;
|
||||
if(buildType == "DEBUG")
|
||||
{
|
||||
cmakeBuildType = cmTarget::DEBUG;
|
||||
}
|
||||
if(buildType.size())
|
||||
{
|
||||
cmakeBuildType = cmTarget::OPTIMIZED;
|
||||
}
|
||||
const char* linkLanguage = tgt.GetLinkerLanguage(this->GetGlobalGenerator());
|
||||
if(!linkLanguage)
|
||||
{
|
||||
cmSystemTools::Error("CMake can not determine linker language for target:",
|
||||
tgt.GetName());
|
||||
cmSystemTools::
|
||||
Error("CMake can not determine linker language for target:",
|
||||
tgt.GetName());
|
||||
return;
|
||||
}
|
||||
std::string runTimeFlagVar = "CMAKE_SHARED_LIBRARY_RUNTIME_";
|
||||
|
@ -1137,8 +1156,32 @@ void cmLocalGenerator::OutputLinkLibraries(std::ostream& fout,
|
|||
linkLibs += " ";
|
||||
}
|
||||
|
||||
const std::vector<std::string>& libdirs = tgt.GetLinkDirectories();
|
||||
for(std::vector<std::string>::const_iterator libDir = libdirs.begin();
|
||||
cmOrderLinkDirectories orderLibs;
|
||||
std::string ext =
|
||||
m_Makefile->GetSafeDefinition("CMAKE_STATIC_LIBRARY_SUFFIX");
|
||||
if(ext.size())
|
||||
{
|
||||
orderLibs.AddLinkExtension(ext.c_str());
|
||||
}
|
||||
ext =
|
||||
m_Makefile->GetSafeDefinition("CMAKE_SHARED_LIBRARY_SUFFIX");
|
||||
if(ext.size())
|
||||
{
|
||||
orderLibs.AddLinkExtension(ext.c_str());
|
||||
}
|
||||
ext =
|
||||
m_Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_SUFFIX");
|
||||
if(ext.size())
|
||||
{
|
||||
orderLibs.AddLinkExtension(ext.c_str());
|
||||
}
|
||||
// compute the correct order for -L paths
|
||||
orderLibs.SetLinkInformation(tgt, cmakeBuildType, targetLibrary);
|
||||
orderLibs.DetermineLibraryPathOrder();
|
||||
std::vector<cmStdString> libdirs;
|
||||
std::vector<cmStdString> linkItems;
|
||||
orderLibs.GetLinkerInformation(libdirs, linkItems);
|
||||
for(std::vector<cmStdString>::const_iterator libDir = libdirs.begin();
|
||||
libDir != libdirs.end(); ++libDir)
|
||||
{
|
||||
std::string libpath = this->ConvertToOutputForExisting(libDir->c_str());
|
||||
|
@ -1169,103 +1212,30 @@ void cmLocalGenerator::OutputLinkLibraries(std::ostream& fout,
|
|||
}
|
||||
}
|
||||
|
||||
std::string linkSuffix = m_Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_SUFFIX");
|
||||
std::string linkSuffix =
|
||||
m_Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_SUFFIX");
|
||||
std::string regexp = ".*\\";
|
||||
regexp += linkSuffix;
|
||||
regexp += "$";
|
||||
cmsys::RegularExpression hasSuffix(regexp.c_str());
|
||||
std::string librariesLinked;
|
||||
const cmTarget::LinkLibraries& libs = tgt.GetLinkLibraries();
|
||||
for(cmTarget::LinkLibraries::const_iterator lib = libs.begin();
|
||||
lib != libs.end(); ++lib)
|
||||
for(std::vector<cmStdString>::iterator lib = linkItems.begin();
|
||||
lib != linkItems.end(); ++lib)
|
||||
{
|
||||
// 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 && buildType != "DEBUG")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (lib->second == cmTarget::OPTIMIZED && buildType == "DEBUG")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// skip zero size library entries, this may happen
|
||||
// if a variable expands to nothing.
|
||||
if (lib->first.size() == 0) continue;
|
||||
// if it is a full path break it into -L and -l
|
||||
cmStdString& linkItem = *lib;
|
||||
// check to see if the link item has a -l already
|
||||
cmsys::RegularExpression reg("^([ \t]*\\-[lWRB])|([ \t]*\\-framework)|(\\${)|([ \t]*\\-pthread)|([ \t]*`)");
|
||||
if(lib->first.find('/') != std::string::npos
|
||||
&& !reg.find(lib->first))
|
||||
if(!reg.find(linkItem))
|
||||
{
|
||||
std::string dir, file;
|
||||
cmSystemTools::SplitProgramPath(lib->first.c_str(),
|
||||
dir, file);
|
||||
std::string libpath = this->ConvertToOutputForExisting(dir.c_str());
|
||||
if(emitted.insert(libpath).second)
|
||||
{
|
||||
linkLibs += libPathFlag;
|
||||
linkLibs += libpath;
|
||||
linkLibs += " ";
|
||||
if(outputRuntime)
|
||||
{
|
||||
runtimeDirs.push_back( libpath );
|
||||
}
|
||||
}
|
||||
cmsys::RegularExpression libname("^lib([^/]*)(\\.so|\\.lib|\\.dll|\\.sl|\\.a|\\.dylib).*");
|
||||
cmsys::RegularExpression libname_noprefix("([^/]*)(\\.so|\\.lib|\\.dll|\\.sl|\\.a|\\.dylib).*");
|
||||
if(libname.find(file))
|
||||
{
|
||||
// Library had "lib" prefix.
|
||||
librariesLinked += libLinkFlag;
|
||||
file = libname.match(1);
|
||||
// if ignore libprefix is on,
|
||||
// then add the lib prefix back into the name
|
||||
if(m_IgnoreLibPrefix)
|
||||
{
|
||||
file = "lib" + file;
|
||||
}
|
||||
librariesLinked += file;
|
||||
if(linkSuffix.size() && !hasSuffix.find(file))
|
||||
{
|
||||
librariesLinked += linkSuffix;
|
||||
}
|
||||
librariesLinked += " ";
|
||||
}
|
||||
else if(libname_noprefix.find(file))
|
||||
{
|
||||
// Library had no "lib" prefix.
|
||||
librariesLinked += libLinkFlag;
|
||||
file = libname_noprefix.match(1);
|
||||
librariesLinked += file;
|
||||
if(linkSuffix.size() && !hasSuffix.find(file))
|
||||
{
|
||||
librariesLinked += linkSuffix;
|
||||
}
|
||||
librariesLinked += " ";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Error parsing the library name. Just use the full path.
|
||||
// The linker will give an error if it is invalid.
|
||||
librariesLinked += lib->first;
|
||||
librariesLinked += " ";
|
||||
}
|
||||
librariesLinked += libLinkFlag;
|
||||
}
|
||||
// not a full path, so add -l name
|
||||
else
|
||||
librariesLinked += linkItem;
|
||||
|
||||
if(linkSuffix.size() && !hasSuffix.find(linkItem))
|
||||
{
|
||||
if(!reg.find(lib->first))
|
||||
{
|
||||
librariesLinked += libLinkFlag;
|
||||
}
|
||||
librariesLinked += lib->first;
|
||||
if(linkSuffix.size() && !hasSuffix.find(lib->first))
|
||||
{
|
||||
librariesLinked += linkSuffix;
|
||||
}
|
||||
librariesLinked += " ";
|
||||
librariesLinked += linkSuffix;
|
||||
}
|
||||
librariesLinked += " ";
|
||||
}
|
||||
|
||||
linkLibs += librariesLinked;
|
||||
|
|
|
@ -103,7 +103,9 @@ public:
|
|||
///! for existing files convert to output path and short path if spaces
|
||||
std::string ConvertToOutputForExisting(const char* p);
|
||||
|
||||
|
||||
void DetermineLibraryPathOrder(const cmTarget& target,
|
||||
std::vector<std::string>& linkPaths,
|
||||
std::vector<std::string>& linkLibs);
|
||||
protected:
|
||||
/** Construct a script from the given list of command lines. */
|
||||
std::string ConstructScript(const cmCustomCommandLines& commandLines,
|
||||
|
|
|
@ -0,0 +1,356 @@
|
|||
#include "cmOrderLinkDirectories.h"
|
||||
#include "cmSystemTools.h"
|
||||
#include "cmsys/RegularExpression.hxx"
|
||||
|
||||
|
||||
inline void printv(std::vector<cmStdString>& v)
|
||||
{
|
||||
for(unsigned int i = 0; i < v.size(); ++i)
|
||||
{
|
||||
std::cerr << "[" << v[i] << "]" << " ";
|
||||
}
|
||||
std::cerr << "\n";
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
bool cmOrderLinkDirectories::LibraryInDirectory(const char* dir,
|
||||
const char* lib)
|
||||
{
|
||||
cmStdString path = dir;
|
||||
path += "/";
|
||||
path += lib;
|
||||
// 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
|
||||
if(m_RemoveLibraryExtension.find(lib))
|
||||
{
|
||||
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)
|
||||
{
|
||||
if(LibraryInDirectory(dir->c_str(), lib->second.File.c_str()))
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
void
|
||||
cmOrderLinkDirectories::PrintMap(const char* name,
|
||||
std::map<cmStdString, std::vector<cmStdString> >& m)
|
||||
{
|
||||
std::cerr << name << "\n";
|
||||
for(std::map<cmStdString, std::vector<cmStdString> >::iterator i =
|
||||
m.begin(); i != m.end();
|
||||
++i)
|
||||
{
|
||||
std::cerr << i->first << ": ";
|
||||
for(std::vector<cmStdString>::iterator l = i->second.begin();
|
||||
l != i->second.end(); ++l)
|
||||
{
|
||||
std::cerr << *l << " ";
|
||||
}
|
||||
std::cerr << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
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 += "\\";
|
||||
libext += *i;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
bool cmOrderLinkDirectories::CanBeBefore(const cmStdString& d1,
|
||||
const cmStdString& d2)
|
||||
{
|
||||
if(m_DirectoryToAfterList.count(d2) == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
std::vector<cmStdString>& d2dirs = m_DirectoryToAfterList[d2];
|
||||
// is d1 in the d2's list of directories that d2 must be before
|
||||
// if so, then d1 can not come before d2
|
||||
for(std::vector<cmStdString>::iterator i = d2dirs.begin();
|
||||
i != d2dirs.end(); ++i)
|
||||
{
|
||||
if(*i == d1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// This is a stl function object used to sort
|
||||
// the vector of library paths. It returns true
|
||||
// if left directory can be before right directory (no swap).
|
||||
// It also checks for the impossible case of two libraries and
|
||||
// two directories that have both libraries.
|
||||
struct cmOrderLinkDirectoriesCompare
|
||||
: public std::binary_function <cmStdString, cmStdString, bool>
|
||||
{
|
||||
cmOrderLinkDirectoriesCompare()
|
||||
{
|
||||
This = 0;
|
||||
}
|
||||
bool operator()(
|
||||
const cmStdString& left,
|
||||
const cmStdString& right
|
||||
) const
|
||||
{
|
||||
bool ret = This->CanBeBefore(left, right);
|
||||
if(!ret)
|
||||
{
|
||||
// check for the case when both libraries have to come
|
||||
// before each other
|
||||
if(!This->CanBeBefore(right, left))
|
||||
{
|
||||
This->AddImpossible(right, left);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
cmOrderLinkDirectories* This;
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
void cmOrderLinkDirectories::AddImpossible(const cmStdString& d1,
|
||||
const cmStdString& d2)
|
||||
{
|
||||
m_ImposibleDirectories.insert(d1);
|
||||
m_ImposibleDirectories.insert(d2);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
void cmOrderLinkDirectories::OrderPaths(std::vector<cmStdString>&
|
||||
orderedPaths)
|
||||
{
|
||||
cmOrderLinkDirectoriesCompare comp;
|
||||
comp.This = this;
|
||||
std::sort(orderedPaths.begin(), orderedPaths.end(), comp);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
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();
|
||||
for(std::vector<std::string>::const_iterator p = searchPaths.begin();
|
||||
p != searchPaths.end(); ++p)
|
||||
{
|
||||
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;
|
||||
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);
|
||||
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();
|
||||
for(std::set<cmStdString>::iterator i = m_LinkPathSet.begin();
|
||||
i != m_LinkPathSet.end(); ++i)
|
||||
{
|
||||
m_SortedSearchPaths.push_back(*i);
|
||||
}
|
||||
|
||||
this->OrderPaths(m_SortedSearchPaths);
|
||||
// now turn libfoo.a into foo and foo.a into foo
|
||||
// This will prepare the link items for -litem
|
||||
this->PrepareLinkTargets();
|
||||
// this->PrintMap("m_DirectoryToAfterList", m_DirectoryToAfterList);
|
||||
//this->PrintMap("m_LibraryToDirectories", m_LibraryToDirectories);
|
||||
//std::cerr << "link objects: ";
|
||||
//printv(m_LinkItems);
|
||||
if(m_ImposibleDirectories.size())
|
||||
{
|
||||
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.\nDirectories and libraries involvied are:\n";
|
||||
for(std::set<cmStdString>::iterator i = m_ImposibleDirectories.begin();
|
||||
i != m_ImposibleDirectories.end(); ++i)
|
||||
{
|
||||
warning += "Directory: ";
|
||||
warning += *i;
|
||||
warning += " contains ";
|
||||
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";
|
||||
}
|
||||
}
|
||||
}
|
||||
warning += "\n";
|
||||
return warning;
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
/*=========================================================================
|
||||
|
||||
Program: CMake - Cross-Platform Makefile Generator
|
||||
Module: $RCSfile$
|
||||
Language: C++
|
||||
Date: $Date$
|
||||
Version: $Revision$
|
||||
|
||||
Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
|
||||
See Copyright.txt or http://www.cmake.org/HTML/Copyright.html 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.
|
||||
|
||||
=========================================================================*/
|
||||
#ifndef cmOrderLinkDirectories_h
|
||||
#define cmOrderLinkDirectories_h
|
||||
|
||||
#include <cmStandardIncludes.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "cmTarget.h"
|
||||
#include "cmsys/RegularExpression.hxx"
|
||||
|
||||
|
||||
/** \class cmOrderLinkDirectories
|
||||
* \brief Compute the best -L path order
|
||||
*
|
||||
* This class computes the best order for -L paths.
|
||||
* It tries to make sure full path specified libraries are
|
||||
* used. For example if you have /usr/mylib/libfoo.a on as
|
||||
* a link library for a target, and you also have /usr/lib/libbar.a
|
||||
* and you also have /usr/lib/libfoo.a, then you would
|
||||
* want -L/usr/mylib -L/usr/lib to make sure the correct libfoo.a is
|
||||
* found by the linker. The algorithm is as follows:
|
||||
* - foreach library create a vector of directories it exists in.
|
||||
* - foreach directory create a vector of directories that must come
|
||||
* after it, put this in a map<dir, vector<dir>> mapping from a directory
|
||||
* to the vector of directories that it must be before.
|
||||
* - put all directories into a vector
|
||||
* - sort the vector with a compare function CanBeBefore
|
||||
* CanBeBefore returns true if a directory is OK to be before
|
||||
* another directory. This is determined by looking at the
|
||||
* map<dir vector<dir>> and seeing if d1 is in the vector for d2.
|
||||
*/
|
||||
class cmOrderLinkDirectories
|
||||
{
|
||||
public:
|
||||
///! set link information from the target
|
||||
void SetLinkInformation(const cmTarget&, cmTarget::LinkLibraryType,
|
||||
const char* targetLibrary);
|
||||
///! Compute the best order for -L paths from GetLinkLibraries
|
||||
bool DetermineLibraryPathOrder();
|
||||
///! Get the results from DetermineLibraryPathOrder
|
||||
void GetLinkerInformation(std::vector<cmStdString>& searchPaths,
|
||||
std::vector<cmStdString>& linkItems)
|
||||
{
|
||||
linkItems = m_LinkItems;
|
||||
searchPaths = m_SortedSearchPaths;
|
||||
}
|
||||
// should be set from CMAKE_STATIC_LIBRARY_SUFFIX,
|
||||
// CMAKE_SHARED_LIBRARY_SUFFIX
|
||||
// CMAKE_LINK_LIBRARY_SUFFIX
|
||||
void AddLinkExtension(const char* e)
|
||||
{
|
||||
m_LinkExtensions.push_back(e);
|
||||
}
|
||||
// Return any warnings if the exist
|
||||
std::string GetWarnings();
|
||||
|
||||
// structure to hold a full path library link item
|
||||
struct Library
|
||||
{
|
||||
cmStdString FullPath;
|
||||
cmStdString File;
|
||||
cmStdString Path;
|
||||
};
|
||||
friend struct cmOrderLinkDirectoriesCompare;
|
||||
private:
|
||||
void CreateRegularExpressions();
|
||||
void DetermineLibraryPathOrder(std::vector<cmStdString>& searchPaths,
|
||||
std::vector<cmStdString>& libs,
|
||||
std::vector<cmStdString>& sortedPaths);
|
||||
void PrepareLinkTargets();
|
||||
bool LibraryInDirectory(const char* dir, const char* lib);
|
||||
void FindLibrariesInSeachPaths();
|
||||
void FindIndividualLibraryOrders();
|
||||
void PrintMap(const char* name,
|
||||
std::map<cmStdString, std::vector<cmStdString> >& m);
|
||||
void OrderPaths(std::vector<cmStdString>& paths);
|
||||
bool CanBeBefore(const cmStdString& d1,
|
||||
const cmStdString& d2);
|
||||
void AddImpossible(const cmStdString& ,
|
||||
const cmStdString& );
|
||||
private:
|
||||
// map from library to directories that it is in other than its full path
|
||||
std::map<cmStdString, std::vector<cmStdString> > m_LibraryToDirectories;
|
||||
// map from directory to vector of directories that must be after it
|
||||
std::map<cmStdString, std::vector<cmStdString> > m_DirectoryToAfterList;
|
||||
// map from full path to a Library struct
|
||||
std::map<cmStdString, Library> m_FullPathLibraries;
|
||||
// libraries that are found in multiple directories
|
||||
std::vector<Library> m_MultiDirectoryLibraries;
|
||||
// libraries that are only found in one directory
|
||||
std::vector<Library> m_SingleDirectoryLibraries;
|
||||
// This is a vector of all the link objects -lm or m
|
||||
std::vector<cmStdString> m_LinkItems;
|
||||
// Unprocessed link items
|
||||
std::vector<cmStdString> m_RawLinkItems;
|
||||
// This vector holds the sorted -L paths
|
||||
std::vector<cmStdString> m_SortedSearchPaths;
|
||||
// This is the set of -L paths unsorted, but unique
|
||||
std::set<cmStdString> m_LinkPathSet;
|
||||
// the names of link extensions
|
||||
std::vector<cmStdString> m_LinkExtensions;
|
||||
// set of directories that can not be put in the correct order
|
||||
std::set<cmStdString> m_ImposibleDirectories;
|
||||
// library regular expressions
|
||||
cmsys::RegularExpression m_RemoveLibraryExtension;
|
||||
cmsys::RegularExpression m_ExtractBaseLibraryName;
|
||||
cmsys::RegularExpression m_ExtractBaseLibraryNameNoPrefix;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue