cmOrderLinkDirectories.cxx 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. #include "cmOrderLinkDirectories.h"
  2. #include "cmSystemTools.h"
  3. #include "cmsys/RegularExpression.hxx"
  4. #include <ctype.h>
  5. //-------------------------------------------------------------------
  6. cmOrderLinkDirectories::cmOrderLinkDirectories()
  7. {
  8. this->Debug = false;
  9. }
  10. //-------------------------------------------------------------------
  11. bool cmOrderLinkDirectories::LibraryInDirectory(const char* dir,
  12. const char* libIn)
  13. {
  14. cmStdString path = dir;
  15. path += "/";
  16. path += libIn;
  17. // first look for the library as given
  18. if(cmSystemTools::FileExists(path.c_str()))
  19. {
  20. return true;
  21. }
  22. // next remove the extension (.a, .so ) and look for the library
  23. // under a different name as the linker can do either
  24. if(this->RemoveLibraryExtension.find(libIn))
  25. {
  26. cmStdString lib = this->RemoveLibraryExtension.match(1);
  27. cmStdString ext = this->RemoveLibraryExtension.match(2);
  28. for(std::vector<cmStdString>::iterator i = this->LinkExtensions.begin();
  29. i != this->LinkExtensions.end(); ++i)
  30. {
  31. if(ext != *i)
  32. {
  33. path = dir;
  34. path += "/";
  35. path += lib + *i;
  36. if(cmSystemTools::FileExists(path.c_str()))
  37. {
  38. return true;
  39. }
  40. }
  41. }
  42. }
  43. return false;
  44. }
  45. //-------------------------------------------------------------------
  46. void cmOrderLinkDirectories::FindLibrariesInSearchPaths()
  47. {
  48. for(std::set<cmStdString>::iterator dir = this->LinkPathSet.begin();
  49. dir != this->LinkPathSet.end(); ++dir)
  50. {
  51. for(std::map<cmStdString, Library>::iterator lib
  52. = this->FullPathLibraries.begin();
  53. lib != this->FullPathLibraries.end(); ++lib)
  54. {
  55. if(lib->second.Path != *dir)
  56. {
  57. if(this->LibraryInDirectory(dir->c_str(), lib->second.File.c_str()))
  58. {
  59. this->LibraryToDirectories[lib->second.FullPath].push_back(*dir);
  60. }
  61. }
  62. }
  63. }
  64. }
  65. //-------------------------------------------------------------------
  66. void cmOrderLinkDirectories::FindIndividualLibraryOrders()
  67. {
  68. for(std::vector<Library>::iterator lib = this->MultiDirectoryLibraries.begin();
  69. lib != this->MultiDirectoryLibraries.end(); ++lib)
  70. {
  71. std::vector<cmStdString>& dirs = this->LibraryToDirectories[lib->FullPath];
  72. std::vector<std::pair<cmStdString, std::vector<cmStdString> > >::iterator i;
  73. for(i = this->DirectoryToAfterList.begin(); i != this->DirectoryToAfterList.end();
  74. ++i)
  75. {
  76. if(i->first == lib->Path)
  77. {
  78. break;
  79. }
  80. }
  81. if(i == this->DirectoryToAfterList.end())
  82. {
  83. std::cerr << "ERROR: should not happen\n";
  84. }
  85. else
  86. {
  87. for(std::vector<cmStdString>::iterator d = dirs.begin();
  88. d != dirs.end(); ++d)
  89. {
  90. i->second.push_back(*d);
  91. }
  92. }
  93. }
  94. }
  95. //-------------------------------------------------------------------
  96. std::string cmOrderLinkDirectories::NoCaseExpression(const char* str)
  97. {
  98. std::string ret;
  99. const char* s = str;
  100. while(*s)
  101. {
  102. if(*s == '.')
  103. {
  104. ret += *s;
  105. }
  106. else
  107. {
  108. ret += "[";
  109. ret += tolower(*s);
  110. ret += toupper(*s);
  111. ret += "]";
  112. }
  113. s++;
  114. }
  115. return ret;
  116. }
  117. //-------------------------------------------------------------------
  118. void cmOrderLinkDirectories::CreateRegularExpressions()
  119. {
  120. this->SplitFramework.compile("(.*)/(.*)\\.framework$");
  121. cmStdString libext = "(";
  122. bool first = true;
  123. for(std::vector<cmStdString>::iterator i = this->LinkExtensions.begin();
  124. i != this->LinkExtensions.end(); ++i)
  125. {
  126. if(!first)
  127. {
  128. libext += "|";
  129. }
  130. first = false;
  131. libext += "\\";
  132. #if defined(_WIN32) && !defined(__CYGWIN__)
  133. libext += this->NoCaseExpression(i->c_str());
  134. #else
  135. libext += *i;
  136. #endif
  137. }
  138. libext += ").*";
  139. cmStdString reg("(.*)");
  140. reg += libext;
  141. this->RemoveLibraryExtension.compile(reg.c_str());
  142. reg = "";
  143. if(this->LinkPrefix.size())
  144. {
  145. reg = "^";
  146. reg += this->LinkPrefix;
  147. }
  148. reg += "([^/]*)";
  149. reg += libext;
  150. this->ExtractBaseLibraryName.compile(reg.c_str());
  151. reg = "([^/]*)";
  152. reg += libext;
  153. this->ExtractBaseLibraryNameNoPrefix.compile(reg.c_str());
  154. }
  155. //-------------------------------------------------------------------
  156. void cmOrderLinkDirectories::PrepareLinkTargets()
  157. {
  158. for(std::vector<cmStdString>::iterator i = this->LinkItems.begin();
  159. i != this->LinkItems.end(); ++i)
  160. {
  161. // separate the library name from libfoo.a or foo.a
  162. if(this->ExtractBaseLibraryName.find(*i))
  163. {
  164. *i = this->ExtractBaseLibraryName.match(1);
  165. }
  166. else if(this->ExtractBaseLibraryNameNoPrefix.find(*i))
  167. {
  168. *i = this->ExtractBaseLibraryNameNoPrefix.match(1);
  169. }
  170. }
  171. }
  172. //-------------------------------------------------------------------
  173. bool cmOrderLinkDirectories::FindPathNotInDirectoryToAfterList(
  174. cmStdString& path)
  175. {
  176. for(std::vector<std::pair<cmStdString, std::vector<cmStdString> > >::iterator i
  177. = this->DirectoryToAfterList.begin();
  178. i != this->DirectoryToAfterList.end(); ++i)
  179. {
  180. const cmStdString& p = i->first;
  181. bool found = false;
  182. for(std::vector<std::pair<cmStdString, std::vector<cmStdString> > >::iterator j
  183. = this->DirectoryToAfterList.begin(); j != this->DirectoryToAfterList.end()
  184. && !found; ++j)
  185. {
  186. if(j != i)
  187. {
  188. found = (std::find(j->second.begin(), j->second.end(), p) != j->second.end());
  189. }
  190. }
  191. if(!found)
  192. {
  193. path = p;
  194. this->DirectoryToAfterList.erase(i);
  195. return true;
  196. }
  197. }
  198. path = "";
  199. return false;
  200. }
  201. //-------------------------------------------------------------------
  202. void cmOrderLinkDirectories::OrderPaths(std::vector<cmStdString>&
  203. orderedPaths)
  204. {
  205. cmStdString path;
  206. // This is a topological sort implementation
  207. // One at a time find paths that are not in any other paths after list
  208. // and put them into the orderedPaths vector in that order
  209. // FindPathNotInDirectoryToAfterList removes the path from the
  210. // this->DirectoryToAfterList once it is found
  211. while(this->FindPathNotInDirectoryToAfterList(path))
  212. {
  213. orderedPaths.push_back(path);
  214. }
  215. // at this point if there are still paths in this->DirectoryToAfterList
  216. // then there is a cycle and we are stuck
  217. if(this->DirectoryToAfterList.size())
  218. {
  219. for(std::vector<std::pair<cmStdString, std::vector<cmStdString> > >::iterator i
  220. = this->DirectoryToAfterList.begin();
  221. i != this->DirectoryToAfterList.end(); ++i)
  222. {
  223. this->ImpossibleDirectories.insert(i->first);
  224. // still put it in the path list in the order we find them
  225. orderedPaths.push_back(i->first);
  226. }
  227. }
  228. }
  229. //-------------------------------------------------------------------
  230. void cmOrderLinkDirectories::SetLinkInformation(
  231. const char* targetName,
  232. const std::vector<std::string>& linkLibraries,
  233. const std::vector<std::string>& linkDirectories
  234. )
  235. {
  236. // Save the target name.
  237. this->TargetName = targetName;
  238. // Merge the link directory search path given into our path set.
  239. std::vector<cmStdString> empty;
  240. for(std::vector<std::string>::const_iterator p = linkDirectories.begin();
  241. p != linkDirectories.end(); ++p)
  242. {
  243. if(this->DirectoryToAfterListEmitted.insert(*p).second)
  244. {
  245. std::pair<cmStdString, std::vector<cmStdString> > dp;
  246. dp.first = *p;
  247. this->DirectoryToAfterList.push_back(dp);
  248. this->LinkPathSet.insert(*p);
  249. }
  250. }
  251. // Append the link library list into our raw list.
  252. for(std::vector<std::string>::const_iterator l = linkLibraries.begin();
  253. l != linkLibraries.end(); ++l)
  254. {
  255. this->RawLinkItems.push_back(*l);
  256. }
  257. }
  258. //-------------------------------------------------------------------
  259. bool cmOrderLinkDirectories::DetermineLibraryPathOrder()
  260. {
  261. // set up all the regular expressions
  262. this->CreateRegularExpressions();
  263. std::vector<cmStdString> finalOrderPaths;
  264. // find all libs that are full paths
  265. Library aLib;
  266. cmStdString dir;
  267. cmStdString file;
  268. std::vector<cmStdString> empty;
  269. // do not add a -F for the system frameworks
  270. this->EmittedFrameworkPaths.insert("/System/Library/Frameworks");
  271. for(unsigned int i=0; i < this->RawLinkItems.size(); ++i)
  272. {
  273. bool framework = false;
  274. if(cmSystemTools::FileIsFullPath(this->RawLinkItems[i].c_str()))
  275. {
  276. if(cmSystemTools::FileIsDirectory(this->RawLinkItems[i].c_str()))
  277. {
  278. if(cmSystemTools::IsPathToFramework(this->RawLinkItems[i].c_str()))
  279. {
  280. this->SplitFramework.find(this->RawLinkItems[i]);
  281. cmStdString path = this->SplitFramework.match(1);
  282. // Add the -F path if we have not yet done so
  283. if(this->EmittedFrameworkPaths.insert(path).second)
  284. {
  285. std::string fpath = "-F";
  286. fpath += cmSystemTools::ConvertToOutputPath(path.c_str());
  287. this->LinkItems.push_back(fpath);
  288. }
  289. // now add the -framework option
  290. std::string frame = "-framework ";
  291. frame += this->SplitFramework.match(2);
  292. this->LinkItems.push_back(frame);
  293. framework = true;
  294. }
  295. else
  296. {
  297. std::string message = "Warning: Ignoring path found in link libraries for target: ";
  298. message += this->TargetName;
  299. message += ", path is: ";
  300. message += this->RawLinkItems[i];
  301. message += ". Expected a library name or a full path to a library name.";
  302. cmSystemTools::Message(message.c_str());
  303. continue;
  304. }
  305. }
  306. if(!framework)
  307. {
  308. cmSystemTools::SplitProgramPath(this->RawLinkItems[i].c_str(),
  309. dir, file);
  310. #ifdef _WIN32
  311. // Avoid case problems for windows paths.
  312. if(dir.size() > 2 && dir[1] == ':')
  313. {
  314. if(dir[0] >= 'A' && dir[0] <= 'Z')
  315. {
  316. dir[0] += 'a' - 'A';
  317. }
  318. }
  319. dir = cmSystemTools::GetActualCaseForPath(dir.c_str());
  320. #endif
  321. if(this->DirectoryToAfterListEmitted.insert(dir).second)
  322. {
  323. std::pair<cmStdString, std::vector<cmStdString> > dp;
  324. dp.first = dir;
  325. this->DirectoryToAfterList.push_back(dp);
  326. }
  327. this->LinkPathSet.insert(dir);
  328. aLib.FullPath = this->RawLinkItems[i];
  329. aLib.File = file;
  330. aLib.Path = dir;
  331. this->FullPathLibraries[aLib.FullPath] = aLib;
  332. this->LinkItems.push_back(file);
  333. }
  334. }
  335. else
  336. {
  337. this->LinkItems.push_back(this->RawLinkItems[i]);
  338. }
  339. }
  340. this->FindLibrariesInSearchPaths();
  341. for(std::map<cmStdString, std::vector<cmStdString> >::iterator lib =
  342. this->LibraryToDirectories.begin(); lib!= this->LibraryToDirectories.end();
  343. ++lib)
  344. {
  345. if(lib->second.size() > 0)
  346. {
  347. this->MultiDirectoryLibraries.push_back(this->FullPathLibraries[lib->first]);
  348. }
  349. else
  350. {
  351. this->SingleDirectoryLibraries.push_back(this->FullPathLibraries[lib->first]);
  352. }
  353. }
  354. this->FindIndividualLibraryOrders();
  355. this->SortedSearchPaths.clear();
  356. if(this->Debug)
  357. {
  358. this->PrintMap("this->LibraryToDirectories", this->LibraryToDirectories);
  359. this->PrintVector("this->DirectoryToAfterList", this->DirectoryToAfterList);
  360. }
  361. this->OrderPaths(this->SortedSearchPaths);
  362. // now turn libfoo.a into foo and foo.a into foo
  363. // This will prepare the link items for -litem
  364. this->PrepareLinkTargets();
  365. if(this->ImpossibleDirectories.size())
  366. {
  367. cmSystemTools::Message(this->GetWarnings().c_str());
  368. return false;
  369. }
  370. return true;
  371. }
  372. std::string cmOrderLinkDirectories::GetWarnings()
  373. {
  374. 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";
  375. for(std::set<cmStdString>::iterator i = this->ImpossibleDirectories.begin();
  376. i != this->ImpossibleDirectories.end(); ++i)
  377. {
  378. warning += "Directory: ";
  379. warning += *i;
  380. warning += " contains:\n";
  381. std::map<cmStdString, std::vector<cmStdString> >::iterator j;
  382. for(j = this->LibraryToDirectories.begin();
  383. j != this->LibraryToDirectories.end(); ++j)
  384. {
  385. if(std::find(j->second.begin(), j->second.end(), *i)
  386. != j->second.end())
  387. {
  388. warning += "Library: ";
  389. warning += j->first;
  390. warning += "\n";
  391. }
  392. }
  393. warning += "\n";
  394. }
  395. warning += "\n";
  396. return warning;
  397. }
  398. //-------------------------------------------------------------------
  399. void
  400. cmOrderLinkDirectories::PrintMap(const char* name,
  401. std::map<cmStdString, std::vector<cmStdString> >& m)
  402. {
  403. std::cout << name << "\n";
  404. for(std::map<cmStdString, std::vector<cmStdString> >::iterator i =
  405. m.begin(); i != m.end();
  406. ++i)
  407. {
  408. std::cout << i->first << ": ";
  409. for(std::vector<cmStdString>::iterator l = i->second.begin();
  410. l != i->second.end(); ++l)
  411. {
  412. std::cout << *l << " ";
  413. }
  414. std::cout << "\n";
  415. }
  416. }
  417. //-------------------------------------------------------------------
  418. void
  419. cmOrderLinkDirectories::PrintVector(const char* name,
  420. std::vector<std::pair<cmStdString,
  421. std::vector<cmStdString> > >& m)
  422. {
  423. std::cout << name << "\n";
  424. for(std::vector<std::pair<cmStdString, std::vector<cmStdString> > >::iterator i =
  425. m.begin(); i != m.end();
  426. ++i)
  427. {
  428. std::cout << i->first << ": ";
  429. for(std::vector<cmStdString>::iterator l = i->second.begin();
  430. l != i->second.end(); ++l)
  431. {
  432. std::cout << *l << " ";
  433. }
  434. std::cout << "\n";
  435. }
  436. }
  437. void cmOrderLinkDirectories::GetFullPathLibraries(std::vector<cmStdString>&
  438. libs)
  439. {
  440. for(std::map<cmStdString, Library>::iterator i = this->FullPathLibraries.begin();
  441. i != this->FullPathLibraries.end(); ++i)
  442. {
  443. libs.push_back(i->first);
  444. }
  445. }