mirror of
https://github.com/reactos/CMake.git
synced 2024-11-30 23:10:26 +00:00
22c62c9e65
fix many bugs related to target names being computed inconsistently. - Centralized computation of a target's file name to a method in cmTarget. Now that global knowledge is always available the *_CMAKE_PATH cache variables are no longer needed. - Centralized computation of link library command lines and link directory search order. - Moved computation of link directories needed to link CMake targets to be after evaluation of linking dependencies. This also removed alot of duplicate code in which each version had its own bugs. This commit is surrounded by the tags CMake-TargetNameCentralization1-pre and CMake-TargetNameCentralization1-post so make the large set of changes easy to identify.
404 lines
12 KiB
C++
404 lines
12 KiB
C++
#include "cmOrderLinkDirectories.h"
|
|
#include "cmSystemTools.h"
|
|
#include "cmsys/RegularExpression.hxx"
|
|
#include <ctype.h>
|
|
|
|
|
|
//-------------------------------------------------------------------
|
|
cmOrderLinkDirectories::cmOrderLinkDirectories()
|
|
{
|
|
m_Debug = false;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
bool cmOrderLinkDirectories::LibraryInDirectory(const char* dir,
|
|
const char* libIn)
|
|
{
|
|
cmStdString path = dir;
|
|
path += "/";
|
|
path += libIn;
|
|
// 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(libIn))
|
|
{
|
|
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(this->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;
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
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;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
void cmOrderLinkDirectories::CreateRegularExpressions()
|
|
{
|
|
m_SplitFramework.compile("(.*)/(.*)\\.framework$");
|
|
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 += "\\";
|
|
#if defined(_WIN32) && !defined(__CYGWIN__)
|
|
libext += this->NoCaseExpression(i->c_str());
|
|
#else
|
|
libext += *i;
|
|
#endif
|
|
}
|
|
libext += ").*";
|
|
cmStdString reg("(.*)");
|
|
reg += libext;
|
|
m_RemoveLibraryExtension.compile(reg.c_str());
|
|
reg = "";
|
|
if(m_LinkPrefix.size())
|
|
{
|
|
reg = "^";
|
|
reg += m_LinkPrefix;
|
|
}
|
|
reg += "([^/]*)";
|
|
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::FindPathNotInDirectoryToAfterList(
|
|
cmStdString& path)
|
|
{
|
|
for(std::map<cmStdString, std::vector<cmStdString> >::iterator i
|
|
= m_DirectoryToAfterList.begin();
|
|
i != m_DirectoryToAfterList.end(); ++i)
|
|
{
|
|
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)
|
|
{
|
|
if(j != i)
|
|
{
|
|
found = (std::find(j->second.begin(), j->second.end(), p) != j->second.end());
|
|
}
|
|
}
|
|
if(!found)
|
|
{
|
|
path = p;
|
|
m_DirectoryToAfterList.erase(i);
|
|
return true;
|
|
}
|
|
}
|
|
path = "";
|
|
return false;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------
|
|
void cmOrderLinkDirectories::OrderPaths(std::vector<cmStdString>&
|
|
orderedPaths)
|
|
{
|
|
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);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
void cmOrderLinkDirectories::SetLinkInformation(
|
|
const char* targetName,
|
|
const std::vector<std::string>& linkLibraries,
|
|
const std::vector<std::string>& linkDirectories
|
|
)
|
|
{
|
|
// Save the target name.
|
|
m_TargetName = targetName;
|
|
|
|
// Merge the link directory search path given into our path set.
|
|
std::vector<cmStdString> empty;
|
|
for(std::vector<std::string>::const_iterator p = linkDirectories.begin();
|
|
p != linkDirectories.end(); ++p)
|
|
{
|
|
m_DirectoryToAfterList[*p] = empty;
|
|
m_LinkPathSet.insert(*p);
|
|
}
|
|
|
|
// Append the link library list into our raw list.
|
|
for(std::vector<std::string>::const_iterator l = linkLibraries.begin();
|
|
l != linkLibraries.end(); ++l)
|
|
{
|
|
m_RawLinkItems.push_back(*l);
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
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;
|
|
std::vector<cmStdString> empty;
|
|
bool framework = false;
|
|
for(unsigned int i=0; i < m_RawLinkItems.size(); ++i)
|
|
{
|
|
if(cmSystemTools::FileIsFullPath(m_RawLinkItems[i].c_str()))
|
|
{
|
|
if(cmSystemTools::FileIsDirectory(m_RawLinkItems[i].c_str()))
|
|
{
|
|
if(cmSystemTools::IsPathToFramework(m_RawLinkItems[i].c_str()))
|
|
{
|
|
m_SplitFramework.find(m_RawLinkItems[i]);
|
|
cmStdString path = m_SplitFramework.match(1);
|
|
// Add the -F path if we have not yet done so
|
|
if(m_EmittedFrameworkPaths.insert(path).second)
|
|
{
|
|
std::string fpath = "-F";
|
|
fpath += cmSystemTools::ConvertToOutputPath(path.c_str());
|
|
m_LinkItems.push_back(fpath);
|
|
}
|
|
// now add the -framework option
|
|
std::string frame = "-framework ";
|
|
frame += m_SplitFramework.match(2);
|
|
m_LinkItems.push_back(frame);
|
|
framework = true;
|
|
}
|
|
else
|
|
{
|
|
std::string message = "Warning: Ignoring path found in link libraries for target: ";
|
|
message += m_TargetName;
|
|
message += ", path is: ";
|
|
message += m_RawLinkItems[i];
|
|
message += ". Expected a library name or a full path to a library name.";
|
|
cmSystemTools::Message(message.c_str());
|
|
continue;
|
|
}
|
|
}
|
|
if(!framework)
|
|
{
|
|
cmSystemTools::SplitProgramPath(m_RawLinkItems[i].c_str(),
|
|
dir, file);
|
|
m_DirectoryToAfterList[dir] = empty;
|
|
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();
|
|
if(m_Debug)
|
|
{
|
|
this->PrintMap("m_LibraryToDirectories", m_LibraryToDirectories);
|
|
this->PrintMap("m_DirectoryToAfterList", m_DirectoryToAfterList);
|
|
}
|
|
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();
|
|
if(m_ImposibleDirectories.size())
|
|
{
|
|
cmSystemTools::Message(this->GetWarnings().c_str());
|
|
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 involved are:\n";
|
|
for(std::set<cmStdString>::iterator i = m_ImposibleDirectories.begin();
|
|
i != m_ImposibleDirectories.end(); ++i)
|
|
{
|
|
warning += "Directory: ";
|
|
warning += *i;
|
|
warning += " contains:\n";
|
|
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";
|
|
}
|
|
warning += "\n";
|
|
return warning;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
void
|
|
cmOrderLinkDirectories::PrintMap(const char* name,
|
|
std::map<cmStdString, std::vector<cmStdString> >& m)
|
|
{
|
|
std::cout << name << "\n";
|
|
for(std::map<cmStdString, std::vector<cmStdString> >::iterator i =
|
|
m.begin(); i != m.end();
|
|
++i)
|
|
{
|
|
std::cout << i->first << ": ";
|
|
for(std::vector<cmStdString>::iterator l = i->second.begin();
|
|
l != i->second.end(); ++l)
|
|
{
|
|
std::cout << *l << " ";
|
|
}
|
|
std::cout << "\n";
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
}
|