cmDepends.cxx 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  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 "cmDepends.h"
  11. #include "cmLocalGenerator.h"
  12. #include "cmMakefile.h"
  13. #include "cmGeneratedFileStream.h"
  14. #include "cmSystemTools.h"
  15. #include "cmFileTimeComparison.h"
  16. #include <string.h>
  17. //----------------------------------------------------------------------------
  18. cmDepends::cmDepends(cmLocalGenerator* lg, const char* targetDir):
  19. CompileDirectory(),
  20. LocalGenerator(lg),
  21. Verbose(false),
  22. FileComparison(0),
  23. TargetDirectory(targetDir),
  24. MaxPath(16384),
  25. Dependee(new char[MaxPath]),
  26. Depender(new char[MaxPath])
  27. {
  28. }
  29. //----------------------------------------------------------------------------
  30. cmDepends::~cmDepends()
  31. {
  32. delete [] this->Dependee;
  33. delete [] this->Depender;
  34. }
  35. //----------------------------------------------------------------------------
  36. bool cmDepends::Write(std::ostream &makeDepends,
  37. std::ostream &internalDepends)
  38. {
  39. // Lookup the set of sources to scan.
  40. std::string srcLang = "CMAKE_DEPENDS_CHECK_";
  41. srcLang += this->Language;
  42. cmMakefile* mf = this->LocalGenerator->GetMakefile();
  43. const char* srcStr = mf->GetSafeDefinition(srcLang.c_str());
  44. std::vector<std::string> pairs;
  45. cmSystemTools::ExpandListArgument(srcStr, pairs);
  46. std::map<std::string, std::set<std::string> > dependencies;
  47. for(std::vector<std::string>::iterator si = pairs.begin();
  48. si != pairs.end();)
  49. {
  50. // Get the source and object file.
  51. std::string const& src = *si++;
  52. if(si == pairs.end()) { break; }
  53. std::string obj = *si++;
  54. // Make sure the object file is relative to the top of the build tree.
  55. obj = this->LocalGenerator->Convert(obj.c_str(),
  56. cmLocalGenerator::HOME_OUTPUT,
  57. cmLocalGenerator::MAKEFILE);
  58. dependencies[obj].insert(src);
  59. }
  60. for(std::map<std::string, std::set<std::string> >::const_iterator
  61. it = dependencies.begin(); it != dependencies.end(); ++it)
  62. {
  63. // Write the dependencies for this pair.
  64. if(!this->WriteDependencies(it->second, it->first,
  65. makeDepends, internalDepends))
  66. {
  67. return false;
  68. }
  69. }
  70. return this->Finalize(makeDepends, internalDepends);
  71. }
  72. //----------------------------------------------------------------------------
  73. bool cmDepends::Finalize(std::ostream&,
  74. std::ostream&)
  75. {
  76. return true;
  77. }
  78. //----------------------------------------------------------------------------
  79. bool cmDepends::Check(const char *makeFile, const char *internalFile,
  80. std::map<std::string, DependencyVector>& validDeps)
  81. {
  82. // Dependency checks must be done in proper working directory.
  83. std::string oldcwd = ".";
  84. if(this->CompileDirectory != ".")
  85. {
  86. // Get the CWD but do not call CollapseFullPath because
  87. // we only need it to cd back, and the form does not matter
  88. oldcwd = cmSystemTools::GetCurrentWorkingDirectory(false);
  89. cmSystemTools::ChangeDirectory(this->CompileDirectory.c_str());
  90. }
  91. // Check whether dependencies must be regenerated.
  92. bool okay = true;
  93. std::ifstream fin(internalFile);
  94. if(!(fin && this->CheckDependencies(fin, internalFile, validDeps)))
  95. {
  96. // Clear all dependencies so they will be regenerated.
  97. this->Clear(makeFile);
  98. cmSystemTools::RemoveFile(internalFile);
  99. okay = false;
  100. }
  101. // Restore working directory.
  102. if(oldcwd != ".")
  103. {
  104. cmSystemTools::ChangeDirectory(oldcwd.c_str());
  105. }
  106. return okay;
  107. }
  108. //----------------------------------------------------------------------------
  109. void cmDepends::Clear(const char *file)
  110. {
  111. // Print verbose output.
  112. if(this->Verbose)
  113. {
  114. cmOStringStream msg;
  115. msg << "Clearing dependencies in \"" << file << "\"." << std::endl;
  116. cmSystemTools::Stdout(msg.str().c_str());
  117. }
  118. // Write an empty dependency file.
  119. cmGeneratedFileStream depFileStream(file);
  120. depFileStream
  121. << "# Empty dependencies file\n"
  122. << "# This may be replaced when dependencies are built." << std::endl;
  123. }
  124. //----------------------------------------------------------------------------
  125. bool cmDepends::WriteDependencies(
  126. const std::set<std::string>&, const std::string&,
  127. std::ostream&, std::ostream&)
  128. {
  129. // This should be implemented by the subclass.
  130. return false;
  131. }
  132. //----------------------------------------------------------------------------
  133. bool cmDepends::CheckDependencies(std::istream& internalDepends,
  134. const char* internalDependsFileName,
  135. std::map<std::string, DependencyVector>& validDeps)
  136. {
  137. // Parse dependencies from the stream. If any dependee is missing
  138. // or newer than the depender then dependencies should be
  139. // regenerated.
  140. bool okay = true;
  141. bool dependerExists = false;
  142. DependencyVector* currentDependencies = 0;
  143. while(internalDepends.getline(this->Dependee, this->MaxPath))
  144. {
  145. if ( this->Dependee[0] == 0 || this->Dependee[0] == '#' ||
  146. this->Dependee[0] == '\r' )
  147. {
  148. continue;
  149. }
  150. size_t len = internalDepends.gcount()-1;
  151. if ( this->Dependee[len-1] == '\r' )
  152. {
  153. len --;
  154. this->Dependee[len] = 0;
  155. }
  156. if ( this->Dependee[0] != ' ' )
  157. {
  158. memcpy(this->Depender, this->Dependee, len+1);
  159. // Calling FileExists() for the depender here saves in many cases 50%
  160. // of the calls to FileExists() further down in the loop. E.g. for
  161. // kdelibs/khtml this reduces the number of calls from 184k down to 92k,
  162. // or the time for cmake -E cmake_depends from 0.3 s down to 0.21 s.
  163. dependerExists = cmSystemTools::FileExists(this->Depender);
  164. DependencyVector tmp;
  165. validDeps[this->Depender] = tmp;
  166. currentDependencies = &validDeps[this->Depender];
  167. continue;
  168. }
  169. /*
  170. // Parse the dependency line.
  171. if(!this->ParseDependency(line.c_str()))
  172. {
  173. continue;
  174. }
  175. */
  176. // Dependencies must be regenerated
  177. // * if the dependee does not exist
  178. // * if the depender exists and is older than the dependee.
  179. // * if the depender does not exist, but the dependee is newer than the
  180. // depends file
  181. bool regenerate = false;
  182. const char* dependee = this->Dependee+1;
  183. const char* depender = this->Depender;
  184. if (currentDependencies != 0)
  185. {
  186. currentDependencies->push_back(dependee);
  187. }
  188. if(!cmSystemTools::FileExists(dependee))
  189. {
  190. // The dependee does not exist.
  191. regenerate = true;
  192. // Print verbose output.
  193. if(this->Verbose)
  194. {
  195. cmOStringStream msg;
  196. msg << "Dependee \"" << dependee
  197. << "\" does not exist for depender \""
  198. << depender << "\"." << std::endl;
  199. cmSystemTools::Stdout(msg.str().c_str());
  200. }
  201. }
  202. else
  203. {
  204. if(dependerExists)
  205. {
  206. // The dependee and depender both exist. Compare file times.
  207. int result = 0;
  208. if((!this->FileComparison->FileTimeCompare(depender, dependee,
  209. &result) || result < 0))
  210. {
  211. // The depender is older than the dependee.
  212. regenerate = true;
  213. // Print verbose output.
  214. if(this->Verbose)
  215. {
  216. cmOStringStream msg;
  217. msg << "Dependee \"" << dependee
  218. << "\" is newer than depender \""
  219. << depender << "\"." << std::endl;
  220. cmSystemTools::Stdout(msg.str().c_str());
  221. }
  222. }
  223. }
  224. else
  225. {
  226. // The dependee exists, but the depender doesn't. Regenerate if the
  227. // internalDepends file is older than the dependee.
  228. int result = 0;
  229. if((!this->FileComparison->FileTimeCompare(internalDependsFileName,
  230. dependee, &result) || result < 0))
  231. {
  232. // The depends-file is older than the dependee.
  233. regenerate = true;
  234. // Print verbose output.
  235. if(this->Verbose)
  236. {
  237. cmOStringStream msg;
  238. msg << "Dependee \"" << dependee
  239. << "\" is newer than depends file \""
  240. << internalDependsFileName << "\"." << std::endl;
  241. cmSystemTools::Stdout(msg.str().c_str());
  242. }
  243. }
  244. }
  245. }
  246. if(regenerate)
  247. {
  248. // Dependencies must be regenerated.
  249. okay = false;
  250. // Remove the information of this depender from the map, it needs
  251. // to be rescanned
  252. if (currentDependencies != 0)
  253. {
  254. validDeps.erase(this->Depender);
  255. currentDependencies = 0;
  256. }
  257. // Remove the depender to be sure it is rebuilt.
  258. if (dependerExists)
  259. {
  260. cmSystemTools::RemoveFile(depender);
  261. dependerExists = false;
  262. }
  263. }
  264. }
  265. return okay;
  266. }
  267. //----------------------------------------------------------------------------
  268. void cmDepends::SetIncludePathFromLanguage(const char* lang)
  269. {
  270. // Look for the new per "TARGET_" variant first:
  271. const char * includePath = 0;
  272. std::string includePathVar = "CMAKE_";
  273. includePathVar += lang;
  274. includePathVar += "_TARGET_INCLUDE_PATH";
  275. cmMakefile* mf = this->LocalGenerator->GetMakefile();
  276. includePath = mf->GetDefinition(includePathVar.c_str());
  277. if(includePath)
  278. {
  279. cmSystemTools::ExpandListArgument(includePath, this->IncludePath);
  280. }
  281. else
  282. {
  283. // Fallback to the old directory level variable if no per-target var:
  284. includePathVar = "CMAKE_";
  285. includePathVar += lang;
  286. includePathVar += "_INCLUDE_PATH";
  287. includePath = mf->GetDefinition(includePathVar.c_str());
  288. if(includePath)
  289. {
  290. cmSystemTools::ExpandListArgument(includePath, this->IncludePath);
  291. }
  292. }
  293. }