cmFindPackageCommand.cxx 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  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. //----------------------------------------------------------------------------
  16. bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
  17. {
  18. if(args.size() < 1)
  19. {
  20. this->SetError("called with incorrect number of arguments");
  21. return false;
  22. }
  23. this->Name = args[0];
  24. bool quiet = false;
  25. if(args.size() > 1)
  26. {
  27. cmsys::RegularExpression version("^[0-9.]+$");
  28. bool haveVersion = false;
  29. for(unsigned int i=1; i < args.size(); ++i)
  30. {
  31. if(!haveVersion && version.find(args[i].c_str()))
  32. {
  33. haveVersion = true;
  34. }
  35. else if(args[i] == "QUIET")
  36. {
  37. quiet = true;
  38. }
  39. else
  40. {
  41. cmOStringStream e;
  42. e << "called with invalid argument \"" << args[i].c_str() << "\"";
  43. this->SetError(e.str().c_str());
  44. return false;
  45. }
  46. }
  47. }
  48. // See if there is a Find<name>.cmake module.
  49. bool foundModule = false;
  50. if(!this->FindModule(foundModule, quiet))
  51. {
  52. return false;
  53. }
  54. if(foundModule)
  55. {
  56. return true;
  57. }
  58. // No find module. Assume the project has a CMake config file. Use
  59. // a <NAME>_DIR cache variable to locate it.
  60. this->Variable = this->Name;
  61. this->Variable += "_DIR";
  62. this->Config = this->Name;
  63. this->Config += "Config.cmake";
  64. const char* def = m_Makefile->GetDefinition(this->Variable.c_str());
  65. if(cmSystemTools::IsOff(def))
  66. {
  67. if(!this->FindConfig())
  68. {
  69. return false;
  70. }
  71. }
  72. // If the config file was found, load it.
  73. bool result = true;
  74. bool found = false;
  75. def = m_Makefile->GetDefinition(this->Variable.c_str());
  76. if(!cmSystemTools::IsOff(def))
  77. {
  78. std::string f = def;
  79. f += "/";
  80. f += this->Config;
  81. if(cmSystemTools::FileExists(f.c_str()))
  82. {
  83. if(this->ReadListFile(f.c_str()))
  84. {
  85. found = true;
  86. }
  87. else
  88. {
  89. result = false;
  90. }
  91. }
  92. else
  93. {
  94. cmOStringStream e;
  95. e << this->Variable << " is set to \"" << def << "\", which is "
  96. << "not a directory containing " << this->Config;
  97. cmSystemTools::Error(e.str().c_str());
  98. result = true;
  99. }
  100. }
  101. else if(!quiet)
  102. {
  103. cmOStringStream e;
  104. e << this->Variable << " is not set. It must be set to the directory "
  105. << "containing " << this->Config << " so in order to use "
  106. << this->Name << ".";
  107. cmSystemTools::Error(e.str().c_str());
  108. result = true;
  109. }
  110. std::string foundVar = this->Name;
  111. foundVar += "_FOUND";
  112. m_Makefile->AddDefinition(foundVar.c_str(), found? "1":"0");
  113. return result;
  114. }
  115. //----------------------------------------------------------------------------
  116. bool cmFindPackageCommand::FindModule(bool& found, bool quiet)
  117. {
  118. // Search the CMAKE_MODULE_PATH for a Find<name>.cmake module.
  119. found = false;
  120. std::string module;
  121. std::vector<std::string> modulePath;
  122. const char* def = m_Makefile->GetDefinition("CMAKE_MODULE_PATH");
  123. if(def)
  124. {
  125. cmSystemTools::ExpandListArgument(def, modulePath);
  126. }
  127. // Also search in the standard modules location.
  128. def = m_Makefile->GetDefinition("CMAKE_ROOT");
  129. if(def)
  130. {
  131. std::string rootModules = def;
  132. rootModules += "/Modules";
  133. modulePath.push_back(rootModules);
  134. }
  135. // Look through the possible module directories.
  136. for(std::vector<std::string>::iterator i = modulePath.begin();
  137. i != modulePath.end(); ++i)
  138. {
  139. module = *i;
  140. cmSystemTools::ConvertToUnixSlashes(module);
  141. module += "/Find";
  142. module += this->Name;
  143. module += ".cmake";
  144. if(cmSystemTools::FileExists(module.c_str()))
  145. {
  146. found = true;
  147. if(quiet)
  148. {
  149. // Tell the module that is about to be read that it should find
  150. // quietly.
  151. std::string quietly = this->Name;
  152. quietly += "_FIND_QUIETLY";
  153. m_Makefile->AddDefinition(quietly.c_str(), "1");
  154. }
  155. // Load the module we found.
  156. return this->ReadListFile(module.c_str());
  157. }
  158. }
  159. return true;
  160. }
  161. //----------------------------------------------------------------------------
  162. bool cmFindPackageCommand::FindConfig()
  163. {
  164. std::string help = "The directory containing ";
  165. help += this->Config;
  166. help += ".";
  167. // Construct the list of relative paths to each prefix to be
  168. // searched.
  169. std::string rel = "/lib/";
  170. rel += cmSystemTools::LowerCase(this->Name);
  171. this->Relatives.push_back(rel);
  172. rel = "/lib/";
  173. rel += this->Name;
  174. this->Relatives.push_back(rel);
  175. // It is likely that CMake will have recently built the project.
  176. for(int i=1; i <= 10; ++i)
  177. {
  178. cmOStringStream r;
  179. r << "[HKEY_CURRENT_USER\\Software\\Kitware\\CMakeSetup\\Settings\\StartPath;WhereBuild"
  180. << i << "]";
  181. std::string entry = r.str();
  182. cmSystemTools::ExpandRegistryValues(entry);
  183. cmSystemTools::ConvertToUnixSlashes(entry);
  184. if(cmSystemTools::FileIsDirectory(entry.c_str()))
  185. {
  186. this->Builds.push_back(entry);
  187. }
  188. }
  189. // The project may be installed. Use the system search path to
  190. // construct a list of possible install prefixes.
  191. std::vector<std::string> systemPath;
  192. cmSystemTools::GetPath(systemPath);
  193. for(std::vector<std::string>::iterator i = systemPath.begin();
  194. i != systemPath.end(); ++i)
  195. {
  196. *i += "/..";
  197. if(cmSystemTools::FileIsDirectory(i->c_str()))
  198. {
  199. this->Prefixes.push_back(cmSystemTools::CollapseFullPath(i->c_str()));
  200. }
  201. }
  202. #if !defined(WIN32) || defined(__CYGWIN__)
  203. this->Prefixes.push_back("/usr/local");
  204. this->Prefixes.push_back("/usr");
  205. #endif
  206. // Look for the project's configuration file.
  207. std::string init = this->SearchForConfig();
  208. // Store the entry in the cache so it can be set by the user.
  209. m_Makefile->AddCacheDefinition(this->Variable.c_str(),
  210. init.c_str(),
  211. help.c_str(),
  212. cmCacheManager::PATH);
  213. return true;
  214. }
  215. //----------------------------------------------------------------------------
  216. std::string cmFindPackageCommand::SearchForConfig() const
  217. {
  218. // Search the build directories.
  219. for(std::vector<cmStdString>::const_iterator b = this->Builds.begin();
  220. b != this->Builds.end(); ++b)
  221. {
  222. std::string f = *b;
  223. f += "/";
  224. f += this->Config;
  225. if(cmSystemTools::FileExists(f.c_str()))
  226. {
  227. return *b;
  228. }
  229. }
  230. // Search paths relative to each installation prefix.
  231. for(std::vector<cmStdString>::const_iterator p = this->Prefixes.begin();
  232. p != this->Prefixes.end(); ++p)
  233. {
  234. std::string prefix = *p;
  235. for(std::vector<cmStdString>::const_iterator r = this->Relatives.begin();
  236. r != this->Relatives.end(); ++r)
  237. {
  238. std::string dir = prefix;
  239. dir += *r;
  240. std::string f = dir;
  241. f += "/";
  242. f += this->Config;
  243. if(cmSystemTools::FileExists(f.c_str()))
  244. {
  245. return dir;
  246. }
  247. }
  248. }
  249. return this->Variable + "-NOTFOUND";
  250. }
  251. //----------------------------------------------------------------------------
  252. bool cmFindPackageCommand::ReadListFile(const char* f)
  253. {
  254. if(m_Makefile->ReadListFile(m_Makefile->GetCurrentListFile(), f))
  255. {
  256. return true;
  257. }
  258. std::string e = "Error reading CMake code from \"";
  259. e += f;
  260. e += "\".";
  261. this->SetError(e.c_str());
  262. return false;
  263. }