cmDepends.cxx 8.9 KB

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