/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmBinUtilsWindowsPELinker.h" #include #include #include #include #include #include #include "cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.h" #include "cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.h" #include "cmRuntimeDependencyArchive.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" #ifdef _WIN32 # include # include "cmsys/Encoding.hxx" #endif #ifdef _WIN32 namespace { void ReplaceWithActualNameCasing(std::string& path) { WIN32_FIND_DATAW findData; HANDLE hFind = ::FindFirstFileW( cmsys::Encoding::ToWindowsExtendedPath(path).c_str(), &findData); if (hFind != INVALID_HANDLE_VALUE) { auto onDiskName = cmsys::Encoding::ToNarrow(findData.cFileName); ::FindClose(hFind); path.replace(path.end() - onDiskName.size(), path.end(), onDiskName); } } } #endif cmBinUtilsWindowsPELinker::cmBinUtilsWindowsPELinker( cmRuntimeDependencyArchive* archive) : cmBinUtilsLinker(archive) { } bool cmBinUtilsWindowsPELinker::Prepare() { std::string tool = this->Archive->GetGetRuntimeDependenciesTool(); if (tool.empty()) { std::vector command; if (this->Archive->GetGetRuntimeDependenciesCommand("dumpbin", command)) { tool = "dumpbin"; } else { tool = "objdump"; } } if (tool == "dumpbin") { this->Tool = cm::make_unique( this->Archive); } else if (tool == "objdump") { this->Tool = cm::make_unique( this->Archive); } else { std::ostringstream e; e << "Invalid value for CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL: " << tool; this->SetError(e.str()); return false; } return true; } bool cmBinUtilsWindowsPELinker::ScanDependencies( std::string const& file, cmStateEnums::TargetType /* unused */) { std::vector needed; if (!this->Tool->GetFileInfo(file, needed)) { return false; } struct WinPEDependency { WinPEDependency(std::string o) : Original(std::move(o)) , LowerCase(cmSystemTools::LowerCase(Original)) { } std::string const Original; std::string const LowerCase; }; std::vector depends; depends.reserve(needed.size()); std::move(needed.begin(), needed.end(), std::back_inserter(depends)); std::string origin = cmSystemTools::GetFilenamePath(file); for (auto const& lib : depends) { if (!this->Archive->IsPreExcluded(lib.LowerCase)) { std::string path; bool resolved = false; if (!this->ResolveDependency(lib.LowerCase, origin, path, resolved)) { return false; } if (resolved) { if (!this->Archive->IsPostExcluded(path)) { #ifdef _WIN32 ReplaceWithActualNameCasing(path); #else path.replace(path.end() - lib.Original.size(), path.end(), lib.Original); #endif bool unique; this->Archive->AddResolvedPath(lib.Original, path, unique); if (unique && !this->ScanDependencies(path, cmStateEnums::SHARED_LIBRARY)) { return false; } } } else { this->Archive->AddUnresolvedPath(lib.Original); } } } return true; } bool cmBinUtilsWindowsPELinker::ResolveDependency(std::string const& name, std::string const& origin, std::string& path, bool& resolved) { auto dirs = this->Archive->GetSearchDirectories(); #ifdef _WIN32 char buf[MAX_PATH]; unsigned int len; if ((len = GetWindowsDirectoryA(buf, MAX_PATH)) > 0) { dirs.insert(dirs.begin(), std::string(buf, len)); } if ((len = GetSystemDirectoryA(buf, MAX_PATH)) > 0) { dirs.insert(dirs.begin(), std::string(buf, len)); } #endif dirs.insert(dirs.begin(), origin); for (auto const& searchPath : dirs) { path = cmStrCat(searchPath, '/', name); if (cmSystemTools::PathExists(path)) { resolved = true; return true; } } resolved = false; return true; }