cmOrderLinkDirectories.cxx 16 KB

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