cmBinUtilsLinuxELFLinker.cxx 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  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 "cmBinUtilsLinuxELFLinker.h"
  4. #include "cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.h"
  5. #include "cmLDConfigLDConfigTool.h"
  6. #include "cmMakefile.h"
  7. #include "cmMessageType.h"
  8. #include "cmRuntimeDependencyArchive.h"
  9. #include "cmStringAlgorithms.h"
  10. #include "cmSystemTools.h"
  11. #include <cmsys/RegularExpression.hxx>
  12. #include <sstream>
  13. #include "cm_memory.hxx"
  14. static std::string ReplaceOrigin(const std::string& rpath,
  15. const std::string& origin)
  16. {
  17. static const cmsys::RegularExpression originRegex(
  18. "(\\$ORIGIN)([^a-zA-Z0-9_]|$)");
  19. static const cmsys::RegularExpression originCurlyRegex("\\${ORIGIN}");
  20. cmsys::RegularExpressionMatch match;
  21. if (originRegex.find(rpath.c_str(), match)) {
  22. std::string begin = rpath.substr(0, match.start(1));
  23. std::string end = rpath.substr(match.end(1));
  24. return begin + origin + end;
  25. }
  26. if (originCurlyRegex.find(rpath.c_str(), match)) {
  27. std::string begin = rpath.substr(0, match.start());
  28. std::string end = rpath.substr(match.end());
  29. return begin + origin + end;
  30. }
  31. return rpath;
  32. }
  33. cmBinUtilsLinuxELFLinker::cmBinUtilsLinuxELFLinker(
  34. cmRuntimeDependencyArchive* archive)
  35. : cmBinUtilsLinker(archive)
  36. {
  37. }
  38. bool cmBinUtilsLinuxELFLinker::Prepare()
  39. {
  40. std::string tool = this->Archive->GetGetRuntimeDependenciesTool();
  41. if (tool.empty()) {
  42. tool = "objdump";
  43. }
  44. if (tool == "objdump") {
  45. this->Tool =
  46. cm::make_unique<cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool>(
  47. this->Archive);
  48. } else {
  49. std::ostringstream e;
  50. e << "Invalid value for CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL: " << tool;
  51. this->SetError(e.str());
  52. return false;
  53. }
  54. std::string ldConfigTool =
  55. this->Archive->GetMakefile()->GetSafeDefinition("CMAKE_LDCONFIG_TOOL");
  56. if (ldConfigTool.empty()) {
  57. ldConfigTool = "ldconfig";
  58. }
  59. if (ldConfigTool == "ldconfig") {
  60. this->LDConfigTool =
  61. cm::make_unique<cmLDConfigLDConfigTool>(this->Archive);
  62. } else {
  63. std::ostringstream e;
  64. e << "Invalid value for CMAKE_LDCONFIG_TOOL: " << ldConfigTool;
  65. this->SetError(e.str());
  66. return false;
  67. }
  68. return true;
  69. }
  70. bool cmBinUtilsLinuxELFLinker::ScanDependencies(
  71. std::string const& file, cmStateEnums::TargetType /* unused */)
  72. {
  73. std::vector<std::string> parentRpaths;
  74. return this->ScanDependencies(file, parentRpaths);
  75. }
  76. bool cmBinUtilsLinuxELFLinker::ScanDependencies(
  77. std::string const& file, std::vector<std::string> const& parentRpaths)
  78. {
  79. std::string origin = cmSystemTools::GetFilenamePath(file);
  80. std::vector<std::string> needed;
  81. std::vector<std::string> rpaths;
  82. std::vector<std::string> runpaths;
  83. if (!this->Tool->GetFileInfo(file, needed, rpaths, runpaths)) {
  84. return false;
  85. }
  86. for (auto& runpath : runpaths) {
  87. runpath = ReplaceOrigin(runpath, origin);
  88. }
  89. for (auto& rpath : rpaths) {
  90. rpath = ReplaceOrigin(rpath, origin);
  91. }
  92. std::vector<std::string> searchPaths;
  93. if (!runpaths.empty()) {
  94. searchPaths = runpaths;
  95. } else {
  96. searchPaths = rpaths;
  97. searchPaths.insert(searchPaths.end(), parentRpaths.begin(),
  98. parentRpaths.end());
  99. }
  100. std::vector<std::string> ldConfigPaths;
  101. if (!this->LDConfigTool->GetLDConfigPaths(ldConfigPaths)) {
  102. return false;
  103. }
  104. searchPaths.insert(searchPaths.end(), ldConfigPaths.begin(),
  105. ldConfigPaths.end());
  106. for (auto const& dep : needed) {
  107. if (!this->Archive->IsPreExcluded(dep)) {
  108. std::string path;
  109. bool resolved = false;
  110. if (dep.find('/') != std::string::npos) {
  111. this->SetError("Paths to dependencies are not supported");
  112. return false;
  113. }
  114. if (!this->ResolveDependency(dep, searchPaths, path, resolved)) {
  115. return false;
  116. }
  117. if (resolved) {
  118. if (!this->Archive->IsPostExcluded(path)) {
  119. bool unique;
  120. this->Archive->AddResolvedPath(dep, path, unique);
  121. if (unique && !this->ScanDependencies(path, rpaths)) {
  122. return false;
  123. }
  124. }
  125. } else {
  126. this->Archive->AddUnresolvedPath(dep);
  127. }
  128. }
  129. }
  130. return true;
  131. }
  132. bool cmBinUtilsLinuxELFLinker::ResolveDependency(
  133. std::string const& name, std::vector<std::string> const& searchPaths,
  134. std::string& path, bool& resolved)
  135. {
  136. for (auto const& searchPath : searchPaths) {
  137. path = cmStrCat(searchPath, '/', name);
  138. if (cmSystemTools::PathExists(path)) {
  139. resolved = true;
  140. return true;
  141. }
  142. }
  143. for (auto const& searchPath : this->Archive->GetSearchDirectories()) {
  144. path = cmStrCat(searchPath, '/', name);
  145. if (cmSystemTools::PathExists(path)) {
  146. std::ostringstream warning;
  147. warning << "Dependency " << name << " found in search directory:\n "
  148. << searchPath
  149. << "\nSee file(GET_RUNTIME_DEPENDENCIES) documentation for "
  150. << "more information.";
  151. this->Archive->GetMakefile()->IssueMessage(MessageType::WARNING,
  152. warning.str());
  153. resolved = true;
  154. return true;
  155. }
  156. }
  157. resolved = false;
  158. return true;
  159. }