cmOrderLinkDirectories.cxx 16 KB

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