diff --git a/Source/cmBinUtilsWindowsPELinker.cxx b/Source/cmBinUtilsWindowsPELinker.cxx index 1e05409d35..c6e5a35efc 100644 --- a/Source/cmBinUtilsWindowsPELinker.cxx +++ b/Source/cmBinUtilsWindowsPELinker.cxx @@ -4,17 +4,18 @@ #include "cmBinUtilsWindowsPELinker.h" #include +#include #include #include #include #include +#include #include #include "cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.h" #include "cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.h" #include "cmRuntimeDependencyArchive.h" -#include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmTargetTypes.h" @@ -22,26 +23,51 @@ # include # include "cmsys/Encoding.hxx" + +# include "cmStringAlgorithms.h" +#else +# include "cmsys/Directory.hxx" #endif -#ifdef _WIN32 namespace { -void ReplaceWithActualNameCasing(std::string& path) +#ifdef _WIN32 +std::string 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); } + return path; } +#else +bool FindCaseInsensitive(std::string const& dir, std::string const& lowerName, + std::string& foundPath) +{ + if (!cmSystemTools::FileIsDirectory(dir)) { + return false; + } + cmsys::Directory directory; + if (!directory.Load(dir)) { + return false; + } + for (std::size_t i = 0; i < directory.GetNumberOfFiles(); ++i) { + cm::filesystem::path fileName = directory.GetFile(i); + if (cmSystemTools::LowerCase(fileName) == lowerName) { + foundPath += dir / fileName; + return true; + } + } + + return false; } #endif +} cmBinUtilsWindowsPELinker::cmBinUtilsWindowsPELinker( cmRuntimeDependencyArchive* archive) @@ -78,6 +104,12 @@ bool cmBinUtilsWindowsPELinker::Prepare() return true; } +cmBinUtilsWindowsPELinker::Dependency::Dependency(std::string casedName) + : CasedName(std::move(casedName)) + , LowerName(cmSystemTools::LowerCase(CasedName)) +{ +} + bool cmBinUtilsWindowsPELinker::ScanDependencies(std::string const& file, cm::TargetType /* unused */) { @@ -86,56 +118,42 @@ bool cmBinUtilsWindowsPELinker::ScanDependencies(std::string const& file, 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; + 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)) { + for (Dependency const& lib : depends) { + if (this->Archive->IsPreExcluded(lib.LowerName)) { + continue; + } + Dependency path; + bool resolved = false; + if (!this->ResolveDependency(lib, origin, path, resolved)) { + return false; + } + if (resolved) { + if (this->Archive->IsPostExcluded(path.LowerName, path.CasedName)) { + continue; + } + bool unique; + this->Archive->AddResolvedPath(lib.CasedName, path.CasedName, unique); + if (unique && + !this->ScanDependencies(path.CasedName, + cm::TargetType::SHARED_LIBRARY)) { 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, cm::TargetType::SHARED_LIBRARY)) { - return false; - } - } - } else { - this->Archive->AddUnresolvedPath(lib.Original); - } + } else { + this->Archive->AddUnresolvedPath(lib.CasedName); } } return true; } -bool cmBinUtilsWindowsPELinker::ResolveDependency(std::string const& name, +bool cmBinUtilsWindowsPELinker::ResolveDependency(Dependency const& lib, std::string const& origin, - std::string& path, + Dependency& path, bool& resolved) { auto dirs = this->Archive->GetSearchDirectories(); @@ -154,12 +172,26 @@ bool cmBinUtilsWindowsPELinker::ResolveDependency(std::string const& name, dirs.insert(dirs.begin(), origin); for (auto const& searchPath : dirs) { - path = cmStrCat(searchPath, '/', name); - if (cmSystemTools::PathExists(path)) { - this->NormalizePath(path); - resolved = true; - return true; +#ifdef _WIN32 + path.LowerName = cmStrCat(searchPath, '/', lib.LowerName); + if (!cmSystemTools::PathExists(path.LowerName)) { + continue; } + this->NormalizePath(path.LowerName); + path.CasedName = ReplaceWithActualNameCasing(path.LowerName); +#else + if (!FindCaseInsensitive(searchPath, lib.LowerName, path.CasedName)) { + continue; + } + this->NormalizePath(path.CasedName); + path.LowerName = [&lib](std::string libPath) -> std::string { + libPath.replace(libPath.end() - lib.LowerName.size(), libPath.end(), + lib.LowerName); + return libPath; + }(path.CasedName); +#endif + resolved = true; + return true; } resolved = false; diff --git a/Source/cmBinUtilsWindowsPELinker.h b/Source/cmBinUtilsWindowsPELinker.h index 839ee001be..8b7a7c186e 100644 --- a/Source/cmBinUtilsWindowsPELinker.h +++ b/Source/cmBinUtilsWindowsPELinker.h @@ -23,6 +23,14 @@ public: private: std::unique_ptr Tool; - bool ResolveDependency(std::string const& name, std::string const& origin, - std::string& path, bool& resolved); + struct Dependency + { + Dependency() = default; + Dependency(std::string casedName); + std::string CasedName; + std::string LowerName; + }; + + bool ResolveDependency(Dependency const& lib, std::string const& origin, + Dependency& path, bool& resolved); }; diff --git a/Source/cmRuntimeDependencyArchive.cxx b/Source/cmRuntimeDependencyArchive.cxx index 00292b5dfd..77dde30e7c 100644 --- a/Source/cmRuntimeDependencyArchive.cxx +++ b/Source/cmRuntimeDependencyArchive.cxx @@ -333,6 +333,12 @@ bool cmRuntimeDependencyArchive::IsPreExcluded(std::string const& name) const } 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 = @@ -344,8 +350,8 @@ bool cmRuntimeDependencyArchive::IsPostExcluded(std::string const& name) const std::vector const& regexes) -> bool { return std::any_of(regexes.begin(), regexes.end(), regexMatch); }; - auto const fileMatch = [name](std::string const& file) -> bool { - return cmSystemTools::SameFile(file, name); + auto const fileMatch = [fileName](std::string const& file) -> bool { + return cmSystemTools::SameFile(file, fileName); }; auto const fileSearch = [&fileMatch](std::vector const& files) -> bool { diff --git a/Source/cmRuntimeDependencyArchive.h b/Source/cmRuntimeDependencyArchive.h index 0349f76d15..638d520b3b 100644 --- a/Source/cmRuntimeDependencyArchive.h +++ b/Source/cmRuntimeDependencyArchive.h @@ -43,6 +43,8 @@ public: std::string const& search, std::vector& command) const; bool IsPreExcluded(std::string const& name) const; bool IsPostExcluded(std::string const& name) const; + bool IsPostExcluded(std::string const& name, + std::string const& fileName) const; void AddResolvedPath(std::string const& name, std::string const& path, bool& unique, std::vector rpaths = {});