/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 | } |