| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466 |
- #include "cmOrderLinkDirectories.h"
- #include "cmSystemTools.h"
- #include "cmsys/RegularExpression.hxx"
- #include <ctype.h>
- //-------------------------------------------------------------------
- cmOrderLinkDirectories::cmOrderLinkDirectories()
- {
- this->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(this->RemoveLibraryExtension.find(libIn))
- {
- cmStdString lib = this->RemoveLibraryExtension.match(1);
- cmStdString ext = this->RemoveLibraryExtension.match(2);
- for(std::vector<cmStdString>::iterator i = this->LinkExtensions.begin();
- i != this->LinkExtensions.end(); ++i)
- {
- if(ext != *i)
- {
- path = dir;
- path += "/";
- path += lib + *i;
- if(cmSystemTools::FileExists(path.c_str()))
- {
- return true;
- }
- }
- }
- }
- return false;
- }
- //-------------------------------------------------------------------
- void cmOrderLinkDirectories::FindLibrariesInSearchPaths()
- {
- for(std::set<cmStdString>::iterator dir = this->LinkPathSet.begin();
- dir != this->LinkPathSet.end(); ++dir)
- {
- for(std::map<cmStdString, Library>::iterator lib
- = this->FullPathLibraries.begin();
- lib != this->FullPathLibraries.end(); ++lib)
- {
- if(lib->second.Path != *dir)
- {
- if(this->LibraryInDirectory(dir->c_str(), lib->second.File.c_str()))
- {
- this->LibraryToDirectories[lib->second.FullPath].push_back(*dir);
- }
- }
- }
- }
- }
-
- //-------------------------------------------------------------------
- void cmOrderLinkDirectories::FindIndividualLibraryOrders()
- {
- for(std::vector<Library>::iterator lib = this->MultiDirectoryLibraries.begin();
- lib != this->MultiDirectoryLibraries.end(); ++lib)
- {
- std::vector<cmStdString>& dirs = this->LibraryToDirectories[lib->FullPath];
- std::vector<std::pair<cmStdString, std::vector<cmStdString> > >::iterator i;
- for(i = this->DirectoryToAfterList.begin(); i != this->DirectoryToAfterList.end();
- ++i)
- {
- if(i->first == lib->Path)
- {
- break;
- }
- }
- if(i == this->DirectoryToAfterList.end())
- {
- std::cerr << "ERROR: should not happen\n";
- }
- else
- {
- for(std::vector<cmStdString>::iterator d = dirs.begin();
- d != dirs.end(); ++d)
- {
- i->second.push_back(*d);
- }
- }
- }
- }
- //-------------------------------------------------------------------
- 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()
- {
- this->SplitFramework.compile("(.*)/(.*)\\.framework$");
- cmStdString libext = "(";
- bool first = true;
- for(std::vector<cmStdString>::iterator i = this->LinkExtensions.begin();
- i != this->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;
- this->RemoveLibraryExtension.compile(reg.c_str());
- reg = "";
- if(this->LinkPrefix.size())
- {
- reg = "^";
- reg += this->LinkPrefix;
- }
- reg += "([^/]*)";
- reg += libext;
- this->ExtractBaseLibraryName.compile(reg.c_str());
- reg = "([^/]*)";
- reg += libext;
- this->ExtractBaseLibraryNameNoPrefix.compile(reg.c_str());
- }
- //-------------------------------------------------------------------
- void cmOrderLinkDirectories::PrepareLinkTargets()
- {
- for(std::vector<cmStdString>::iterator i = this->LinkItems.begin();
- i != this->LinkItems.end(); ++i)
- {
- // separate the library name from libfoo.a or foo.a
- if(this->ExtractBaseLibraryName.find(*i))
- {
- *i = this->ExtractBaseLibraryName.match(1);
- }
- else if(this->ExtractBaseLibraryNameNoPrefix.find(*i))
- {
- *i = this->ExtractBaseLibraryNameNoPrefix.match(1);
- }
- }
- }
- //-------------------------------------------------------------------
- bool cmOrderLinkDirectories::FindPathNotInDirectoryToAfterList(
- cmStdString& path)
- {
- for(std::vector<std::pair<cmStdString, std::vector<cmStdString> > >::iterator i
- = this->DirectoryToAfterList.begin();
- i != this->DirectoryToAfterList.end(); ++i)
- {
- const cmStdString& p = i->first;
- bool found = false;
- for(std::vector<std::pair<cmStdString, std::vector<cmStdString> > >::iterator j
- = this->DirectoryToAfterList.begin(); j != this->DirectoryToAfterList.end()
- && !found; ++j)
- {
- if(j != i)
- {
- found = (std::find(j->second.begin(), j->second.end(), p) != j->second.end());
- }
- }
- if(!found)
- {
- path = p;
- this->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
- // this->DirectoryToAfterList once it is found
- while(this->FindPathNotInDirectoryToAfterList(path))
- {
- orderedPaths.push_back(path);
- }
- // at this point if there are still paths in this->DirectoryToAfterList
- // then there is a cycle and we are stuck
- if(this->DirectoryToAfterList.size())
- {
- for(std::vector<std::pair<cmStdString, std::vector<cmStdString> > >::iterator i
- = this->DirectoryToAfterList.begin();
- i != this->DirectoryToAfterList.end(); ++i)
- {
- this->ImpossibleDirectories.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.
- this->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)
- {
- if(this->DirectoryToAfterListEmitted.insert(*p).second)
- {
- std::pair<cmStdString, std::vector<cmStdString> > dp;
- dp.first = *p;
- this->DirectoryToAfterList.push_back(dp);
- this->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)
- {
- this->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;
- // do not add a -F for the system frameworks
- this->EmittedFrameworkPaths.insert("/System/Library/Frameworks");
- for(unsigned int i=0; i < this->RawLinkItems.size(); ++i)
- {
- bool framework = false;
- if(cmSystemTools::FileIsFullPath(this->RawLinkItems[i].c_str()))
- {
- if(cmSystemTools::FileIsDirectory(this->RawLinkItems[i].c_str()))
- {
- if(cmSystemTools::IsPathToFramework(this->RawLinkItems[i].c_str()))
- {
- this->SplitFramework.find(this->RawLinkItems[i]);
- cmStdString path = this->SplitFramework.match(1);
- // Add the -F path if we have not yet done so
- if(this->EmittedFrameworkPaths.insert(path).second)
- {
- std::string fpath = "-F";
- fpath += cmSystemTools::ConvertToOutputPath(path.c_str());
- this->LinkItems.push_back(fpath);
- }
- // now add the -framework option
- std::string frame = "-framework ";
- frame += this->SplitFramework.match(2);
- this->LinkItems.push_back(frame);
- framework = true;
- }
- else
- {
- std::string message = "Warning: Ignoring path found in link libraries for target: ";
- message += this->TargetName;
- message += ", path is: ";
- message += this->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(this->RawLinkItems[i].c_str(),
- dir, file);
- #ifdef _WIN32
- // Avoid case problems for windows paths.
- if(dir.size() > 2 && dir[1] == ':')
- {
- if(dir[0] >= 'A' && dir[0] <= 'Z')
- {
- dir[0] += 'a' - 'A';
- }
- }
- dir = cmSystemTools::GetActualCaseForPath(dir.c_str());
- #endif
- if(this->DirectoryToAfterListEmitted.insert(dir).second)
- {
- std::pair<cmStdString, std::vector<cmStdString> > dp;
- dp.first = dir;
- this->DirectoryToAfterList.push_back(dp);
- }
- this->LinkPathSet.insert(dir);
- aLib.FullPath = this->RawLinkItems[i];
- aLib.File = file;
- aLib.Path = dir;
- this->FullPathLibraries[aLib.FullPath] = aLib;
- this->LinkItems.push_back(file);
- }
- }
- else
- {
- this->LinkItems.push_back(this->RawLinkItems[i]);
- }
- }
- this->FindLibrariesInSearchPaths();
- for(std::map<cmStdString, std::vector<cmStdString> >::iterator lib =
- this->LibraryToDirectories.begin(); lib!= this->LibraryToDirectories.end();
- ++lib)
- {
- if(lib->second.size() > 0)
- {
- this->MultiDirectoryLibraries.push_back(this->FullPathLibraries[lib->first]);
- }
- else
- {
- this->SingleDirectoryLibraries.push_back(this->FullPathLibraries[lib->first]);
- }
- }
- this->FindIndividualLibraryOrders();
- this->SortedSearchPaths.clear();
- if(this->Debug)
- {
- this->PrintMap("this->LibraryToDirectories", this->LibraryToDirectories);
- this->PrintVector("this->DirectoryToAfterList", this->DirectoryToAfterList);
- }
- this->OrderPaths(this->SortedSearchPaths);
- // now turn libfoo.a into foo and foo.a into foo
- // This will prepare the link items for -litem
- this->PrepareLinkTargets();
- if(this->ImpossibleDirectories.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 = this->ImpossibleDirectories.begin();
- i != this->ImpossibleDirectories.end(); ++i)
- {
- warning += "Directory: ";
- warning += *i;
- warning += " contains:\n";
- std::map<cmStdString, std::vector<cmStdString> >::iterator j;
- for(j = this->LibraryToDirectories.begin();
- j != this->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::PrintVector(const char* name,
- std::vector<std::pair<cmStdString,
- std::vector<cmStdString> > >& m)
- {
- std::cout << name << "\n";
- for(std::vector<std::pair<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 = this->FullPathLibraries.begin();
- i != this->FullPathLibraries.end(); ++i)
- {
- libs.push_back(i->first);
- }
-
- }
|