CMake Nightly Date Stamp
[kiteware-cmake.git] / Source / cmRuntimeDependencyArchive.cxx
blob2fbf2fa04c8be678ffaa2989ea105f6d3929a561
1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing for details. */
4 #include "cmRuntimeDependencyArchive.h"
6 #include <algorithm>
7 #include <sstream>
8 #include <string>
9 #include <utility>
10 #include <vector>
12 #include <cm/memory>
14 #include "cmBinUtilsLinuxELFLinker.h"
15 #include "cmBinUtilsMacOSMachOLinker.h"
16 #include "cmBinUtilsWindowsPELinker.h"
17 #include "cmExecutionStatus.h"
18 #include "cmList.h"
19 #include "cmMakefile.h"
20 #include "cmStateTypes.h"
21 #include "cmSystemTools.h"
23 #if defined(_WIN32)
24 # include "cmGlobalGenerator.h"
25 # ifndef CMAKE_BOOTSTRAP
26 # include "cmGlobalVisualStudioVersionedGenerator.h"
27 # endif
28 # include "cmsys/Glob.hxx"
30 # include "cmVSSetupHelper.h"
31 #endif
33 #if defined(_WIN32)
34 static void AddVisualStudioPath(std::vector<std::string>& paths,
35 const std::string& prefix,
36 unsigned int version, cmGlobalGenerator* gg)
38 // If generating for the VS IDE, use the same instance.
39 std::string vsloc;
40 bool found = false;
41 # ifndef CMAKE_BOOTSTRAP
42 if (cmHasPrefix(gg->GetName(), prefix)) {
43 cmGlobalVisualStudioVersionedGenerator* vsgen =
44 static_cast<cmGlobalVisualStudioVersionedGenerator*>(gg);
45 if (vsgen->GetVSInstance(vsloc)) {
46 found = true;
49 # endif
51 // Otherwise, find a VS instance ourselves.
52 if (!found) {
53 cmVSSetupAPIHelper vsSetupAPIHelper(version);
54 if (vsSetupAPIHelper.GetVSInstanceInfo(vsloc)) {
55 cmSystemTools::ConvertToUnixSlashes(vsloc);
56 found = true;
60 if (found) {
61 cmsys::Glob glob;
62 glob.SetListDirs(true);
63 glob.FindFiles(vsloc + "/VC/Tools/MSVC/*");
64 for (auto const& vcdir : glob.GetFiles()) {
65 paths.push_back(vcdir + "/bin/Hostx64/x64");
66 paths.push_back(vcdir + "/bin/Hostx86/x64");
67 paths.push_back(vcdir + "/bin/Hostx64/x86");
68 paths.push_back(vcdir + "/bin/Hostx86/x86");
73 static void AddRegistryPath(std::vector<std::string>& paths,
74 const std::string& path, cmMakefile* mf)
76 // We should view the registry as the target application would view
77 // it.
78 cmSystemTools::KeyWOW64 view = cmSystemTools::KeyWOW64_32;
79 cmSystemTools::KeyWOW64 other_view = cmSystemTools::KeyWOW64_64;
80 if (mf->PlatformIs64Bit()) {
81 view = cmSystemTools::KeyWOW64_64;
82 other_view = cmSystemTools::KeyWOW64_32;
85 // Expand using the view of the target application.
86 std::string expanded = path;
87 cmSystemTools::ExpandRegistryValues(expanded, view);
88 cmSystemTools::GlobDirs(expanded, paths);
90 // Executables can be either 32-bit or 64-bit, so expand using the
91 // alternative view.
92 expanded = path;
93 cmSystemTools::ExpandRegistryValues(expanded, other_view);
94 cmSystemTools::GlobDirs(expanded, paths);
97 static void AddEnvPath(std::vector<std::string>& paths, const std::string& var,
98 const std::string& suffix)
100 std::string value;
101 if (cmSystemTools::GetEnv(var, value)) {
102 paths.push_back(value + suffix);
105 #endif
107 static cmsys::RegularExpression TransformCompile(const std::string& str)
109 return cmsys::RegularExpression(str);
112 cmRuntimeDependencyArchive::cmRuntimeDependencyArchive(
113 cmExecutionStatus& status, std::vector<std::string> searchDirectories,
114 std::string bundleExecutable,
115 const std::vector<std::string>& preIncludeRegexes,
116 const std::vector<std::string>& preExcludeRegexes,
117 const std::vector<std::string>& postIncludeRegexes,
118 const std::vector<std::string>& postExcludeRegexes,
119 std::vector<std::string> postIncludeFiles,
120 std::vector<std::string> postExcludeFiles,
121 std::vector<std::string> postExcludeFilesStrict)
122 : Status(status)
123 , SearchDirectories(std::move(searchDirectories))
124 , BundleExecutable(std::move(bundleExecutable))
125 , PreIncludeRegexes(preIncludeRegexes.size())
126 , PreExcludeRegexes(preExcludeRegexes.size())
127 , PostIncludeRegexes(postIncludeRegexes.size())
128 , PostExcludeRegexes(postExcludeRegexes.size())
129 , PostIncludeFiles(std::move(postIncludeFiles))
130 , PostExcludeFiles(std::move(postExcludeFiles))
131 , PostExcludeFilesStrict(std::move(postExcludeFilesStrict))
133 std::transform(preIncludeRegexes.begin(), preIncludeRegexes.end(),
134 this->PreIncludeRegexes.begin(), TransformCompile);
135 std::transform(preExcludeRegexes.begin(), preExcludeRegexes.end(),
136 this->PreExcludeRegexes.begin(), TransformCompile);
137 std::transform(postIncludeRegexes.begin(), postIncludeRegexes.end(),
138 this->PostIncludeRegexes.begin(), TransformCompile);
139 std::transform(postExcludeRegexes.begin(), postExcludeRegexes.end(),
140 this->PostExcludeRegexes.begin(), TransformCompile);
143 bool cmRuntimeDependencyArchive::Prepare()
145 std::string platform = this->GetMakefile()->GetSafeDefinition(
146 "CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM");
147 if (platform.empty()) {
148 std::string systemName =
149 this->GetMakefile()->GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME");
150 if (systemName == "Windows") {
151 platform = "windows+pe";
152 } else if (systemName == "Darwin") {
153 platform = "macos+macho";
154 } else if (systemName == "Linux") {
155 platform = "linux+elf";
158 if (platform == "linux+elf") {
159 this->Linker = cm::make_unique<cmBinUtilsLinuxELFLinker>(this);
160 } else if (platform == "windows+pe") {
161 this->Linker = cm::make_unique<cmBinUtilsWindowsPELinker>(this);
162 } else if (platform == "macos+macho") {
163 this->Linker = cm::make_unique<cmBinUtilsMacOSMachOLinker>(this);
164 } else {
165 std::ostringstream e;
166 e << "Invalid value for CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM: "
167 << platform;
168 this->SetError(e.str());
169 return false;
172 return this->Linker->Prepare();
175 bool cmRuntimeDependencyArchive::GetRuntimeDependencies(
176 const std::vector<std::string>& executables,
177 const std::vector<std::string>& libraries,
178 const std::vector<std::string>& modules)
180 for (auto const& exe : executables) {
181 if (!this->Linker->ScanDependencies(exe, cmStateEnums::EXECUTABLE)) {
182 return false;
185 for (auto const& lib : libraries) {
186 if (!this->Linker->ScanDependencies(lib, cmStateEnums::SHARED_LIBRARY)) {
187 return false;
190 return std::all_of(
191 modules.begin(), modules.end(), [this](std::string const& mod) -> bool {
192 return this->Linker->ScanDependencies(mod, cmStateEnums::MODULE_LIBRARY);
196 void cmRuntimeDependencyArchive::SetError(const std::string& e)
198 this->Status.SetError(e);
201 const std::string& cmRuntimeDependencyArchive::GetBundleExecutable() const
203 return this->BundleExecutable;
206 const std::vector<std::string>&
207 cmRuntimeDependencyArchive::GetSearchDirectories() const
209 return this->SearchDirectories;
212 const std::string& cmRuntimeDependencyArchive::GetGetRuntimeDependenciesTool()
213 const
215 return this->GetMakefile()->GetSafeDefinition(
216 "CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL");
219 bool cmRuntimeDependencyArchive::GetGetRuntimeDependenciesCommand(
220 const std::string& search, std::vector<std::string>& command) const
222 // First see if it was supplied by the user
223 std::string toolCommand = this->GetMakefile()->GetSafeDefinition(
224 "CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND");
225 if (toolCommand.empty() && search == "objdump") {
226 toolCommand = this->GetMakefile()->GetSafeDefinition("CMAKE_OBJDUMP");
228 if (!toolCommand.empty()) {
229 cmExpandList(toolCommand, command);
230 return true;
233 // Now go searching for it
234 std::vector<std::string> paths;
235 #ifdef _WIN32
236 cmGlobalGenerator* gg = this->GetMakefile()->GetGlobalGenerator();
238 // Add newer Visual Studio paths
239 AddVisualStudioPath(paths, "Visual Studio 17 ", 17, gg);
240 AddVisualStudioPath(paths, "Visual Studio 16 ", 16, gg);
241 AddVisualStudioPath(paths, "Visual Studio 15 ", 15, gg);
243 // Add older Visual Studio paths
244 AddRegistryPath(
245 paths,
246 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\14.0;InstallDir]/"
247 "../../VC/bin",
248 this->GetMakefile());
249 AddEnvPath(paths, "VS140COMNTOOLS", "/../../VC/bin");
250 paths.push_back(
251 "C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin");
252 AddRegistryPath(
253 paths,
254 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\12.0;InstallDir]/"
255 "../../VC/bin",
256 this->GetMakefile());
257 AddEnvPath(paths, "VS120COMNTOOLS", "/../../VC/bin");
258 paths.push_back(
259 "C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/bin");
260 AddRegistryPath(
261 paths,
262 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\11.0;InstallDir]/"
263 "../../VC/bin",
264 this->GetMakefile());
265 AddEnvPath(paths, "VS110COMNTOOLS", "/../../VC/bin");
266 paths.push_back(
267 "C:/Program Files (x86)/Microsoft Visual Studio 11.0/VC/bin");
268 AddRegistryPath(
269 paths,
270 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\10.0;InstallDir]/"
271 "../../VC/bin",
272 this->GetMakefile());
273 AddEnvPath(paths, "VS100COMNTOOLS", "/../../VC/bin");
274 paths.push_back(
275 "C:/Program Files (x86)/Microsoft Visual Studio 10.0/VC/bin");
276 AddRegistryPath(
277 paths,
278 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\9.0;InstallDir]/"
279 "../../VC/bin",
280 this->GetMakefile());
281 AddEnvPath(paths, "VS90COMNTOOLS", "/../../VC/bin");
282 paths.push_back("C:/Program Files/Microsoft Visual Studio 9.0/VC/bin");
283 paths.push_back("C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/bin");
284 AddRegistryPath(
285 paths,
286 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0;InstallDir]/"
287 "../../VC/bin",
288 this->GetMakefile());
289 AddEnvPath(paths, "VS80COMNTOOLS", "/../../VC/bin");
290 paths.push_back("C:/Program Files/Microsoft Visual Studio 8/VC/BIN");
291 paths.push_back("C:/Program Files (x86)/Microsoft Visual Studio 8/VC/BIN");
292 AddRegistryPath(
293 paths,
294 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\7.1;InstallDir]/"
295 "../../VC7/bin",
296 this->GetMakefile());
297 AddEnvPath(paths, "VS71COMNTOOLS", "/../../VC7/bin");
298 paths.push_back(
299 "C:/Program Files/Microsoft Visual Studio .NET 2003/VC7/BIN");
300 paths.push_back(
301 "C:/Program Files (x86)/Microsoft Visual Studio .NET 2003/VC7/BIN");
302 #endif
304 std::string program = cmSystemTools::FindProgram(search, paths);
305 if (!program.empty()) {
306 command = { program };
307 return true;
310 // Couldn't find it
311 return false;
314 bool cmRuntimeDependencyArchive::IsPreExcluded(const std::string& name) const
316 cmsys::RegularExpressionMatch match;
317 auto const regexMatch =
318 [&match, name](const cmsys::RegularExpression& regex) -> bool {
319 return regex.find(name.c_str(), match);
321 auto const regexSearch =
322 [&regexMatch](
323 const std::vector<cmsys::RegularExpression>& regexes) -> bool {
324 return std::any_of(regexes.begin(), regexes.end(), regexMatch);
327 return !regexSearch(this->PreIncludeRegexes) &&
328 regexSearch(this->PreExcludeRegexes);
331 bool cmRuntimeDependencyArchive::IsPostExcluded(const std::string& name) const
333 cmsys::RegularExpressionMatch match;
334 auto const regexMatch =
335 [&match, name](const cmsys::RegularExpression& regex) -> bool {
336 return regex.find(name.c_str(), match);
338 auto const regexSearch =
339 [&regexMatch](
340 const std::vector<cmsys::RegularExpression>& regexes) -> bool {
341 return std::any_of(regexes.begin(), regexes.end(), regexMatch);
343 auto const fileMatch = [name](const std::string& file) -> bool {
344 return cmSystemTools::SameFile(file, name);
346 auto const fileSearch =
347 [&fileMatch](const std::vector<std::string>& files) -> bool {
348 return std::any_of(files.begin(), files.end(), fileMatch);
351 return fileSearch(this->PostExcludeFilesStrict) ||
352 (!(regexSearch(this->PostIncludeRegexes) ||
353 fileSearch(this->PostIncludeFiles)) &&
354 (regexSearch(this->PostExcludeRegexes) ||
355 fileSearch(this->PostExcludeFiles)));
358 void cmRuntimeDependencyArchive::AddResolvedPath(
359 const std::string& name, const std::string& path, bool& unique,
360 std::vector<std::string> rpaths)
362 auto it = this->ResolvedPaths.emplace(name, std::set<std::string>{}).first;
363 unique = true;
364 for (auto const& other : it->second) {
365 if (cmSystemTools::SameFile(path, other)) {
366 unique = false;
367 break;
370 it->second.insert(path);
371 this->RPaths[path] = std::move(rpaths);
374 void cmRuntimeDependencyArchive::AddUnresolvedPath(const std::string& name)
376 this->UnresolvedPaths.insert(name);
379 cmMakefile* cmRuntimeDependencyArchive::GetMakefile() const
381 return &this->Status.GetMakefile();
384 const std::map<std::string, std::set<std::string>>&
385 cmRuntimeDependencyArchive::GetResolvedPaths() const
387 return this->ResolvedPaths;
390 const std::set<std::string>& cmRuntimeDependencyArchive::GetUnresolvedPaths()
391 const
393 return this->UnresolvedPaths;
396 const std::map<std::string, std::vector<std::string>>&
397 cmRuntimeDependencyArchive::GetRPaths() const
399 return this->RPaths;
402 bool cmRuntimeDependencyArchive::PlatformSupportsRuntimeDependencies(
403 const std::string& platform)
405 static const std::set<std::string> supportedPlatforms = { "Windows", "Linux",
406 "Darwin" };
407 return supportedPlatforms.count(platform);