cmSourceFile.cxx 9.3 KB

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