cmInstallTargetGenerator.cxx 18 KB

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