cmExportFileGenerator.cxx 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  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. {
  116. // Get the makefile in which to lookup target information.
  117. cmMakefile* mf = target->GetMakefile();
  118. // Add the soname for unix shared libraries.
  119. if(target->GetType() == cmTarget::SHARED_LIBRARY ||
  120. target->GetType() == cmTarget::MODULE_LIBRARY)
  121. {
  122. // Check whether this is a DLL platform.
  123. bool dll_platform =
  124. (mf->IsOn("WIN32") || mf->IsOn("CYGWIN") || mf->IsOn("MINGW"));
  125. if(!dll_platform)
  126. {
  127. std::string prop;
  128. std::string value;
  129. if(target->HasSOName(config))
  130. {
  131. prop = "IMPORTED_SONAME";
  132. value = target->GetSOName(config);
  133. }
  134. else
  135. {
  136. prop = "IMPORTED_NO_SONAME";
  137. value = "TRUE";
  138. }
  139. prop += suffix;
  140. properties[prop] = value;
  141. }
  142. }
  143. // Add the transitive link dependencies for this configuration.
  144. if(cmTarget::LinkInterface const* iface = target->GetLinkInterface(config))
  145. {
  146. this->SetImportLinkProperty(suffix, target,
  147. "IMPORTED_LINK_INTERFACE_LANGUAGES",
  148. iface->Languages, properties);
  149. this->SetImportLinkProperty(suffix, target,
  150. "IMPORTED_LINK_INTERFACE_LIBRARIES",
  151. iface->Libraries, properties);
  152. this->SetImportLinkProperty(suffix, target,
  153. "IMPORTED_LINK_DEPENDENT_LIBRARIES",
  154. iface->SharedDeps, properties);
  155. if(iface->Multiplicity > 0)
  156. {
  157. std::string prop = "IMPORTED_LINK_INTERFACE_MULTIPLICITY";
  158. prop += suffix;
  159. cmOStringStream m;
  160. m << iface->Multiplicity;
  161. properties[prop] = m.str();
  162. }
  163. }
  164. }
  165. //----------------------------------------------------------------------------
  166. void
  167. cmExportFileGenerator
  168. ::SetImportLinkProperty(std::string const& suffix,
  169. cmTarget* target,
  170. const char* propName,
  171. std::vector<std::string> const& libs,
  172. ImportPropertyMap& properties)
  173. {
  174. // Skip the property if there are no libraries.
  175. if(libs.empty())
  176. {
  177. return;
  178. }
  179. // Get the makefile in which to lookup target information.
  180. cmMakefile* mf = target->GetMakefile();
  181. // Construct the property value.
  182. std::string link_libs;
  183. const char* sep = "";
  184. for(std::vector<std::string>::const_iterator li = libs.begin();
  185. li != libs.end(); ++li)
  186. {
  187. // Separate this from the previous entry.
  188. link_libs += sep;
  189. sep = ";";
  190. // Append this entry.
  191. if(cmTarget* tgt = mf->FindTargetToUse(li->c_str()))
  192. {
  193. // This is a target.
  194. if(tgt->IsImported())
  195. {
  196. // The target is imported (and therefore is not in the
  197. // export). Append the raw name.
  198. link_libs += *li;
  199. }
  200. else if(this->ExportedTargets.find(tgt) != this->ExportedTargets.end())
  201. {
  202. // The target is in the export. Append it with the export
  203. // namespace.
  204. link_libs += this->Namespace;
  205. link_libs += *li;
  206. }
  207. else
  208. {
  209. std::vector<std::string> namespaces = this->FindNamespaces(mf, *li);
  210. int targetOccurrences = (int)namespaces.size();
  211. if (targetOccurrences == 1)
  212. {
  213. link_libs += namespaces[0];
  214. link_libs += *li;
  215. }
  216. else
  217. {
  218. // The target is not in the export.
  219. if(!this->AppendMode)
  220. {
  221. // We are not appending, so all exported targets should be
  222. // known here. This is probably user-error.
  223. this->ComplainAboutMissingTarget(target, tgt, targetOccurrences);
  224. }
  225. // Assume the target will be exported by another command.
  226. // Append it with the export namespace.
  227. link_libs += this->Namespace;
  228. link_libs += *li;
  229. }
  230. }
  231. }
  232. else
  233. {
  234. // Append the raw name.
  235. link_libs += *li;
  236. }
  237. }
  238. // Store the property.
  239. std::string prop = propName;
  240. prop += suffix;
  241. properties[prop] = link_libs;
  242. }
  243. //----------------------------------------------------------------------------
  244. std::vector<std::string> cmExportFileGenerator::FindNamespaces(cmMakefile* mf,
  245. const std::string& name)
  246. {
  247. std::vector<std::string> namespaces;
  248. cmGlobalGenerator* gg = mf->GetLocalGenerator()->GetGlobalGenerator();
  249. const cmExportSetMap& exportSets = gg->GetExportSets();
  250. for(cmExportSetMap::const_iterator expIt = exportSets.begin();
  251. expIt != exportSets.end();
  252. ++expIt)
  253. {
  254. const cmExportSet* exportSet = expIt->second;
  255. std::vector<cmTargetExport const*> const* targets =
  256. exportSet->GetTargetExports();
  257. bool containsTarget = false;
  258. for(unsigned int i=0; i<targets->size(); i++)
  259. {
  260. if (name == (*targets)[i]->Target->GetName())
  261. {
  262. containsTarget = true;
  263. break;
  264. }
  265. }
  266. if (containsTarget)
  267. {
  268. std::vector<cmInstallExportGenerator const*> const* installs =
  269. exportSet->GetInstallations();
  270. for(unsigned int i=0; i<installs->size(); i++)
  271. {
  272. namespaces.push_back((*installs)[i]->GetNamespace());
  273. }
  274. }
  275. }
  276. return namespaces;
  277. }
  278. //----------------------------------------------------------------------------
  279. void cmExportFileGenerator::GenerateImportHeaderCode(std::ostream& os,
  280. const char* config)
  281. {
  282. os << "#----------------------------------------------------------------\n"
  283. << "# Generated CMake target import file";
  284. if(config)
  285. {
  286. os << " for configuration \"" << config << "\".\n";
  287. }
  288. else
  289. {
  290. os << ".\n";
  291. }
  292. os << "#----------------------------------------------------------------\n"
  293. << "\n";
  294. this->GenerateImportVersionCode(os);
  295. }
  296. //----------------------------------------------------------------------------
  297. void cmExportFileGenerator::GenerateImportFooterCode(std::ostream& os)
  298. {
  299. os << "# Commands beyond this point should not need to know the version.\n"
  300. << "SET(CMAKE_IMPORT_FILE_VERSION)\n";
  301. }
  302. //----------------------------------------------------------------------------
  303. void cmExportFileGenerator::GenerateImportVersionCode(std::ostream& os)
  304. {
  305. // Store an import file format version. This will let us change the
  306. // format later while still allowing old import files to work.
  307. os << "# Commands may need to know the format version.\n"
  308. << "SET(CMAKE_IMPORT_FILE_VERSION 1)\n"
  309. << "\n";
  310. }
  311. //----------------------------------------------------------------------------
  312. void
  313. cmExportFileGenerator
  314. ::GenerateImportTargetCode(std::ostream& os, cmTarget* target)
  315. {
  316. // Construct the imported target name.
  317. std::string targetName = this->Namespace;
  318. targetName += target->GetName();
  319. // Create the imported target.
  320. os << "# Create imported target " << targetName << "\n";
  321. switch(target->GetType())
  322. {
  323. case cmTarget::EXECUTABLE:
  324. os << "ADD_EXECUTABLE(" << targetName << " IMPORTED)\n";
  325. break;
  326. case cmTarget::STATIC_LIBRARY:
  327. os << "ADD_LIBRARY(" << targetName << " STATIC IMPORTED)\n";
  328. break;
  329. case cmTarget::SHARED_LIBRARY:
  330. os << "ADD_LIBRARY(" << targetName << " SHARED IMPORTED)\n";
  331. break;
  332. case cmTarget::MODULE_LIBRARY:
  333. os << "ADD_LIBRARY(" << targetName << " MODULE IMPORTED)\n";
  334. break;
  335. default: // should never happen
  336. break;
  337. }
  338. // Mark the imported executable if it has exports.
  339. if(target->IsExecutableWithExports())
  340. {
  341. os << "SET_PROPERTY(TARGET " << targetName
  342. << " PROPERTY ENABLE_EXPORTS 1)\n";
  343. }
  344. // Mark the imported library if it is a framework.
  345. if(target->IsFrameworkOnApple())
  346. {
  347. os << "SET_PROPERTY(TARGET " << targetName
  348. << " PROPERTY FRAMEWORK 1)\n";
  349. }
  350. // Mark the imported executable if it is an application bundle.
  351. if(target->IsAppBundleOnApple())
  352. {
  353. os << "SET_PROPERTY(TARGET " << targetName
  354. << " PROPERTY MACOSX_BUNDLE 1)\n";
  355. }
  356. if (target->IsCFBundleOnApple())
  357. {
  358. os << "SET_PROPERTY(TARGET " << targetName
  359. << " PROPERTY BUNDLE 1)\n";
  360. }
  361. os << "\n";
  362. }
  363. //----------------------------------------------------------------------------
  364. void
  365. cmExportFileGenerator
  366. ::GenerateImportPropertyCode(std::ostream& os, const char* config,
  367. cmTarget* target,
  368. ImportPropertyMap const& properties)
  369. {
  370. // Construct the imported target name.
  371. std::string targetName = this->Namespace;
  372. targetName += target->GetName();
  373. // Set the import properties.
  374. os << "# Import target \"" << targetName << "\" for configuration \""
  375. << config << "\"\n";
  376. os << "SET_PROPERTY(TARGET " << targetName
  377. << " APPEND PROPERTY IMPORTED_CONFIGURATIONS ";
  378. if(config && *config)
  379. {
  380. os << cmSystemTools::UpperCase(config);
  381. }
  382. else
  383. {
  384. os << "NOCONFIG";
  385. }
  386. os << ")\n";
  387. os << "SET_TARGET_PROPERTIES(" << targetName << " PROPERTIES\n";
  388. for(ImportPropertyMap::const_iterator pi = properties.begin();
  389. pi != properties.end(); ++pi)
  390. {
  391. os << " " << pi->first << " \"" << pi->second << "\"\n";
  392. }
  393. os << " )\n"
  394. << "\n";
  395. }
  396. //----------------------------------------------------------------------------
  397. void
  398. cmExportFileGenerator::GenerateImportedFileCheckLoop(std::ostream& os)
  399. {
  400. // Add code which verifies at cmake time that the file which is being
  401. // imported actually exists on disk. This should in theory always be theory
  402. // case, but still when packages are split into normal and development
  403. // packages this might get broken (e.g. the Config.cmake could be part of
  404. // the non-development package, something similar happened to me without
  405. // on SUSE with a mysql pkg-config file, which claimed everything is fine,
  406. // but the development package was not installed.).
  407. os << "# Loop over all imported files and verify that they actually exist\n"
  408. "FOREACH(target ${_IMPORT_CHECK_TARGETS} )\n"
  409. " FOREACH(file ${_IMPORT_CHECK_FILES_FOR_${target}} )\n"
  410. " IF(NOT EXISTS \"${file}\" )\n"
  411. " MESSAGE(FATAL_ERROR \"The imported target \\\"${target}\\\""
  412. " references the file\n"
  413. " \\\"${file}\\\"\n"
  414. "but this file does not exist. Possible reasons include:\n"
  415. "* The file was deleted, renamed, or moved to another location.\n"
  416. "* An install or uninstall procedure did not complete successfully.\n"
  417. "* The installation package was faulty and contained\n"
  418. " \\\"${CMAKE_CURRENT_LIST_FILE}\\\"\n"
  419. "but not all the files it references.\n"
  420. "\")\n"
  421. " ENDIF()\n"
  422. " ENDFOREACH()\n"
  423. " UNSET(_IMPORT_CHECK_FILES_FOR_${target})\n"
  424. "ENDFOREACH()\n"
  425. "UNSET(_IMPORT_CHECK_TARGETS)\n"
  426. "\n";
  427. }
  428. //----------------------------------------------------------------------------
  429. void
  430. cmExportFileGenerator
  431. ::GenerateImportedFileChecksCode(std::ostream& os, cmTarget* target,
  432. ImportPropertyMap const& properties,
  433. const std::set<std::string>& importedLocations)
  434. {
  435. // Construct the imported target name.
  436. std::string targetName = this->Namespace;
  437. targetName += target->GetName();
  438. os << "LIST(APPEND _IMPORT_CHECK_TARGETS " << targetName << " )\n"
  439. "LIST(APPEND _IMPORT_CHECK_FILES_FOR_" << targetName << " ";
  440. for(std::set<std::string>::const_iterator li = importedLocations.begin();
  441. li != importedLocations.end();
  442. ++li)
  443. {
  444. ImportPropertyMap::const_iterator pi = properties.find(*li);
  445. if (pi != properties.end())
  446. {
  447. os << "\"" << pi->second << "\" ";
  448. }
  449. }
  450. os << ")\n\n";
  451. }