cmInstallTargetGenerator.cxx 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #include "cmInstallTargetGenerator.h"
  4. #include <cassert>
  5. #include <map>
  6. #include <set>
  7. #include <sstream>
  8. #include <utility>
  9. #include "cmComputeLinkInformation.h"
  10. #include "cmGeneratorExpression.h"
  11. #include "cmGeneratorTarget.h"
  12. #include "cmGlobalGenerator.h"
  13. #include "cmInstallType.h"
  14. #include "cmLocalGenerator.h"
  15. #include "cmMakefile.h"
  16. #include "cmMessageType.h"
  17. #include "cmOutputConverter.h"
  18. #include "cmPolicies.h"
  19. #include "cmStateTypes.h"
  20. #include "cmStringAlgorithms.h"
  21. #include "cmSystemTools.h"
  22. #include "cmTarget.h"
  23. #include "cmake.h"
  24. cmInstallTargetGenerator::cmInstallTargetGenerator(
  25. std::string targetName, const char* dest, bool implib,
  26. const char* file_permissions, std::vector<std::string> const& configurations,
  27. const char* component, MessageLevel message, bool exclude_from_all,
  28. bool optional, cmListFileBacktrace backtrace)
  29. : cmInstallGenerator(dest, configurations, component, message,
  30. exclude_from_all)
  31. , TargetName(std::move(targetName))
  32. , Target(nullptr)
  33. , FilePermissions(file_permissions)
  34. , ImportLibrary(implib)
  35. , Optional(optional)
  36. , Backtrace(std::move(backtrace))
  37. {
  38. this->ActionsPerConfig = true;
  39. this->NamelinkMode = NamelinkModeNone;
  40. }
  41. cmInstallTargetGenerator::~cmInstallTargetGenerator() = default;
  42. void cmInstallTargetGenerator::GenerateScriptForConfig(
  43. std::ostream& os, const std::string& config, Indent indent)
  44. {
  45. cmStateEnums::TargetType targetType = this->Target->GetType();
  46. cmInstallType type = cmInstallType();
  47. switch (targetType) {
  48. case cmStateEnums::EXECUTABLE:
  49. type = cmInstallType_EXECUTABLE;
  50. break;
  51. case cmStateEnums::STATIC_LIBRARY:
  52. type = cmInstallType_STATIC_LIBRARY;
  53. break;
  54. case cmStateEnums::SHARED_LIBRARY:
  55. type = cmInstallType_SHARED_LIBRARY;
  56. break;
  57. case cmStateEnums::MODULE_LIBRARY:
  58. type = cmInstallType_MODULE_LIBRARY;
  59. break;
  60. case cmStateEnums::INTERFACE_LIBRARY:
  61. // Not reachable. We never create a cmInstallTargetGenerator for
  62. // an INTERFACE_LIBRARY.
  63. assert(false &&
  64. "INTERFACE_LIBRARY targets have no installable outputs.");
  65. break;
  66. case cmStateEnums::OBJECT_LIBRARY:
  67. this->GenerateScriptForConfigObjectLibrary(os, config, indent);
  68. return;
  69. case cmStateEnums::UTILITY:
  70. case cmStateEnums::GLOBAL_TARGET:
  71. case cmStateEnums::UNKNOWN_LIBRARY:
  72. this->Target->GetLocalGenerator()->IssueMessage(
  73. MessageType::INTERNAL_ERROR,
  74. "cmInstallTargetGenerator created with non-installable target.");
  75. return;
  76. }
  77. // Compute the build tree directory from which to copy the target.
  78. std::string fromDirConfig;
  79. if (this->Target->NeedRelinkBeforeInstall(config)) {
  80. fromDirConfig =
  81. cmStrCat(this->Target->GetLocalGenerator()->GetCurrentBinaryDirectory(),
  82. "/CMakeFiles/CMakeRelink.dir/");
  83. } else {
  84. cmStateEnums::ArtifactType artifact = this->ImportLibrary
  85. ? cmStateEnums::ImportLibraryArtifact
  86. : cmStateEnums::RuntimeBinaryArtifact;
  87. fromDirConfig =
  88. cmStrCat(this->Target->GetDirectory(config, artifact), '/');
  89. }
  90. std::string toDir = cmStrCat(
  91. this->ConvertToAbsoluteDestination(this->GetDestination(config)), '/');
  92. // Compute the list of files to install for this target.
  93. std::vector<std::string> filesFrom;
  94. std::vector<std::string> filesTo;
  95. std::string literal_args;
  96. if (targetType == cmStateEnums::EXECUTABLE) {
  97. // There is a bug in cmInstallCommand if this fails.
  98. assert(this->NamelinkMode == NamelinkModeNone);
  99. cmGeneratorTarget::Names targetNames =
  100. this->Target->GetExecutableNames(config);
  101. if (this->ImportLibrary) {
  102. std::string from1 = fromDirConfig + targetNames.ImportLibrary;
  103. std::string to1 = toDir + targetNames.ImportLibrary;
  104. filesFrom.push_back(std::move(from1));
  105. filesTo.push_back(std::move(to1));
  106. std::string targetNameImportLib;
  107. if (this->Target->GetImplibGNUtoMS(config, targetNames.ImportLibrary,
  108. targetNameImportLib)) {
  109. filesFrom.push_back(fromDirConfig + targetNameImportLib);
  110. filesTo.push_back(toDir + targetNameImportLib);
  111. }
  112. // An import library looks like a static library.
  113. type = cmInstallType_STATIC_LIBRARY;
  114. } else {
  115. std::string from1 = fromDirConfig + targetNames.Output;
  116. std::string to1 = toDir + targetNames.Output;
  117. // Handle OSX Bundles.
  118. if (this->Target->IsAppBundleOnApple()) {
  119. cmMakefile const* mf = this->Target->Target->GetMakefile();
  120. // Get App Bundle Extension
  121. const char* ext = this->Target->GetProperty("BUNDLE_EXTENSION");
  122. if (!ext) {
  123. ext = "app";
  124. }
  125. // Install the whole app bundle directory.
  126. type = cmInstallType_DIRECTORY;
  127. literal_args += " USE_SOURCE_PERMISSIONS";
  128. from1 += ".";
  129. from1 += ext;
  130. // Tweaks apply to the binary inside the bundle.
  131. to1 += ".";
  132. to1 += ext;
  133. to1 += "/";
  134. if (!mf->PlatformIsAppleEmbedded()) {
  135. to1 += "Contents/MacOS/";
  136. }
  137. to1 += targetNames.Output;
  138. } else {
  139. // Tweaks apply to the real file, so list it first.
  140. if (targetNames.Real != targetNames.Output) {
  141. std::string from2 = fromDirConfig + targetNames.Real;
  142. std::string to2 = toDir += targetNames.Real;
  143. filesFrom.push_back(std::move(from2));
  144. filesTo.push_back(std::move(to2));
  145. }
  146. }
  147. filesFrom.push_back(std::move(from1));
  148. filesTo.push_back(std::move(to1));
  149. }
  150. } else {
  151. cmGeneratorTarget::Names targetNames =
  152. this->Target->GetLibraryNames(config);
  153. if (this->ImportLibrary) {
  154. // There is a bug in cmInstallCommand if this fails.
  155. assert(this->NamelinkMode == NamelinkModeNone);
  156. std::string from1 = fromDirConfig + targetNames.ImportLibrary;
  157. std::string to1 = toDir + targetNames.ImportLibrary;
  158. filesFrom.push_back(std::move(from1));
  159. filesTo.push_back(std::move(to1));
  160. std::string targetNameImportLib;
  161. if (this->Target->GetImplibGNUtoMS(config, targetNames.ImportLibrary,
  162. targetNameImportLib)) {
  163. filesFrom.push_back(fromDirConfig + targetNameImportLib);
  164. filesTo.push_back(toDir + targetNameImportLib);
  165. }
  166. // An import library looks like a static library.
  167. type = cmInstallType_STATIC_LIBRARY;
  168. } else if (this->Target->IsFrameworkOnApple()) {
  169. // FIXME: In principle we should be able to
  170. // assert(this->NamelinkMode == NamelinkModeNone);
  171. // but since the current install() command implementation checks
  172. // the FRAMEWORK property immediately instead of delaying until
  173. // generate time, it is possible for project code to set the
  174. // property after calling install(). In such a case, the install()
  175. // command will use the LIBRARY code path and create two install
  176. // generators, one for the namelink component (NamelinkModeOnly)
  177. // and one for the primary artifact component (NamelinkModeSkip).
  178. // Historically this was not diagnosed and resulted in silent
  179. // installation of a framework to the LIBRARY destination.
  180. // Retain that behavior and warn about the case.
  181. switch (this->NamelinkMode) {
  182. case NamelinkModeNone:
  183. // Normal case.
  184. break;
  185. case NamelinkModeOnly:
  186. // Assume the NamelinkModeSkip instance will warn and install.
  187. return;
  188. case NamelinkModeSkip: {
  189. std::string e = "Target '" + this->Target->GetName() +
  190. "' was changed to a FRAMEWORK sometime after install(). "
  191. "This may result in the wrong install DESTINATION. "
  192. "Set the FRAMEWORK property earlier.";
  193. this->Target->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage(
  194. MessageType::AUTHOR_WARNING, e, this->GetBacktrace());
  195. } break;
  196. }
  197. // Install the whole framework directory.
  198. type = cmInstallType_DIRECTORY;
  199. literal_args += " USE_SOURCE_PERMISSIONS";
  200. std::string from1 = fromDirConfig + targetNames.Output;
  201. from1 = cmSystemTools::GetFilenamePath(from1);
  202. // Tweaks apply to the binary inside the bundle.
  203. std::string to1 = toDir + targetNames.Real;
  204. filesFrom.push_back(std::move(from1));
  205. filesTo.push_back(std::move(to1));
  206. } else if (this->Target->IsCFBundleOnApple()) {
  207. // Install the whole app bundle directory.
  208. type = cmInstallType_DIRECTORY;
  209. literal_args += " USE_SOURCE_PERMISSIONS";
  210. std::string targetNameBase =
  211. targetNames.Output.substr(0, targetNames.Output.find('/'));
  212. std::string from1 = fromDirConfig + targetNameBase;
  213. std::string to1 = toDir + targetNames.Output;
  214. filesFrom.push_back(std::move(from1));
  215. filesTo.push_back(std::move(to1));
  216. } else {
  217. bool haveNamelink = false;
  218. // Library link name.
  219. std::string fromName = fromDirConfig + targetNames.Output;
  220. std::string toName = toDir + targetNames.Output;
  221. // Library interface name.
  222. std::string fromSOName;
  223. std::string toSOName;
  224. if (targetNames.SharedObject != targetNames.Output) {
  225. haveNamelink = true;
  226. fromSOName = fromDirConfig + targetNames.SharedObject;
  227. toSOName = toDir + targetNames.SharedObject;
  228. }
  229. // Library implementation name.
  230. std::string fromRealName;
  231. std::string toRealName;
  232. if (targetNames.Real != targetNames.Output &&
  233. targetNames.Real != targetNames.SharedObject) {
  234. haveNamelink = true;
  235. fromRealName = fromDirConfig + targetNames.Real;
  236. toRealName = toDir + targetNames.Real;
  237. }
  238. // Add the names based on the current namelink mode.
  239. if (haveNamelink) {
  240. // With a namelink we need to check the mode.
  241. if (this->NamelinkMode == NamelinkModeOnly) {
  242. // Install the namelink only.
  243. filesFrom.push_back(fromName);
  244. filesTo.push_back(toName);
  245. } else {
  246. // Install the real file if it has its own name.
  247. if (!fromRealName.empty()) {
  248. filesFrom.push_back(fromRealName);
  249. filesTo.push_back(toRealName);
  250. }
  251. // Install the soname link if it has its own name.
  252. if (!fromSOName.empty()) {
  253. filesFrom.push_back(fromSOName);
  254. filesTo.push_back(toSOName);
  255. }
  256. // Install the namelink if it is not to be skipped.
  257. if (this->NamelinkMode != NamelinkModeSkip) {
  258. filesFrom.push_back(fromName);
  259. filesTo.push_back(toName);
  260. }
  261. }
  262. } else {
  263. // Without a namelink there will be only one file. Install it
  264. // if this is not a namelink-only rule.
  265. if (this->NamelinkMode != NamelinkModeOnly) {
  266. filesFrom.push_back(fromName);
  267. filesTo.push_back(toName);
  268. }
  269. }
  270. }
  271. }
  272. // If this fails the above code is buggy.
  273. assert(filesFrom.size() == filesTo.size());
  274. // Skip this rule if no files are to be installed for the target.
  275. if (filesFrom.empty()) {
  276. return;
  277. }
  278. // Add pre-installation tweaks.
  279. this->AddTweak(os, indent, config, filesTo,
  280. &cmInstallTargetGenerator::PreReplacementTweaks);
  281. // Write code to install the target file.
  282. const char* no_dir_permissions = nullptr;
  283. const char* no_rename = nullptr;
  284. bool optional = this->Optional || this->ImportLibrary;
  285. this->AddInstallRule(os, this->GetDestination(config), type, filesFrom,
  286. optional, this->FilePermissions.c_str(),
  287. no_dir_permissions, no_rename, literal_args.c_str(),
  288. indent);
  289. // Add post-installation tweaks.
  290. this->AddTweak(os, indent, config, filesTo,
  291. &cmInstallTargetGenerator::PostReplacementTweaks);
  292. }
  293. static std::string computeInstallObjectDir(cmGeneratorTarget* gt,
  294. std::string const& config)
  295. {
  296. std::string objectDir = "objects";
  297. if (!config.empty()) {
  298. objectDir += "-";
  299. objectDir += config;
  300. }
  301. objectDir += "/";
  302. objectDir += gt->GetName();
  303. return objectDir;
  304. }
  305. void cmInstallTargetGenerator::GenerateScriptForConfigObjectLibrary(
  306. std::ostream& os, const std::string& config, Indent indent)
  307. {
  308. // Compute all the object files inside this target
  309. std::vector<std::string> objects;
  310. this->Target->GetTargetObjectNames(config, objects);
  311. std::string const dest = this->GetDestination(config) + "/" +
  312. computeInstallObjectDir(this->Target, config);
  313. std::string const obj_dir = this->Target->GetObjectDirectory(config);
  314. std::string const literal_args = " FILES_FROM_DIR \"" + obj_dir + "\"";
  315. const char* no_dir_permissions = nullptr;
  316. const char* no_rename = nullptr;
  317. this->AddInstallRule(os, dest, cmInstallType_FILES, objects, this->Optional,
  318. this->FilePermissions.c_str(), no_dir_permissions,
  319. no_rename, literal_args.c_str(), indent);
  320. }
  321. void cmInstallTargetGenerator::GetInstallObjectNames(
  322. std::string const& config, std::vector<std::string>& objects) const
  323. {
  324. this->Target->GetTargetObjectNames(config, objects);
  325. for (std::string& o : objects) {
  326. o = cmStrCat(computeInstallObjectDir(this->Target, config), "/", o);
  327. }
  328. }
  329. std::string cmInstallTargetGenerator::GetDestination(
  330. std::string const& config) const
  331. {
  332. return cmGeneratorExpression::Evaluate(
  333. this->Destination, this->Target->GetLocalGenerator(), config);
  334. }
  335. std::string cmInstallTargetGenerator::GetInstallFilename(
  336. const std::string& config) const
  337. {
  338. NameType nameType = this->ImportLibrary ? NameImplib : NameNormal;
  339. return cmInstallTargetGenerator::GetInstallFilename(this->Target, config,
  340. nameType);
  341. }
  342. std::string cmInstallTargetGenerator::GetInstallFilename(
  343. cmGeneratorTarget const* target, const std::string& config,
  344. NameType nameType)
  345. {
  346. std::string fname;
  347. // Compute the name of the library.
  348. if (target->GetType() == cmStateEnums::EXECUTABLE) {
  349. cmGeneratorTarget::Names targetNames = target->GetExecutableNames(config);
  350. if (nameType == NameImplib) {
  351. // Use the import library name.
  352. if (!target->GetImplibGNUtoMS(config, targetNames.ImportLibrary, fname,
  353. "${CMAKE_IMPORT_LIBRARY_SUFFIX}")) {
  354. fname = targetNames.ImportLibrary;
  355. }
  356. } else if (nameType == NameReal) {
  357. // Use the canonical name.
  358. fname = targetNames.Real;
  359. } else {
  360. // Use the canonical name.
  361. fname = targetNames.Output;
  362. }
  363. } else {
  364. cmGeneratorTarget::Names targetNames = target->GetLibraryNames(config);
  365. if (nameType == NameImplib) {
  366. // Use the import library name.
  367. if (!target->GetImplibGNUtoMS(config, targetNames.ImportLibrary, fname,
  368. "${CMAKE_IMPORT_LIBRARY_SUFFIX}")) {
  369. fname = targetNames.ImportLibrary;
  370. }
  371. } else if (nameType == NameSO) {
  372. // Use the soname.
  373. fname = targetNames.SharedObject;
  374. } else if (nameType == NameReal) {
  375. // Use the real name.
  376. fname = targetNames.Real;
  377. } else {
  378. // Use the canonical name.
  379. fname = targetNames.Output;
  380. }
  381. }
  382. return fname;
  383. }
  384. bool cmInstallTargetGenerator::Compute(cmLocalGenerator* lg)
  385. {
  386. // Lookup this target in the current directory.
  387. this->Target = lg->FindLocalNonAliasGeneratorTarget(this->TargetName);
  388. if (!this->Target) {
  389. // If no local target has been found, find it in the global scope.
  390. this->Target =
  391. lg->GetGlobalGenerator()->FindGeneratorTarget(this->TargetName);
  392. }
  393. return true;
  394. }
  395. void cmInstallTargetGenerator::AddTweak(std::ostream& os, Indent indent,
  396. const std::string& config,
  397. std::string const& file,
  398. TweakMethod tweak)
  399. {
  400. std::ostringstream tw;
  401. (this->*tweak)(tw, indent.Next(), config, file);
  402. std::string tws = tw.str();
  403. if (!tws.empty()) {
  404. os << indent << "if(EXISTS \"" << file << "\" AND\n"
  405. << indent << " NOT IS_SYMLINK \"" << file << "\")\n";
  406. os << tws;
  407. os << indent << "endif()\n";
  408. }
  409. }
  410. void cmInstallTargetGenerator::AddTweak(std::ostream& os, Indent indent,
  411. const std::string& config,
  412. std::vector<std::string> const& files,
  413. TweakMethod tweak)
  414. {
  415. if (files.size() == 1) {
  416. // Tweak a single file.
  417. this->AddTweak(os, indent, config, this->GetDestDirPath(files[0]), tweak);
  418. } else {
  419. // Generate a foreach loop to tweak multiple files.
  420. std::ostringstream tw;
  421. this->AddTweak(tw, indent.Next(), config, "${file}", tweak);
  422. std::string tws = tw.str();
  423. if (!tws.empty()) {
  424. Indent indent2 = indent.Next().Next();
  425. os << indent << "foreach(file\n";
  426. for (std::string const& f : files) {
  427. os << indent2 << "\"" << this->GetDestDirPath(f) << "\"\n";
  428. }
  429. os << indent2 << ")\n";
  430. os << tws;
  431. os << indent << "endforeach()\n";
  432. }
  433. }
  434. }
  435. std::string cmInstallTargetGenerator::GetDestDirPath(std::string const& file)
  436. {
  437. // Construct the path of the file on disk after installation on
  438. // which tweaks may be performed.
  439. std::string toDestDirPath = "$ENV{DESTDIR}";
  440. if (file[0] != '/' && file[0] != '$') {
  441. toDestDirPath += "/";
  442. }
  443. toDestDirPath += file;
  444. return toDestDirPath;
  445. }
  446. void cmInstallTargetGenerator::PreReplacementTweaks(std::ostream& os,
  447. Indent indent,
  448. const std::string& config,
  449. std::string const& file)
  450. {
  451. this->AddRPathCheckRule(os, indent, config, file);
  452. }
  453. void cmInstallTargetGenerator::PostReplacementTweaks(std::ostream& os,
  454. Indent indent,
  455. const std::string& config,
  456. std::string const& file)
  457. {
  458. this->AddInstallNamePatchRule(os, indent, config, file);
  459. this->AddChrpathPatchRule(os, indent, config, file);
  460. this->AddUniversalInstallRule(os, indent, file);
  461. this->AddRanlibRule(os, indent, file);
  462. this->AddStripRule(os, indent, file);
  463. }
  464. void cmInstallTargetGenerator::AddInstallNamePatchRule(
  465. std::ostream& os, Indent indent, const std::string& config,
  466. std::string const& toDestDirPath)
  467. {
  468. if (this->ImportLibrary ||
  469. !(this->Target->GetType() == cmStateEnums::SHARED_LIBRARY ||
  470. this->Target->GetType() == cmStateEnums::MODULE_LIBRARY ||
  471. this->Target->GetType() == cmStateEnums::EXECUTABLE)) {
  472. return;
  473. }
  474. // Fix the install_name settings in installed binaries.
  475. std::string installNameTool =
  476. this->Target->Target->GetMakefile()->GetSafeDefinition(
  477. "CMAKE_INSTALL_NAME_TOOL");
  478. if (installNameTool.empty()) {
  479. return;
  480. }
  481. // Build a map of build-tree install_name to install-tree install_name for
  482. // shared libraries linked to this target.
  483. std::map<std::string, std::string> install_name_remap;
  484. if (cmComputeLinkInformation* cli =
  485. this->Target->GetLinkInformation(config)) {
  486. std::set<cmGeneratorTarget const*> const& sharedLibs =
  487. cli->GetSharedLibrariesLinked();
  488. for (cmGeneratorTarget const* tgt : sharedLibs) {
  489. // The install_name of an imported target does not change.
  490. if (tgt->IsImported()) {
  491. continue;
  492. }
  493. // If the build tree and install tree use different path
  494. // components of the install_name field then we need to create a
  495. // mapping to be applied after installation.
  496. std::string for_build = tgt->GetInstallNameDirForBuildTree(config);
  497. std::string for_install = tgt->GetInstallNameDirForInstallTree(
  498. config, "${CMAKE_INSTALL_PREFIX}");
  499. if (for_build != for_install) {
  500. // The directory portions differ. Append the filename to
  501. // create the mapping.
  502. std::string fname = this->GetInstallFilename(tgt, config, NameSO);
  503. // Map from the build-tree install_name.
  504. for_build += fname;
  505. // Map to the install-tree install_name.
  506. for_install += fname;
  507. // Store the mapping entry.
  508. install_name_remap[for_build] = for_install;
  509. }
  510. }
  511. }
  512. // Edit the install_name of the target itself if necessary.
  513. std::string new_id;
  514. if (this->Target->GetType() == cmStateEnums::SHARED_LIBRARY) {
  515. std::string for_build =
  516. this->Target->GetInstallNameDirForBuildTree(config);
  517. std::string for_install = this->Target->GetInstallNameDirForInstallTree(
  518. config, "${CMAKE_INSTALL_PREFIX}");
  519. if (this->Target->IsFrameworkOnApple() && for_install.empty()) {
  520. // Frameworks seem to have an id corresponding to their own full
  521. // path.
  522. // ...
  523. // for_install = fullDestPath_without_DESTDIR_or_name;
  524. }
  525. // If the install name will change on installation set the new id
  526. // on the installed file.
  527. if (for_build != for_install) {
  528. // Prepare to refer to the install-tree install_name.
  529. new_id = cmStrCat(
  530. for_install, this->GetInstallFilename(this->Target, config, NameSO));
  531. }
  532. }
  533. // Write a rule to run install_name_tool to set the install-tree
  534. // install_name value and references.
  535. if (!new_id.empty() || !install_name_remap.empty()) {
  536. os << indent << "execute_process(COMMAND \"" << installNameTool;
  537. os << "\"";
  538. if (!new_id.empty()) {
  539. os << "\n" << indent << " -id \"" << new_id << "\"";
  540. }
  541. for (auto const& i : install_name_remap) {
  542. os << "\n"
  543. << indent << " -change \"" << i.first << "\" \"" << i.second << "\"";
  544. }
  545. os << "\n" << indent << " \"" << toDestDirPath << "\")\n";
  546. }
  547. }
  548. void cmInstallTargetGenerator::AddRPathCheckRule(
  549. std::ostream& os, Indent indent, const std::string& config,
  550. std::string const& toDestDirPath)
  551. {
  552. // Skip the chrpath if the target does not need it.
  553. if (this->ImportLibrary || !this->Target->IsChrpathUsed(config)) {
  554. return;
  555. }
  556. // Skip if on Apple
  557. if (this->Target->Target->GetMakefile()->IsOn(
  558. "CMAKE_PLATFORM_HAS_INSTALLNAME")) {
  559. return;
  560. }
  561. // Get the link information for this target.
  562. // It can provide the RPATH.
  563. cmComputeLinkInformation* cli = this->Target->GetLinkInformation(config);
  564. if (!cli) {
  565. return;
  566. }
  567. // Write a rule to remove the installed file if its rpath is not the
  568. // new rpath. This is needed for existing build/install trees when
  569. // the installed rpath changes but the file is not rebuilt.
  570. os << indent << "file(RPATH_CHECK\n"
  571. << indent << " FILE \"" << toDestDirPath << "\"\n";
  572. // CMP0095: ``RPATH`` entries are properly escaped in the intermediary
  573. // CMake install script.
  574. switch (this->Target->GetPolicyStatusCMP0095()) {
  575. case cmPolicies::WARN:
  576. // No author warning needed here, we warn later in
  577. // cmInstallTargetGenerator::AddChrpathPatchRule().
  578. CM_FALLTHROUGH;
  579. case cmPolicies::OLD: {
  580. // Get the install RPATH from the link information.
  581. std::string newRpath = cli->GetChrpathString();
  582. os << indent << " RPATH \"" << newRpath << "\")\n";
  583. break;
  584. }
  585. default: {
  586. // Get the install RPATH from the link information and
  587. // escape any CMake syntax in the install RPATH.
  588. std::string escapedNewRpath =
  589. cmOutputConverter::EscapeForCMake(cli->GetChrpathString());
  590. os << indent << " RPATH " << escapedNewRpath << ")\n";
  591. break;
  592. }
  593. }
  594. }
  595. void cmInstallTargetGenerator::AddChrpathPatchRule(
  596. std::ostream& os, Indent indent, const std::string& config,
  597. std::string const& toDestDirPath)
  598. {
  599. // Skip the chrpath if the target does not need it.
  600. if (this->ImportLibrary || !this->Target->IsChrpathUsed(config)) {
  601. return;
  602. }
  603. // Get the link information for this target.
  604. // It can provide the RPATH.
  605. cmComputeLinkInformation* cli = this->Target->GetLinkInformation(config);
  606. if (!cli) {
  607. return;
  608. }
  609. cmMakefile* mf = this->Target->Target->GetMakefile();
  610. if (mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
  611. // If using install_name_tool, set up the rules to modify the rpaths.
  612. std::string installNameTool =
  613. mf->GetSafeDefinition("CMAKE_INSTALL_NAME_TOOL");
  614. std::vector<std::string> oldRuntimeDirs;
  615. std::vector<std::string> newRuntimeDirs;
  616. cli->GetRPath(oldRuntimeDirs, false);
  617. cli->GetRPath(newRuntimeDirs, true);
  618. std::string darwin_major_version_s =
  619. mf->GetSafeDefinition("DARWIN_MAJOR_VERSION");
  620. std::istringstream ss(darwin_major_version_s);
  621. int darwin_major_version;
  622. ss >> darwin_major_version;
  623. if (!ss.fail() && darwin_major_version <= 9 &&
  624. (!oldRuntimeDirs.empty() || !newRuntimeDirs.empty())) {
  625. std::ostringstream msg;
  626. msg
  627. << "WARNING: Target \"" << this->Target->GetName()
  628. << "\" has runtime paths which cannot be changed during install. "
  629. << "To change runtime paths, OS X version 10.6 or newer is required. "
  630. << "Therefore, runtime paths will not be changed when installing. "
  631. << "CMAKE_BUILD_WITH_INSTALL_RPATH may be used to work around"
  632. " this limitation.";
  633. mf->IssueMessage(MessageType::WARNING, msg.str());
  634. } else {
  635. // Note: These paths are kept unique to avoid
  636. // install_name_tool corruption.
  637. std::set<std::string> runpaths;
  638. for (std::string const& i : oldRuntimeDirs) {
  639. std::string runpath =
  640. mf->GetGlobalGenerator()->ExpandCFGIntDir(i, config);
  641. if (runpaths.find(runpath) == runpaths.end()) {
  642. runpaths.insert(runpath);
  643. os << indent << "execute_process(COMMAND " << installNameTool
  644. << "\n";
  645. os << indent << " -delete_rpath \"" << runpath << "\"\n";
  646. os << indent << " \"" << toDestDirPath << "\")\n";
  647. }
  648. }
  649. runpaths.clear();
  650. for (std::string const& i : newRuntimeDirs) {
  651. std::string runpath =
  652. mf->GetGlobalGenerator()->ExpandCFGIntDir(i, config);
  653. if (runpaths.find(runpath) == runpaths.end()) {
  654. os << indent << "execute_process(COMMAND " << installNameTool
  655. << "\n";
  656. os << indent << " -add_rpath \"" << runpath << "\"\n";
  657. os << indent << " \"" << toDestDirPath << "\")\n";
  658. }
  659. }
  660. }
  661. } else {
  662. // Construct the original rpath string to be replaced.
  663. std::string oldRpath = cli->GetRPathString(false);
  664. // Get the install RPATH from the link information.
  665. std::string newRpath = cli->GetChrpathString();
  666. // Skip the rule if the paths are identical
  667. if (oldRpath == newRpath) {
  668. return;
  669. }
  670. // Escape any CMake syntax in the RPATHs.
  671. std::string escapedOldRpath = cmOutputConverter::EscapeForCMake(oldRpath);
  672. std::string escapedNewRpath = cmOutputConverter::EscapeForCMake(newRpath);
  673. // Write a rule to run chrpath to set the install-tree RPATH
  674. os << indent << "file(RPATH_CHANGE\n"
  675. << indent << " FILE \"" << toDestDirPath << "\"\n"
  676. << indent << " OLD_RPATH " << escapedOldRpath << "\n";
  677. // CMP0095: ``RPATH`` entries are properly escaped in the intermediary
  678. // CMake install script.
  679. switch (this->Target->GetPolicyStatusCMP0095()) {
  680. case cmPolicies::WARN:
  681. this->IssueCMP0095Warning(newRpath);
  682. CM_FALLTHROUGH;
  683. case cmPolicies::OLD:
  684. os << indent << " NEW_RPATH \"" << newRpath << "\"";
  685. break;
  686. default:
  687. os << indent << " NEW_RPATH " << escapedNewRpath;
  688. break;
  689. }
  690. if (this->Target->GetPropertyAsBool("INSTALL_REMOVE_ENVIRONMENT_RPATH")) {
  691. os << "\n" << indent << " INSTALL_REMOVE_ENVIRONMENT_RPATH)\n";
  692. } else {
  693. os << indent << ")\n";
  694. }
  695. }
  696. }
  697. void cmInstallTargetGenerator::AddStripRule(std::ostream& os, Indent indent,
  698. const std::string& toDestDirPath)
  699. {
  700. // don't strip static and import libraries, because it removes the only
  701. // symbol table they have so you can't link to them anymore
  702. if (this->Target->GetType() == cmStateEnums::STATIC_LIBRARY ||
  703. this->ImportLibrary) {
  704. return;
  705. }
  706. // Don't handle OSX Bundles.
  707. if (this->Target->Target->GetMakefile()->IsOn("APPLE") &&
  708. this->Target->GetPropertyAsBool("MACOSX_BUNDLE")) {
  709. return;
  710. }
  711. if (!this->Target->Target->GetMakefile()->IsSet("CMAKE_STRIP")) {
  712. return;
  713. }
  714. std::string stripArgs;
  715. // macOS 'strip' is picky, executables need '-u -r' and dylibs need '-x'.
  716. if (this->Target->Target->GetMakefile()->IsOn("APPLE")) {
  717. if (this->Target->GetType() == cmStateEnums::SHARED_LIBRARY ||
  718. this->Target->GetType() == cmStateEnums::MODULE_LIBRARY) {
  719. stripArgs = "-x ";
  720. } else if (this->Target->GetType() == cmStateEnums::EXECUTABLE) {
  721. stripArgs = "-u -r ";
  722. }
  723. }
  724. os << indent << "if(CMAKE_INSTALL_DO_STRIP)\n";
  725. os << indent << " execute_process(COMMAND \""
  726. << this->Target->Target->GetMakefile()->GetDefinition("CMAKE_STRIP")
  727. << "\" " << stripArgs << "\"" << toDestDirPath << "\")\n";
  728. os << indent << "endif()\n";
  729. }
  730. void cmInstallTargetGenerator::AddRanlibRule(std::ostream& os, Indent indent,
  731. const std::string& toDestDirPath)
  732. {
  733. // Static libraries need ranlib on this platform.
  734. if (this->Target->GetType() != cmStateEnums::STATIC_LIBRARY) {
  735. return;
  736. }
  737. // Perform post-installation processing on the file depending
  738. // on its type.
  739. if (!this->Target->Target->GetMakefile()->IsOn("APPLE")) {
  740. return;
  741. }
  742. const std::string& ranlib =
  743. this->Target->Target->GetMakefile()->GetRequiredDefinition("CMAKE_RANLIB");
  744. if (ranlib.empty()) {
  745. return;
  746. }
  747. os << indent << "execute_process(COMMAND \"" << ranlib << "\" \""
  748. << toDestDirPath << "\")\n";
  749. }
  750. void cmInstallTargetGenerator::AddUniversalInstallRule(
  751. std::ostream& os, Indent indent, const std::string& toDestDirPath)
  752. {
  753. cmMakefile const* mf = this->Target->Target->GetMakefile();
  754. if (!mf->PlatformIsAppleEmbedded() || !mf->IsOn("XCODE")) {
  755. return;
  756. }
  757. const char* xcodeVersion = mf->GetDefinition("XCODE_VERSION");
  758. if (!xcodeVersion ||
  759. cmSystemTools::VersionCompareGreater("6", xcodeVersion)) {
  760. return;
  761. }
  762. switch (this->Target->GetType()) {
  763. case cmStateEnums::EXECUTABLE:
  764. case cmStateEnums::STATIC_LIBRARY:
  765. case cmStateEnums::SHARED_LIBRARY:
  766. case cmStateEnums::MODULE_LIBRARY:
  767. break;
  768. default:
  769. return;
  770. }
  771. if (!this->Target->Target->GetPropertyAsBool("IOS_INSTALL_COMBINED")) {
  772. return;
  773. }
  774. os << indent << "include(CMakeIOSInstallCombined)\n";
  775. os << indent << "ios_install_combined("
  776. << "\"" << this->Target->Target->GetName() << "\" "
  777. << "\"" << toDestDirPath << "\")\n";
  778. }
  779. void cmInstallTargetGenerator::IssueCMP0095Warning(
  780. const std::string& unescapedRpath)
  781. {
  782. // Reduce warning noise to cases where used RPATHs may actually be affected
  783. // by CMP0095. This filter is meant to skip warnings in cases when
  784. // non-curly-braces syntax (e.g. $ORIGIN) or no keyword is used which has
  785. // worked already before CMP0095. We intend to issue a warning in all cases
  786. // with curly-braces syntax, even if the workaround of double-escaping is in
  787. // place, since we deprecate the need for it with CMP0095.
  788. const bool potentially_affected(unescapedRpath.find("${") !=
  789. std::string::npos);
  790. if (potentially_affected) {
  791. std::ostringstream w;
  792. w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0095) << "\n";
  793. w << "RPATH entries for target '" << this->Target->GetName() << "' "
  794. << "will not be escaped in the intermediary "
  795. << "cmake_install.cmake script.";
  796. this->Target->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage(
  797. MessageType::AUTHOR_WARNING, w.str(), this->GetBacktrace());
  798. }
  799. }