cmExportInstallFileGenerator.cxx 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564
  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 "cmExportInstallFileGenerator.h"
  11. #include "cmExportSet.h"
  12. #include "cmExportSetMap.h"
  13. #include "cmGeneratedFileStream.h"
  14. #include "cmGlobalGenerator.h"
  15. #include "cmLocalGenerator.h"
  16. #include "cmInstallExportGenerator.h"
  17. #include "cmInstallTargetGenerator.h"
  18. #include "cmTargetExport.h"
  19. #include "cmVersionMacros.h"
  20. #include "cmVersion.h"
  21. #define STRINGIFY_HELPER(X) #X
  22. #define STRINGIFY(X) STRINGIFY_HELPER(X)
  23. #define DEVEL_CMAKE_VERSION(maj, min, patch) \
  24. (CMake_VERSION_ENCODE(maj, min, patch) > \
  25. CMake_VERSION_ENCODE(CMake_VERSION_MAJOR, CMake_VERSION_MINOR, \
  26. CMake_VERSION_PATCH) \
  27. ) ? \
  28. STRINGIFY(CMake_VERSION_MAJOR) "." STRINGIFY(CMake_VERSION_MINOR) "." \
  29. STRINGIFY(CMake_VERSION_PATCH) "." STRINGIFY(CMake_VERSION_TWEAK) \
  30. : #maj "." #min "." #patch
  31. //----------------------------------------------------------------------------
  32. cmExportInstallFileGenerator
  33. ::cmExportInstallFileGenerator(cmInstallExportGenerator* iegen):
  34. IEGen(iegen)
  35. {
  36. }
  37. //----------------------------------------------------------------------------
  38. std::string cmExportInstallFileGenerator::GetConfigImportFileGlob()
  39. {
  40. std::string glob = this->FileBase;
  41. glob += "-*";
  42. glob += this->FileExt;
  43. return glob;
  44. }
  45. //----------------------------------------------------------------------------
  46. bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
  47. {
  48. std::vector<cmTargetExport*> allTargets;
  49. {
  50. std::string expectedTargets;
  51. std::string sep;
  52. for(std::vector<cmTargetExport*>::const_iterator
  53. tei = this->IEGen->GetExportSet()->GetTargetExports()->begin();
  54. tei != this->IEGen->GetExportSet()->GetTargetExports()->end(); ++tei)
  55. {
  56. expectedTargets += sep + this->Namespace + (*tei)->Target->GetExportName();
  57. sep = " ";
  58. cmTargetExport * te = *tei;
  59. if(this->ExportedTargets.insert(te->Target).second)
  60. {
  61. allTargets.push_back(te);
  62. }
  63. else
  64. {
  65. cmOStringStream e;
  66. e << "install(EXPORT \""
  67. << this->IEGen->GetExportSet()->GetName()
  68. << "\" ...) " << "includes target \"" << te->Target->GetName()
  69. << "\" more than once in the export set.";
  70. cmSystemTools::Error(e.str().c_str());
  71. return false;
  72. }
  73. }
  74. this->GenerateExpectedTargetsCode(os, expectedTargets);
  75. }
  76. // Add code to compute the installation prefix relative to the
  77. // import file location.
  78. const char* installDest = this->IEGen->GetDestination();
  79. if(!cmSystemTools::FileIsFullPath(installDest))
  80. {
  81. std::string installPrefix =
  82. this->IEGen->GetMakefile()->GetSafeDefinition("CMAKE_INSTALL_PREFIX");
  83. std::string absDest = installPrefix + "/" + installDest;
  84. std::string absDestS = absDest + "/";
  85. os << "# Compute the installation prefix relative to this file.\n"
  86. << "get_filename_component(_IMPORT_PREFIX"
  87. << " \"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n";
  88. if(cmHasLiteralPrefix(absDestS.c_str(), "/lib/") ||
  89. cmHasLiteralPrefix(absDestS.c_str(), "/lib64/") ||
  90. cmHasLiteralPrefix(absDestS.c_str(), "/usr/lib/") ||
  91. cmHasLiteralPrefix(absDestS.c_str(), "/usr/lib64/"))
  92. {
  93. // Handle "/usr move" symlinks created by some Linux distros.
  94. os <<
  95. "# Use original install prefix when loaded through a\n"
  96. "# cross-prefix symbolic link such as /lib -> /usr/lib.\n"
  97. "get_filename_component(_realCurr \"${_IMPORT_PREFIX}\" REALPATH)\n"
  98. "get_filename_component(_realOrig \"" << absDest << "\" REALPATH)\n"
  99. "if(_realCurr STREQUAL _realOrig)\n"
  100. " set(_IMPORT_PREFIX \"" << absDest << "\")\n"
  101. "endif()\n"
  102. "unset(_realOrig)\n"
  103. "unset(_realCurr)\n";
  104. }
  105. std::string dest = installDest;
  106. while(!dest.empty())
  107. {
  108. os <<
  109. "get_filename_component(_IMPORT_PREFIX \"${_IMPORT_PREFIX}\" PATH)\n";
  110. dest = cmSystemTools::GetFilenamePath(dest);
  111. }
  112. os << "\n";
  113. // Import location properties may reference this variable.
  114. this->ImportPrefix = "${_IMPORT_PREFIX}/";
  115. }
  116. std::vector<std::string> missingTargets;
  117. bool require2_8_12 = false;
  118. bool require3_0_0 = false;
  119. bool requiresConfigFiles = false;
  120. // Create all the imported targets.
  121. for(std::vector<cmTargetExport*>::const_iterator
  122. tei = allTargets.begin();
  123. tei != allTargets.end(); ++tei)
  124. {
  125. cmTarget* te = (*tei)->Target;
  126. requiresConfigFiles = requiresConfigFiles
  127. || te->GetType() != cmTarget::INTERFACE_LIBRARY;
  128. this->GenerateImportTargetCode(os, te);
  129. ImportPropertyMap properties;
  130. this->PopulateIncludeDirectoriesInterface(*tei,
  131. cmGeneratorExpression::InstallInterface,
  132. properties, missingTargets);
  133. this->PopulateInterfaceProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES",
  134. te,
  135. cmGeneratorExpression::InstallInterface,
  136. properties, missingTargets);
  137. this->PopulateInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS",
  138. te,
  139. cmGeneratorExpression::InstallInterface,
  140. properties, missingTargets);
  141. this->PopulateInterfaceProperty("INTERFACE_COMPILE_OPTIONS",
  142. te,
  143. cmGeneratorExpression::InstallInterface,
  144. properties, missingTargets);
  145. this->PopulateInterfaceProperty("INTERFACE_AUTOUIC_OPTIONS",
  146. te,
  147. cmGeneratorExpression::InstallInterface,
  148. properties, missingTargets);
  149. const bool newCMP0022Behavior =
  150. te->GetPolicyStatusCMP0022() != cmPolicies::WARN
  151. && te->GetPolicyStatusCMP0022() != cmPolicies::OLD;
  152. if (newCMP0022Behavior)
  153. {
  154. if (this->PopulateInterfaceLinkLibrariesProperty(te,
  155. cmGeneratorExpression::InstallInterface,
  156. properties, missingTargets)
  157. && !this->ExportOld)
  158. {
  159. require2_8_12 = true;
  160. }
  161. }
  162. if (te->GetType() == cmTarget::INTERFACE_LIBRARY)
  163. {
  164. require3_0_0 = true;
  165. }
  166. this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE",
  167. te, properties);
  168. this->PopulateCompatibleInterfaceProperties(te, properties);
  169. this->GenerateInterfaceProperties(te, os, properties);
  170. }
  171. if (require3_0_0)
  172. {
  173. this->GenerateRequiredCMakeVersion(os, DEVEL_CMAKE_VERSION(3, 0, 0));
  174. }
  175. else if (require2_8_12)
  176. {
  177. this->GenerateRequiredCMakeVersion(os, "2.8.12");
  178. }
  179. // Now load per-configuration properties for them.
  180. os << "# Load information for each installed configuration.\n"
  181. << "get_filename_component(_DIR \"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n"
  182. << "file(GLOB CONFIG_FILES \"${_DIR}/"
  183. << this->GetConfigImportFileGlob() << "\")\n"
  184. << "foreach(f ${CONFIG_FILES})\n"
  185. << " include(${f})\n"
  186. << "endforeach()\n"
  187. << "\n";
  188. // Cleanup the import prefix variable.
  189. if(!this->ImportPrefix.empty())
  190. {
  191. os << "# Cleanup temporary variables.\n"
  192. << "set(_IMPORT_PREFIX)\n"
  193. << "\n";
  194. }
  195. this->GenerateImportedFileCheckLoop(os);
  196. bool result = true;
  197. // Generate an import file for each configuration.
  198. // Don't do this if we only export INTERFACE_LIBRARY targets.
  199. if (requiresConfigFiles)
  200. {
  201. for(std::vector<std::string>::const_iterator
  202. ci = this->Configurations.begin();
  203. ci != this->Configurations.end(); ++ci)
  204. {
  205. if(!this->GenerateImportFileConfig(ci->c_str(), missingTargets))
  206. {
  207. result = false;
  208. }
  209. }
  210. }
  211. this->GenerateMissingTargetsCheckCode(os, missingTargets);
  212. return result;
  213. }
  214. //----------------------------------------------------------------------------
  215. void
  216. cmExportInstallFileGenerator::ReplaceInstallPrefix(std::string &input)
  217. {
  218. std::string::size_type pos = 0;
  219. std::string::size_type lastPos = pos;
  220. while((pos = input.find("$<INSTALL_PREFIX>", lastPos)) != input.npos)
  221. {
  222. std::string::size_type endPos = pos + sizeof("$<INSTALL_PREFIX>") - 1;
  223. input.replace(pos, endPos - pos, "${_IMPORT_PREFIX}");
  224. lastPos = endPos;
  225. }
  226. }
  227. //----------------------------------------------------------------------------
  228. bool
  229. cmExportInstallFileGenerator::GenerateImportFileConfig(const char* config,
  230. std::vector<std::string> &missingTargets)
  231. {
  232. // Skip configurations not enabled for this export.
  233. if(!this->IEGen->InstallsForConfig(config))
  234. {
  235. return true;
  236. }
  237. // Construct the name of the file to generate.
  238. std::string fileName = this->FileDir;
  239. fileName += "/";
  240. fileName += this->FileBase;
  241. fileName += "-";
  242. if(config && *config)
  243. {
  244. fileName += cmSystemTools::LowerCase(config);
  245. }
  246. else
  247. {
  248. fileName += "noconfig";
  249. }
  250. fileName += this->FileExt;
  251. // Open the output file to generate it.
  252. cmGeneratedFileStream exportFileStream(fileName.c_str(), true);
  253. if(!exportFileStream)
  254. {
  255. std::string se = cmSystemTools::GetLastSystemError();
  256. cmOStringStream e;
  257. e << "cannot write to file \"" << fileName.c_str()
  258. << "\": " << se;
  259. cmSystemTools::Error(e.str().c_str());
  260. return false;
  261. }
  262. std::ostream& os = exportFileStream;
  263. // Start with the import file header.
  264. this->GenerateImportHeaderCode(os, config);
  265. // Generate the per-config target information.
  266. this->GenerateImportConfig(os, config, missingTargets);
  267. // End with the import file footer.
  268. this->GenerateImportFooterCode(os);
  269. // Record this per-config import file.
  270. this->ConfigImportFiles[config] = fileName;
  271. return true;
  272. }
  273. //----------------------------------------------------------------------------
  274. void
  275. cmExportInstallFileGenerator
  276. ::GenerateImportTargetsConfig(std::ostream& os,
  277. const char* config, std::string const& suffix,
  278. std::vector<std::string> &missingTargets)
  279. {
  280. // Add each target in the set to the export.
  281. for(std::vector<cmTargetExport*>::const_iterator
  282. tei = this->IEGen->GetExportSet()->GetTargetExports()->begin();
  283. tei != this->IEGen->GetExportSet()->GetTargetExports()->end(); ++tei)
  284. {
  285. // Collect import properties for this target.
  286. cmTargetExport const* te = *tei;
  287. if (te->Target->GetType() == cmTarget::INTERFACE_LIBRARY)
  288. {
  289. continue;
  290. }
  291. ImportPropertyMap properties;
  292. std::set<std::string> importedLocations;
  293. this->SetImportLocationProperty(config, suffix, te->ArchiveGenerator,
  294. properties, importedLocations);
  295. this->SetImportLocationProperty(config, suffix, te->LibraryGenerator,
  296. properties, importedLocations);
  297. this->SetImportLocationProperty(config, suffix,
  298. te->RuntimeGenerator, properties,
  299. importedLocations);
  300. this->SetImportLocationProperty(config, suffix, te->FrameworkGenerator,
  301. properties, importedLocations);
  302. this->SetImportLocationProperty(config, suffix, te->BundleGenerator,
  303. properties, importedLocations);
  304. // If any file location was set for the target add it to the
  305. // import file.
  306. if(!properties.empty())
  307. {
  308. // Get the rest of the target details.
  309. this->SetImportDetailProperties(config, suffix,
  310. te->Target, properties, missingTargets);
  311. this->SetImportLinkInterface(config, suffix,
  312. cmGeneratorExpression::InstallInterface,
  313. te->Target, properties, missingTargets);
  314. // TOOD: PUBLIC_HEADER_LOCATION
  315. // This should wait until the build feature propagation stuff
  316. // is done. Then this can be a propagated include directory.
  317. // this->GenerateImportProperty(config, te->HeaderGenerator,
  318. // properties);
  319. // Generate code in the export file.
  320. this->GenerateImportPropertyCode(os, config, te->Target, properties);
  321. this->GenerateImportedFileChecksCode(os, te->Target, properties,
  322. importedLocations);
  323. }
  324. }
  325. }
  326. //----------------------------------------------------------------------------
  327. void
  328. cmExportInstallFileGenerator
  329. ::SetImportLocationProperty(const char* config, std::string const& suffix,
  330. cmInstallTargetGenerator* itgen,
  331. ImportPropertyMap& properties,
  332. std::set<std::string>& importedLocations
  333. )
  334. {
  335. // Skip rules that do not match this configuration.
  336. if(!(itgen && itgen->InstallsForConfig(config)))
  337. {
  338. return;
  339. }
  340. // Get the target to be installed.
  341. cmTarget* target = itgen->GetTarget();
  342. // Construct the installed location of the target.
  343. std::string dest = itgen->GetDestination();
  344. std::string value;
  345. if(!cmSystemTools::FileIsFullPath(dest.c_str()))
  346. {
  347. // The target is installed relative to the installation prefix.
  348. if(this->ImportPrefix.empty())
  349. {
  350. this->ComplainAboutImportPrefix(itgen);
  351. }
  352. value = this->ImportPrefix;
  353. }
  354. value += dest;
  355. value += "/";
  356. if(itgen->IsImportLibrary())
  357. {
  358. // Construct the property name.
  359. std::string prop = "IMPORTED_IMPLIB";
  360. prop += suffix;
  361. // Append the installed file name.
  362. value += itgen->GetInstallFilename(target, config,
  363. cmInstallTargetGenerator::NameImplib);
  364. // Store the property.
  365. properties[prop] = value;
  366. importedLocations.insert(prop);
  367. }
  368. else
  369. {
  370. // Construct the property name.
  371. std::string prop = "IMPORTED_LOCATION";
  372. prop += suffix;
  373. // Append the installed file name.
  374. if(target->IsAppBundleOnApple())
  375. {
  376. value += itgen->GetInstallFilename(target, config);
  377. value += ".app/Contents/MacOS/";
  378. value += itgen->GetInstallFilename(target, config);
  379. }
  380. else
  381. {
  382. value += itgen->GetInstallFilename(target, config,
  383. cmInstallTargetGenerator::NameReal);
  384. }
  385. // Store the property.
  386. properties[prop] = value;
  387. importedLocations.insert(prop);
  388. }
  389. }
  390. //----------------------------------------------------------------------------
  391. void
  392. cmExportInstallFileGenerator::HandleMissingTarget(
  393. std::string& link_libs, std::vector<std::string>& missingTargets,
  394. cmMakefile* mf, cmTarget* depender, cmTarget* dependee)
  395. {
  396. const std::string name = dependee->GetName();
  397. std::vector<std::string> namespaces = this->FindNamespaces(mf, name);
  398. int targetOccurrences = (int)namespaces.size();
  399. if (targetOccurrences == 1)
  400. {
  401. std::string missingTarget = namespaces[0];
  402. missingTarget += dependee->GetExportName();
  403. link_libs += missingTarget;
  404. missingTargets.push_back(missingTarget);
  405. }
  406. else
  407. {
  408. // All exported targets should be known here and should be unique.
  409. // This is probably user-error.
  410. this->ComplainAboutMissingTarget(depender, dependee, targetOccurrences);
  411. }
  412. }
  413. //----------------------------------------------------------------------------
  414. std::vector<std::string>
  415. cmExportInstallFileGenerator
  416. ::FindNamespaces(cmMakefile* mf, const std::string& name)
  417. {
  418. std::vector<std::string> namespaces;
  419. cmGlobalGenerator* gg = mf->GetLocalGenerator()->GetGlobalGenerator();
  420. const cmExportSetMap& exportSets = gg->GetExportSets();
  421. for(cmExportSetMap::const_iterator expIt = exportSets.begin();
  422. expIt != exportSets.end();
  423. ++expIt)
  424. {
  425. const cmExportSet* exportSet = expIt->second;
  426. std::vector<cmTargetExport*> const* targets =
  427. exportSet->GetTargetExports();
  428. bool containsTarget = false;
  429. for(unsigned int i=0; i<targets->size(); i++)
  430. {
  431. if (name == (*targets)[i]->Target->GetName())
  432. {
  433. containsTarget = true;
  434. break;
  435. }
  436. }
  437. if (containsTarget)
  438. {
  439. std::vector<cmInstallExportGenerator const*> const* installs =
  440. exportSet->GetInstallations();
  441. for(unsigned int i=0; i<installs->size(); i++)
  442. {
  443. namespaces.push_back((*installs)[i]->GetNamespace());
  444. }
  445. }
  446. }
  447. return namespaces;
  448. }
  449. //----------------------------------------------------------------------------
  450. void
  451. cmExportInstallFileGenerator
  452. ::ComplainAboutImportPrefix(cmInstallTargetGenerator* itgen)
  453. {
  454. const char* installDest = this->IEGen->GetDestination();
  455. cmOStringStream e;
  456. e << "install(EXPORT \""
  457. << this->IEGen->GetExportSet()->GetName()
  458. << "\") given absolute "
  459. << "DESTINATION \"" << installDest << "\" but the export "
  460. << "references an installation of target \""
  461. << itgen->GetTarget()->GetName() << "\" which has relative "
  462. << "DESTINATION \"" << itgen->GetDestination() << "\".";
  463. cmSystemTools::Error(e.str().c_str());
  464. }
  465. //----------------------------------------------------------------------------
  466. void
  467. cmExportInstallFileGenerator
  468. ::ComplainAboutMissingTarget(cmTarget* depender,
  469. cmTarget* dependee,
  470. int occurrences)
  471. {
  472. cmOStringStream e;
  473. e << "install(EXPORT \""
  474. << this->IEGen->GetExportSet()->GetName()
  475. << "\" ...) "
  476. << "includes target \"" << depender->GetName()
  477. << "\" which requires target \"" << dependee->GetName() << "\" ";
  478. if (occurrences == 0)
  479. {
  480. e << "that is not in the export set.";
  481. }
  482. else
  483. {
  484. e << "that is not in this export set, but " << occurrences
  485. << " times in others.";
  486. }
  487. cmSystemTools::Error(e.str().c_str());
  488. }
  489. std::string
  490. cmExportInstallFileGenerator::InstallNameDir(cmTarget* target,
  491. const std::string&)
  492. {
  493. std::string install_name_dir;
  494. cmMakefile* mf = target->GetMakefile();
  495. if(mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME"))
  496. {
  497. install_name_dir =
  498. target->GetInstallNameDirForInstallTree();
  499. }
  500. return install_name_dir;
  501. }