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