| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
| file Copyright.txt or https://cmake.org/licensing for details. */ |
| |
| #include "cmRuntimeDependencyArchive.h" |
| |
| #include "cmBinUtilsLinuxELFLinker.h" |
| #include "cmBinUtilsMacOSMachOLinker.h" |
| #include "cmBinUtilsWindowsPELinker.h" |
| #include "cmExecutionStatus.h" |
| #include "cmMakefile.h" |
| #include "cmStateTypes.h" |
| #include "cmStringAlgorithms.h" |
| #include "cmSystemTools.h" |
| |
| #if defined(_WIN32) |
| # include "cmGlobalGenerator.h" |
| # ifndef CMAKE_BOOTSTRAP |
| # include "cmGlobalVisualStudioVersionedGenerator.h" |
| # endif |
| # include "cmsys/Glob.hxx" |
| |
| # include "cmVSSetupHelper.h" |
| #endif |
| |
| #include <algorithm> |
| #include <sstream> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include <cm/memory> |
| |
| #if defined(_WIN32) |
| static void AddVisualStudioPath(std::vector<std::string>& paths, |
| const std::string& 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, |
| const std::string& 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, const std::string& var, |
| const std::string& suffix) |
| { |
| std::string value; |
| if (cmSystemTools::GetEnv(var, value)) { |
| paths.push_back(value + suffix); |
| } |
| } |
| #endif |
| |
| static cmsys::RegularExpression TransformCompile(const std::string& str) |
| { |
| return cmsys::RegularExpression(str); |
| } |
| |
| cmRuntimeDependencyArchive::cmRuntimeDependencyArchive( |
| cmExecutionStatus& status, std::vector<std::string> searchDirectories, |
| std::string bundleExecutable, |
| const std::vector<std::string>& preIncludeRegexes, |
| const std::vector<std::string>& preExcludeRegexes, |
| const std::vector<std::string>& postIncludeRegexes, |
| const std::vector<std::string>& 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"; |
| } |
| } |
| if (platform == "linux+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 { |
| std::ostringstream e; |
| e << "Invalid value for CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM: " |
| << platform; |
| this->SetError(e.str()); |
| return false; |
| } |
| |
| return this->Linker->Prepare(); |
| } |
| |
| bool cmRuntimeDependencyArchive::GetRuntimeDependencies( |
| const std::vector<std::string>& executables, |
| const std::vector<std::string>& libraries, |
| const std::vector<std::string>& modules) |
| { |
| for (auto const& exe : executables) { |
| if (!this->Linker->ScanDependencies(exe, cmStateEnums::EXECUTABLE)) { |
| return false; |
| } |
| } |
| for (auto const& lib : libraries) { |
| if (!this->Linker->ScanDependencies(lib, cmStateEnums::SHARED_LIBRARY)) { |
| return false; |
| } |
| } |
| return std::all_of( |
| modules.begin(), modules.end(), [this](std::string const& mod) -> bool { |
| return this->Linker->ScanDependencies(mod, cmStateEnums::MODULE_LIBRARY); |
| }); |
| } |
| |
| void cmRuntimeDependencyArchive::SetError(const std::string& e) |
| { |
| this->Status.SetError(e); |
| } |
| |
| const std::string& cmRuntimeDependencyArchive::GetBundleExecutable() const |
| { |
| return this->BundleExecutable; |
| } |
| |
| const std::vector<std::string>& |
| cmRuntimeDependencyArchive::GetSearchDirectories() const |
| { |
| return this->SearchDirectories; |
| } |
| |
| const std::string& cmRuntimeDependencyArchive::GetGetRuntimeDependenciesTool() |
| const |
| { |
| return this->GetMakefile()->GetSafeDefinition( |
| "CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL"); |
| } |
| |
| bool cmRuntimeDependencyArchive::GetGetRuntimeDependenciesCommand( |
| const std::string& 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 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(const std::string& name) const |
| { |
| cmsys::RegularExpressionMatch match; |
| auto const regexMatch = |
| [&match, name](const cmsys::RegularExpression& regex) -> bool { |
| return regex.find(name.c_str(), match); |
| }; |
| auto const regexSearch = |
| [®exMatch]( |
| const std::vector<cmsys::RegularExpression>& regexes) -> bool { |
| return std::any_of(regexes.begin(), regexes.end(), regexMatch); |
| }; |
| |
| return !regexSearch(this->PreIncludeRegexes) && |
| regexSearch(this->PreExcludeRegexes); |
| } |
| |
| bool cmRuntimeDependencyArchive::IsPostExcluded(const std::string& name) const |
| { |
| cmsys::RegularExpressionMatch match; |
| auto const regexMatch = |
| [&match, name](const cmsys::RegularExpression& regex) -> bool { |
| return regex.find(name.c_str(), match); |
| }; |
| auto const regexSearch = |
| [®exMatch]( |
| const std::vector<cmsys::RegularExpression>& regexes) -> bool { |
| return std::any_of(regexes.begin(), regexes.end(), regexMatch); |
| }; |
| auto const fileMatch = [name](const std::string& file) -> bool { |
| return cmSystemTools::SameFile(file, name); |
| }; |
| auto const fileSearch = |
| [&fileMatch](const std::vector<std::string>& 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( |
| const std::string& name, const std::string& 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.insert(path); |
| this->RPaths[path] = std::move(rpaths); |
| } |
| |
| void cmRuntimeDependencyArchive::AddUnresolvedPath(const std::string& name) |
| { |
| this->UnresolvedPaths.insert(name); |
| } |
| |
| cmMakefile* cmRuntimeDependencyArchive::GetMakefile() const |
| { |
| return &this->Status.GetMakefile(); |
| } |
| |
| const std::map<std::string, std::set<std::string>>& |
| cmRuntimeDependencyArchive::GetResolvedPaths() const |
| { |
| return this->ResolvedPaths; |
| } |
| |
| const std::set<std::string>& cmRuntimeDependencyArchive::GetUnresolvedPaths() |
| const |
| { |
| return this->UnresolvedPaths; |
| } |
| |
| const std::map<std::string, std::vector<std::string>>& |
| cmRuntimeDependencyArchive::GetRPaths() const |
| { |
| return this->RPaths; |
| } |
| |
| bool cmRuntimeDependencyArchive::PlatformSupportsRuntimeDependencies( |
| const std::string& platform) |
| { |
| static const std::set<std::string> supportedPlatforms = { "Windows", "Linux", |
| "Darwin" }; |
| return supportedPlatforms.count(platform); |
| } |