cmExportFileGenerator.cxx 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  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 "cmExportFileGenerator.h"
  11. #include "cmExportSet.h"
  12. #include "cmGeneratedFileStream.h"
  13. #include "cmGlobalGenerator.h"
  14. #include "cmInstallExportGenerator.h"
  15. #include "cmLocalGenerator.h"
  16. #include "cmMakefile.h"
  17. #include "cmSystemTools.h"
  18. #include "cmTarget.h"
  19. #include "cmTargetExport.h"
  20. #include "cmVersion.h"
  21. #include <cmsys/auto_ptr.hxx>
  22. //----------------------------------------------------------------------------
  23. cmExportFileGenerator::cmExportFileGenerator()
  24. {
  25. this->AppendMode = false;
  26. }
  27. //----------------------------------------------------------------------------
  28. void cmExportFileGenerator::AddConfiguration(const char* config)
  29. {
  30. this->Configurations.push_back(config);
  31. }
  32. //----------------------------------------------------------------------------
  33. void cmExportFileGenerator::SetExportFile(const char* mainFile)
  34. {
  35. this->MainImportFile = mainFile;
  36. this->FileDir =
  37. cmSystemTools::GetFilenamePath(this->MainImportFile);
  38. this->FileBase =
  39. cmSystemTools::GetFilenameWithoutLastExtension(this->MainImportFile);
  40. this->FileExt =
  41. cmSystemTools::GetFilenameLastExtension(this->MainImportFile);
  42. }
  43. //----------------------------------------------------------------------------
  44. bool cmExportFileGenerator::GenerateImportFile()
  45. {
  46. // Open the output file to generate it.
  47. cmsys::auto_ptr<std::ofstream> foutPtr;
  48. if(this->AppendMode)
  49. {
  50. // Open for append.
  51. cmsys::auto_ptr<std::ofstream>
  52. ap(new std::ofstream(this->MainImportFile.c_str(), std::ios::app));
  53. foutPtr = ap;
  54. }
  55. else
  56. {
  57. // Generate atomically and with copy-if-different.
  58. cmsys::auto_ptr<cmGeneratedFileStream>
  59. ap(new cmGeneratedFileStream(this->MainImportFile.c_str(), true));
  60. ap->SetCopyIfDifferent(true);
  61. foutPtr = ap;
  62. }
  63. if(!foutPtr.get() || !*foutPtr)
  64. {
  65. std::string se = cmSystemTools::GetLastSystemError();
  66. cmOStringStream e;
  67. e << "cannot write to file \"" << this->MainImportFile
  68. << "\": " << se;
  69. cmSystemTools::Error(e.str().c_str());
  70. return false;
  71. }
  72. std::ostream& os = *foutPtr;
  73. // Protect that file against use with older CMake versions.
  74. os << "# Generated by CMake " << cmVersion::GetCMakeVersion() << "\n\n";
  75. os << "IF(\"${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}\" LESS 2.5)\n"
  76. << " MESSAGE(FATAL_ERROR \"CMake >= 2.6.0 required\")\n"
  77. << "ENDIF(\"${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}\" LESS 2.5)\n";
  78. // Isolate the file policy level.
  79. // We use 2.6 here instead of the current version because newer
  80. // versions of CMake should be able to export files imported by 2.6
  81. // until the import format changes.
  82. os << "CMAKE_POLICY(PUSH)\n"
  83. << "CMAKE_POLICY(VERSION 2.6)\n";
  84. // Start with the import file header.
  85. this->GenerateImportHeaderCode(os);
  86. // Create all the imported targets.
  87. bool result = this->GenerateMainFile(os);
  88. // End with the import file footer.
  89. this->GenerateImportFooterCode(os);
  90. os << "CMAKE_POLICY(POP)\n";
  91. return result;
  92. }
  93. //----------------------------------------------------------------------------
  94. void cmExportFileGenerator::GenerateImportConfig(std::ostream& os,
  95. const char* config)
  96. {
  97. // Construct the property configuration suffix.
  98. std::string suffix = "_";
  99. if(config && *config)
  100. {
  101. suffix += cmSystemTools::UpperCase(config);
  102. }
  103. else
  104. {
  105. suffix += "NOCONFIG";
  106. }
  107. // Generate the per-config target information.
  108. this->GenerateImportTargetsConfig(os, config, suffix);
  109. }
  110. //----------------------------------------------------------------------------
  111. void
  112. cmExportFileGenerator
  113. ::SetImportDetailProperties(const char* config, std::string const& suffix,
  114. cmTarget* target, ImportPropertyMap& properties,
  115. std::vector<std::string>& missingTargets
  116. )
  117. {
  118. // Get the makefile in which to lookup target information.
  119. cmMakefile* mf = target->GetMakefile();
  120. // Add the soname for unix shared libraries.
  121. if(target->GetType() == cmTarget::SHARED_LIBRARY ||
  122. target->GetType() == cmTarget::MODULE_LIBRARY)
  123. {
  124. // Check whether this is a DLL platform.
  125. bool dll_platform =
  126. (mf->IsOn("WIN32") || mf->IsOn("CYGWIN") || mf->IsOn("MINGW"));
  127. if(!dll_platform)
  128. {
  129. std::string prop;
  130. std::string value;
  131. if(target->HasSOName(config))
  132. {
  133. prop = "IMPORTED_SONAME";
  134. value = target->GetSOName(config);
  135. }
  136. else
  137. {
  138. prop = "IMPORTED_NO_SONAME";
  139. value = "TRUE";
  140. }
  141. prop += suffix;
  142. properties[prop] = value;
  143. }
  144. }
  145. // Add the transitive link dependencies for this configuration.
  146. if(cmTarget::LinkInterface const* iface = target->GetLinkInterface(config))
  147. {
  148. this->SetImportLinkProperty(suffix, target,
  149. "IMPORTED_LINK_INTERFACE_LANGUAGES",
  150. iface->Languages, properties, missingTargets);
  151. this->SetImportLinkProperty(suffix, target,
  152. "IMPORTED_LINK_INTERFACE_LIBRARIES",
  153. iface->Libraries, properties, missingTargets);
  154. this->SetImportLinkProperty(suffix, target,
  155. "IMPORTED_LINK_DEPENDENT_LIBRARIES",
  156. iface->SharedDeps, properties, missingTargets);
  157. if(iface->Multiplicity > 0)
  158. {
  159. std::string prop = "IMPORTED_LINK_INTERFACE_MULTIPLICITY";
  160. prop += suffix;
  161. cmOStringStream m;
  162. m << iface->Multiplicity;
  163. properties[prop] = m.str();
  164. }
  165. }
  166. }
  167. //----------------------------------------------------------------------------
  168. void
  169. cmExportFileGenerator
  170. ::SetImportLinkProperty(std::string const& suffix,
  171. cmTarget* target,
  172. const char* propName,
  173. std::vector<std::string> const& libs,
  174. ImportPropertyMap& properties,
  175. std::vector<std::string>& missingTargets
  176. )
  177. {
  178. // Skip the property if there are no libraries.
  179. if(libs.empty())
  180. {
  181. return;
  182. }
  183. // Get the makefile in which to lookup target information.
  184. cmMakefile* mf = target->GetMakefile();
  185. // Construct the property value.
  186. std::string link_libs;
  187. const char* sep = "";
  188. for(std::vector<std::string>::const_iterator li = libs.begin();
  189. li != libs.end(); ++li)
  190. {
  191. // Separate this from the previous entry.
  192. link_libs += sep;
  193. sep = ";";
  194. // Append this entry.
  195. if(cmTarget* tgt = mf->FindTargetToUse(li->c_str()))
  196. {
  197. // This is a target.
  198. if(tgt->IsImported())
  199. {
  200. // The target is imported (and therefore is not in the
  201. // export). Append the raw name.
  202. link_libs += *li;
  203. }
  204. else if(this->ExportedTargets.find(tgt) != this->ExportedTargets.end())
  205. {
  206. // The target is in the export. Append it with the export
  207. // namespace.
  208. link_libs += this->Namespace;
  209. link_libs += *li;
  210. }
  211. else
  212. {
  213. this->HandleMissingTarget(link_libs, missingTargets, mf, target, tgt);
  214. }
  215. }
  216. else
  217. {
  218. // Append the raw name.
  219. link_libs += *li;
  220. }
  221. }
  222. // Store the property.
  223. std::string prop = propName;
  224. prop += suffix;
  225. properties[prop] = link_libs;
  226. }
  227. //----------------------------------------------------------------------------
  228. void cmExportFileGenerator::GenerateImportHeaderCode(std::ostream& os,
  229. const char* config)
  230. {
  231. os << "#----------------------------------------------------------------\n"
  232. << "# Generated CMake target import file";
  233. if(config)
  234. {
  235. os << " for configuration \"" << config << "\".\n";
  236. }
  237. else
  238. {
  239. os << ".\n";
  240. }
  241. os << "#----------------------------------------------------------------\n"
  242. << "\n";
  243. this->GenerateImportVersionCode(os);
  244. }
  245. //----------------------------------------------------------------------------
  246. void cmExportFileGenerator::GenerateImportFooterCode(std::ostream& os)
  247. {
  248. os << "# Commands beyond this point should not need to know the version.\n"
  249. << "SET(CMAKE_IMPORT_FILE_VERSION)\n";
  250. }
  251. //----------------------------------------------------------------------------
  252. void cmExportFileGenerator::GenerateImportVersionCode(std::ostream& os)
  253. {
  254. // Store an import file format version. This will let us change the
  255. // format later while still allowing old import files to work.
  256. os << "# Commands may need to know the format version.\n"
  257. << "SET(CMAKE_IMPORT_FILE_VERSION 1)\n"
  258. << "\n";
  259. }
  260. //----------------------------------------------------------------------------
  261. void
  262. cmExportFileGenerator
  263. ::GenerateImportTargetCode(std::ostream& os, cmTarget* target)
  264. {
  265. // Construct the imported target name.
  266. std::string targetName = this->Namespace;
  267. targetName += target->GetName();
  268. // Create the imported target.
  269. os << "# Create imported target " << targetName << "\n";
  270. switch(target->GetType())
  271. {
  272. case cmTarget::EXECUTABLE:
  273. os << "ADD_EXECUTABLE(" << targetName << " IMPORTED)\n";
  274. break;
  275. case cmTarget::STATIC_LIBRARY:
  276. os << "ADD_LIBRARY(" << targetName << " STATIC IMPORTED)\n";
  277. break;
  278. case cmTarget::SHARED_LIBRARY:
  279. os << "ADD_LIBRARY(" << targetName << " SHARED IMPORTED)\n";
  280. break;
  281. case cmTarget::MODULE_LIBRARY:
  282. os << "ADD_LIBRARY(" << targetName << " MODULE IMPORTED)\n";
  283. break;
  284. default: // should never happen
  285. break;
  286. }
  287. // Mark the imported executable if it has exports.
  288. if(target->IsExecutableWithExports())
  289. {
  290. os << "SET_PROPERTY(TARGET " << targetName
  291. << " PROPERTY ENABLE_EXPORTS 1)\n";
  292. }
  293. // Mark the imported library if it is a framework.
  294. if(target->IsFrameworkOnApple())
  295. {
  296. os << "SET_PROPERTY(TARGET " << targetName
  297. << " PROPERTY FRAMEWORK 1)\n";
  298. }
  299. // Mark the imported executable if it is an application bundle.
  300. if(target->IsAppBundleOnApple())
  301. {
  302. os << "SET_PROPERTY(TARGET " << targetName
  303. << " PROPERTY MACOSX_BUNDLE 1)\n";
  304. }
  305. if (target->IsCFBundleOnApple())
  306. {
  307. os << "SET_PROPERTY(TARGET " << targetName
  308. << " PROPERTY BUNDLE 1)\n";
  309. }
  310. os << "\n";
  311. }
  312. //----------------------------------------------------------------------------
  313. void
  314. cmExportFileGenerator
  315. ::GenerateImportPropertyCode(std::ostream& os, const char* config,
  316. cmTarget* target,
  317. ImportPropertyMap const& properties)
  318. {
  319. // Construct the imported target name.
  320. std::string targetName = this->Namespace;
  321. targetName += target->GetName();
  322. // Set the import properties.
  323. os << "# Import target \"" << targetName << "\" for configuration \""
  324. << config << "\"\n";
  325. os << "SET_PROPERTY(TARGET " << targetName
  326. << " APPEND PROPERTY IMPORTED_CONFIGURATIONS ";
  327. if(config && *config)
  328. {
  329. os << cmSystemTools::UpperCase(config);
  330. }
  331. else
  332. {
  333. os << "NOCONFIG";
  334. }
  335. os << ")\n";
  336. os << "SET_TARGET_PROPERTIES(" << targetName << " PROPERTIES\n";
  337. for(ImportPropertyMap::const_iterator pi = properties.begin();
  338. pi != properties.end(); ++pi)
  339. {
  340. os << " " << pi->first << " \"" << pi->second << "\"\n";
  341. }
  342. os << " )\n"
  343. << "\n";
  344. }
  345. //----------------------------------------------------------------------------
  346. void cmExportFileGenerator::GenerateMissingTargetsCheckCode(std::ostream& os,
  347. const std::vector<std::string>& missingTargets)
  348. {
  349. os << "# Make sure the targets which have been exported in some other \n"
  350. "# export set exist.\n";
  351. for(unsigned int i=0; i<missingTargets.size(); ++i)
  352. {
  353. os << "IF(NOT TARGET \"" << missingTargets[i] << "\" )\n"
  354. << " MESSAGE(FATAL_ERROR \"Required imported target \\\""
  355. << missingTargets[i] << "\\\" not found ! \")\n"
  356. << "ENDIF()\n";
  357. }
  358. os << "\n";
  359. }
  360. //----------------------------------------------------------------------------
  361. void
  362. cmExportFileGenerator::GenerateImportedFileCheckLoop(std::ostream& os)
  363. {
  364. // Add code which verifies at cmake time that the file which is being
  365. // imported actually exists on disk. This should in theory always be theory
  366. // case, but still when packages are split into normal and development
  367. // packages this might get broken (e.g. the Config.cmake could be part of
  368. // the non-development package, something similar happened to me without
  369. // on SUSE with a mysql pkg-config file, which claimed everything is fine,
  370. // but the development package was not installed.).
  371. os << "# Loop over all imported files and verify that they actually exist\n"
  372. "FOREACH(target ${_IMPORT_CHECK_TARGETS} )\n"
  373. " FOREACH(file ${_IMPORT_CHECK_FILES_FOR_${target}} )\n"
  374. " IF(NOT EXISTS \"${file}\" )\n"
  375. " MESSAGE(FATAL_ERROR \"The imported target \\\"${target}\\\""
  376. " references the file\n"
  377. " \\\"${file}\\\"\n"
  378. "but this file does not exist. Possible reasons include:\n"
  379. "* The file was deleted, renamed, or moved to another location.\n"
  380. "* An install or uninstall procedure did not complete successfully.\n"
  381. "* The installation package was faulty and contained\n"
  382. " \\\"${CMAKE_CURRENT_LIST_FILE}\\\"\n"
  383. "but not all the files it references.\n"
  384. "\")\n"
  385. " ENDIF()\n"
  386. " ENDFOREACH()\n"
  387. " UNSET(_IMPORT_CHECK_FILES_FOR_${target})\n"
  388. "ENDFOREACH()\n"
  389. "UNSET(_IMPORT_CHECK_TARGETS)\n"
  390. "\n";
  391. }
  392. //----------------------------------------------------------------------------
  393. void
  394. cmExportFileGenerator
  395. ::GenerateImportedFileChecksCode(std::ostream& os, cmTarget* target,
  396. ImportPropertyMap const& properties,
  397. const std::set<std::string>& importedLocations)
  398. {
  399. // Construct the imported target name.
  400. std::string targetName = this->Namespace;
  401. targetName += target->GetName();
  402. os << "LIST(APPEND _IMPORT_CHECK_TARGETS " << targetName << " )\n"
  403. "LIST(APPEND _IMPORT_CHECK_FILES_FOR_" << targetName << " ";
  404. for(std::set<std::string>::const_iterator li = importedLocations.begin();
  405. li != importedLocations.end();
  406. ++li)
  407. {
  408. ImportPropertyMap::const_iterator pi = properties.find(*li);
  409. if (pi != properties.end())
  410. {
  411. os << "\"" << pi->second << "\" ";
  412. }
  413. }
  414. os << ")\n\n";
  415. }