| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying | |
| file LICENSE.rst or https://cmake.org/licensing for details. */ | |
| #include "cmRuntimeDependencyArchive.h" | |
| #include <algorithm> | |
| #include <string> | |
| #include <utility> | |
| #include <vector> | |
| #include <cm/memory> | |
| #include "cmBinUtilsLinuxELFLinker.h" | |
| #include "cmBinUtilsMacOSMachOLinker.h" | |
| #include "cmBinUtilsWindowsPELinker.h" | |
| #include "cmExecutionStatus.h" | |
| #include "cmList.h" | |
| #include "cmMakefile.h" | |
| #include "cmStringAlgorithms.h" | |
| #include "cmSystemTools.h" | |
| #include "cmTargetTypes.h" | |
| #if defined(_WIN32) | |
| # include "cmGlobalGenerator.h" | |
| # ifndef CMAKE_BOOTSTRAP | |
| # include "cmGlobalVisualStudioVersionedGenerator.h" | |
| # endif | |
| # include "cmsys/Glob.hxx" | |
| # include "cmVSSetupHelper.h" | |
| #endif | |
| #if defined(_WIN32) | |
| static void AddVisualStudioPath(std::vector<std::string>& paths, | |
| std::string const& prefix, | |
| unsigned int version, cmGlobalGenerator* gg) | |
| { | |
| // If generating for the VS IDE, use the same instance. | |
| std::string vsloc; | |
| bool found = false; | |
| # ifndef CMAKE_BOOTSTRAP | |
| if (cmHasPrefix(gg->GetName(), prefix)) { | |
| cmGlobalVisualStudioVersionedGenerator* vsgen = | |
| static_cast<cmGlobalVisualStudioVersionedGenerator*>(gg); | |
| if (vsgen->GetVSInstance(vsloc)) { | |
| found = true; | |
| } | |
| } | |
| # endif | |
| // Otherwise, find a VS instance ourselves. | |
| if (!found) { | |
| cmVSSetupAPIHelper vsSetupAPIHelper(version); | |
| if (vsSetupAPIHelper.GetVSInstanceInfo(vsloc)) { | |
| cmSystemTools::ConvertToUnixSlashes(vsloc); | |
| found = true; | |
| } | |
| } | |
| if (found) { | |
| cmsys::Glob glob; | |
| glob.SetListDirs(true); | |
| glob.FindFiles(vsloc + "/VC/Tools/MSVC/*"); | |
| for (auto const& vcdir : glob.GetFiles()) { | |
| paths.push_back(vcdir + "/bin/Hostx64/x64"); | |
| paths.push_back(vcdir + "/bin/Hostx86/x64"); | |
| paths.push_back(vcdir + "/bin/Hostx64/x86"); | |
| paths.push_back(vcdir + "/bin/Hostx86/x86"); | |
| } | |
| } | |
| } | |
| static void AddRegistryPath(std::vector<std::string>& paths, | |
| std::string const& path, cmMakefile* mf) | |
| { | |
| // We should view the registry as the target application would view | |
| // it. | |
| cmSystemTools::KeyWOW64 view = cmSystemTools::KeyWOW64_32; | |
| cmSystemTools::KeyWOW64 other_view = cmSystemTools::KeyWOW64_64; | |
| if (mf->PlatformIs64Bit()) { | |
| view = cmSystemTools::KeyWOW64_64; | |
| other_view = cmSystemTools::KeyWOW64_32; | |
| } | |
| // Expand using the view of the target application. | |
| std::string expanded = path; | |
| cmSystemTools::ExpandRegistryValues(expanded, view); | |
| cmSystemTools::GlobDirs(expanded, paths); | |
| // Executables can be either 32-bit or 64-bit, so expand using the | |
| // alternative view. | |
| expanded = path; | |
| cmSystemTools::ExpandRegistryValues(expanded, other_view); | |
| cmSystemTools::GlobDirs(expanded, paths); | |
| } | |
| static void AddEnvPath(std::vector<std::string>& paths, std::string const& var, | |
| std::string const& suffix) | |
| { | |
| std::string value; | |
| if (cmSystemTools::GetEnv(var, value)) { | |
| paths.push_back(value + suffix); | |
| } | |
| } | |
| #endif | |
| static cmsys::RegularExpression TransformCompile(std::string const& str) | |
| { | |
| return cmsys::RegularExpression(str); | |
| } | |
| cmRuntimeDependencyArchive::cmRuntimeDependencyArchive( | |
| cmExecutionStatus& status, std::vector<std::string> searchDirectories, | |
| std::string bundleExecutable, | |
| std::vector<std::string> const& preIncludeRegexes, | |
| std::vector<std::string> const& preExcludeRegexes, | |
| std::vector<std::string> const& postIncludeRegexes, | |
| std::vector<std::string> const& postExcludeRegexes, | |
| std::vector<std::string> postIncludeFiles, | |
| std::vector<std::string> postExcludeFiles, | |
| std::vector<std::string> postExcludeFilesStrict) | |
| : Status(status) | |
| , SearchDirectories(std::move(searchDirectories)) | |
| , BundleExecutable(std::move(bundleExecutable)) | |
| , PreIncludeRegexes(preIncludeRegexes.size()) | |
| , PreExcludeRegexes(preExcludeRegexes.size()) | |
| , PostIncludeRegexes(postIncludeRegexes.size()) | |
| , PostExcludeRegexes(postExcludeRegexes.size()) | |
| , PostIncludeFiles(std::move(postIncludeFiles)) | |
| , PostExcludeFiles(std::move(postExcludeFiles)) | |
| , PostExcludeFilesStrict(std::move(postExcludeFilesStrict)) | |
| { | |
| std::transform(preIncludeRegexes.begin(), preIncludeRegexes.end(), | |
| this->PreIncludeRegexes.begin(), TransformCompile); | |
| std::transform(preExcludeRegexes.begin(), preExcludeRegexes.end(), | |
| this->PreExcludeRegexes.begin(), TransformCompile); | |
| std::transform(postIncludeRegexes.begin(), postIncludeRegexes.end(), | |
| this->PostIncludeRegexes.begin(), TransformCompile); | |
| std::transform(postExcludeRegexes.begin(), postExcludeRegexes.end(), | |
| this->PostExcludeRegexes.begin(), TransformCompile); | |
| } | |
| bool cmRuntimeDependencyArchive::Prepare() | |
| { | |
| std::string platform = this->GetMakefile()->GetSafeDefinition( | |
| "CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM"); | |
| if (platform.empty()) { | |
| std::string systemName = | |
| this->GetMakefile()->GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME"); | |
| if (systemName == "Windows") { | |
| platform = "windows+pe"; | |
| } else if (systemName == "Darwin") { | |
| platform = "macos+macho"; | |
| } else if (systemName == "Linux") { | |
| platform = "linux+elf"; | |
| } else if (systemName == "FreeBSD") { | |
| platform = "freebsd+elf"; | |
| } | |
| } | |
| if (platform == "linux+elf" || platform == "freebsd+elf") { | |
| this->Linker = cm::make_unique<cmBinUtilsLinuxELFLinker>(this); | |
| } else if (platform == "windows+pe") { | |
| this->Linker = cm::make_unique<cmBinUtilsWindowsPELinker>(this); | |
| } else if (platform == "macos+macho") { | |
| this->Linker = cm::make_unique<cmBinUtilsMacOSMachOLinker>(this); | |
| } else { | |
| this->SetError( | |
| cmStrCat("Invalid value for CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM: ", | |
| platform)); | |
| return false; | |
| } | |
| return this->Linker->Prepare(); | |
| } | |
| bool cmRuntimeDependencyArchive::GetRuntimeDependencies( | |
| std::vector<std::string> const& executables, | |
| std::vector<std::string> const& libraries, | |
| std::vector<std::string> const& modules) | |
| { | |
| for (auto const& exe : executables) { | |
| if (!this->Linker->ScanDependencies(exe, cm::TargetType::EXECUTABLE)) { | |
| return false; | |
| } | |
| } | |
| for (auto const& lib : libraries) { | |
| if (!this->Linker->ScanDependencies(lib, cm::TargetType::SHARED_LIBRARY)) { | |
| return false; | |
| } | |
| } | |
| return std::all_of(modules.begin(), modules.end(), | |
| [this](std::string const& mod) -> bool { | |
| return this->Linker->ScanDependencies( | |
| mod, cm::TargetType::MODULE_LIBRARY); | |
| }); | |
| } | |
| void cmRuntimeDependencyArchive::SetError(std::string const& e) | |
| { | |
| this->Status.SetError(e); | |
| } | |
| std::string const& cmRuntimeDependencyArchive::GetBundleExecutable() const | |
| { | |
| return this->BundleExecutable; | |
| } | |
| std::vector<std::string> const& | |
| cmRuntimeDependencyArchive::GetSearchDirectories() const | |
| { | |
| return this->SearchDirectories; | |
| } | |
| std::string const& cmRuntimeDependencyArchive::GetGetRuntimeDependenciesTool() | |
| const | |
| { | |
| return this->GetMakefile()->GetSafeDefinition( | |
| "CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL"); | |
| } | |
| bool cmRuntimeDependencyArchive::GetGetRuntimeDependenciesCommand( | |
| std::string const& search, std::vector<std::string>& command) const | |
| { | |
| // First see if it was supplied by the user | |
| std::string toolCommand = this->GetMakefile()->GetSafeDefinition( | |
| "CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND"); | |
| if (toolCommand.empty() && search == "objdump") { | |
| toolCommand = this->GetMakefile()->GetSafeDefinition("CMAKE_OBJDUMP"); | |
| } | |
| if (!toolCommand.empty()) { | |
| cmExpandList(toolCommand, command); | |
| return true; | |
| } | |
| // Now go searching for it | |
| std::vector<std::string> paths; | |
| #ifdef _WIN32 | |
| cmGlobalGenerator* gg = this->GetMakefile()->GetGlobalGenerator(); | |
| // Add newer Visual Studio paths | |
| AddVisualStudioPath(paths, "Visual Studio 18 ", 18, gg); | |
| AddVisualStudioPath(paths, "Visual Studio 17 ", 17, gg); | |
| AddVisualStudioPath(paths, "Visual Studio 16 ", 16, gg); | |
| AddVisualStudioPath(paths, "Visual Studio 15 ", 15, gg); | |
| // Add older Visual Studio paths | |
| AddRegistryPath( | |
| paths, | |
| "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\14.0;InstallDir]/" | |
| "../../VC/bin", | |
| this->GetMakefile()); | |
| AddEnvPath(paths, "VS140COMNTOOLS", "/../../VC/bin"); | |
| paths.push_back( | |
| "C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin"); | |
| AddRegistryPath( | |
| paths, | |
| "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\12.0;InstallDir]/" | |
| "../../VC/bin", | |
| this->GetMakefile()); | |
| AddEnvPath(paths, "VS120COMNTOOLS", "/../../VC/bin"); | |
| paths.push_back( | |
| "C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/bin"); | |
| AddRegistryPath( | |
| paths, | |
| "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\11.0;InstallDir]/" | |
| "../../VC/bin", | |
| this->GetMakefile()); | |
| AddEnvPath(paths, "VS110COMNTOOLS", "/../../VC/bin"); | |
| paths.push_back( | |
| "C:/Program Files (x86)/Microsoft Visual Studio 11.0/VC/bin"); | |
| AddRegistryPath( | |
| paths, | |
| "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\10.0;InstallDir]/" | |
| "../../VC/bin", | |
| this->GetMakefile()); | |
| AddEnvPath(paths, "VS100COMNTOOLS", "/../../VC/bin"); | |
| paths.push_back( | |
| "C:/Program Files (x86)/Microsoft Visual Studio 10.0/VC/bin"); | |
| AddRegistryPath( | |
| paths, | |
| "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\9.0;InstallDir]/" | |
| "../../VC/bin", | |
| this->GetMakefile()); | |
| AddEnvPath(paths, "VS90COMNTOOLS", "/../../VC/bin"); | |
| paths.push_back("C:/Program Files/Microsoft Visual Studio 9.0/VC/bin"); | |
| paths.push_back("C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/bin"); | |
| AddRegistryPath( | |
| paths, | |
| "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0;InstallDir]/" | |
| "../../VC/bin", | |
| this->GetMakefile()); | |
| AddEnvPath(paths, "VS80COMNTOOLS", "/../../VC/bin"); | |
| paths.push_back("C:/Program Files/Microsoft Visual Studio 8/VC/BIN"); | |
| paths.push_back("C:/Program Files (x86)/Microsoft Visual Studio 8/VC/BIN"); | |
| AddRegistryPath( | |
| paths, | |
| "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\7.1;InstallDir]/" | |
| "../../VC7/bin", | |
| this->GetMakefile()); | |
| AddEnvPath(paths, "VS71COMNTOOLS", "/../../VC7/bin"); | |
| paths.push_back( | |
| "C:/Program Files/Microsoft Visual Studio .NET 2003/VC7/BIN"); | |
| paths.push_back( | |
| "C:/Program Files (x86)/Microsoft Visual Studio .NET 2003/VC7/BIN"); | |
| #endif | |
| std::string program = cmSystemTools::FindProgram(search, paths); | |
| if (!program.empty()) { | |
| command = { program }; | |
| return true; | |
| } | |
| // Couldn't find it | |
| return false; | |
| } | |
| bool cmRuntimeDependencyArchive::IsPreExcluded(std::string const& name) const | |
| { | |
| cmsys::RegularExpressionMatch match; | |
| auto const regexMatch = | |
| [&match, name](cmsys::RegularExpression const& regex) -> bool { | |
| return regex.find(name.c_str(), match); | |
| }; | |
| auto const regexSearch = | |
| [®exMatch]( | |
| std::vector<cmsys::RegularExpression> const& regexes) -> bool { | |
| return std::any_of(regexes.begin(), regexes.end(), regexMatch); | |
| }; | |
| return !regexSearch(this->PreIncludeRegexes) && | |
| regexSearch(this->PreExcludeRegexes); | |
| } | |
| bool cmRuntimeDependencyArchive::IsPostExcluded(std::string const& name) const | |
| { | |
| return this->IsPostExcluded(name, name); | |
| } | |
| bool cmRuntimeDependencyArchive::IsPostExcluded( | |
| std::string const& name, std::string const& fileName) const | |
| { | |
| cmsys::RegularExpressionMatch match; | |
| auto const regexMatch = | |
| [&match, name](cmsys::RegularExpression const& regex) -> bool { | |
| return regex.find(name.c_str(), match); | |
| }; | |
| auto const regexSearch = | |
| [®exMatch]( | |
| std::vector<cmsys::RegularExpression> const& regexes) -> bool { | |
| return std::any_of(regexes.begin(), regexes.end(), regexMatch); | |
| }; | |
| auto const fileMatch = [fileName](std::string const& file) -> bool { | |
| return cmSystemTools::SameFile(file, fileName); | |
| }; | |
| auto const fileSearch = | |
| [&fileMatch](std::vector<std::string> const& files) -> bool { | |
| return std::any_of(files.begin(), files.end(), fileMatch); | |
| }; | |
| return fileSearch(this->PostExcludeFilesStrict) || | |
| (!(regexSearch(this->PostIncludeRegexes) || | |
| fileSearch(this->PostIncludeFiles)) && | |
| (regexSearch(this->PostExcludeRegexes) || | |
| fileSearch(this->PostExcludeFiles))); | |
| } | |
| void cmRuntimeDependencyArchive::AddResolvedPath( | |
| std::string const& name, std::string const& path, bool& unique, | |
| std::vector<std::string> rpaths) | |
| { | |
| auto it = this->ResolvedPaths.emplace(name, std::set<std::string>{}).first; | |
| unique = true; | |
| for (auto const& other : it->second) { | |
| if (cmSystemTools::SameFile(path, other)) { | |
| unique = false; | |
| break; | |
| } | |
| } | |
| it->second.emplace(path); | |
| this->RPaths[path] = std::move(rpaths); | |
| } | |
| void cmRuntimeDependencyArchive::AddUnresolvedPath(std::string const& name) | |
| { | |
| this->UnresolvedPaths.insert(name); | |
| } | |
| cmMakefile* cmRuntimeDependencyArchive::GetMakefile() const | |
| { | |
| return &this->Status.GetMakefile(); | |
| } | |
| std::map<std::string, std::set<std::string>> const& | |
| cmRuntimeDependencyArchive::GetResolvedPaths() const | |
| { | |
| return this->ResolvedPaths; | |
| } | |
| std::set<std::string> const& cmRuntimeDependencyArchive::GetUnresolvedPaths() | |
| const | |
| { | |
| return this->UnresolvedPaths; | |
| } | |
| std::map<std::string, std::vector<std::string>> const& | |
| cmRuntimeDependencyArchive::GetRPaths() const | |
| { | |
| return this->RPaths; | |
| } | |
| bool cmRuntimeDependencyArchive::PlatformSupportsRuntimeDependencies( | |
| std::string const& platform) | |
| { | |
| static std::set<std::string> const supportedPlatforms = { | |
| "Windows", | |
| "Linux", | |
| "Darwin", | |
| "FreeBSD", | |
| }; | |
| return supportedPlatforms.count(platform); | |
| } |