cmSourceFileLocation.cxx 8.4 KB

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