Coverage Report

Created: 2026-07-14 07:09

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