cmSourceFile.cxx 12 KB

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