cmFindBase.cxx 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. /*============================================================================
  2. CMake - Cross Platform Makefile Generator
  3. Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
  4. Distributed under the OSI-approved BSD License (the "License");
  5. see accompanying file Copyright.txt for details.
  6. This software is distributed WITHOUT ANY WARRANTY; without even the
  7. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  8. See the License for more information.
  9. ============================================================================*/
  10. #include "cmFindBase.h"
  11. cmFindBase::cmFindBase()
  12. {
  13. this->AlreadyInCache = false;
  14. this->AlreadyInCacheWithoutMetaInfo = false;
  15. this->NamesPerDir = false;
  16. this->NamesPerDirAllowed = false;
  17. }
  18. //----------------------------------------------------------------------------
  19. bool cmFindBase::ParseArguments(std::vector<std::string> const& argsIn)
  20. {
  21. if(argsIn.size() < 2 )
  22. {
  23. this->SetError("called with incorrect number of arguments");
  24. return false;
  25. }
  26. // CMake versions below 2.3 did not search all these extra
  27. // locations. Preserve compatibility unless a modern argument is
  28. // passed.
  29. bool compatibility = this->Makefile->NeedBackwardsCompatibility(2,3);
  30. // copy argsIn into args so it can be modified,
  31. // in the process extract the DOC "documentation"
  32. size_t size = argsIn.size();
  33. std::vector<std::string> args;
  34. bool foundDoc = false;
  35. for(unsigned int j = 0; j < size; ++j)
  36. {
  37. if(foundDoc || argsIn[j] != "DOC" )
  38. {
  39. if(argsIn[j] == "ENV")
  40. {
  41. if(j+1 < size)
  42. {
  43. j++;
  44. cmSystemTools::GetPath(args, argsIn[j].c_str());
  45. }
  46. }
  47. else
  48. {
  49. args.push_back(argsIn[j]);
  50. }
  51. }
  52. else
  53. {
  54. if(j+1 < size)
  55. {
  56. foundDoc = true;
  57. this->VariableDocumentation = argsIn[j+1];
  58. j++;
  59. if(j >= size)
  60. {
  61. break;
  62. }
  63. }
  64. }
  65. }
  66. if(args.size() < 2 )
  67. {
  68. this->SetError("called with incorrect number of arguments");
  69. return false;
  70. }
  71. this->VariableName = args[0];
  72. if(this->CheckForVariableInCache())
  73. {
  74. this->AlreadyInCache = true;
  75. return true;
  76. }
  77. this->AlreadyInCache = false;
  78. // Find the current root path mode.
  79. this->SelectDefaultRootPathMode();
  80. // Find the current bundle/framework search policy.
  81. this->SelectDefaultMacMode();
  82. bool newStyle = false;
  83. enum Doing { DoingNone, DoingNames, DoingPaths, DoingPathSuffixes,
  84. DoingHints };
  85. Doing doing = DoingNames; // assume it starts with a name
  86. for (unsigned int j = 1; j < args.size(); ++j)
  87. {
  88. if(args[j] == "NAMES")
  89. {
  90. doing = DoingNames;
  91. newStyle = true;
  92. }
  93. else if (args[j] == "PATHS")
  94. {
  95. doing = DoingPaths;
  96. newStyle = true;
  97. }
  98. else if (args[j] == "HINTS")
  99. {
  100. doing = DoingHints;
  101. newStyle = true;
  102. }
  103. else if (args[j] == "PATH_SUFFIXES")
  104. {
  105. doing = DoingPathSuffixes;
  106. compatibility = false;
  107. newStyle = true;
  108. }
  109. else if (args[j] == "NAMES_PER_DIR")
  110. {
  111. doing = DoingNone;
  112. if(this->NamesPerDirAllowed)
  113. {
  114. this->NamesPerDir = true;
  115. }
  116. else
  117. {
  118. this->SetError("does not support NAMES_PER_DIR");
  119. return false;
  120. }
  121. }
  122. else if (args[j] == "NO_SYSTEM_PATH")
  123. {
  124. doing = DoingNone;
  125. this->NoDefaultPath = true;
  126. }
  127. else if (this->CheckCommonArgument(args[j]))
  128. {
  129. doing = DoingNone;
  130. compatibility = false;
  131. // Some common arguments were accidentally supported by CMake
  132. // 2.4 and 2.6.0 in the short-hand form of the command, so we
  133. // must support it even though it is not documented.
  134. }
  135. else if(doing == DoingNames)
  136. {
  137. this->Names.push_back(args[j]);
  138. }
  139. else if(doing == DoingPaths)
  140. {
  141. this->AddUserPath(args[j], this->UserPaths);
  142. }
  143. else if(doing == DoingHints)
  144. {
  145. this->AddUserPath(args[j], this->UserHints);
  146. }
  147. else if(doing == DoingPathSuffixes)
  148. {
  149. this->AddPathSuffix(args[j]);
  150. }
  151. }
  152. // Now that arguments have been parsed check the compatibility
  153. // setting. If we need to be compatible with CMake 2.2 and earlier
  154. // do not add the CMake system paths. It is safe to add the CMake
  155. // environment paths and system environment paths because that
  156. // existed in 2.2. It is safe to add the CMake user variable paths
  157. // because the user or project has explicitly set them.
  158. if(compatibility)
  159. {
  160. this->NoCMakeSystemPath = true;
  161. }
  162. if(this->VariableDocumentation.size() == 0)
  163. {
  164. this->VariableDocumentation = "Where can ";
  165. if(this->Names.size() == 0)
  166. {
  167. this->VariableDocumentation += "the (unknown) library be found";
  168. }
  169. else if(this->Names.size() == 1)
  170. {
  171. this->VariableDocumentation += "the "
  172. + this->Names[0] + " library be found";
  173. }
  174. else
  175. {
  176. this->VariableDocumentation += "one of the " + this->Names[0];
  177. for (unsigned int j = 1; j < this->Names.size() - 1; ++j)
  178. {
  179. this->VariableDocumentation += ", " + this->Names[j];
  180. }
  181. this->VariableDocumentation += " or "
  182. + this->Names[this->Names.size() - 1] + " libraries be found";
  183. }
  184. }
  185. // look for old style
  186. // FIND_*(VAR name path1 path2 ...)
  187. if(!newStyle)
  188. {
  189. // All the short-hand arguments have been recorded as names.
  190. std::vector<std::string> shortArgs = this->Names;
  191. this->Names.clear(); // clear out any values in Names
  192. this->Names.push_back(shortArgs[0]);
  193. for(unsigned int j = 1; j < shortArgs.size(); ++j)
  194. {
  195. this->AddUserPath(shortArgs[j], this->UserPaths);
  196. }
  197. }
  198. this->ExpandPaths();
  199. // Filter out ignored paths from the prefix list
  200. std::set<std::string> ignored;
  201. this->GetIgnoredPaths(ignored);
  202. this->FilterPaths(this->SearchPaths, ignored);
  203. this->ComputeFinalPaths();
  204. return true;
  205. }
  206. void cmFindBase::ExpandPaths()
  207. {
  208. this->AddCMakeVariablePath();
  209. this->AddCMakeEnvironmentPath();
  210. this->AddUserHintsPath();
  211. this->AddSystemEnvironmentPath();
  212. this->AddCMakeSystemVariablePath();
  213. this->AddUserGuessPath();
  214. // Add suffixes and clean up paths.
  215. this->AddPathSuffixes();
  216. }
  217. //----------------------------------------------------------------------------
  218. void cmFindBase::AddPrefixPaths(std::vector<std::string> const& in_paths,
  219. PathType pathType)
  220. {
  221. // default for programs
  222. std::string subdir = "bin";
  223. if (this->CMakePathName == "INCLUDE")
  224. {
  225. subdir = "include";
  226. }
  227. else if (this->CMakePathName == "LIBRARY")
  228. {
  229. subdir = "lib";
  230. }
  231. else if (this->CMakePathName == "FRAMEWORK")
  232. {
  233. subdir = ""; // ? what to do for frameworks ?
  234. }
  235. for(std::vector<std::string>::const_iterator it = in_paths.begin();
  236. it != in_paths.end(); ++it)
  237. {
  238. std::string dir = it->c_str();
  239. if(!subdir.empty() && !dir.empty() && dir[dir.size()-1] != '/')
  240. {
  241. dir += "/";
  242. }
  243. if(subdir == "include" || subdir == "lib")
  244. {
  245. const char* arch =
  246. this->Makefile->GetDefinition("CMAKE_LIBRARY_ARCHITECTURE");
  247. if(arch && *arch)
  248. {
  249. this->AddPathInternal(dir+subdir+"/"+arch, pathType);
  250. }
  251. }
  252. std::string add = dir + subdir;
  253. if(add != "/")
  254. {
  255. this->AddPathInternal(add, pathType);
  256. }
  257. if (subdir == "bin")
  258. {
  259. this->AddPathInternal(dir+"sbin", pathType);
  260. }
  261. if(!subdir.empty() && *it != "/")
  262. {
  263. this->AddPathInternal(*it, pathType);
  264. }
  265. }
  266. }
  267. //----------------------------------------------------------------------------
  268. void cmFindBase::AddCMakePrefixPath(const char* variable)
  269. {
  270. // Get a path from a CMake variable.
  271. if(const char* varPath = this->Makefile->GetDefinition(variable))
  272. {
  273. std::vector<std::string> tmp;
  274. cmSystemTools::ExpandListArgument(varPath, tmp);
  275. this->AddPrefixPaths(tmp, CMakePath);
  276. }
  277. }
  278. //----------------------------------------------------------------------------
  279. void cmFindBase::AddEnvPrefixPath(const char* variable)
  280. {
  281. // Get a path from the environment.
  282. std::vector<std::string> tmp;
  283. cmSystemTools::GetPath(tmp, variable);
  284. this->AddPrefixPaths(tmp, EnvPath);
  285. }
  286. //----------------------------------------------------------------------------
  287. void cmFindBase::AddCMakeEnvironmentPath()
  288. {
  289. if(!this->NoCMakeEnvironmentPath && !this->NoDefaultPath)
  290. {
  291. // Add CMAKE_*_PATH environment variables
  292. std::string var = "CMAKE_";
  293. var += this->CMakePathName;
  294. var += "_PATH";
  295. this->AddEnvPrefixPath("CMAKE_PREFIX_PATH");
  296. this->AddEnvPath(var.c_str());
  297. if(this->CMakePathName == "PROGRAM")
  298. {
  299. this->AddEnvPath("CMAKE_APPBUNDLE_PATH");
  300. }
  301. else
  302. {
  303. this->AddEnvPath("CMAKE_FRAMEWORK_PATH");
  304. }
  305. }
  306. }
  307. //----------------------------------------------------------------------------
  308. void cmFindBase::AddCMakeVariablePath()
  309. {
  310. if(!this->NoCMakePath && !this->NoDefaultPath)
  311. {
  312. // Add CMake varibles of the same name as the previous environment
  313. // varibles CMAKE_*_PATH to be used most of the time with -D
  314. // command line options
  315. std::string var = "CMAKE_";
  316. var += this->CMakePathName;
  317. var += "_PATH";
  318. this->AddCMakePrefixPath("CMAKE_PREFIX_PATH");
  319. this->AddCMakePath(var.c_str());
  320. if(this->CMakePathName == "PROGRAM")
  321. {
  322. this->AddCMakePath("CMAKE_APPBUNDLE_PATH");
  323. }
  324. else
  325. {
  326. this->AddCMakePath("CMAKE_FRAMEWORK_PATH");
  327. }
  328. }
  329. }
  330. //----------------------------------------------------------------------------
  331. void cmFindBase::AddSystemEnvironmentPath()
  332. {
  333. if(!this->NoSystemEnvironmentPath && !this->NoDefaultPath)
  334. {
  335. // Add LIB or INCLUDE
  336. if(!this->EnvironmentPath.empty())
  337. {
  338. this->AddEnvPath(this->EnvironmentPath.c_str());
  339. }
  340. // Add PATH
  341. this->AddEnvPath(0);
  342. }
  343. }
  344. //----------------------------------------------------------------------------
  345. void cmFindBase::AddCMakeSystemVariablePath()
  346. {
  347. if(!this->NoCMakeSystemPath && !this->NoDefaultPath)
  348. {
  349. std::string var = "CMAKE_SYSTEM_";
  350. var += this->CMakePathName;
  351. var += "_PATH";
  352. this->AddCMakePrefixPath("CMAKE_SYSTEM_PREFIX_PATH");
  353. this->AddCMakePath(var.c_str());
  354. if(this->CMakePathName == "PROGRAM")
  355. {
  356. this->AddCMakePath("CMAKE_SYSTEM_APPBUNDLE_PATH");
  357. }
  358. else
  359. {
  360. this->AddCMakePath("CMAKE_SYSTEM_FRAMEWORK_PATH");
  361. }
  362. }
  363. }
  364. //----------------------------------------------------------------------------
  365. void cmFindBase::AddUserHintsPath()
  366. {
  367. this->AddPathsInternal(this->UserHints, CMakePath);
  368. }
  369. //----------------------------------------------------------------------------
  370. void cmFindBase::AddUserGuessPath()
  371. {
  372. this->AddPathsInternal(this->UserPaths, CMakePath);
  373. }
  374. //----------------------------------------------------------------------------
  375. void cmFindBase::AddPathSuffixes()
  376. {
  377. std::vector<std::string>& paths = this->SearchPaths;
  378. std::vector<std::string> finalPath = paths;
  379. std::vector<std::string>::iterator i;
  380. // clear the path
  381. paths.clear();
  382. // convert all paths to unix slashes and add search path suffixes
  383. // if there are any
  384. for(i = finalPath.begin();
  385. i != finalPath.end(); ++i)
  386. {
  387. cmSystemTools::ConvertToUnixSlashes(*i);
  388. // copy each finalPath combined with SearchPathSuffixes
  389. // to the SearchPaths ivar
  390. for(std::vector<std::string>::iterator j =
  391. this->SearchPathSuffixes.begin();
  392. j != this->SearchPathSuffixes.end(); ++j)
  393. {
  394. // if *i is only / then do not add a //
  395. // this will get incorrectly considered a network
  396. // path on windows and cause huge delays.
  397. std::string p = *i;
  398. if(p.size() && p[p.size()-1] != '/')
  399. {
  400. p += std::string("/");
  401. }
  402. p += *j;
  403. // add to all paths because the search path may be modified
  404. // later with lib being replaced for lib64 which may exist
  405. paths.push_back(p);
  406. }
  407. // now put the path without the path suffixes in the SearchPaths
  408. paths.push_back(*i);
  409. }
  410. }
  411. void cmFindBase::PrintFindStuff()
  412. {
  413. std::cerr << "SearchFrameworkLast: " << this->SearchFrameworkLast << "\n";
  414. std::cerr << "SearchFrameworkOnly: " << this->SearchFrameworkOnly << "\n";
  415. std::cerr << "SearchFrameworkFirst: " << this->SearchFrameworkFirst << "\n";
  416. std::cerr << "SearchAppBundleLast: " << this->SearchAppBundleLast << "\n";
  417. std::cerr << "SearchAppBundleOnly: " << this->SearchAppBundleOnly << "\n";
  418. std::cerr << "SearchAppBundleFirst: " << this->SearchAppBundleFirst << "\n";
  419. std::cerr << "VariableName " << this->VariableName << "\n";
  420. std::cerr << "VariableDocumentation "
  421. << this->VariableDocumentation << "\n";
  422. std::cerr << "NoDefaultPath " << this->NoDefaultPath << "\n";
  423. std::cerr << "NoCMakeEnvironmentPath "
  424. << this->NoCMakeEnvironmentPath << "\n";
  425. std::cerr << "NoCMakePath " << this->NoCMakePath << "\n";
  426. std::cerr << "NoSystemEnvironmentPath "
  427. << this->NoSystemEnvironmentPath << "\n";
  428. std::cerr << "NoCMakeSystemPath " << this->NoCMakeSystemPath << "\n";
  429. std::cerr << "EnvironmentPath " << this->EnvironmentPath << "\n";
  430. std::cerr << "CMakePathName " << this->CMakePathName << "\n";
  431. std::cerr << "Names ";
  432. for(unsigned int i =0; i < this->Names.size(); ++i)
  433. {
  434. std::cerr << this->Names[i] << " ";
  435. }
  436. std::cerr << "\n";
  437. std::cerr << "\n";
  438. std::cerr << "SearchPathSuffixes ";
  439. for(unsigned int i =0; i < this->SearchPathSuffixes.size(); ++i)
  440. {
  441. std::cerr << this->SearchPathSuffixes[i] << "\n";
  442. }
  443. std::cerr << "\n";
  444. std::cerr << "SearchPaths\n";
  445. for(unsigned int i =0; i < this->SearchPaths.size(); ++i)
  446. {
  447. std::cerr << "[" << this->SearchPaths[i] << "]\n";
  448. }
  449. }
  450. bool cmFindBase::CheckForVariableInCache()
  451. {
  452. if(const char* cacheValue =
  453. this->Makefile->GetDefinition(this->VariableName.c_str()))
  454. {
  455. cmCacheManager::CacheIterator it =
  456. this->Makefile->GetCacheManager()->
  457. GetCacheIterator(this->VariableName.c_str());
  458. bool found = !cmSystemTools::IsNOTFOUND(cacheValue);
  459. bool cached = !it.IsAtEnd();
  460. if(found)
  461. {
  462. // If the user specifies the entry on the command line without a
  463. // type we should add the type and docstring but keep the
  464. // original value. Tell the subclass implementations to do
  465. // this.
  466. if(cached && it.GetType() == cmCacheManager::UNINITIALIZED)
  467. {
  468. this->AlreadyInCacheWithoutMetaInfo = true;
  469. }
  470. return true;
  471. }
  472. else if(cached)
  473. {
  474. const char* hs = it.GetProperty("HELPSTRING");
  475. this->VariableDocumentation = hs?hs:"(none)";
  476. }
  477. }
  478. return false;
  479. }