cmSourceFileLocation.cxx 7.6 KB

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