/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 <cstddef> |
8 | | #include <iterator> |
9 | | #include <utility> |
10 | | #include <vector> |
11 | | |
12 | | #include <cm/filesystem> |
13 | | #include <cm/memory> |
14 | | |
15 | | #include "cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.h" |
16 | | #include "cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.h" |
17 | | #include "cmRuntimeDependencyArchive.h" |
18 | | #include "cmStringAlgorithms.h" |
19 | | #include "cmSystemTools.h" |
20 | | #include "cmTargetTypes.h" |
21 | | |
22 | | #ifdef _WIN32 |
23 | | # include <windows.h> |
24 | | |
25 | | # include "cmsys/Encoding.hxx" |
26 | | #else |
27 | | # include "cmsys/Directory.hxx" |
28 | | #endif |
29 | | |
30 | | namespace { |
31 | | |
32 | | #ifdef _WIN32 |
33 | | std::string ReplaceWithActualNameCasing(std::string path) |
34 | | { |
35 | | WIN32_FIND_DATAW findData; |
36 | | HANDLE hFind = ::FindFirstFileW( |
37 | | cmsys::Encoding::ToWindowsExtendedPath(path).c_str(), &findData); |
38 | | if (hFind != INVALID_HANDLE_VALUE) { |
39 | | auto onDiskName = cmsys::Encoding::ToNarrow(findData.cFileName); |
40 | | ::FindClose(hFind); |
41 | | path.replace(path.end() - onDiskName.size(), path.end(), onDiskName); |
42 | | } |
43 | | return path; |
44 | | } |
45 | | #else |
46 | | bool FindCaseInsensitive(std::string const& dir, std::string const& lowerName, |
47 | | std::string& foundPath) |
48 | 0 | { |
49 | 0 | if (!cmSystemTools::FileIsDirectory(dir)) { |
50 | 0 | return false; |
51 | 0 | } |
52 | 0 | cmsys::Directory directory; |
53 | 0 | if (!directory.Load(dir)) { |
54 | 0 | return false; |
55 | 0 | } |
56 | 0 | for (std::size_t i = 0; i < directory.GetNumberOfFiles(); ++i) { |
57 | 0 | cm::filesystem::path fileName = directory.GetFile(i); |
58 | |
|
59 | 0 | if (cmSystemTools::LowerCase(fileName) == lowerName) { |
60 | 0 | foundPath += dir / fileName; |
61 | 0 | return true; |
62 | 0 | } |
63 | 0 | } |
64 | | |
65 | 0 | return false; |
66 | 0 | } |
67 | | #endif |
68 | | } |
69 | | |
70 | | cmBinUtilsWindowsPELinker::cmBinUtilsWindowsPELinker( |
71 | | cmRuntimeDependencyArchive* archive) |
72 | 0 | : cmBinUtilsLinker(archive) |
73 | 0 | { |
74 | 0 | } |
75 | | |
76 | | bool cmBinUtilsWindowsPELinker::Prepare() |
77 | 0 | { |
78 | 0 | std::string tool = this->Archive->GetGetRuntimeDependenciesTool(); |
79 | 0 | if (tool.empty()) { |
80 | 0 | std::vector<std::string> command; |
81 | 0 | if (this->Archive->GetGetRuntimeDependenciesCommand("dumpbin", command)) { |
82 | 0 | tool = "dumpbin"; |
83 | 0 | } else { |
84 | 0 | tool = "objdump"; |
85 | 0 | } |
86 | 0 | } |
87 | 0 | if (tool == "dumpbin") { |
88 | 0 | this->Tool = |
89 | 0 | cm::make_unique<cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool>( |
90 | 0 | this->Archive); |
91 | 0 | } else if (tool == "objdump") { |
92 | 0 | this->Tool = |
93 | 0 | cm::make_unique<cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool>( |
94 | 0 | this->Archive); |
95 | 0 | } else { |
96 | 0 | this->SetError(cmStrCat( |
97 | 0 | "Invalid value for CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL: ", tool)); |
98 | 0 | return false; |
99 | 0 | } |
100 | | |
101 | 0 | return true; |
102 | 0 | } |
103 | | |
104 | | cmBinUtilsWindowsPELinker::Dependency::Dependency(std::string casedName) |
105 | 0 | : CasedName(std::move(casedName)) |
106 | 0 | , LowerName(cmSystemTools::LowerCase(CasedName)) |
107 | 0 | { |
108 | 0 | } |
109 | | |
110 | | bool cmBinUtilsWindowsPELinker::ScanDependencies(std::string const& file, |
111 | | cm::TargetType /* unused */) |
112 | 0 | { |
113 | 0 | std::vector<std::string> needed; |
114 | 0 | if (!this->Tool->GetFileInfo(file, needed)) { |
115 | 0 | return false; |
116 | 0 | } |
117 | | |
118 | 0 | std::vector<Dependency> depends; |
119 | 0 | depends.reserve(needed.size()); |
120 | 0 | std::move(needed.begin(), needed.end(), std::back_inserter(depends)); |
121 | 0 | std::string origin = cmSystemTools::GetFilenamePath(file); |
122 | |
|
123 | 0 | for (Dependency const& lib : depends) { |
124 | 0 | if (this->Archive->IsPreExcluded(lib.LowerName)) { |
125 | 0 | continue; |
126 | 0 | } |
127 | 0 | Dependency path; |
128 | 0 | bool resolved = false; |
129 | 0 | if (!this->ResolveDependency(lib, origin, path, resolved)) { |
130 | 0 | return false; |
131 | 0 | } |
132 | 0 | if (resolved) { |
133 | 0 | if (this->Archive->IsPostExcluded(path.LowerName, path.CasedName)) { |
134 | 0 | continue; |
135 | 0 | } |
136 | 0 | bool unique; |
137 | 0 | this->Archive->AddResolvedPath(lib.CasedName, path.CasedName, unique); |
138 | 0 | if (unique && |
139 | 0 | !this->ScanDependencies(path.CasedName, |
140 | 0 | cm::TargetType::SHARED_LIBRARY)) { |
141 | 0 | return false; |
142 | 0 | } |
143 | 0 | } else { |
144 | 0 | this->Archive->AddUnresolvedPath(lib.CasedName); |
145 | 0 | } |
146 | 0 | } |
147 | | |
148 | 0 | return true; |
149 | 0 | } |
150 | | |
151 | | bool cmBinUtilsWindowsPELinker::ResolveDependency(Dependency const& lib, |
152 | | std::string const& origin, |
153 | | Dependency& path, |
154 | | bool& resolved) |
155 | 0 | { |
156 | 0 | auto dirs = this->Archive->GetSearchDirectories(); |
157 | |
|
158 | | #ifdef _WIN32 |
159 | | char buf[MAX_PATH]; |
160 | | unsigned int len; |
161 | | if ((len = GetWindowsDirectoryA(buf, MAX_PATH)) > 0) { |
162 | | dirs.insert(dirs.begin(), std::string(buf, len)); |
163 | | } |
164 | | if ((len = GetSystemDirectoryA(buf, MAX_PATH)) > 0) { |
165 | | dirs.insert(dirs.begin(), std::string(buf, len)); |
166 | | } |
167 | | #endif |
168 | |
|
169 | 0 | dirs.insert(dirs.begin(), origin); |
170 | |
|
171 | 0 | for (auto const& searchPath : dirs) { |
172 | | #ifdef _WIN32 |
173 | | path.LowerName = cmStrCat(searchPath, '/', lib.LowerName); |
174 | | if (!cmSystemTools::PathExists(path.LowerName)) { |
175 | | continue; |
176 | | } |
177 | | this->NormalizePath(path.LowerName); |
178 | | path.CasedName = ReplaceWithActualNameCasing(path.LowerName); |
179 | | #else |
180 | 0 | if (!FindCaseInsensitive(searchPath, lib.LowerName, path.CasedName)) { |
181 | 0 | continue; |
182 | 0 | } |
183 | 0 | this->NormalizePath(path.CasedName); |
184 | 0 | path.LowerName = [&lib](std::string libPath) -> std::string { |
185 | 0 | libPath.replace(libPath.end() - lib.LowerName.size(), libPath.end(), |
186 | 0 | lib.LowerName); |
187 | 0 | return libPath; |
188 | 0 | }(path.CasedName); |
189 | 0 | #endif |
190 | 0 | resolved = true; |
191 | 0 | return true; |
192 | 0 | } |
193 | | |
194 | 0 | resolved = false; |
195 | 0 | return true; |
196 | 0 | } |