cmInstallTargetGenerator.cxx 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  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 "cmInstallTargetGenerator.h"
  14. #include "cmComputeLinkInformation.h"
  15. #include "cmGlobalGenerator.h"
  16. #include "cmLocalGenerator.h"
  17. #include "cmMakefile.h"
  18. #include "cmake.h"
  19. // TODO:
  20. // - Skip IF(EXISTS) checks if nothing is done with the installed file
  21. //----------------------------------------------------------------------------
  22. cmInstallTargetGenerator
  23. ::cmInstallTargetGenerator(cmTarget& t, const char* dest, bool implib,
  24. const char* file_permissions,
  25. std::vector<std::string> const& configurations,
  26. const char* component, bool optional):
  27. cmInstallGenerator(dest, configurations, component), Target(&t),
  28. ImportLibrary(implib), FilePermissions(file_permissions), Optional(optional)
  29. {
  30. this->Target->SetHaveInstallRule(true);
  31. }
  32. //----------------------------------------------------------------------------
  33. cmInstallTargetGenerator
  34. ::~cmInstallTargetGenerator()
  35. {
  36. }
  37. //----------------------------------------------------------------------------
  38. void cmInstallTargetGenerator::GenerateScript(std::ostream& os)
  39. {
  40. // Warn if installing an exclude-from-all target.
  41. if(this->Target->GetPropertyAsBool("EXCLUDE_FROM_ALL"))
  42. {
  43. cmOStringStream msg;
  44. msg << "WARNING: Target \"" << this->Target->GetName()
  45. << "\" has EXCLUDE_FROM_ALL set and will not be built by default "
  46. << "but an install rule has been provided for it. CMake does "
  47. << "not define behavior for this case.";
  48. cmSystemTools::Message(msg.str().c_str(), "Warning");
  49. }
  50. // Track indentation.
  51. Indent indent;
  52. // Begin this block of installation.
  53. std::string component_test =
  54. this->CreateComponentTest(this->Component.c_str());
  55. os << indent << "IF(" << component_test << ")\n";
  56. // Compute the build tree directory from which to copy the target.
  57. std::string fromDir;
  58. if(this->Target->NeedRelinkBeforeInstall())
  59. {
  60. fromDir = this->Target->GetMakefile()->GetStartOutputDirectory();
  61. fromDir += cmake::GetCMakeFilesDirectory();
  62. fromDir += "/CMakeRelink.dir/";
  63. }
  64. else
  65. {
  66. fromDir = this->Target->GetDirectory(0, this->ImportLibrary);
  67. fromDir += "/";
  68. }
  69. // Generate a portion of the script for each configuration.
  70. if(this->ConfigurationTypes->empty())
  71. {
  72. this->GenerateScriptForConfig(os, fromDir.c_str(),
  73. this->ConfigurationName,
  74. indent.Next());
  75. }
  76. else
  77. {
  78. for(std::vector<std::string>::const_iterator i =
  79. this->ConfigurationTypes->begin();
  80. i != this->ConfigurationTypes->end(); ++i)
  81. {
  82. this->GenerateScriptForConfig(os, fromDir.c_str(), i->c_str(),
  83. indent.Next());
  84. }
  85. }
  86. // End this block of installation.
  87. os << indent << "ENDIF(" << component_test << ")\n\n";
  88. }
  89. //----------------------------------------------------------------------------
  90. void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os,
  91. const char* fromDir,
  92. const char* config,
  93. Indent const& indent)
  94. {
  95. // Compute the per-configuration directory containing the files.
  96. std::string fromDirConfig = fromDir;
  97. this->Target->GetMakefile()->GetLocalGenerator()->GetGlobalGenerator()
  98. ->AppendDirectoryForConfig("", config, "/", fromDirConfig);
  99. if(config && *config)
  100. {
  101. // Skip this configuration for config-specific installation that
  102. // does not match it.
  103. if(!this->InstallsForConfig(config))
  104. {
  105. return;
  106. }
  107. // Generate a per-configuration block.
  108. std::string config_test = this->CreateConfigTest(config);
  109. os << indent << "IF(" << config_test << ")\n";
  110. this->GenerateScriptForConfigDir(os, fromDirConfig.c_str(), config,
  111. indent.Next());
  112. os << indent << "ENDIF(" << config_test << ")\n";
  113. }
  114. else
  115. {
  116. this->GenerateScriptForConfigDir(os, fromDirConfig.c_str(), config,
  117. indent);
  118. }
  119. }
  120. //----------------------------------------------------------------------------
  121. void
  122. cmInstallTargetGenerator
  123. ::GenerateScriptForConfigDir(std::ostream& os,
  124. const char* fromDirConfig,
  125. const char* config,
  126. Indent const& indent)
  127. {
  128. // Compute the full path to the main installed file for this target.
  129. std::string toInstallPath = this->GetInstallDestination();
  130. toInstallPath += "/";
  131. toInstallPath += this->GetInstallFilename(this->Target, config,
  132. this->ImportLibrary, false);
  133. // Compute the list of files to install for this target.
  134. std::vector<std::string> files;
  135. std::string literal_args;
  136. cmTarget::TargetType type = this->Target->GetType();
  137. if(type == cmTarget::EXECUTABLE)
  138. {
  139. std::string targetName;
  140. std::string targetNameReal;
  141. std::string targetNameImport;
  142. std::string targetNamePDB;
  143. this->Target->GetExecutableNames(targetName, targetNameReal,
  144. targetNameImport, targetNamePDB,
  145. config);
  146. if(this->ImportLibrary)
  147. {
  148. std::string from1 = fromDirConfig;
  149. from1 += targetNameImport;
  150. files.push_back(from1);
  151. // An import library looks like a static library.
  152. type = cmTarget::STATIC_LIBRARY;
  153. }
  154. else
  155. {
  156. std::string from1 = fromDirConfig;
  157. from1 += targetName;
  158. // Handle OSX Bundles.
  159. if(this->Target->IsAppBundleOnApple())
  160. {
  161. // Compute the source locations of the bundle executable and
  162. // Info.plist file.
  163. from1 += ".app";
  164. files.push_back(from1);
  165. type = cmTarget::INSTALL_DIRECTORY;
  166. // Need to apply install_name_tool and stripping to binary
  167. // inside bundle.
  168. toInstallPath += ".app/Contents/MacOS/";
  169. toInstallPath += this->GetInstallFilename(this->Target, config,
  170. this->ImportLibrary, false);
  171. literal_args += " USE_SOURCE_PERMISSIONS";
  172. }
  173. else
  174. {
  175. files.push_back(from1);
  176. if(targetNameReal != targetName)
  177. {
  178. std::string from2 = fromDirConfig;
  179. from2 += targetNameReal;
  180. files.push_back(from2);
  181. }
  182. }
  183. }
  184. }
  185. else
  186. {
  187. std::string targetName;
  188. std::string targetNameSO;
  189. std::string targetNameReal;
  190. std::string targetNameImport;
  191. std::string targetNamePDB;
  192. this->Target->GetLibraryNames(targetName, targetNameSO, targetNameReal,
  193. targetNameImport, targetNamePDB,
  194. config);
  195. if(this->ImportLibrary)
  196. {
  197. std::string from1 = fromDirConfig;
  198. from1 += targetNameImport;
  199. files.push_back(from1);
  200. // An import library looks like a static library.
  201. type = cmTarget::STATIC_LIBRARY;
  202. }
  203. else if(this->Target->IsFrameworkOnApple())
  204. {
  205. // Compute the build tree location of the framework directory
  206. std::string from1 = fromDirConfig;
  207. // Remove trailing slashes... so that from1 ends with ".framework":
  208. //
  209. cmSystemTools::ConvertToUnixSlashes(from1);
  210. files.push_back(from1);
  211. type = cmTarget::INSTALL_DIRECTORY;
  212. // Need to apply install_name_tool and stripping to binary
  213. // inside framework.
  214. toInstallPath += ".framework/";
  215. toInstallPath += this->GetInstallFilename(this->Target, config,
  216. this->ImportLibrary, false);
  217. literal_args += " USE_SOURCE_PERMISSIONS";
  218. }
  219. else
  220. {
  221. std::string from1 = fromDirConfig;
  222. from1 += targetName;
  223. files.push_back(from1);
  224. if(targetNameSO != targetName)
  225. {
  226. std::string from2 = fromDirConfig;
  227. from2 += targetNameSO;
  228. files.push_back(from2);
  229. }
  230. if(targetNameReal != targetName &&
  231. targetNameReal != targetNameSO)
  232. {
  233. std::string from3 = fromDirConfig;
  234. from3 += targetNameReal;
  235. files.push_back(from3);
  236. }
  237. }
  238. }
  239. // Write code to install the target file.
  240. const char* no_dir_permissions = 0;
  241. const char* no_rename = 0;
  242. const char* no_properties = 0;
  243. bool optional = this->Optional || this->ImportLibrary;
  244. this->AddInstallRule(os, type, files,
  245. optional, no_properties,
  246. this->FilePermissions.c_str(), no_dir_permissions,
  247. no_rename, literal_args.c_str(),
  248. indent);
  249. std::string toDestDirPath = "$ENV{DESTDIR}";
  250. if(toInstallPath[0] != '/')
  251. {
  252. toDestDirPath += "/";
  253. }
  254. toDestDirPath += toInstallPath;
  255. this->Target->SetInstallNameFixupPath(toInstallPath.c_str());
  256. os << indent << "IF(EXISTS \"" << toDestDirPath << "\")\n";
  257. this->AddInstallNamePatchRule(os, indent.Next(), config, toDestDirPath);
  258. this->AddChrpathPatchRule(os, indent.Next(), config, toDestDirPath);
  259. this->AddRanlibRule(os, indent.Next(), type, toDestDirPath);
  260. this->AddStripRule(os, indent.Next(), type, toDestDirPath);
  261. os << indent << "ENDIF(EXISTS \"" << toDestDirPath << "\")\n";
  262. }
  263. //----------------------------------------------------------------------------
  264. std::string
  265. cmInstallTargetGenerator::GetInstallFilename(const char* config) const
  266. {
  267. return
  268. cmInstallTargetGenerator::GetInstallFilename(this->Target, config,
  269. this->ImportLibrary, false);
  270. }
  271. //----------------------------------------------------------------------------
  272. std::string cmInstallTargetGenerator::GetInstallFilename(cmTarget* target,
  273. const char* config,
  274. bool implib,
  275. bool useSOName)
  276. {
  277. std::string fname;
  278. // Compute the name of the library.
  279. if(target->GetType() == cmTarget::EXECUTABLE)
  280. {
  281. std::string targetName;
  282. std::string targetNameReal;
  283. std::string targetNameImport;
  284. std::string targetNamePDB;
  285. target->GetExecutableNames(targetName, targetNameReal,
  286. targetNameImport, targetNamePDB,
  287. config);
  288. if(implib)
  289. {
  290. // Use the import library name.
  291. fname = targetNameImport;
  292. }
  293. else
  294. {
  295. // Use the canonical name.
  296. fname = targetName;
  297. }
  298. }
  299. else
  300. {
  301. std::string targetName;
  302. std::string targetNameSO;
  303. std::string targetNameReal;
  304. std::string targetNameImport;
  305. std::string targetNamePDB;
  306. target->GetLibraryNames(targetName, targetNameSO, targetNameReal,
  307. targetNameImport, targetNamePDB, config);
  308. if(implib)
  309. {
  310. // Use the import library name.
  311. fname = targetNameImport;
  312. }
  313. else if(useSOName)
  314. {
  315. // Use the soname.
  316. fname = targetNameSO;
  317. }
  318. else
  319. {
  320. // Use the canonical name.
  321. fname = targetName;
  322. }
  323. }
  324. return fname;
  325. }
  326. //----------------------------------------------------------------------------
  327. void
  328. cmInstallTargetGenerator
  329. ::AddInstallNamePatchRule(std::ostream& os, Indent const& indent,
  330. const char* config, std::string const& toDestDirPath)
  331. {
  332. if(this->ImportLibrary ||
  333. !(this->Target->GetType() == cmTarget::SHARED_LIBRARY ||
  334. this->Target->GetType() == cmTarget::MODULE_LIBRARY ||
  335. this->Target->GetType() == cmTarget::EXECUTABLE))
  336. {
  337. return;
  338. }
  339. // Fix the install_name settings in installed binaries.
  340. std::string installNameTool =
  341. this->Target->GetMakefile()->GetSafeDefinition("CMAKE_INSTALL_NAME_TOOL");
  342. if(!installNameTool.size())
  343. {
  344. return;
  345. }
  346. // Build a map of build-tree install_name to install-tree install_name for
  347. // shared libraries linked to this target.
  348. std::map<cmStdString, cmStdString> install_name_remap;
  349. cmTarget::LinkLibraryType linkType = cmTarget::OPTIMIZED;
  350. if(config && cmSystemTools::UpperCase(config) == "DEBUG")
  351. {
  352. linkType = cmTarget::DEBUG;
  353. }
  354. // TODO: Merge with ComputeLinkInformation.
  355. const cmTarget::LinkLibraryVectorType& inLibs =
  356. this->Target->GetLinkLibraries();
  357. for(cmTarget::LinkLibraryVectorType::const_iterator j = inLibs.begin();
  358. j != inLibs.end(); ++j)
  359. {
  360. std::string lib = j->first;
  361. if((this->Target->GetType() == cmTarget::EXECUTABLE ||
  362. lib != this->Target->GetName()) &&
  363. (j->second == cmTarget::GENERAL || j->second == linkType))
  364. {
  365. if(cmTarget* tgt = this->Target->GetMakefile()->
  366. GetLocalGenerator()->GetGlobalGenerator()->
  367. FindTarget(0, lib.c_str()))
  368. {
  369. if(tgt->GetType() == cmTarget::SHARED_LIBRARY)
  370. {
  371. // If the build tree and install tree use different path
  372. // components of the install_name field then we need to create a
  373. // mapping to be applied after installation.
  374. std::string for_build = tgt->GetInstallNameDirForBuildTree(config);
  375. std::string for_install =
  376. tgt->GetInstallNameDirForInstallTree(config);
  377. std::string fname =
  378. this->GetInstallFilename(tgt, config, false, true);
  379. // Map from the build-tree install_name.
  380. for_build += fname;
  381. // Map to the install-tree install_name.
  382. if (!for_install.empty())
  383. {
  384. for_install += fname;
  385. }
  386. else
  387. {
  388. for_install = tgt->GetInstallNameFixupPath();
  389. }
  390. if(for_build != for_install)
  391. {
  392. // Store the mapping entry.
  393. install_name_remap[for_build] = for_install;
  394. }
  395. }
  396. }
  397. }
  398. }
  399. // Edit the install_name of the target itself if necessary.
  400. std::string new_id;
  401. if(this->Target->GetType() == cmTarget::SHARED_LIBRARY)
  402. {
  403. std::string for_build =
  404. this->Target->GetInstallNameDirForBuildTree(config);
  405. std::string for_install =
  406. this->Target->GetInstallNameDirForInstallTree(config);
  407. std::string fname =
  408. this->GetInstallFilename(this->Target, config, this->ImportLibrary,
  409. true);
  410. for_build += fname;
  411. if (!for_install.empty())
  412. {
  413. for_install += fname;
  414. }
  415. else
  416. {
  417. for_install = this->Target->GetInstallNameFixupPath();
  418. }
  419. if(for_build != for_install)
  420. {
  421. // Prepare to refer to the install-tree install_name.
  422. new_id = for_install;
  423. }
  424. }
  425. // Write a rule to run install_name_tool to set the install-tree
  426. // install_name value and references.
  427. if(!new_id.empty() || !install_name_remap.empty())
  428. {
  429. os << indent << "EXECUTE_PROCESS(COMMAND \"" << installNameTool;
  430. os << "\"";
  431. if(!new_id.empty())
  432. {
  433. os << "\n" << indent << " -id \"" << new_id << "\"";
  434. }
  435. for(std::map<cmStdString, cmStdString>::const_iterator
  436. i = install_name_remap.begin();
  437. i != install_name_remap.end(); ++i)
  438. {
  439. os << "\n" << indent << " -change \""
  440. << i->first << "\" \"" << i->second << "\"";
  441. }
  442. os << "\n" << indent << " \"" << toDestDirPath << "\")\n";
  443. }
  444. }
  445. //----------------------------------------------------------------------------
  446. void
  447. cmInstallTargetGenerator
  448. ::AddChrpathPatchRule(std::ostream& os, Indent const& indent,
  449. const char* config, std::string const& toDestDirPath)
  450. {
  451. if(this->ImportLibrary ||
  452. !(this->Target->GetType() == cmTarget::SHARED_LIBRARY ||
  453. this->Target->GetType() == cmTarget::MODULE_LIBRARY ||
  454. this->Target->GetType() == cmTarget::EXECUTABLE))
  455. {
  456. return;
  457. }
  458. if(!this->Target->IsChrpathUsed())
  459. {
  460. return;
  461. }
  462. // Get the link information for this target.
  463. // It can provide the RPATH.
  464. cmComputeLinkInformation* cli = this->Target->GetLinkInformation(config);
  465. if(!cli)
  466. {
  467. return;
  468. }
  469. // Get the install RPATH from the link information.
  470. std::string newRpath = cli->GetChrpathString();
  471. // Fix the RPATH in installed ELF binaries using chrpath.
  472. std::string chrpathTool = cli->GetChrpathTool();
  473. // Write a rule to run chrpath to set the install-tree RPATH
  474. os << indent << "EXECUTE_PROCESS(COMMAND \"" << chrpathTool;
  475. os << "\" -r \"" << newRpath << "\" \"" << toDestDirPath << "\")\n";
  476. }
  477. //----------------------------------------------------------------------------
  478. void
  479. cmInstallTargetGenerator::AddStripRule(std::ostream& os,
  480. Indent const& indent,
  481. cmTarget::TargetType type,
  482. const std::string& toDestDirPath)
  483. {
  484. // don't strip static libraries, because it removes the only symbol table
  485. // they have so you can't link to them anymore
  486. if(type == cmTarget::STATIC_LIBRARY)
  487. {
  488. return;
  489. }
  490. // Don't handle OSX Bundles.
  491. if(this->Target->GetMakefile()->IsOn("APPLE") &&
  492. this->Target->GetPropertyAsBool("MACOSX_BUNDLE"))
  493. {
  494. return;
  495. }
  496. if(! this->Target->GetMakefile()->IsSet("CMAKE_STRIP"))
  497. {
  498. return;
  499. }
  500. os << indent << "IF(CMAKE_INSTALL_DO_STRIP)\n";
  501. os << indent << " EXECUTE_PROCESS(COMMAND \""
  502. << this->Target->GetMakefile()->GetDefinition("CMAKE_STRIP")
  503. << "\" \"" << toDestDirPath << "\")\n";
  504. os << indent << "ENDIF(CMAKE_INSTALL_DO_STRIP)\n";
  505. }
  506. //----------------------------------------------------------------------------
  507. void
  508. cmInstallTargetGenerator::AddRanlibRule(std::ostream& os,
  509. Indent const& indent,
  510. cmTarget::TargetType type,
  511. const std::string& toDestDirPath)
  512. {
  513. // Static libraries need ranlib on this platform.
  514. if(type != cmTarget::STATIC_LIBRARY)
  515. {
  516. return;
  517. }
  518. // Perform post-installation processing on the file depending
  519. // on its type.
  520. if(!this->Target->GetMakefile()->IsOn("APPLE"))
  521. {
  522. return;
  523. }
  524. std::string ranlib =
  525. this->Target->GetMakefile()->GetRequiredDefinition("CMAKE_RANLIB");
  526. if(ranlib.empty())
  527. {
  528. return;
  529. }
  530. os << indent << "EXECUTE_PROCESS(COMMAND \""
  531. << ranlib << "\" \"" << toDestDirPath << "\")\n";
  532. }