cmSourceFileLocation.cxx 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  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 "cmSourceFileLocation.h"
  11. #include "cmMakefile.h"
  12. #include "cmLocalGenerator.h"
  13. #include "cmGlobalGenerator.h"
  14. #include "cmSystemTools.h"
  15. //----------------------------------------------------------------------------
  16. cmSourceFileLocation
  17. ::cmSourceFileLocation(cmMakefile const* mf, const char* name): Makefile(mf)
  18. {
  19. this->AmbiguousDirectory = !cmSystemTools::FileIsFullPath(name);
  20. this->AmbiguousExtension = true;
  21. this->Directory = cmSystemTools::GetFilenamePath(name);
  22. this->Name = cmSystemTools::GetFilenameName(name);
  23. this->UpdateExtension(name);
  24. }
  25. //----------------------------------------------------------------------------
  26. void cmSourceFileLocation::Update(const char* name)
  27. {
  28. if(this->AmbiguousDirectory)
  29. {
  30. this->UpdateDirectory(name);
  31. }
  32. if(this->AmbiguousExtension)
  33. {
  34. this->UpdateExtension(name);
  35. }
  36. }
  37. //----------------------------------------------------------------------------
  38. void cmSourceFileLocation::Update(cmSourceFileLocation const& loc)
  39. {
  40. if(this->AmbiguousDirectory && !loc.AmbiguousDirectory)
  41. {
  42. this->Directory = loc.Directory;
  43. this->AmbiguousDirectory = false;
  44. }
  45. if(this->AmbiguousExtension && !loc.AmbiguousExtension)
  46. {
  47. this->Name = loc.Name;
  48. this->AmbiguousExtension = false;
  49. }
  50. }
  51. //----------------------------------------------------------------------------
  52. void cmSourceFileLocation::DirectoryUseSource()
  53. {
  54. if(this->AmbiguousDirectory)
  55. {
  56. this->Directory =
  57. cmSystemTools::CollapseFullPath(
  58. this->Directory.c_str(), this->Makefile->GetCurrentDirectory());
  59. this->AmbiguousDirectory = false;
  60. }
  61. }
  62. //----------------------------------------------------------------------------
  63. void cmSourceFileLocation::DirectoryUseBinary()
  64. {
  65. if(this->AmbiguousDirectory)
  66. {
  67. this->Directory =
  68. cmSystemTools::CollapseFullPath(
  69. this->Directory.c_str(), this->Makefile->GetCurrentOutputDirectory());
  70. this->AmbiguousDirectory = false;
  71. }
  72. }
  73. //----------------------------------------------------------------------------
  74. void cmSourceFileLocation::UpdateExtension(const char* name)
  75. {
  76. // Check the extension.
  77. std::string ext = cmSystemTools::GetFilenameLastExtension(name);
  78. if(!ext.empty()) { ext = ext.substr(1); }
  79. // The global generator checks extensions of enabled languages.
  80. cmGlobalGenerator* gg =
  81. this->Makefile->GetLocalGenerator()->GetGlobalGenerator();
  82. cmMakefile const* mf = this->Makefile;
  83. const std::vector<std::string>& srcExts = mf->GetSourceExtensions();
  84. const std::vector<std::string>& hdrExts = mf->GetHeaderExtensions();
  85. if(gg->GetLanguageFromExtension(ext.c_str()) ||
  86. std::find(srcExts.begin(), srcExts.end(), ext) != srcExts.end() ||
  87. std::find(hdrExts.begin(), hdrExts.end(), ext) != hdrExts.end())
  88. {
  89. // This is a known extension. Use the given filename with extension.
  90. this->Name = cmSystemTools::GetFilenameName(name);
  91. this->AmbiguousExtension = false;
  92. }
  93. else
  94. {
  95. // This is not a known extension. See if the file exists on disk as
  96. // named.
  97. std::string tryPath;
  98. if(this->AmbiguousDirectory)
  99. {
  100. // Check the source tree only because a file in the build tree should
  101. // be specified by full path at least once. We do not want this
  102. // detection to depend on whether the project has already been built.
  103. tryPath = this->Makefile->GetCurrentDirectory();
  104. tryPath += "/";
  105. }
  106. if(!this->Directory.empty())
  107. {
  108. tryPath += this->Directory;
  109. tryPath += "/";
  110. }
  111. tryPath += this->Name;
  112. if(cmSystemTools::FileExists(tryPath.c_str(), true))
  113. {
  114. // We found a source file named by the user on disk. Trust it's
  115. // extension.
  116. this->Name = cmSystemTools::GetFilenameName(name);
  117. this->AmbiguousExtension = false;
  118. // If the directory was ambiguous, it isn't anymore.
  119. if(this->AmbiguousDirectory)
  120. {
  121. this->DirectoryUseSource();
  122. }
  123. }
  124. }
  125. }
  126. //----------------------------------------------------------------------------
  127. void cmSourceFileLocation::UpdateDirectory(const char* name)
  128. {
  129. // If a full path was given we know the directory.
  130. if(cmSystemTools::FileIsFullPath(name))
  131. {
  132. this->Directory = cmSystemTools::GetFilenamePath(name);
  133. this->AmbiguousDirectory = false;
  134. }
  135. }
  136. //----------------------------------------------------------------------------
  137. bool
  138. cmSourceFileLocation
  139. ::MatchesAmbiguousExtension(cmSourceFileLocation const& loc) const
  140. {
  141. // This location's extension is not ambiguous but loc's extension
  142. // is. See if the names match as-is.
  143. if(this->Name == loc.Name)
  144. {
  145. return true;
  146. }
  147. // Check if loc's name could possibly be extended to our name by
  148. // adding an extension.
  149. if(!(this->Name.size() > loc.Name.size() &&
  150. this->Name.substr(0, loc.Name.size()) == loc.Name &&
  151. this->Name[loc.Name.size()] == '.'))
  152. {
  153. return false;
  154. }
  155. // Only a fixed set of extensions will be tried to match a file on
  156. // disk. One of these must match if loc refers to this source file.
  157. std::string ext = this->Name.substr(loc.Name.size()+1);
  158. cmMakefile const* mf = this->Makefile;
  159. const std::vector<std::string>& srcExts = mf->GetSourceExtensions();
  160. if(std::find(srcExts.begin(), srcExts.end(), ext) != srcExts.end())
  161. {
  162. return true;
  163. }
  164. const std::vector<std::string>& hdrExts = mf->GetHeaderExtensions();
  165. if(std::find(hdrExts.begin(), hdrExts.end(), ext) != hdrExts.end())
  166. {
  167. return true;
  168. }
  169. return false;
  170. }
  171. //----------------------------------------------------------------------------
  172. bool cmSourceFileLocation::Matches(cmSourceFileLocation const& loc)
  173. {
  174. if(this->AmbiguousExtension && loc.AmbiguousExtension)
  175. {
  176. // Both extensions are ambiguous. Since only the old fixed set of
  177. // extensions will be tried, the names must match at this point to
  178. // be the same file.
  179. if(this->Name != loc.Name)
  180. {
  181. return false;
  182. }
  183. }
  184. else if(this->AmbiguousExtension)
  185. {
  186. // Only "this" extension is ambiguous.
  187. if(!loc.MatchesAmbiguousExtension(*this))
  188. {
  189. return false;
  190. }
  191. }
  192. else if(loc.AmbiguousExtension)
  193. {
  194. // Only "loc" extension is ambiguous.
  195. if(!this->MatchesAmbiguousExtension(loc))
  196. {
  197. return false;
  198. }
  199. }
  200. else
  201. {
  202. // Neither extension is ambiguous.
  203. if(this->Name != loc.Name)
  204. {
  205. return false;
  206. }
  207. }
  208. if(!this->AmbiguousDirectory && !loc.AmbiguousDirectory)
  209. {
  210. // Both sides have absolute directories.
  211. if(this->Directory != loc.Directory)
  212. {
  213. return false;
  214. }
  215. }
  216. else if(this->AmbiguousDirectory && loc.AmbiguousDirectory &&
  217. this->Makefile == loc.Makefile)
  218. {
  219. // Both sides have directories relative to the same location.
  220. if(this->Directory != loc.Directory)
  221. {
  222. return false;
  223. }
  224. }
  225. else if(this->AmbiguousDirectory && loc.AmbiguousDirectory)
  226. {
  227. // Each side has a directory relative to a different location.
  228. // This can occur when referencing a source file from a different
  229. // directory. This is not yet allowed.
  230. this->Makefile->IssueMessage(
  231. cmake::INTERNAL_ERROR,
  232. "Matches error: Each side has a directory relative to a different "
  233. "location. This can occur when referencing a source file from a "
  234. "different directory. This is not yet allowed."
  235. );
  236. return false;
  237. }
  238. else if(this->AmbiguousDirectory)
  239. {
  240. // Compare possible directory combinations.
  241. std::string srcDir =
  242. cmSystemTools::CollapseFullPath(
  243. this->Directory.c_str(), this->Makefile->GetCurrentDirectory());
  244. std::string binDir =
  245. cmSystemTools::CollapseFullPath(
  246. this->Directory.c_str(), this->Makefile->GetCurrentOutputDirectory());
  247. if(srcDir != loc.Directory &&
  248. binDir != loc.Directory)
  249. {
  250. return false;
  251. }
  252. }
  253. else if(loc.AmbiguousDirectory)
  254. {
  255. // Compare possible directory combinations.
  256. std::string srcDir =
  257. cmSystemTools::CollapseFullPath(
  258. loc.Directory.c_str(), loc.Makefile->GetCurrentDirectory());
  259. std::string binDir =
  260. cmSystemTools::CollapseFullPath(
  261. loc.Directory.c_str(), loc.Makefile->GetCurrentOutputDirectory());
  262. if(srcDir != this->Directory &&
  263. binDir != this->Directory)
  264. {
  265. return false;
  266. }
  267. }
  268. // File locations match.
  269. this->Update(loc);
  270. return true;
  271. }