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
|
cmMakeDepend.h
|
||||||
cmMakefile.cxx
|
cmMakefile.cxx
|
||||||
cmMakefile.h
|
cmMakefile.h
|
||||||
|
cmOrderLinkDirectories.cxx
|
||||||
cmSourceFile.cxx
|
cmSourceFile.cxx
|
||||||
cmSourceFile.h
|
cmSourceFile.h
|
||||||
cmSourceGroup.cxx
|
cmSourceGroup.cxx
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "cmMakefile.h"
|
#include "cmMakefile.h"
|
||||||
#include "cmGeneratedFileStream.h"
|
#include "cmGeneratedFileStream.h"
|
||||||
#include "cmSourceFile.h"
|
#include "cmSourceFile.h"
|
||||||
|
#include "cmOrderLinkDirectories.h"
|
||||||
|
|
||||||
cmLocalGenerator::cmLocalGenerator()
|
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,
|
* Output the linking rules on a command line. For executables,
|
||||||
* targetLibrary should be a NULL pointer. For libraries, it should point
|
* 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
|
// Try to emit each search path once
|
||||||
std::set<cmStdString> emitted;
|
std::set<cmStdString> emitted;
|
||||||
|
|
||||||
// Embed runtime search paths if possible and if required.
|
// Embed runtime search paths if possible and if required.
|
||||||
bool outputRuntime = true;
|
bool outputRuntime = true;
|
||||||
std::string runtimeFlag;
|
std::string runtimeFlag;
|
||||||
@ -1097,12 +1107,21 @@ void cmLocalGenerator::OutputLinkLibraries(std::ostream& fout,
|
|||||||
|
|
||||||
std::string buildType = m_Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
|
std::string buildType = m_Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
|
||||||
buildType = cmSystemTools::UpperCase(buildType);
|
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());
|
const char* linkLanguage = tgt.GetLinkerLanguage(this->GetGlobalGenerator());
|
||||||
if(!linkLanguage)
|
if(!linkLanguage)
|
||||||
{
|
{
|
||||||
cmSystemTools::Error("CMake can not determine linker language for target:",
|
cmSystemTools::
|
||||||
tgt.GetName());
|
Error("CMake can not determine linker language for target:",
|
||||||
|
tgt.GetName());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::string runTimeFlagVar = "CMAKE_SHARED_LIBRARY_RUNTIME_";
|
std::string runTimeFlagVar = "CMAKE_SHARED_LIBRARY_RUNTIME_";
|
||||||
@ -1137,8 +1156,32 @@ void cmLocalGenerator::OutputLinkLibraries(std::ostream& fout,
|
|||||||
linkLibs += " ";
|
linkLibs += " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<std::string>& libdirs = tgt.GetLinkDirectories();
|
cmOrderLinkDirectories orderLibs;
|
||||||
for(std::vector<std::string>::const_iterator libDir = libdirs.begin();
|
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)
|
libDir != libdirs.end(); ++libDir)
|
||||||
{
|
{
|
||||||
std::string libpath = this->ConvertToOutputForExisting(libDir->c_str());
|
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 = ".*\\";
|
std::string regexp = ".*\\";
|
||||||
regexp += linkSuffix;
|
regexp += linkSuffix;
|
||||||
regexp += "$";
|
regexp += "$";
|
||||||
cmsys::RegularExpression hasSuffix(regexp.c_str());
|
cmsys::RegularExpression hasSuffix(regexp.c_str());
|
||||||
std::string librariesLinked;
|
std::string librariesLinked;
|
||||||
const cmTarget::LinkLibraries& libs = tgt.GetLinkLibraries();
|
for(std::vector<cmStdString>::iterator lib = linkItems.begin();
|
||||||
for(cmTarget::LinkLibraries::const_iterator lib = libs.begin();
|
lib != linkItems.end(); ++lib)
|
||||||
lib != libs.end(); ++lib)
|
|
||||||
{
|
{
|
||||||
// Don't link the library against itself!
|
cmStdString& linkItem = *lib;
|
||||||
if(targetLibrary && (lib->first == targetLibrary)) continue;
|
// check to see if the link item has a -l already
|
||||||
// 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
|
|
||||||
cmsys::RegularExpression reg("^([ \t]*\\-[lWRB])|([ \t]*\\-framework)|(\\${)|([ \t]*\\-pthread)|([ \t]*`)");
|
cmsys::RegularExpression reg("^([ \t]*\\-[lWRB])|([ \t]*\\-framework)|(\\${)|([ \t]*\\-pthread)|([ \t]*`)");
|
||||||
if(lib->first.find('/') != std::string::npos
|
if(!reg.find(linkItem))
|
||||||
&& !reg.find(lib->first))
|
|
||||||
{
|
{
|
||||||
std::string dir, file;
|
librariesLinked += libLinkFlag;
|
||||||
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 += " ";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// not a full path, so add -l name
|
librariesLinked += linkItem;
|
||||||
else
|
|
||||||
|
if(linkSuffix.size() && !hasSuffix.find(linkItem))
|
||||||
{
|
{
|
||||||
if(!reg.find(lib->first))
|
librariesLinked += linkSuffix;
|
||||||
{
|
|
||||||
librariesLinked += libLinkFlag;
|
|
||||||
}
|
|
||||||
librariesLinked += lib->first;
|
|
||||||
if(linkSuffix.size() && !hasSuffix.find(lib->first))
|
|
||||||
{
|
|
||||||
librariesLinked += linkSuffix;
|
|
||||||
}
|
|
||||||
librariesLinked += " ";
|
|
||||||
}
|
}
|
||||||
|
librariesLinked += " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
linkLibs += librariesLinked;
|
linkLibs += librariesLinked;
|
||||||
|
@ -103,7 +103,9 @@ public:
|
|||||||
///! for existing files convert to output path and short path if spaces
|
///! for existing files convert to output path and short path if spaces
|
||||||
std::string ConvertToOutputForExisting(const char* p);
|
std::string ConvertToOutputForExisting(const char* p);
|
||||||
|
|
||||||
|
void DetermineLibraryPathOrder(const cmTarget& target,
|
||||||
|
std::vector<std::string>& linkPaths,
|
||||||
|
std::vector<std::string>& linkLibs);
|
||||||
protected:
|
protected:
|
||||||
/** Construct a script from the given list of command lines. */
|
/** Construct a script from the given list of command lines. */
|
||||||
std::string ConstructScript(const cmCustomCommandLines& commandLines,
|
std::string ConstructScript(const cmCustomCommandLines& commandLines,
|
||||||
|
356
Source/cmOrderLinkDirectories.cxx
Normal file
356
Source/cmOrderLinkDirectories.cxx
Normal file
@ -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;
|
||||||
|
}
|
126
Source/cmOrderLinkDirectories.h
Normal file
126
Source/cmOrderLinkDirectories.h
Normal file
@ -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…
x
Reference in New Issue
Block a user