cmOrderLinkDirectories.cxx 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  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. std::string dir = *p;
  246. #ifdef _WIN32
  247. // Avoid case problems for windows paths.
  248. if(dir.size() > 2 && dir[1] == ':')
  249. {
  250. if(dir[0] >= 'A' && dir[0] <= 'Z')
  251. {
  252. dir[0] += 'a' - 'A';
  253. }
  254. }
  255. dir = cmSystemTools::GetActualCaseForPath(dir.c_str());
  256. #endif
  257. if(this->DirectoryToAfterListEmitted.insert(dir).second)
  258. {
  259. std::pair<cmStdString, std::vector<cmStdString> > dp;
  260. dp.first = dir;
  261. this->DirectoryToAfterList.push_back(dp);
  262. this->LinkPathSet.insert(dir);
  263. }
  264. }
  265. // Append the link library list into our raw list.
  266. for(std::vector<std::string>::const_iterator l = linkLibraries.begin();
  267. l != linkLibraries.end(); ++l)
  268. {
  269. this->RawLinkItems.push_back(*l);
  270. }
  271. // Construct a set of files that will exist after building.
  272. for(cmTargetManifest::const_iterator i = manifest.begin();
  273. i != manifest.end(); ++i)
  274. {
  275. for(cmTargetSet::const_iterator j = i->second.begin();
  276. j != i->second.end(); ++j)
  277. {
  278. this->ManifestFiles.insert(*j);
  279. }
  280. }
  281. }
  282. //-------------------------------------------------------------------
  283. bool cmOrderLinkDirectories::DetermineLibraryPathOrder()
  284. {
  285. // set up all the regular expressions
  286. this->CreateRegularExpressions();
  287. std::vector<cmStdString> finalOrderPaths;
  288. // find all libs that are full paths
  289. Library aLib;
  290. cmStdString dir;
  291. cmStdString file;
  292. std::vector<cmStdString> empty;
  293. // do not add a -F for the system frameworks
  294. this->EmittedFrameworkPaths.insert("/System/Library/Frameworks");
  295. for(unsigned int i=0; i < this->RawLinkItems.size(); ++i)
  296. {
  297. bool framework = false;
  298. if(cmSystemTools::FileIsFullPath(this->RawLinkItems[i].c_str()))
  299. {
  300. if(cmSystemTools::FileIsDirectory(this->RawLinkItems[i].c_str()))
  301. {
  302. if(cmSystemTools::IsPathToFramework(this->RawLinkItems[i].c_str()))
  303. {
  304. this->SplitFramework.find(this->RawLinkItems[i]);
  305. cmStdString path = this->SplitFramework.match(1);
  306. // Add the -F path if we have not yet done so
  307. if(this->EmittedFrameworkPaths.insert(path).second)
  308. {
  309. std::string fpath = "-F";
  310. fpath += cmSystemTools::ConvertToOutputPath(path.c_str());
  311. this->LinkItems.push_back(fpath);
  312. }
  313. // now add the -framework option
  314. std::string frame = "-framework ";
  315. frame += this->SplitFramework.match(2);
  316. this->LinkItems.push_back(frame);
  317. framework = true;
  318. }
  319. else
  320. {
  321. std::string message = "Warning: Ignoring path found in link libraries for target: ";
  322. message += this->TargetName;
  323. message += ", path is: ";
  324. message += this->RawLinkItems[i];
  325. message += ". Expected a library name or a full path to a library name.";
  326. cmSystemTools::Message(message.c_str());
  327. continue;
  328. }
  329. }
  330. if(!framework)
  331. {
  332. dir = cmSystemTools::GetFilenamePath(this->RawLinkItems[i]);
  333. file = cmSystemTools::GetFilenameName(this->RawLinkItems[i]);
  334. #ifdef _WIN32
  335. // Avoid case problems for windows paths.
  336. if(dir.size() > 2 && dir[1] == ':')
  337. {
  338. if(dir[0] >= 'A' && dir[0] <= 'Z')
  339. {
  340. dir[0] += 'a' - 'A';
  341. }
  342. }
  343. dir = cmSystemTools::GetActualCaseForPath(dir.c_str());
  344. #endif
  345. if(this->DirectoryToAfterListEmitted.insert(dir).second)
  346. {
  347. std::pair<cmStdString, std::vector<cmStdString> > dp;
  348. dp.first = dir;
  349. this->DirectoryToAfterList.push_back(dp);
  350. }
  351. this->LinkPathSet.insert(dir);
  352. aLib.FullPath = this->RawLinkItems[i];
  353. aLib.File = file;
  354. aLib.Path = dir;
  355. this->FullPathLibraries[aLib.FullPath] = aLib;
  356. this->LinkItems.push_back(file);
  357. }
  358. }
  359. else
  360. {
  361. this->LinkItems.push_back(this->RawLinkItems[i]);
  362. }
  363. }
  364. this->FindLibrariesInSearchPaths();
  365. for(std::map<cmStdString, std::vector<cmStdString> >::iterator lib =
  366. this->LibraryToDirectories.begin(); lib!= this->LibraryToDirectories.end();
  367. ++lib)
  368. {
  369. if(lib->second.size() > 0)
  370. {
  371. this->MultiDirectoryLibraries.push_back(this->FullPathLibraries[lib->first]);
  372. }
  373. else
  374. {
  375. this->SingleDirectoryLibraries.push_back(this->FullPathLibraries[lib->first]);
  376. }
  377. }
  378. this->FindIndividualLibraryOrders();
  379. this->SortedSearchPaths.clear();
  380. if(this->Debug)
  381. {
  382. this->PrintMap("this->LibraryToDirectories", this->LibraryToDirectories);
  383. this->PrintVector("this->DirectoryToAfterList", this->DirectoryToAfterList);
  384. }
  385. this->OrderPaths(this->SortedSearchPaths);
  386. // now turn libfoo.a into foo and foo.a into foo
  387. // This will prepare the link items for -litem
  388. this->PrepareLinkTargets();
  389. if(this->ImpossibleDirectories.size())
  390. {
  391. cmSystemTools::Message(this->GetWarnings().c_str());
  392. return false;
  393. }
  394. return true;
  395. }
  396. std::string cmOrderLinkDirectories::GetWarnings()
  397. {
  398. 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";
  399. for(std::set<cmStdString>::iterator i = this->ImpossibleDirectories.begin();
  400. i != this->ImpossibleDirectories.end(); ++i)
  401. {
  402. warning += "Directory: ";
  403. warning += *i;
  404. warning += " contains:\n";
  405. std::map<cmStdString, std::vector<cmStdString> >::iterator j;
  406. for(j = this->LibraryToDirectories.begin();
  407. j != this->LibraryToDirectories.end(); ++j)
  408. {
  409. if(std::find(j->second.begin(), j->second.end(), *i)
  410. != j->second.end())
  411. {
  412. warning += "Library: ";
  413. warning += j->first;
  414. warning += "\n";
  415. }
  416. }
  417. warning += "\n";
  418. }
  419. warning += "\n";
  420. return warning;
  421. }
  422. //-------------------------------------------------------------------
  423. void
  424. cmOrderLinkDirectories::PrintMap(const char* name,
  425. std::map<cmStdString, std::vector<cmStdString> >& m)
  426. {
  427. std::cout << name << "\n";
  428. for(std::map<cmStdString, std::vector<cmStdString> >::iterator i =
  429. m.begin(); i != m.end();
  430. ++i)
  431. {
  432. std::cout << i->first << ": ";
  433. for(std::vector<cmStdString>::iterator l = i->second.begin();
  434. l != i->second.end(); ++l)
  435. {
  436. std::cout << *l << " ";
  437. }
  438. std::cout << "\n";
  439. }
  440. }
  441. //-------------------------------------------------------------------
  442. void
  443. cmOrderLinkDirectories::PrintVector(const char* name,
  444. std::vector<std::pair<cmStdString,
  445. std::vector<cmStdString> > >& m)
  446. {
  447. std::cout << name << "\n";
  448. for(std::vector<std::pair<cmStdString, std::vector<cmStdString> > >::iterator i =
  449. m.begin(); i != m.end();
  450. ++i)
  451. {
  452. std::cout << i->first << ": ";
  453. for(std::vector<cmStdString>::iterator l = i->second.begin();
  454. l != i->second.end(); ++l)
  455. {
  456. std::cout << *l << " ";
  457. }
  458. std::cout << "\n";
  459. }
  460. }
  461. void cmOrderLinkDirectories::GetFullPathLibraries(std::vector<cmStdString>&
  462. libs)
  463. {
  464. for(std::map<cmStdString, Library>::iterator i = this->FullPathLibraries.begin();
  465. i != this->FullPathLibraries.end(); ++i)
  466. {
  467. libs.push_back(i->first);
  468. }
  469. }
  470. //----------------------------------------------------------------------------
  471. bool cmOrderLinkDirectories::LibraryMayConflict(const char* desiredLib,
  472. const char* dir,
  473. const char* fname)
  474. {
  475. // We need to check whether the given file may be picked up by the
  476. // linker. This will occur if it exists as given or may be built
  477. // using the name given.
  478. bool found = false;
  479. std::string path = dir;
  480. path += "/";
  481. path += fname;
  482. if(this->ManifestFiles.find(path) != this->ManifestFiles.end())
  483. {
  484. found = true;
  485. }
  486. else if(cmSystemTools::FileExists(path.c_str()))
  487. {
  488. found = true;
  489. }
  490. // When linking with a multi-configuration build tool the
  491. // per-configuration subdirectory is added to each link path. Check
  492. // this subdirectory too.
  493. if(!found && !this->ConfigSubdir.empty())
  494. {
  495. path = dir;
  496. path += "/";
  497. path += this->ConfigSubdir;
  498. path += "/";
  499. path += fname;
  500. if(this->ManifestFiles.find(path) != this->ManifestFiles.end())
  501. {
  502. found = true;
  503. }
  504. else if(cmSystemTools::FileExists(path.c_str()))
  505. {
  506. found = true;
  507. }
  508. }
  509. // A library conflicts if it is found and is not a symlink back to
  510. // the desired library.
  511. if(found)
  512. {
  513. return !cmSystemTools::SameFile(desiredLib, path.c_str());
  514. }
  515. return false;
  516. }