cmExportFileGenerator.cxx 12 KB

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