cmFindBase.cxx 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  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. }
  16. //----------------------------------------------------------------------------
  17. void cmFindBase::GenerateDocumentation()
  18. {
  19. this->cmFindCommon::GenerateDocumentation();
  20. cmSystemTools::ReplaceString(this->GenericDocumentationPathsOrder,
  21. "FIND_ARGS_XXX", "<VAR> NAMES name");
  22. this->GenericDocumentation =
  23. " FIND_XXX(<VAR> name1 [path1 path2 ...])\n"
  24. "This is the short-hand signature for the command that "
  25. "is sufficient in many cases. It is the same "
  26. "as FIND_XXX(<VAR> name1 [PATHS path1 path2 ...])\n"
  27. " FIND_XXX(\n"
  28. " <VAR>\n"
  29. " name | NAMES name1 [name2 ...]\n"
  30. " [HINTS path1 [path2 ... ENV var]]\n"
  31. " [PATHS path1 [path2 ... ENV var]]\n"
  32. " [PATH_SUFFIXES suffix1 [suffix2 ...]]\n"
  33. " [DOC \"cache documentation string\"]\n"
  34. " [NO_DEFAULT_PATH]\n"
  35. " [NO_CMAKE_ENVIRONMENT_PATH]\n"
  36. " [NO_CMAKE_PATH]\n"
  37. " [NO_SYSTEM_ENVIRONMENT_PATH]\n"
  38. " [NO_CMAKE_SYSTEM_PATH]\n"
  39. " [CMAKE_FIND_ROOT_PATH_BOTH |\n"
  40. " ONLY_CMAKE_FIND_ROOT_PATH |\n"
  41. " NO_CMAKE_FIND_ROOT_PATH]\n"
  42. " )\n"
  43. ""
  44. "This command is used to find a SEARCH_XXX_DESC. "
  45. "A cache entry named by <VAR> is created to store the result "
  46. "of this command. "
  47. "If the SEARCH_XXX is found the result is stored in the variable "
  48. "and the search will not be repeated unless the variable is cleared. "
  49. "If nothing is found, the result will be "
  50. "<VAR>-NOTFOUND, and the search will be attempted again the "
  51. "next time FIND_XXX is invoked with the same variable. "
  52. "The name of the SEARCH_XXX that "
  53. "is searched for is specified by the names listed "
  54. "after the NAMES argument. Additional search locations "
  55. "can be specified after the PATHS argument. If ENV var is "
  56. "found in the HINTS or PATHS section the environment variable var "
  57. "will be read and converted from a system environment variable to "
  58. "a cmake style list of paths. For example ENV PATH would be a way "
  59. "to list the system path variable. The argument "
  60. "after DOC will be used for the documentation string in "
  61. "the cache. "
  62. "PATH_SUFFIXES specifies additional subdirectories to check below "
  63. "each search path."
  64. "\n"
  65. "If NO_DEFAULT_PATH is specified, then no additional paths are "
  66. "added to the search. "
  67. "If NO_DEFAULT_PATH is not specified, the search process is as follows:\n"
  68. "1. Search paths specified in cmake-specific cache variables. "
  69. "These are intended to be used on the command line with a -DVAR=value. "
  70. "This can be skipped if NO_CMAKE_PATH is passed.\n"
  71. "XXX_EXTRA_PREFIX_ENTRY"
  72. " <prefix>/XXX_SUBDIR for each <prefix> in CMAKE_PREFIX_PATH\n"
  73. " CMAKE_XXX_PATH\n"
  74. " CMAKE_XXX_MAC_PATH\n"
  75. "2. Search paths specified in cmake-specific environment variables. "
  76. "These are intended to be set in the user's shell configuration. "
  77. "This can be skipped if NO_CMAKE_ENVIRONMENT_PATH is passed.\n"
  78. "XXX_EXTRA_PREFIX_ENTRY"
  79. " <prefix>/XXX_SUBDIR for each <prefix> in CMAKE_PREFIX_PATH\n"
  80. " CMAKE_XXX_PATH\n"
  81. " CMAKE_XXX_MAC_PATH\n"
  82. "3. Search the paths specified by the HINTS option. "
  83. "These should be paths computed by system introspection, such as a "
  84. "hint provided by the location of another item already found. "
  85. "Hard-coded guesses should be specified with the PATHS option.\n"
  86. "4. Search the standard system environment variables. "
  87. "This can be skipped if NO_SYSTEM_ENVIRONMENT_PATH is an argument.\n"
  88. " PATH\n"
  89. " XXX_SYSTEM\n" // replace with "", LIB, or INCLUDE
  90. "5. Search cmake variables defined in the Platform files "
  91. "for the current system. This can be skipped if NO_CMAKE_SYSTEM_PATH "
  92. "is passed.\n"
  93. "XXX_EXTRA_PREFIX_ENTRY"
  94. " <prefix>/XXX_SUBDIR for each <prefix> in CMAKE_SYSTEM_PREFIX_PATH\n"
  95. " CMAKE_SYSTEM_XXX_PATH\n"
  96. " CMAKE_SYSTEM_XXX_MAC_PATH\n"
  97. "6. Search the paths specified by the PATHS option "
  98. "or in the short-hand version of the command. "
  99. "These are typically hard-coded guesses.\n"
  100. ;
  101. this->GenericDocumentation += this->GenericDocumentationMacPolicy;
  102. this->GenericDocumentation += this->GenericDocumentationRootPath;
  103. this->GenericDocumentation += this->GenericDocumentationPathsOrder;
  104. }
  105. //----------------------------------------------------------------------------
  106. const char* cmFindBase::GetFullDocumentation() const
  107. {
  108. if(this->GenericDocumentation.empty())
  109. {
  110. const_cast<cmFindBase *>(this)->GenerateDocumentation();
  111. }
  112. return this->GenericDocumentation.c_str();
  113. }
  114. //----------------------------------------------------------------------------
  115. bool cmFindBase::ParseArguments(std::vector<std::string> const& argsIn)
  116. {
  117. if(argsIn.size() < 2 )
  118. {
  119. this->SetError("called with incorrect number of arguments");
  120. return false;
  121. }
  122. // CMake versions below 2.3 did not search all these extra
  123. // locations. Preserve compatibility unless a modern argument is
  124. // passed.
  125. bool compatibility = this->Makefile->NeedBackwardsCompatibility(2,3);
  126. // copy argsIn into args so it can be modified,
  127. // in the process extract the DOC "documentation"
  128. size_t size = argsIn.size();
  129. std::vector<std::string> args;
  130. bool foundDoc = false;
  131. for(unsigned int j = 0; j < size; ++j)
  132. {
  133. if(foundDoc || argsIn[j] != "DOC" )
  134. {
  135. if(argsIn[j] == "ENV")
  136. {
  137. if(j+1 < size)
  138. {
  139. j++;
  140. cmSystemTools::GetPath(args, argsIn[j].c_str());
  141. }
  142. }
  143. else
  144. {
  145. args.push_back(argsIn[j]);
  146. }
  147. }
  148. else
  149. {
  150. if(j+1 < size)
  151. {
  152. foundDoc = true;
  153. this->VariableDocumentation = argsIn[j+1];
  154. j++;
  155. if(j >= size)
  156. {
  157. break;
  158. }
  159. }
  160. }
  161. }
  162. if(args.size() < 2 )
  163. {
  164. this->SetError("called with incorrect number of arguments");
  165. return false;
  166. }
  167. this->VariableName = args[0];
  168. if(this->CheckForVariableInCache())
  169. {
  170. this->AlreadyInCache = true;
  171. return true;
  172. }
  173. this->AlreadyInCache = false;
  174. // Find the current root path mode.
  175. this->SelectDefaultRootPathMode();
  176. // Find the current bundle/framework search policy.
  177. this->SelectDefaultMacMode();
  178. bool newStyle = false;
  179. enum Doing { DoingNone, DoingNames, DoingPaths, DoingPathSuffixes,
  180. DoingHints };
  181. Doing doing = DoingNames; // assume it starts with a name
  182. for (unsigned int j = 1; j < args.size(); ++j)
  183. {
  184. if(args[j] == "NAMES")
  185. {
  186. doing = DoingNames;
  187. newStyle = true;
  188. }
  189. else if (args[j] == "PATHS")
  190. {
  191. doing = DoingPaths;
  192. newStyle = true;
  193. }
  194. else if (args[j] == "HINTS")
  195. {
  196. doing = DoingHints;
  197. newStyle = true;
  198. }
  199. else if (args[j] == "PATH_SUFFIXES")
  200. {
  201. doing = DoingPathSuffixes;
  202. compatibility = false;
  203. newStyle = true;
  204. }
  205. else if (args[j] == "NO_SYSTEM_PATH")
  206. {
  207. doing = DoingNone;
  208. this->NoDefaultPath = true;
  209. }
  210. else if (this->CheckCommonArgument(args[j]))
  211. {
  212. doing = DoingNone;
  213. compatibility = false;
  214. // Some common arguments were accidentally supported by CMake
  215. // 2.4 and 2.6.0 in the short-hand form of the command, so we
  216. // must support it even though it is not documented.
  217. }
  218. else if(doing == DoingNames)
  219. {
  220. this->Names.push_back(args[j]);
  221. }
  222. else if(doing == DoingPaths)
  223. {
  224. this->AddUserPath(args[j], this->UserPaths);
  225. }
  226. else if(doing == DoingHints)
  227. {
  228. this->AddUserPath(args[j], this->UserHints);
  229. }
  230. else if(doing == DoingPathSuffixes)
  231. {
  232. this->AddPathSuffix(args[j]);
  233. }
  234. }
  235. // Now that arguments have been parsed check the compatibility
  236. // setting. If we need to be compatible with CMake 2.2 and earlier
  237. // do not add the CMake system paths. It is safe to add the CMake
  238. // environment paths and system environment paths because that
  239. // existed in 2.2. It is safe to add the CMake user variable paths
  240. // because the user or project has explicitly set them.
  241. if(compatibility)
  242. {
  243. this->NoCMakeSystemPath = true;
  244. }
  245. if(this->VariableDocumentation.size() == 0)
  246. {
  247. this->VariableDocumentation = "Where can ";
  248. if(this->Names.size() == 0)
  249. {
  250. this->VariableDocumentation += "the (unknown) library be found";
  251. }
  252. else if(this->Names.size() == 1)
  253. {
  254. this->VariableDocumentation += "the "
  255. + this->Names[0] + " library be found";
  256. }
  257. else
  258. {
  259. this->VariableDocumentation += "one of the " + this->Names[0];
  260. for (unsigned int j = 1; j < this->Names.size() - 1; ++j)
  261. {
  262. this->VariableDocumentation += ", " + this->Names[j];
  263. }
  264. this->VariableDocumentation += " or "
  265. + this->Names[this->Names.size() - 1] + " libraries be found";
  266. }
  267. }
  268. // look for old style
  269. // FIND_*(VAR name path1 path2 ...)
  270. if(!newStyle)
  271. {
  272. // All the short-hand arguments have been recorded as names.
  273. std::vector<std::string> shortArgs = this->Names;
  274. this->Names.clear(); // clear out any values in Names
  275. this->Names.push_back(shortArgs[0]);
  276. for(unsigned int j = 1; j < shortArgs.size(); ++j)
  277. {
  278. this->AddUserPath(shortArgs[j], this->UserPaths);
  279. }
  280. }
  281. this->ExpandPaths();
  282. // Filter out ignored paths from the prefix list
  283. std::set<std::string> ignored;
  284. this->GetIgnoredPaths(ignored);
  285. this->FilterPaths(this->SearchPaths, ignored);
  286. this->ComputeFinalPaths();
  287. return true;
  288. }
  289. void cmFindBase::ExpandPaths()
  290. {
  291. this->AddCMakeVariablePath();
  292. this->AddCMakeEnvironmentPath();
  293. this->AddUserHintsPath();
  294. this->AddSystemEnvironmentPath();
  295. this->AddCMakeSystemVariablePath();
  296. this->AddUserGuessPath();
  297. // Add suffixes and clean up paths.
  298. this->AddPathSuffixes();
  299. }
  300. //----------------------------------------------------------------------------
  301. void cmFindBase::AddPrefixPaths(std::vector<std::string> const& in_paths,
  302. PathType pathType)
  303. {
  304. // default for programs
  305. std::string subdir = "bin";
  306. if (this->CMakePathName == "INCLUDE")
  307. {
  308. subdir = "include";
  309. }
  310. else if (this->CMakePathName == "LIBRARY")
  311. {
  312. subdir = "lib";
  313. }
  314. else if (this->CMakePathName == "FRAMEWORK")
  315. {
  316. subdir = ""; // ? what to do for frameworks ?
  317. }
  318. for(std::vector<std::string>::const_iterator it = in_paths.begin();
  319. it != in_paths.end(); ++it)
  320. {
  321. std::string dir = it->c_str();
  322. if(!subdir.empty() && !dir.empty() && dir[dir.size()-1] != '/')
  323. {
  324. dir += "/";
  325. }
  326. if(subdir == "lib")
  327. {
  328. const char* arch =
  329. this->Makefile->GetDefinition("CMAKE_LIBRARY_ARCHITECTURE");
  330. if(arch && *arch)
  331. {
  332. this->AddPathInternal(dir+"lib/"+arch, pathType);
  333. }
  334. }
  335. std::string add = dir + subdir;
  336. if(add != "/")
  337. {
  338. this->AddPathInternal(add, pathType);
  339. }
  340. if (subdir == "bin")
  341. {
  342. this->AddPathInternal(dir+"sbin", pathType);
  343. }
  344. if(!subdir.empty() && *it != "/")
  345. {
  346. this->AddPathInternal(*it, pathType);
  347. }
  348. }
  349. }
  350. //----------------------------------------------------------------------------
  351. void cmFindBase::AddCMakePrefixPath(const char* variable)
  352. {
  353. // Get a path from a CMake variable.
  354. if(const char* varPath = this->Makefile->GetDefinition(variable))
  355. {
  356. std::vector<std::string> tmp;
  357. cmSystemTools::ExpandListArgument(varPath, tmp);
  358. this->AddPrefixPaths(tmp, CMakePath);
  359. }
  360. }
  361. //----------------------------------------------------------------------------
  362. void cmFindBase::AddEnvPrefixPath(const char* variable)
  363. {
  364. // Get a path from the environment.
  365. std::vector<std::string> tmp;
  366. cmSystemTools::GetPath(tmp, variable);
  367. this->AddPrefixPaths(tmp, EnvPath);
  368. }
  369. //----------------------------------------------------------------------------
  370. void cmFindBase::AddCMakeEnvironmentPath()
  371. {
  372. if(!this->NoCMakeEnvironmentPath && !this->NoDefaultPath)
  373. {
  374. // Add CMAKE_*_PATH environment variables
  375. std::string var = "CMAKE_";
  376. var += this->CMakePathName;
  377. var += "_PATH";
  378. this->AddEnvPrefixPath("CMAKE_PREFIX_PATH");
  379. this->AddEnvPath(var.c_str());
  380. if(this->CMakePathName == "PROGRAM")
  381. {
  382. this->AddEnvPath("CMAKE_APPBUNDLE_PATH");
  383. }
  384. else
  385. {
  386. this->AddEnvPath("CMAKE_FRAMEWORK_PATH");
  387. }
  388. }
  389. }
  390. //----------------------------------------------------------------------------
  391. void cmFindBase::AddCMakeVariablePath()
  392. {
  393. if(!this->NoCMakePath && !this->NoDefaultPath)
  394. {
  395. // Add CMake varibles of the same name as the previous environment
  396. // varibles CMAKE_*_PATH to be used most of the time with -D
  397. // command line options
  398. std::string var = "CMAKE_";
  399. var += this->CMakePathName;
  400. var += "_PATH";
  401. this->AddCMakePrefixPath("CMAKE_PREFIX_PATH");
  402. this->AddCMakePath(var.c_str());
  403. if(this->CMakePathName == "PROGRAM")
  404. {
  405. this->AddCMakePath("CMAKE_APPBUNDLE_PATH");
  406. }
  407. else
  408. {
  409. this->AddCMakePath("CMAKE_FRAMEWORK_PATH");
  410. }
  411. }
  412. }
  413. //----------------------------------------------------------------------------
  414. void cmFindBase::AddSystemEnvironmentPath()
  415. {
  416. if(!this->NoSystemEnvironmentPath && !this->NoDefaultPath)
  417. {
  418. // Add LIB or INCLUDE
  419. if(!this->EnvironmentPath.empty())
  420. {
  421. this->AddEnvPath(this->EnvironmentPath.c_str());
  422. }
  423. // Add PATH
  424. this->AddEnvPath(0);
  425. }
  426. }
  427. //----------------------------------------------------------------------------
  428. void cmFindBase::AddCMakeSystemVariablePath()
  429. {
  430. if(!this->NoCMakeSystemPath && !this->NoDefaultPath)
  431. {
  432. std::string var = "CMAKE_SYSTEM_";
  433. var += this->CMakePathName;
  434. var += "_PATH";
  435. this->AddCMakePrefixPath("CMAKE_SYSTEM_PREFIX_PATH");
  436. this->AddCMakePath(var.c_str());
  437. if(this->CMakePathName == "PROGRAM")
  438. {
  439. this->AddCMakePath("CMAKE_SYSTEM_APPBUNDLE_PATH");
  440. }
  441. else
  442. {
  443. this->AddCMakePath("CMAKE_SYSTEM_FRAMEWORK_PATH");
  444. }
  445. }
  446. }
  447. //----------------------------------------------------------------------------
  448. void cmFindBase::AddUserHintsPath()
  449. {
  450. this->AddPathsInternal(this->UserHints, CMakePath);
  451. }
  452. //----------------------------------------------------------------------------
  453. void cmFindBase::AddUserGuessPath()
  454. {
  455. this->AddPathsInternal(this->UserPaths, CMakePath);
  456. }
  457. //----------------------------------------------------------------------------
  458. void cmFindBase::AddPathSuffixes()
  459. {
  460. std::vector<std::string>& paths = this->SearchPaths;
  461. std::vector<std::string> finalPath = paths;
  462. std::vector<std::string>::iterator i;
  463. // clear the path
  464. paths.clear();
  465. // convert all paths to unix slashes and add search path suffixes
  466. // if there are any
  467. for(i = finalPath.begin();
  468. i != finalPath.end(); ++i)
  469. {
  470. cmSystemTools::ConvertToUnixSlashes(*i);
  471. // copy each finalPath combined with SearchPathSuffixes
  472. // to the SearchPaths ivar
  473. for(std::vector<std::string>::iterator j =
  474. this->SearchPathSuffixes.begin();
  475. j != this->SearchPathSuffixes.end(); ++j)
  476. {
  477. // if *i is only / then do not add a //
  478. // this will get incorrectly considered a network
  479. // path on windows and cause huge delays.
  480. std::string p = *i;
  481. if(p.size() && p[p.size()-1] != '/')
  482. {
  483. p += std::string("/");
  484. }
  485. p += *j;
  486. // add to all paths because the search path may be modified
  487. // later with lib being replaced for lib64 which may exist
  488. paths.push_back(p);
  489. }
  490. // now put the path without the path suffixes in the SearchPaths
  491. paths.push_back(*i);
  492. }
  493. }
  494. void cmFindBase::PrintFindStuff()
  495. {
  496. std::cerr << "SearchFrameworkLast: " << this->SearchFrameworkLast << "\n";
  497. std::cerr << "SearchFrameworkOnly: " << this->SearchFrameworkOnly << "\n";
  498. std::cerr << "SearchFrameworkFirst: " << this->SearchFrameworkFirst << "\n";
  499. std::cerr << "SearchAppBundleLast: " << this->SearchAppBundleLast << "\n";
  500. std::cerr << "SearchAppBundleOnly: " << this->SearchAppBundleOnly << "\n";
  501. std::cerr << "SearchAppBundleFirst: " << this->SearchAppBundleFirst << "\n";
  502. std::cerr << "VariableName " << this->VariableName << "\n";
  503. std::cerr << "VariableDocumentation "
  504. << this->VariableDocumentation << "\n";
  505. std::cerr << "NoDefaultPath " << this->NoDefaultPath << "\n";
  506. std::cerr << "NoCMakeEnvironmentPath "
  507. << this->NoCMakeEnvironmentPath << "\n";
  508. std::cerr << "NoCMakePath " << this->NoCMakePath << "\n";
  509. std::cerr << "NoSystemEnvironmentPath "
  510. << this->NoSystemEnvironmentPath << "\n";
  511. std::cerr << "NoCMakeSystemPath " << this->NoCMakeSystemPath << "\n";
  512. std::cerr << "EnvironmentPath " << this->EnvironmentPath << "\n";
  513. std::cerr << "CMakePathName " << this->CMakePathName << "\n";
  514. std::cerr << "Names ";
  515. for(unsigned int i =0; i < this->Names.size(); ++i)
  516. {
  517. std::cerr << this->Names[i] << " ";
  518. }
  519. std::cerr << "\n";
  520. std::cerr << "\n";
  521. std::cerr << "SearchPathSuffixes ";
  522. for(unsigned int i =0; i < this->SearchPathSuffixes.size(); ++i)
  523. {
  524. std::cerr << this->SearchPathSuffixes[i] << "\n";
  525. }
  526. std::cerr << "\n";
  527. std::cerr << "SearchPaths\n";
  528. for(unsigned int i =0; i < this->SearchPaths.size(); ++i)
  529. {
  530. std::cerr << "[" << this->SearchPaths[i] << "]\n";
  531. }
  532. }
  533. bool cmFindBase::CheckForVariableInCache()
  534. {
  535. if(const char* cacheValue =
  536. this->Makefile->GetDefinition(this->VariableName.c_str()))
  537. {
  538. cmCacheManager::CacheIterator it =
  539. this->Makefile->GetCacheManager()->
  540. GetCacheIterator(this->VariableName.c_str());
  541. bool found = !cmSystemTools::IsNOTFOUND(cacheValue);
  542. bool cached = !it.IsAtEnd();
  543. if(found)
  544. {
  545. // If the user specifies the entry on the command line without a
  546. // type we should add the type and docstring but keep the
  547. // original value. Tell the subclass implementations to do
  548. // this.
  549. if(cached && it.GetType() == cmCacheManager::UNINITIALIZED)
  550. {
  551. this->AlreadyInCacheWithoutMetaInfo = true;
  552. }
  553. return true;
  554. }
  555. else if(cached)
  556. {
  557. const char* hs = it.GetProperty("HELPSTRING");
  558. this->VariableDocumentation = hs?hs:"(none)";
  559. }
  560. }
  561. return false;
  562. }