cmSourceFile.cxx 9.6 KB

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