cmExportFileGenerator.cxx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. /*=========================================================================
  2. Program: CMake - Cross-Platform Makefile Generator
  3. Module: $RCSfile$
  4. Language: C++
  5. Date: $Date$
  6. Version: $Revision$
  7. Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
  8. See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
  9. This software is distributed WITHOUT ANY WARRANTY; without even
  10. the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  11. PURPOSE. See the above copyright notices for more information.
  12. =========================================================================*/
  13. #include "cmExportFileGenerator.h"
  14. #include "cmGeneratedFileStream.h"
  15. #include "cmMakefile.h"
  16. #include "cmSystemTools.h"
  17. #include "cmTarget.h"
  18. #include <cmsys/auto_ptr.hxx>
  19. //----------------------------------------------------------------------------
  20. cmExportFileGenerator::cmExportFileGenerator()
  21. {
  22. this->AppendMode = false;
  23. }
  24. //----------------------------------------------------------------------------
  25. void cmExportFileGenerator::AddConfiguration(const char* config)
  26. {
  27. this->Configurations.push_back(config);
  28. }
  29. //----------------------------------------------------------------------------
  30. void cmExportFileGenerator::SetExportFile(const char* mainFile)
  31. {
  32. this->MainImportFile = mainFile;
  33. this->FileDir =
  34. cmSystemTools::GetFilenamePath(this->MainImportFile);
  35. this->FileBase =
  36. cmSystemTools::GetFilenameWithoutLastExtension(this->MainImportFile);
  37. this->FileExt =
  38. cmSystemTools::GetFilenameLastExtension(this->MainImportFile);
  39. }
  40. //----------------------------------------------------------------------------
  41. bool cmExportFileGenerator::GenerateImportFile()
  42. {
  43. // Open the output file to generate it.
  44. cmsys::auto_ptr<std::ofstream> foutPtr;
  45. if(this->AppendMode)
  46. {
  47. // Open for append.
  48. cmsys::auto_ptr<std::ofstream>
  49. ap(new std::ofstream(this->MainImportFile.c_str(), std::ios::app));
  50. foutPtr = ap;
  51. }
  52. else
  53. {
  54. // Generate atomically and with copy-if-different.
  55. cmsys::auto_ptr<cmGeneratedFileStream>
  56. ap(new cmGeneratedFileStream(this->MainImportFile.c_str(), true));
  57. ap->SetCopyIfDifferent(true);
  58. foutPtr = ap;
  59. }
  60. if(!foutPtr.get() || !*foutPtr)
  61. {
  62. std::string se = cmSystemTools::GetLastSystemError();
  63. cmOStringStream e;
  64. e << "cannot write to file \"" << this->MainImportFile
  65. << "\": " << se;
  66. cmSystemTools::Error(e.str().c_str());
  67. return false;
  68. }
  69. std::ostream& os = *foutPtr;
  70. // Start with the import file header.
  71. this->GenerateImportHeaderCode(os);
  72. // Create all the imported targets.
  73. bool result = this->GenerateMainFile(os);
  74. // End with the import file footer.
  75. this->GenerateImportFooterCode(os);
  76. return result;
  77. }
  78. //----------------------------------------------------------------------------
  79. void cmExportFileGenerator::GenerateImportConfig(std::ostream& os,
  80. const char* config)
  81. {
  82. // Construct the property configuration suffix.
  83. std::string suffix = "_";
  84. if(config && *config)
  85. {
  86. suffix += cmSystemTools::UpperCase(config);
  87. }
  88. else
  89. {
  90. suffix += "NOCONFIG";
  91. }
  92. // Generate the per-config target information.
  93. this->GenerateImportTargetsConfig(os, config, suffix);
  94. }
  95. //----------------------------------------------------------------------------
  96. void
  97. cmExportFileGenerator
  98. ::SetImportDetailProperties(const char* config, std::string const& suffix,
  99. cmTarget* target, ImportPropertyMap& properties)
  100. {
  101. // Get the makefile in which to lookup target information.
  102. cmMakefile* mf = target->GetMakefile();
  103. // Add the soname for unix shared libraries.
  104. if(target->GetType() == cmTarget::SHARED_LIBRARY ||
  105. target->GetType() == cmTarget::MODULE_LIBRARY)
  106. {
  107. // Check whether this is a DLL platform.
  108. bool dll_platform =
  109. (mf->IsOn("WIN32") || mf->IsOn("CYGWIN") || mf->IsOn("MINGW"));
  110. if(!dll_platform)
  111. {
  112. std::string soname = target->GetSOName(config);
  113. std::string prop = "IMPORTED_SONAME";
  114. prop += suffix;
  115. properties[prop] = soname;
  116. }
  117. }
  118. // Add the transitive link dependencies for this configuration.
  119. if(cmTargetLinkInterface const* interface =
  120. target->GetLinkInterface(config))
  121. {
  122. // This target provides a link interface, so use it.
  123. this->SetImportLinkProperty(suffix, target,
  124. "IMPORTED_LINK_INTERFACE_LIBRARIES",
  125. interface->Libraries, properties);
  126. this->SetImportLinkProperty(suffix, target,
  127. "IMPORTED_LINK_DEPENDENT_LIBRARIES",
  128. interface->SharedDeps, properties);
  129. }
  130. else if(target->GetType() == cmTarget::STATIC_LIBRARY ||
  131. target->GetType() == cmTarget::SHARED_LIBRARY)
  132. {
  133. // The default link interface for static and shared libraries is
  134. // their link implementation library list.
  135. this->SetImportLinkProperties(config, suffix, target, properties);
  136. }
  137. }
  138. //----------------------------------------------------------------------------
  139. void
  140. cmExportFileGenerator
  141. ::SetImportLinkProperties(const char* config, std::string const& suffix,
  142. cmTarget* target, ImportPropertyMap& properties)
  143. {
  144. // Compute which library configuration to link.
  145. cmTarget::LinkLibraryType linkType = cmTarget::OPTIMIZED;
  146. if(config && cmSystemTools::UpperCase(config) == "DEBUG")
  147. {
  148. linkType = cmTarget::DEBUG;
  149. }
  150. // Construct the list of libs linked for this configuration.
  151. std::vector<std::string> actual_libs;
  152. cmTarget::LinkLibraryVectorType const& libs =
  153. target->GetOriginalLinkLibraries();
  154. for(cmTarget::LinkLibraryVectorType::const_iterator li = libs.begin();
  155. li != libs.end(); ++li)
  156. {
  157. // Skip entries that will resolve to the target itself, are empty,
  158. // or are not meant for this configuration.
  159. if(li->first == target->GetName() || li->first.empty() ||
  160. !(li->second == cmTarget::GENERAL || li->second == linkType))
  161. {
  162. continue;
  163. }
  164. // Store this entry.
  165. actual_libs.push_back(li->first);
  166. }
  167. // Store the entries in the property.
  168. this->SetImportLinkProperty(suffix, target,
  169. "IMPORTED_LINK_INTERFACE_LIBRARIES",
  170. actual_libs, properties);
  171. }
  172. //----------------------------------------------------------------------------
  173. void
  174. cmExportFileGenerator
  175. ::SetImportLinkProperty(std::string const& suffix,
  176. cmTarget* target,
  177. const char* propName,
  178. std::vector<std::string> const& libs,
  179. ImportPropertyMap& properties)
  180. {
  181. // Skip the property if there are no libraries.
  182. if(libs.empty())
  183. {
  184. return;
  185. }
  186. // Get the makefile in which to lookup target information.
  187. cmMakefile* mf = target->GetMakefile();
  188. // Construct the property value.
  189. std::string link_libs;
  190. const char* sep = "";
  191. for(std::vector<std::string>::const_iterator li = libs.begin();
  192. li != libs.end(); ++li)
  193. {
  194. // Separate this from the previous entry.
  195. link_libs += sep;
  196. sep = ";";
  197. // Append this entry.
  198. if(cmTarget* tgt = mf->FindTargetToUse(li->c_str()))
  199. {
  200. // This is a target.
  201. if(tgt->IsImported())
  202. {
  203. // The target is imported (and therefore is not in the
  204. // export). Append the raw name.
  205. link_libs += *li;
  206. }
  207. else if(this->ExportedTargets.find(tgt) != this->ExportedTargets.end())
  208. {
  209. // The target is in the export. Append it with the export
  210. // namespace.
  211. link_libs += this->Namespace;
  212. link_libs += *li;
  213. }
  214. else
  215. {
  216. // The target is not in the export.
  217. if(!this->AppendMode)
  218. {
  219. // We are not appending, so all exported targets should be
  220. // known here. This is probably user-error.
  221. this->ComplainAboutMissingTarget(target, li->c_str());
  222. }
  223. // Assume the target will be exported by another command.
  224. // Append it with the export namespace.
  225. link_libs += this->Namespace;
  226. link_libs += *li;
  227. }
  228. }
  229. else
  230. {
  231. // Append the raw name.
  232. link_libs += *li;
  233. }
  234. }
  235. // Store the property.
  236. std::string prop = propName;
  237. prop += suffix;
  238. properties[prop] = link_libs;
  239. }
  240. //----------------------------------------------------------------------------
  241. void cmExportFileGenerator::GenerateImportHeaderCode(std::ostream& os,
  242. const char* config)
  243. {
  244. os << "#----------------------------------------------------------------\n"
  245. << "# Generated CMake target import file";
  246. if(config)
  247. {
  248. os << " for configuration \"" << config << "\".\n";
  249. }
  250. else
  251. {
  252. os << ".\n";
  253. }
  254. os << "#----------------------------------------------------------------\n"
  255. << "\n";
  256. this->GenerateImportVersionCode(os);
  257. }
  258. //----------------------------------------------------------------------------
  259. void cmExportFileGenerator::GenerateImportFooterCode(std::ostream& os)
  260. {
  261. os << "# Commands beyond this point should not need to know the version.\n"
  262. << "SET(CMAKE_IMPORT_FILE_VERSION)\n";
  263. }
  264. //----------------------------------------------------------------------------
  265. void cmExportFileGenerator::GenerateImportVersionCode(std::ostream& os)
  266. {
  267. // Store an import file format version. This will let us change the
  268. // format later while still allowing old import files to work.
  269. os << "# Commands may need to know the format version.\n"
  270. << "SET(CMAKE_IMPORT_FILE_VERSION 1)\n"
  271. << "\n";
  272. }
  273. //----------------------------------------------------------------------------
  274. void
  275. cmExportFileGenerator
  276. ::GenerateImportTargetCode(std::ostream& os, cmTarget* target)
  277. {
  278. // Construct the imported target name.
  279. std::string targetName = this->Namespace;
  280. targetName += target->GetName();
  281. // Create the imported target.
  282. os << "# Create imported target " << targetName << "\n";
  283. switch(target->GetType())
  284. {
  285. case cmTarget::EXECUTABLE:
  286. os << "ADD_EXECUTABLE(" << targetName << " IMPORTED)\n";
  287. break;
  288. case cmTarget::STATIC_LIBRARY:
  289. os << "ADD_LIBRARY(" << targetName << " STATIC IMPORTED)\n";
  290. break;
  291. case cmTarget::SHARED_LIBRARY:
  292. os << "ADD_LIBRARY(" << targetName << " SHARED IMPORTED)\n";
  293. break;
  294. case cmTarget::MODULE_LIBRARY:
  295. os << "ADD_LIBRARY(" << targetName << " MODULE IMPORTED)\n";
  296. break;
  297. default: // should never happen
  298. break;
  299. }
  300. // Mark the imported executable if it has exports.
  301. if(target->IsExecutableWithExports())
  302. {
  303. os << "SET_PROPERTY(TARGET " << targetName
  304. << " PROPERTY ENABLE_EXPORTS 1)\n";
  305. }
  306. // Mark the imported library if it is a framework.
  307. if(target->IsFrameworkOnApple())
  308. {
  309. os << "SET_PROPERTY(TARGET " << targetName
  310. << " PROPERTY FRAMEWORK 1)\n";
  311. }
  312. // Mark the imported executable if it is an application bundle.
  313. if(target->IsAppBundleOnApple())
  314. {
  315. os << "SET_PROPERTY(TARGET " << targetName
  316. << " PROPERTY MACOSX_BUNDLE 1)\n";
  317. }
  318. os << "\n";
  319. }
  320. //----------------------------------------------------------------------------
  321. void
  322. cmExportFileGenerator
  323. ::GenerateImportPropertyCode(std::ostream& os, const char* config,
  324. cmTarget* target,
  325. ImportPropertyMap const& properties)
  326. {
  327. // Construct the imported target name.
  328. std::string targetName = this->Namespace;
  329. targetName += target->GetName();
  330. // Set the import properties.
  331. os << "# Import target \"" << targetName << "\" for configuration \""
  332. << config << "\"\n";
  333. os << "SET_PROPERTY(TARGET " << targetName
  334. << " APPEND PROPERTY IMPORTED_CONFIGURATIONS ";
  335. if(config && *config)
  336. {
  337. os << cmSystemTools::UpperCase(config);
  338. }
  339. else
  340. {
  341. os << "NOCONFIG";
  342. }
  343. os << ")\n";
  344. os << "SET_TARGET_PROPERTIES(" << targetName << " PROPERTIES\n";
  345. for(ImportPropertyMap::const_iterator pi = properties.begin();
  346. pi != properties.end(); ++pi)
  347. {
  348. os << " " << pi->first << " \"" << pi->second << "\"\n";
  349. }
  350. os << " )\n"
  351. << "\n";
  352. }