cmFindPackageCommand.cxx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. /*=========================================================================
  2. Program: CMake - Cross-Platform Makefile Generator
  3. Module: $RCSfile$
  4. Language: C++
  5. Date: $Date$
  6. Version: $Revision$
  7. Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
  8. See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
  9. This software is distributed WITHOUT ANY WARRANTY; without even
  10. the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  11. PURPOSE. See the above copyright notices for more information.
  12. =========================================================================*/
  13. #include "cmFindPackageCommand.h"
  14. #include <cmsys/RegularExpression.hxx>
  15. #include "cmVariableWatch.h"
  16. void cmFindPackageNeedBackwardsCompatibility(const std::string& variable,
  17. int access_type, void* )
  18. {
  19. if(access_type == cmVariableWatch::UNKNOWN_VARIABLE_READ_ACCESS)
  20. {
  21. std::string message = "An attempt was made to access a variable: ";
  22. message += variable;
  23. message +=
  24. " that has not been defined. This variable is created by the "
  25. "FIND_PACKAGE command. CMake version 1.6 always converted the "
  26. "variable name to upper-case, but this behavior is no longer the "
  27. "case. To fix this you might need to set the cache value of "
  28. "CMAKE_BACKWARDS_COMPATIBILITY to 1.6 or less. If you are writing a "
  29. "CMake listfile, you should change the variable reference to use "
  30. "the case of the argument to FIND_PACKAGE.";
  31. cmSystemTools::Error(message.c_str());
  32. }
  33. }
  34. //----------------------------------------------------------------------------
  35. bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
  36. {
  37. if(args.size() < 1)
  38. {
  39. this->SetError("called with incorrect number of arguments");
  40. return false;
  41. }
  42. this->Name = args[0];
  43. bool quiet = false;
  44. bool required = false;
  45. if(args.size() > 1)
  46. {
  47. cmsys::RegularExpression version("^[0-9.]+$");
  48. bool haveVersion = false;
  49. for(unsigned int i=1; i < args.size(); ++i)
  50. {
  51. if(!haveVersion && version.find(args[i].c_str()))
  52. {
  53. haveVersion = true;
  54. }
  55. else if(args[i] == "QUIET")
  56. {
  57. quiet = true;
  58. }
  59. else if(args[i] == "REQUIRED")
  60. {
  61. required = true;
  62. }
  63. else
  64. {
  65. cmOStringStream e;
  66. e << "called with invalid argument \"" << args[i].c_str() << "\"";
  67. this->SetError(e.str().c_str());
  68. return false;
  69. }
  70. }
  71. }
  72. // See if there is a Find<name>.cmake module.
  73. bool foundModule = false;
  74. if(!this->FindModule(foundModule, quiet, required))
  75. {
  76. return false;
  77. }
  78. if(foundModule)
  79. {
  80. return true;
  81. }
  82. // No find module. Assume the project has a CMake config file. Use
  83. // a <NAME>_DIR cache variable to locate it.
  84. this->Variable = this->Name;
  85. this->Variable += "_DIR";
  86. this->Config = this->Name;
  87. this->Config += "Config.cmake";
  88. // Support old capitalization behavior.
  89. std::string upperDir = cmSystemTools::UpperCase(this->Name);
  90. std::string upperFound = cmSystemTools::UpperCase(this->Name);
  91. upperDir += "_DIR";
  92. upperFound += "_FOUND";
  93. bool needCompatibility = false;
  94. if(!(upperDir == this->Variable))
  95. {
  96. const char* versionValue =
  97. m_Makefile->GetDefinition("CMAKE_BACKWARDS_COMPATIBILITY");
  98. if(atof(versionValue) < 1.7)
  99. {
  100. needCompatibility = true;
  101. }
  102. }
  103. // Try to find the config file.
  104. const char* def = m_Makefile->GetDefinition(this->Variable.c_str());
  105. if(needCompatibility && cmSystemTools::IsOff(def))
  106. {
  107. // Use the setting of the old name of the variable to provide the
  108. // value of the new.
  109. const char* oldDef = m_Makefile->GetDefinition(upperDir.c_str());
  110. if(!cmSystemTools::IsOff(oldDef))
  111. {
  112. m_Makefile->AddDefinition(this->Variable.c_str(), oldDef);
  113. def = m_Makefile->GetDefinition(this->Variable.c_str());
  114. }
  115. }
  116. if(cmSystemTools::IsOff(def))
  117. {
  118. if(!this->FindConfig())
  119. {
  120. return false;
  121. }
  122. }
  123. // If the config file was found, load it.
  124. bool result = true;
  125. bool found = false;
  126. def = m_Makefile->GetDefinition(this->Variable.c_str());
  127. if(!cmSystemTools::IsOff(def))
  128. {
  129. std::string f = def;
  130. f += "/";
  131. f += this->Config;
  132. if(cmSystemTools::FileExists(f.c_str()))
  133. {
  134. if(this->ReadListFile(f.c_str()))
  135. {
  136. found = true;
  137. }
  138. else
  139. {
  140. result = false;
  141. }
  142. }
  143. else
  144. {
  145. cmOStringStream e;
  146. e << this->Variable << " is set to \"" << def << "\", which is "
  147. << "not a directory containing " << this->Config;
  148. cmSystemTools::Error(e.str().c_str());
  149. if(required)
  150. {
  151. cmSystemTools::SetFatalErrorOccured();
  152. }
  153. result = true;
  154. }
  155. }
  156. else if(!quiet || required)
  157. {
  158. cmOStringStream e;
  159. e << this->Variable << " is not set. It must be set to the directory "
  160. << "containing " << this->Config << " in order to use "
  161. << this->Name << ".";
  162. cmSystemTools::Error(e.str().c_str());
  163. if(required)
  164. {
  165. cmSystemTools::SetFatalErrorOccured();
  166. }
  167. result = true;
  168. }
  169. // Set a variable marking whether the package was found.
  170. std::string foundVar = this->Name;
  171. foundVar += "_FOUND";
  172. m_Makefile->AddDefinition(foundVar.c_str(), found? "1":"0");
  173. if(needCompatibility)
  174. {
  175. // Listfiles will be looking for the capitalized version of the
  176. // name. Provide it.
  177. m_Makefile->AddDefinition(upperDir.c_str(),
  178. m_Makefile->GetDefinition(this->Variable.c_str()));
  179. m_Makefile->AddDefinition(upperFound.c_str(),
  180. m_Makefile->GetDefinition(foundVar.c_str()));
  181. }
  182. if(!(upperDir == this->Variable))
  183. {
  184. if(needCompatibility)
  185. {
  186. // Listfiles may use the capitalized version of the name.
  187. // Remove any previously added watch.
  188. m_Makefile->GetVariableWatch()->RemoveWatch(
  189. upperDir.c_str(),
  190. cmFindPackageNeedBackwardsCompatibility
  191. );
  192. m_Makefile->GetVariableWatch()->RemoveWatch(
  193. upperFound.c_str(),
  194. cmFindPackageNeedBackwardsCompatibility
  195. );
  196. }
  197. else
  198. {
  199. // Listfiles should not be using the capitalized version of the
  200. // name. Add a watch to warn the user.
  201. m_Makefile->GetVariableWatch()->AddWatch(
  202. upperDir.c_str(),
  203. cmFindPackageNeedBackwardsCompatibility
  204. );
  205. m_Makefile->GetVariableWatch()->AddWatch(
  206. upperFound.c_str(),
  207. cmFindPackageNeedBackwardsCompatibility
  208. );
  209. }
  210. }
  211. return result;
  212. }
  213. //----------------------------------------------------------------------------
  214. bool cmFindPackageCommand::FindModule(bool& found, bool quiet, bool required)
  215. {
  216. std::string module = "Find";
  217. module += this->Name;
  218. module += ".cmake";
  219. std::string mfile = m_Makefile->GetModulesFile(module.c_str());
  220. if ( mfile.size() )
  221. {
  222. if(quiet)
  223. {
  224. // Tell the module that is about to be read that it should find
  225. // quietly.
  226. std::string quietly = this->Name;
  227. quietly += "_FIND_QUIETLY";
  228. m_Makefile->AddDefinition(quietly.c_str(), "1");
  229. }
  230. if(required)
  231. {
  232. // Tell the module that is about to be read that it should report
  233. // a fatal error if the package is not found.
  234. std::string req = this->Name;
  235. req += "_FIND_REQUIRED";
  236. m_Makefile->AddDefinition(req.c_str(), "1");
  237. }
  238. // Load the module we found.
  239. found = true;
  240. return this->ReadListFile(mfile.c_str());
  241. }
  242. return true;
  243. }
  244. //----------------------------------------------------------------------------
  245. bool cmFindPackageCommand::FindConfig()
  246. {
  247. std::string help = "The directory containing ";
  248. help += this->Config;
  249. help += ".";
  250. // Construct the list of relative paths to each prefix to be
  251. // searched.
  252. std::string rel = "/lib/";
  253. rel += cmSystemTools::LowerCase(this->Name);
  254. this->Relatives.push_back(rel);
  255. rel = "/lib/";
  256. rel += this->Name;
  257. this->Relatives.push_back(rel);
  258. // It is likely that CMake will have recently built the project.
  259. for(int i=1; i <= 10; ++i)
  260. {
  261. cmOStringStream r;
  262. r << "[HKEY_CURRENT_USER\\Software\\Kitware\\CMakeSetup\\Settings\\StartPath;WhereBuild"
  263. << i << "]";
  264. std::string entry = r.str();
  265. cmSystemTools::ExpandRegistryValues(entry);
  266. cmSystemTools::ConvertToUnixSlashes(entry);
  267. if(cmSystemTools::FileIsDirectory(entry.c_str()))
  268. {
  269. this->Builds.push_back(entry);
  270. }
  271. }
  272. // The project may be installed. Use the system search path to
  273. // construct a list of possible install prefixes.
  274. std::vector<std::string> systemPath;
  275. cmSystemTools::GetPath(systemPath);
  276. for(std::vector<std::string>::iterator i = systemPath.begin();
  277. i != systemPath.end(); ++i)
  278. {
  279. *i += "/..";
  280. if(cmSystemTools::FileIsDirectory(i->c_str()))
  281. {
  282. this->Prefixes.push_back(cmSystemTools::CollapseFullPath(i->c_str()));
  283. }
  284. }
  285. #if !defined(WIN32) || defined(__CYGWIN__)
  286. this->Prefixes.push_back("/usr/local");
  287. this->Prefixes.push_back("/usr");
  288. #endif
  289. // Look for the project's configuration file.
  290. std::string init = this->SearchForConfig();
  291. // Store the entry in the cache so it can be set by the user.
  292. m_Makefile->AddCacheDefinition(this->Variable.c_str(),
  293. init.c_str(),
  294. help.c_str(),
  295. cmCacheManager::PATH);
  296. return true;
  297. }
  298. //----------------------------------------------------------------------------
  299. std::string cmFindPackageCommand::SearchForConfig() const
  300. {
  301. // Check the environment variable.
  302. std::string env;
  303. if(cmSystemTools::GetEnv(this->Variable.c_str(), env) && env.length() > 0)
  304. {
  305. cmSystemTools::ConvertToUnixSlashes(env);
  306. std::string f = env;
  307. f += "/";
  308. f += this->Config;
  309. if(cmSystemTools::FileExists(f.c_str()))
  310. {
  311. return env;
  312. }
  313. }
  314. // Search the build directories.
  315. for(std::vector<cmStdString>::const_iterator b = this->Builds.begin();
  316. b != this->Builds.end(); ++b)
  317. {
  318. std::string f = *b;
  319. f += "/";
  320. f += this->Config;
  321. if(cmSystemTools::FileExists(f.c_str()))
  322. {
  323. return *b;
  324. }
  325. }
  326. // Search paths relative to each installation prefix.
  327. for(std::vector<cmStdString>::const_iterator p = this->Prefixes.begin();
  328. p != this->Prefixes.end(); ++p)
  329. {
  330. std::string prefix = *p;
  331. for(std::vector<cmStdString>::const_iterator r = this->Relatives.begin();
  332. r != this->Relatives.end(); ++r)
  333. {
  334. std::string dir = prefix;
  335. dir += *r;
  336. std::string f = dir;
  337. f += "/";
  338. f += this->Config;
  339. if(cmSystemTools::FileExists(f.c_str()))
  340. {
  341. return dir;
  342. }
  343. }
  344. }
  345. return this->Variable + "-NOTFOUND";
  346. }
  347. //----------------------------------------------------------------------------
  348. bool cmFindPackageCommand::ReadListFile(const char* f)
  349. {
  350. if(m_Makefile->ReadListFile(m_Makefile->GetCurrentListFile(), f))
  351. {
  352. return true;
  353. }
  354. std::string e = "Error reading CMake code from \"";
  355. e += f;
  356. e += "\".";
  357. this->SetError(e.c_str());
  358. return false;
  359. }