cmSourceFile.cxx 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  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 "cmSourceFile.h"
  4. #include <sstream>
  5. #include "cmCustomCommand.h"
  6. #include "cmGlobalGenerator.h"
  7. #include "cmMakefile.h"
  8. #include "cmProperty.h"
  9. #include "cmState.h"
  10. #include "cmSystemTools.h"
  11. #include "cmake.h"
  12. cmSourceFile::cmSourceFile(cmMakefile* mf, const std::string& name,
  13. cmSourceFileLocationKind kind)
  14. : Location(mf, name, kind)
  15. {
  16. this->CustomCommand = nullptr;
  17. this->FindFullPathFailed = false;
  18. }
  19. cmSourceFile::~cmSourceFile()
  20. {
  21. this->SetCustomCommand(nullptr);
  22. }
  23. std::string const& cmSourceFile::GetExtension() const
  24. {
  25. return this->Extension;
  26. }
  27. const std::string cmSourceFile::propLANGUAGE = "LANGUAGE";
  28. void cmSourceFile::SetObjectLibrary(std::string const& objlib)
  29. {
  30. this->ObjectLibrary = objlib;
  31. }
  32. std::string cmSourceFile::GetObjectLibrary() const
  33. {
  34. return this->ObjectLibrary;
  35. }
  36. std::string cmSourceFile::GetLanguage()
  37. {
  38. // If the language was set explicitly by the user then use it.
  39. if (const char* lang = this->GetProperty(propLANGUAGE)) {
  40. return lang;
  41. }
  42. // Perform computation needed to get the language if necessary.
  43. if (this->FullPath.empty() && this->Language.empty()) {
  44. // If a known extension is given or a known full path is given
  45. // then trust that the current extension is sufficient to
  46. // determine the language. This will fail only if the user
  47. // specifies a full path to the source but leaves off the
  48. // extension, which is kind of weird.
  49. if (this->Location.ExtensionIsAmbiguous() &&
  50. this->Location.DirectoryIsAmbiguous()) {
  51. // Finalize the file location to get the extension and set the
  52. // language.
  53. this->GetFullPath();
  54. } else {
  55. // Use the known extension to get the language if possible.
  56. std::string ext =
  57. cmSystemTools::GetFilenameLastExtension(this->Location.GetName());
  58. this->CheckLanguage(ext);
  59. }
  60. }
  61. // Now try to determine the language.
  62. return static_cast<cmSourceFile const*>(this)->GetLanguage();
  63. }
  64. std::string cmSourceFile::GetLanguage() const
  65. {
  66. // If the language was set explicitly by the user then use it.
  67. if (const char* lang = this->GetProperty(propLANGUAGE)) {
  68. return lang;
  69. }
  70. // If the language was determined from the source file extension use it.
  71. if (!this->Language.empty()) {
  72. return this->Language;
  73. }
  74. // The language is not known.
  75. return "";
  76. }
  77. cmSourceFileLocation const& cmSourceFile::GetLocation() const
  78. {
  79. return this->Location;
  80. }
  81. std::string const& cmSourceFile::GetFullPath(std::string* error)
  82. {
  83. if (this->FullPath.empty()) {
  84. if (this->FindFullPath(error)) {
  85. this->CheckExtension();
  86. }
  87. }
  88. return this->FullPath;
  89. }
  90. std::string const& cmSourceFile::GetFullPath() const
  91. {
  92. return this->FullPath;
  93. }
  94. bool cmSourceFile::FindFullPath(std::string* error)
  95. {
  96. // If this method has already failed once do not try again.
  97. if (this->FindFullPathFailed) {
  98. return false;
  99. }
  100. // If the file is generated compute the location without checking on
  101. // disk.
  102. if (this->GetPropertyAsBool("GENERATED")) {
  103. // The file is either already a full path or is relative to the
  104. // build directory for the target.
  105. this->Location.DirectoryUseBinary();
  106. this->FullPath = this->Location.GetDirectory();
  107. this->FullPath += "/";
  108. this->FullPath += this->Location.GetName();
  109. return true;
  110. }
  111. // The file is not generated. It must exist on disk.
  112. cmMakefile const* mf = this->Location.GetMakefile();
  113. const char* tryDirs[3] = { nullptr, nullptr, nullptr };
  114. if (this->Location.DirectoryIsAmbiguous()) {
  115. tryDirs[0] = mf->GetCurrentSourceDirectory();
  116. tryDirs[1] = mf->GetCurrentBinaryDirectory();
  117. } else {
  118. tryDirs[0] = "";
  119. }
  120. cmake const* const cmakeInst = mf->GetCMakeInstance();
  121. std::vector<std::string> const& srcExts = cmakeInst->GetSourceExtensions();
  122. std::vector<std::string> const& hdrExts = cmakeInst->GetHeaderExtensions();
  123. for (const char* const* di = tryDirs; *di; ++di) {
  124. std::string tryPath = this->Location.GetDirectory();
  125. if (!tryPath.empty()) {
  126. tryPath += "/";
  127. }
  128. tryPath += this->Location.GetName();
  129. tryPath = cmSystemTools::CollapseFullPath(tryPath, *di);
  130. if (this->TryFullPath(tryPath, "")) {
  131. return true;
  132. }
  133. for (std::string const& ext : srcExts) {
  134. if (this->TryFullPath(tryPath, ext)) {
  135. return true;
  136. }
  137. }
  138. for (std::string const& ext : hdrExts) {
  139. if (this->TryFullPath(tryPath, ext)) {
  140. return true;
  141. }
  142. }
  143. }
  144. std::ostringstream e;
  145. std::string missing = this->Location.GetDirectory();
  146. if (!missing.empty()) {
  147. missing += "/";
  148. }
  149. missing += this->Location.GetName();
  150. e << "Cannot find source file:\n " << missing << "\nTried extensions";
  151. for (std::string const& srcExt : srcExts) {
  152. e << " ." << srcExt;
  153. }
  154. for (std::string const& ext : hdrExts) {
  155. e << " ." << ext;
  156. }
  157. if (error) {
  158. *error = e.str();
  159. } else {
  160. this->Location.GetMakefile()->IssueMessage(cmake::FATAL_ERROR, e.str());
  161. }
  162. this->FindFullPathFailed = true;
  163. return false;
  164. }
  165. bool cmSourceFile::TryFullPath(const std::string& path, const std::string& ext)
  166. {
  167. std::string tryPath = path;
  168. if (!ext.empty()) {
  169. tryPath += ".";
  170. tryPath += ext;
  171. }
  172. if (cmSystemTools::FileExists(tryPath)) {
  173. this->FullPath = tryPath;
  174. return true;
  175. }
  176. return false;
  177. }
  178. void cmSourceFile::CheckExtension()
  179. {
  180. // Compute the extension.
  181. std::string realExt =
  182. cmSystemTools::GetFilenameLastExtension(this->FullPath);
  183. if (!realExt.empty()) {
  184. // Store the extension without the leading '.'.
  185. this->Extension = realExt.substr(1);
  186. }
  187. // Look for object files.
  188. if (this->Extension == "obj" || this->Extension == "o" ||
  189. this->Extension == "lo") {
  190. this->SetProperty("EXTERNAL_OBJECT", "1");
  191. }
  192. // Try to identify the source file language from the extension.
  193. if (this->Language.empty()) {
  194. this->CheckLanguage(this->Extension);
  195. }
  196. }
  197. void cmSourceFile::CheckLanguage(std::string const& ext)
  198. {
  199. // Try to identify the source file language from the extension.
  200. cmMakefile const* mf = this->Location.GetMakefile();
  201. cmGlobalGenerator* gg = mf->GetGlobalGenerator();
  202. std::string l = gg->GetLanguageFromExtension(ext.c_str());
  203. if (!l.empty()) {
  204. this->Language = l;
  205. }
  206. }
  207. bool cmSourceFile::Matches(cmSourceFileLocation const& loc)
  208. {
  209. return this->Location.Matches(loc);
  210. }
  211. void cmSourceFile::SetProperty(const std::string& prop, const char* value)
  212. {
  213. this->Properties.SetProperty(prop, value);
  214. }
  215. void cmSourceFile::AppendProperty(const std::string& prop, const char* value,
  216. bool asString)
  217. {
  218. this->Properties.AppendProperty(prop, value, asString);
  219. }
  220. const char* cmSourceFile::GetPropertyForUser(const std::string& prop)
  221. {
  222. // This method is a consequence of design history and backwards
  223. // compatibility. GetProperty is (and should be) a const method.
  224. // Computed properties should not be stored back in the property map
  225. // but instead reference information already known. If they need to
  226. // cache information in a mutable ivar to provide the return string
  227. // safely then so be it.
  228. //
  229. // The LOCATION property is particularly problematic. The CMake
  230. // language has very loose restrictions on the names that will match
  231. // a given source file (for historical reasons). Implementing
  232. // lookups correctly with such loose naming requires the
  233. // cmSourceFileLocation class to commit to a particular full path to
  234. // the source file as late as possible. If the users requests the
  235. // LOCATION property we must commit now.
  236. if (prop == "LOCATION") {
  237. // Commit to a location.
  238. this->GetFullPath();
  239. }
  240. // Perform the normal property lookup.
  241. return this->GetProperty(prop);
  242. }
  243. const char* cmSourceFile::GetProperty(const std::string& prop) const
  244. {
  245. // Check for computed properties.
  246. if (prop == "LOCATION") {
  247. if (this->FullPath.empty()) {
  248. return nullptr;
  249. }
  250. return this->FullPath.c_str();
  251. }
  252. const char* retVal = this->Properties.GetPropertyValue(prop);
  253. if (!retVal) {
  254. cmMakefile const* mf = this->Location.GetMakefile();
  255. const bool chain =
  256. mf->GetState()->IsPropertyChained(prop, cmProperty::SOURCE_FILE);
  257. if (chain) {
  258. return mf->GetProperty(prop, chain);
  259. }
  260. }
  261. return retVal;
  262. }
  263. bool cmSourceFile::GetPropertyAsBool(const std::string& prop) const
  264. {
  265. return cmSystemTools::IsOn(this->GetProperty(prop));
  266. }
  267. cmCustomCommand* cmSourceFile::GetCustomCommand()
  268. {
  269. return this->CustomCommand;
  270. }
  271. cmCustomCommand const* cmSourceFile::GetCustomCommand() const
  272. {
  273. return this->CustomCommand;
  274. }
  275. void cmSourceFile::SetCustomCommand(cmCustomCommand* cc)
  276. {
  277. cmCustomCommand* old = this->CustomCommand;
  278. this->CustomCommand = cc;
  279. delete old;
  280. }