cmInstallRuntimeDependencySetGenerator.cxx 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  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 "cmInstallRuntimeDependencySetGenerator.h"
  4. #include <ostream>
  5. #include <string>
  6. #include <utility>
  7. #include <vector>
  8. #include "cmGeneratorExpression.h"
  9. #include "cmInstallGenerator.h"
  10. #include "cmInstallType.h"
  11. #include "cmListFileCache.h"
  12. #include "cmLocalGenerator.h"
  13. #include "cmMakefile.h"
  14. #include "cmMessageType.h"
  15. #include "cmOutputConverter.h"
  16. #include "cmScriptGenerator.h"
  17. #include "cmStringAlgorithms.h"
  18. #include "cmake.h"
  19. cmInstallRuntimeDependencySetGenerator::cmInstallRuntimeDependencySetGenerator(
  20. DependencyType type, cmInstallRuntimeDependencySet* dependencySet,
  21. std::vector<std::string> installRPaths, bool noInstallRPath,
  22. std::string installNameDir, bool noInstallName, const char* depsVar,
  23. const char* rpathPrefix, const char* tmpVarPrefix, std::string destination,
  24. std::vector<std::string> const& configurations, std::string component,
  25. std::string permissions, MessageLevel message, bool exclude_from_all,
  26. cmListFileBacktrace backtrace)
  27. : cmInstallGenerator(std::move(destination), configurations,
  28. std::move(component), message, exclude_from_all, false,
  29. std::move(backtrace))
  30. , Type(type)
  31. , DependencySet(dependencySet)
  32. , InstallRPaths(std::move(installRPaths))
  33. , NoInstallRPath(noInstallRPath)
  34. , InstallNameDir(std::move(installNameDir))
  35. , NoInstallName(noInstallName)
  36. , Permissions(std::move(permissions))
  37. , DepsVar(depsVar)
  38. , RPathPrefix(rpathPrefix)
  39. , TmpVarPrefix(tmpVarPrefix)
  40. {
  41. this->ActionsPerConfig = true;
  42. }
  43. bool cmInstallRuntimeDependencySetGenerator::Compute(cmLocalGenerator* lg)
  44. {
  45. this->LocalGenerator = lg;
  46. return true;
  47. }
  48. void cmInstallRuntimeDependencySetGenerator::GenerateScriptForConfig(
  49. std::ostream& os, const std::string& config, Indent indent)
  50. {
  51. if (!this->LocalGenerator->GetMakefile()
  52. ->GetSafeDefinition("CMAKE_INSTALL_NAME_TOOL")
  53. .empty() &&
  54. !this->NoInstallName) {
  55. std::string installNameDir = "@rpath/";
  56. if (!this->InstallNameDir.empty()) {
  57. installNameDir = this->InstallNameDir;
  58. cmGeneratorExpression::ReplaceInstallPrefix(installNameDir,
  59. "${CMAKE_INSTALL_PREFIX}");
  60. installNameDir = cmGeneratorExpression::Evaluate(
  61. installNameDir, this->LocalGenerator, config);
  62. if (installNameDir.empty()) {
  63. this->LocalGenerator->GetMakefile()->GetCMakeInstance()->IssueMessage(
  64. MessageType::FATAL_ERROR,
  65. "INSTALL_NAME_DIR argument must not evaluate to an "
  66. "empty string",
  67. this->Backtrace);
  68. return;
  69. }
  70. if (installNameDir.back() != '/') {
  71. installNameDir += '/';
  72. }
  73. }
  74. os << indent << "set(" << this->TmpVarPrefix << "_install_name_dir \""
  75. << installNameDir << "\")\n";
  76. }
  77. os << indent << "foreach(" << this->TmpVarPrefix << "_dep IN LISTS "
  78. << this->DepsVar << ")\n";
  79. if (!this->LocalGenerator->GetMakefile()
  80. ->GetSafeDefinition("CMAKE_INSTALL_NAME_TOOL")
  81. .empty()) {
  82. std::vector<std::string> evaluatedRPaths;
  83. for (auto const& rpath : this->InstallRPaths) {
  84. std::string result =
  85. cmGeneratorExpression::Evaluate(rpath, this->LocalGenerator, config);
  86. if (!result.empty()) {
  87. evaluatedRPaths.push_back(std::move(result));
  88. }
  89. }
  90. switch (this->Type) {
  91. case DependencyType::Library:
  92. this->GenerateAppleLibraryScript(os, config, evaluatedRPaths,
  93. indent.Next());
  94. break;
  95. case DependencyType::Framework:
  96. this->GenerateAppleFrameworkScript(os, config, evaluatedRPaths,
  97. indent.Next());
  98. break;
  99. }
  100. } else {
  101. std::string depVar = cmStrCat(this->TmpVarPrefix, "_dep");
  102. this->AddInstallRule(
  103. os, this->GetDestination(config), cmInstallType_SHARED_LIBRARY, {},
  104. false, this->Permissions.c_str(), nullptr, nullptr,
  105. " FOLLOW_SYMLINK_CHAIN", indent.Next(), depVar.c_str());
  106. if (this->LocalGenerator->GetMakefile()->GetSafeDefinition(
  107. "CMAKE_SYSTEM_NAME") == "Linux" &&
  108. !this->NoInstallRPath) {
  109. std::string evaluatedRPath;
  110. for (auto const& rpath : this->InstallRPaths) {
  111. std::string result =
  112. cmGeneratorExpression::Evaluate(rpath, this->LocalGenerator, config);
  113. if (!result.empty()) {
  114. if (evaluatedRPath.empty()) {
  115. evaluatedRPath = std::move(result);
  116. } else {
  117. evaluatedRPath += ':';
  118. evaluatedRPath += result;
  119. }
  120. }
  121. }
  122. os << indent.Next() << "get_filename_component(" << this->TmpVarPrefix
  123. << "_dep_name \"${" << this->TmpVarPrefix << "_dep}\" NAME)\n";
  124. if (evaluatedRPath.empty()) {
  125. os << indent.Next() << "file(RPATH_REMOVE FILE \""
  126. << GetDestDirPath(
  127. ConvertToAbsoluteDestination(this->GetDestination(config)))
  128. << "/${" << this->TmpVarPrefix << "_dep_name}\")\n";
  129. } else {
  130. os << indent.Next() << "file(RPATH_SET FILE \""
  131. << GetDestDirPath(
  132. ConvertToAbsoluteDestination(this->GetDestination(config)))
  133. << "/${" << this->TmpVarPrefix << "_dep_name}\" NEW_RPATH "
  134. << cmOutputConverter::EscapeForCMake(evaluatedRPath) << ")\n";
  135. }
  136. }
  137. }
  138. os << indent << "endforeach()\n";
  139. }
  140. void cmInstallRuntimeDependencySetGenerator::GenerateAppleLibraryScript(
  141. std::ostream& os, const std::string& config,
  142. const std::vector<std::string>& evaluatedRPaths, Indent indent)
  143. {
  144. os << indent << "if(NOT " << this->TmpVarPrefix
  145. << "_dep MATCHES \"\\\\.framework/\")\n";
  146. auto depName = cmStrCat(this->TmpVarPrefix, "_dep");
  147. this->AddInstallRule(
  148. os, this->GetDestination(config), cmInstallType_SHARED_LIBRARY, {}, false,
  149. this->Permissions.c_str(), nullptr, nullptr, " FOLLOW_SYMLINK_CHAIN",
  150. indent.Next(), depName.c_str());
  151. os << indent.Next() << "get_filename_component(" << this->TmpVarPrefix
  152. << "_dep_name \"${" << this->TmpVarPrefix << "_dep}\" NAME)\n";
  153. auto depNameVar = cmStrCat("${", this->TmpVarPrefix, "_dep_name}");
  154. this->GenerateInstallNameFixup(os, config, evaluatedRPaths,
  155. cmStrCat("${", this->TmpVarPrefix, "_dep}"),
  156. depNameVar, indent.Next());
  157. os << indent << "endif()\n";
  158. }
  159. void cmInstallRuntimeDependencySetGenerator::GenerateAppleFrameworkScript(
  160. std::ostream& os, const std::string& config,
  161. const std::vector<std::string>& evaluatedRPaths, Indent indent)
  162. {
  163. os << indent << "if(" << this->TmpVarPrefix
  164. << "_dep MATCHES \"^(.*/)?([^/]*\\\\.framework)/(.*)$\")\n"
  165. << indent.Next() << "set(" << this->TmpVarPrefix
  166. << "_dir \"${CMAKE_MATCH_1}\")\n"
  167. << indent.Next() << "set(" << this->TmpVarPrefix
  168. << "_name \"${CMAKE_MATCH_2}\")\n"
  169. << indent.Next() << "set(" << this->TmpVarPrefix
  170. << "_file \"${CMAKE_MATCH_3}\")\n"
  171. << indent.Next() << "set(" << this->TmpVarPrefix << "_path \"${"
  172. << this->TmpVarPrefix << "_dir}${" << this->TmpVarPrefix << "_name}\")\n";
  173. auto depName = cmStrCat(this->TmpVarPrefix, "_path");
  174. this->AddInstallRule(
  175. os, this->GetDestination(config), cmInstallType_DIRECTORY, {}, false,
  176. this->Permissions.c_str(), nullptr, nullptr, " USE_SOURCE_PERMISSIONS",
  177. indent.Next(), depName.c_str());
  178. auto depNameVar = cmStrCat("${", this->TmpVarPrefix, "_name}/${",
  179. this->TmpVarPrefix, "_file}");
  180. this->GenerateInstallNameFixup(os, config, evaluatedRPaths,
  181. cmStrCat("${", this->TmpVarPrefix, "_dep}"),
  182. depNameVar, indent.Next());
  183. os << indent << "endif()\n";
  184. }
  185. void cmInstallRuntimeDependencySetGenerator::GenerateInstallNameFixup(
  186. std::ostream& os, const std::string& config,
  187. const std::vector<std::string>& evaluatedRPaths, const std::string& filename,
  188. const std::string& depName, Indent indent)
  189. {
  190. if (!(this->NoInstallRPath && this->NoInstallName)) {
  191. auto indent2 = indent;
  192. if (evaluatedRPaths.empty() && this->NoInstallName) {
  193. indent2 = indent2.Next();
  194. os << indent << "if(" << this->RPathPrefix << "_" << filename << ")\n";
  195. }
  196. os << indent2 << "set(" << this->TmpVarPrefix << "_rpath_args)\n";
  197. if (!this->NoInstallRPath) {
  198. os << indent2 << "foreach(" << this->TmpVarPrefix << "_rpath IN LISTS "
  199. << this->RPathPrefix << '_' << filename << ")\n"
  200. << indent2.Next() << "list(APPEND " << this->TmpVarPrefix
  201. << "_rpath_args -delete_rpath \"${" << this->TmpVarPrefix
  202. << "_rpath}\")\n"
  203. << indent2 << "endforeach()\n";
  204. }
  205. os << indent2 << "execute_process(COMMAND \""
  206. << this->LocalGenerator->GetMakefile()->GetSafeDefinition(
  207. "CMAKE_INSTALL_NAME_TOOL")
  208. << "\" ${" << this->TmpVarPrefix << "_rpath_args}\n";
  209. if (!this->NoInstallRPath) {
  210. for (auto const& rpath : evaluatedRPaths) {
  211. os << indent2 << " -add_rpath "
  212. << cmOutputConverter::EscapeForCMake(rpath) << "\n";
  213. }
  214. }
  215. if (!this->NoInstallName) {
  216. os << indent2 << " -id \"${" << this->TmpVarPrefix
  217. << "_install_name_dir}" << depName << "\"\n";
  218. }
  219. os << indent2 << " \""
  220. << GetDestDirPath(
  221. ConvertToAbsoluteDestination(this->GetDestination(config)))
  222. << "/" << depName << "\")\n";
  223. if (evaluatedRPaths.empty() && this->NoInstallName) {
  224. os << indent << "endif()\n";
  225. }
  226. }
  227. }
  228. void cmInstallRuntimeDependencySetGenerator::GenerateStripFixup(
  229. std::ostream& os, const std::string& config, const std::string& depName,
  230. Indent indent)
  231. {
  232. std::string strip =
  233. this->LocalGenerator->GetMakefile()->GetSafeDefinition("CMAKE_STRIP");
  234. if (!strip.empty()) {
  235. os << indent << "if(CMAKE_INSTALL_DO_STRIP)\n"
  236. << indent.Next() << "execute_process(COMMAND \"" << strip << "\" ";
  237. if (this->LocalGenerator->GetMakefile()->GetSafeDefinition(
  238. "CMAKE_HOST_SYSTEM_NAME") == "Darwin") {
  239. os << "-x ";
  240. }
  241. os << "\""
  242. << GetDestDirPath(
  243. ConvertToAbsoluteDestination(this->GetDestination(config)))
  244. << "/" << depName << "\")\n"
  245. << indent << "endif()\n";
  246. }
  247. }
  248. std::string cmInstallRuntimeDependencySetGenerator::GetDestination(
  249. std::string const& config) const
  250. {
  251. return cmGeneratorExpression::Evaluate(this->Destination,
  252. this->LocalGenerator, config);
  253. }