cmBinUtilsWindowsPELinker.cxx 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  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 "cmBinUtilsWindowsPELinker.h"
  4. #include <algorithm>
  5. #include <iterator>
  6. #include <sstream>
  7. #include <utility>
  8. #include <vector>
  9. #include <cm/memory>
  10. #include "cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.h"
  11. #include "cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.h"
  12. #include "cmRuntimeDependencyArchive.h"
  13. #include "cmStringAlgorithms.h"
  14. #include "cmSystemTools.h"
  15. #ifdef _WIN32
  16. # include <windows.h>
  17. # include "cmsys/Encoding.hxx"
  18. #endif
  19. #ifdef _WIN32
  20. namespace {
  21. void ReplaceWithActualNameCasing(std::string& path)
  22. {
  23. WIN32_FIND_DATAW findData;
  24. HANDLE hFind = ::FindFirstFileW(
  25. cmsys::Encoding::ToWindowsExtendedPath(path).c_str(), &findData);
  26. if (hFind != INVALID_HANDLE_VALUE) {
  27. auto onDiskName = cmsys::Encoding::ToNarrow(findData.cFileName);
  28. ::FindClose(hFind);
  29. path.replace(path.end() - onDiskName.size(), path.end(), onDiskName);
  30. }
  31. }
  32. }
  33. #endif
  34. cmBinUtilsWindowsPELinker::cmBinUtilsWindowsPELinker(
  35. cmRuntimeDependencyArchive* archive)
  36. : cmBinUtilsLinker(archive)
  37. {
  38. }
  39. bool cmBinUtilsWindowsPELinker::Prepare()
  40. {
  41. std::string tool = this->Archive->GetGetRuntimeDependenciesTool();
  42. if (tool.empty()) {
  43. std::vector<std::string> command;
  44. if (this->Archive->GetGetRuntimeDependenciesCommand("dumpbin", command)) {
  45. tool = "dumpbin";
  46. } else {
  47. tool = "objdump";
  48. }
  49. }
  50. if (tool == "dumpbin") {
  51. this->Tool =
  52. cm::make_unique<cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool>(
  53. this->Archive);
  54. } else if (tool == "objdump") {
  55. this->Tool =
  56. cm::make_unique<cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool>(
  57. this->Archive);
  58. } else {
  59. std::ostringstream e;
  60. e << "Invalid value for CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL: " << tool;
  61. this->SetError(e.str());
  62. return false;
  63. }
  64. return true;
  65. }
  66. bool cmBinUtilsWindowsPELinker::ScanDependencies(
  67. std::string const& file, cmStateEnums::TargetType /* unused */)
  68. {
  69. std::vector<std::string> needed;
  70. if (!this->Tool->GetFileInfo(file, needed)) {
  71. return false;
  72. }
  73. struct WinPEDependency
  74. {
  75. WinPEDependency(std::string o)
  76. : Original(std::move(o))
  77. , LowerCase(cmSystemTools::LowerCase(Original))
  78. {
  79. }
  80. std::string const Original;
  81. std::string const LowerCase;
  82. };
  83. std::vector<WinPEDependency> depends;
  84. depends.reserve(needed.size());
  85. std::move(needed.begin(), needed.end(), std::back_inserter(depends));
  86. std::string origin = cmSystemTools::GetFilenamePath(file);
  87. for (auto const& lib : depends) {
  88. if (!this->Archive->IsPreExcluded(lib.LowerCase)) {
  89. std::string path;
  90. bool resolved = false;
  91. if (!this->ResolveDependency(lib.LowerCase, origin, path, resolved)) {
  92. return false;
  93. }
  94. if (resolved) {
  95. if (!this->Archive->IsPostExcluded(path)) {
  96. #ifdef _WIN32
  97. ReplaceWithActualNameCasing(path);
  98. #else
  99. path.replace(path.end() - lib.Original.size(), path.end(),
  100. lib.Original);
  101. #endif
  102. bool unique;
  103. this->Archive->AddResolvedPath(lib.Original, path, unique);
  104. if (unique &&
  105. !this->ScanDependencies(path, cmStateEnums::SHARED_LIBRARY)) {
  106. return false;
  107. }
  108. }
  109. } else {
  110. this->Archive->AddUnresolvedPath(lib.Original);
  111. }
  112. }
  113. }
  114. return true;
  115. }
  116. bool cmBinUtilsWindowsPELinker::ResolveDependency(std::string const& name,
  117. std::string const& origin,
  118. std::string& path,
  119. bool& resolved)
  120. {
  121. auto dirs = this->Archive->GetSearchDirectories();
  122. #ifdef _WIN32
  123. char buf[MAX_PATH];
  124. unsigned int len;
  125. if ((len = GetWindowsDirectoryA(buf, MAX_PATH)) > 0) {
  126. dirs.insert(dirs.begin(), std::string(buf, len));
  127. }
  128. if ((len = GetSystemDirectoryA(buf, MAX_PATH)) > 0) {
  129. dirs.insert(dirs.begin(), std::string(buf, len));
  130. }
  131. #endif
  132. dirs.insert(dirs.begin(), origin);
  133. for (auto const& searchPath : dirs) {
  134. path = cmStrCat(searchPath, '/', name);
  135. if (cmSystemTools::PathExists(path)) {
  136. resolved = true;
  137. return true;
  138. }
  139. }
  140. resolved = false;
  141. return true;
  142. }