Coverage Report

Created: 2026-03-12 06:35

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