From 343723dd56f5a0d5ec0d1b37d3de1b381e972ded Mon Sep 17 00:00:00 2001 From: Stepanov Igor Date: Tue, 25 Aug 2026 14:50:11 +0300 Subject: [PATCH 1/6] cmBinUtilsWindowsPELinker: Reduce conditional block nesting --- Source/cmBinUtilsWindowsPELinker.cxx | 54 ++++++++++++++-------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/Source/cmBinUtilsWindowsPELinker.cxx b/Source/cmBinUtilsWindowsPELinker.cxx index 1e05409d35..db46e289d2 100644 --- a/Source/cmBinUtilsWindowsPELinker.cxx +++ b/Source/cmBinUtilsWindowsPELinker.cxx @@ -103,30 +103,31 @@ bool cmBinUtilsWindowsPELinker::ScanDependencies(std::string const& file, 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)) { + if (this->Archive->IsPreExcluded(lib.LowerCase)) { + continue; + } + std::string path; + bool resolved = false; + if (!this->ResolveDependency(lib.LowerCase, origin, path, resolved)) { + return false; + } + if (resolved) { + if (this->Archive->IsPostExcluded(path)) { + continue; + } +#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; } - 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.Original); } } @@ -155,11 +156,12 @@ bool cmBinUtilsWindowsPELinker::ResolveDependency(std::string const& name, for (auto const& searchPath : dirs) { path = cmStrCat(searchPath, '/', name); - if (cmSystemTools::PathExists(path)) { - this->NormalizePath(path); - resolved = true; - return true; + if (!cmSystemTools::PathExists(path)) { + continue; } + this->NormalizePath(path); + resolved = true; + return true; } resolved = false; From 86846f57b83674afb6b64503e64b30d676df5bf6 Mon Sep 17 00:00:00 2001 From: Brad King Date: Thu, 27 Aug 2026 11:24:53 -0400 Subject: [PATCH 2/6] cmBinUtilsWindowsPELinker: Factor out helper to store cased and lower names --- Source/cmBinUtilsWindowsPELinker.cxx | 32 ++++++++++++---------------- Source/cmBinUtilsWindowsPELinker.h | 7 ++++++ 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/Source/cmBinUtilsWindowsPELinker.cxx b/Source/cmBinUtilsWindowsPELinker.cxx index db46e289d2..e3ee1cb1aa 100644 --- a/Source/cmBinUtilsWindowsPELinker.cxx +++ b/Source/cmBinUtilsWindowsPELinker.cxx @@ -78,6 +78,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,29 +92,18 @@ 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)) { + for (Dependency const& lib : depends) { + if (this->Archive->IsPreExcluded(lib.LowerName)) { continue; } std::string path; bool resolved = false; - if (!this->ResolveDependency(lib.LowerCase, origin, path, resolved)) { + if (!this->ResolveDependency(lib.LowerName, origin, path, resolved)) { return false; } if (resolved) { @@ -118,16 +113,17 @@ bool cmBinUtilsWindowsPELinker::ScanDependencies(std::string const& file, #ifdef _WIN32 ReplaceWithActualNameCasing(path); #else - path.replace(path.end() - lib.Original.size(), path.end(), lib.Original); + path.replace(path.end() - lib.CasedName.size(), path.end(), + lib.CasedName); #endif bool unique; - this->Archive->AddResolvedPath(lib.Original, path, unique); + this->Archive->AddResolvedPath(lib.CasedName, path, unique); if (unique && !this->ScanDependencies(path, cm::TargetType::SHARED_LIBRARY)) { return false; } } else { - this->Archive->AddUnresolvedPath(lib.Original); + this->Archive->AddUnresolvedPath(lib.CasedName); } } diff --git a/Source/cmBinUtilsWindowsPELinker.h b/Source/cmBinUtilsWindowsPELinker.h index 839ee001be..e608a4e6c4 100644 --- a/Source/cmBinUtilsWindowsPELinker.h +++ b/Source/cmBinUtilsWindowsPELinker.h @@ -23,6 +23,13 @@ public: private: std::unique_ptr Tool; + struct Dependency + { + Dependency(std::string casedName); + std::string CasedName; + std::string LowerName; + }; + bool ResolveDependency(std::string const& name, std::string const& origin, std::string& path, bool& resolved); }; From f7ce592c98cd6b258666b6a6bc1cb41beeb02eca Mon Sep 17 00:00:00 2001 From: Brad King Date: Thu, 27 Aug 2026 16:51:15 -0400 Subject: [PATCH 3/6] cmBinUtilsWindowsPELinker: Switch case conversion to value semantics --- Source/cmBinUtilsWindowsPELinker.cxx | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Source/cmBinUtilsWindowsPELinker.cxx b/Source/cmBinUtilsWindowsPELinker.cxx index e3ee1cb1aa..939cb41a99 100644 --- a/Source/cmBinUtilsWindowsPELinker.cxx +++ b/Source/cmBinUtilsWindowsPELinker.cxx @@ -27,17 +27,17 @@ #ifdef _WIN32 namespace { -void ReplaceWithActualNameCasing(std::string& path) +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; } } @@ -111,10 +111,13 @@ bool cmBinUtilsWindowsPELinker::ScanDependencies(std::string const& file, continue; } #ifdef _WIN32 - ReplaceWithActualNameCasing(path); + path = ReplaceWithActualNameCasing(path); #else - path.replace(path.end() - lib.CasedName.size(), path.end(), - lib.CasedName); + path = [&lib](std::string libPath) -> std::string { + libPath.replace(libPath.end() - lib.CasedName.size(), libPath.end(), + lib.CasedName); + return libPath; + }(path); #endif bool unique; this->Archive->AddResolvedPath(lib.CasedName, path, unique); From 6ed37c9ed09f596ebbec45f3259789e88213fdc5 Mon Sep 17 00:00:00 2001 From: Brad King Date: Thu, 27 Aug 2026 16:48:50 -0400 Subject: [PATCH 4/6] cmBinUtilsWindowsPELinker: Track cased and lower names more clearly --- Source/cmBinUtilsWindowsPELinker.cxx | 18 ++++++++++-------- Source/cmBinUtilsWindowsPELinker.h | 1 + 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Source/cmBinUtilsWindowsPELinker.cxx b/Source/cmBinUtilsWindowsPELinker.cxx index 939cb41a99..d515fdd032 100644 --- a/Source/cmBinUtilsWindowsPELinker.cxx +++ b/Source/cmBinUtilsWindowsPELinker.cxx @@ -101,28 +101,30 @@ bool cmBinUtilsWindowsPELinker::ScanDependencies(std::string const& file, if (this->Archive->IsPreExcluded(lib.LowerName)) { continue; } - std::string path; + Dependency path; bool resolved = false; - if (!this->ResolveDependency(lib.LowerName, origin, path, resolved)) { + if (!this->ResolveDependency(lib.LowerName, origin, path.LowerName, + resolved)) { return false; } if (resolved) { - if (this->Archive->IsPostExcluded(path)) { + if (this->Archive->IsPostExcluded(path.LowerName)) { continue; } #ifdef _WIN32 - path = ReplaceWithActualNameCasing(path); + path.CasedName = ReplaceWithActualNameCasing(path.LowerName); #else - path = [&lib](std::string libPath) -> std::string { + path.CasedName = [&lib](std::string libPath) -> std::string { libPath.replace(libPath.end() - lib.CasedName.size(), libPath.end(), lib.CasedName); return libPath; - }(path); + }(path.LowerName); #endif bool unique; - this->Archive->AddResolvedPath(lib.CasedName, path, unique); + this->Archive->AddResolvedPath(lib.CasedName, path.CasedName, unique); if (unique && - !this->ScanDependencies(path, cm::TargetType::SHARED_LIBRARY)) { + !this->ScanDependencies(path.CasedName, + cm::TargetType::SHARED_LIBRARY)) { return false; } } else { diff --git a/Source/cmBinUtilsWindowsPELinker.h b/Source/cmBinUtilsWindowsPELinker.h index e608a4e6c4..8fdf9417cc 100644 --- a/Source/cmBinUtilsWindowsPELinker.h +++ b/Source/cmBinUtilsWindowsPELinker.h @@ -25,6 +25,7 @@ private: struct Dependency { + Dependency() = default; Dependency(std::string casedName); std::string CasedName; std::string LowerName; From 4ce278389f478752522797dc021f8acec7eeca81 Mon Sep 17 00:00:00 2001 From: Brad King Date: Thu, 27 Aug 2026 16:35:11 -0400 Subject: [PATCH 5/6] cmBinUtilsWindowsPELinker: Resolve cased and lower names together --- Source/cmBinUtilsWindowsPELinker.cxx | 31 ++++++++++++++-------------- Source/cmBinUtilsWindowsPELinker.h | 4 ++-- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/Source/cmBinUtilsWindowsPELinker.cxx b/Source/cmBinUtilsWindowsPELinker.cxx index d515fdd032..0c9c2a5fc4 100644 --- a/Source/cmBinUtilsWindowsPELinker.cxx +++ b/Source/cmBinUtilsWindowsPELinker.cxx @@ -103,23 +103,13 @@ bool cmBinUtilsWindowsPELinker::ScanDependencies(std::string const& file, } Dependency path; bool resolved = false; - if (!this->ResolveDependency(lib.LowerName, origin, path.LowerName, - resolved)) { + if (!this->ResolveDependency(lib, origin, path, resolved)) { return false; } if (resolved) { if (this->Archive->IsPostExcluded(path.LowerName)) { continue; } -#ifdef _WIN32 - path.CasedName = ReplaceWithActualNameCasing(path.LowerName); -#else - path.CasedName = [&lib](std::string libPath) -> std::string { - libPath.replace(libPath.end() - lib.CasedName.size(), libPath.end(), - lib.CasedName); - return libPath; - }(path.LowerName); -#endif bool unique; this->Archive->AddResolvedPath(lib.CasedName, path.CasedName, unique); if (unique && @@ -135,9 +125,9 @@ bool cmBinUtilsWindowsPELinker::ScanDependencies(std::string const& file, 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(); @@ -156,11 +146,20 @@ 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)) { + path.LowerName = cmStrCat(searchPath, '/', lib.LowerName); + if (!cmSystemTools::PathExists(path.LowerName)) { continue; } - this->NormalizePath(path); + this->NormalizePath(path.LowerName); +#ifdef _WIN32 + path.CasedName = ReplaceWithActualNameCasing(path.LowerName); +#else + path.CasedName = [&lib](std::string libPath) -> std::string { + libPath.replace(libPath.end() - lib.CasedName.size(), libPath.end(), + lib.CasedName); + return libPath; + }(path.LowerName); +#endif resolved = true; return true; } diff --git a/Source/cmBinUtilsWindowsPELinker.h b/Source/cmBinUtilsWindowsPELinker.h index 8fdf9417cc..8b7a7c186e 100644 --- a/Source/cmBinUtilsWindowsPELinker.h +++ b/Source/cmBinUtilsWindowsPELinker.h @@ -31,6 +31,6 @@ private: std::string LowerName; }; - bool ResolveDependency(std::string const& name, std::string const& origin, - std::string& path, bool& resolved); + bool ResolveDependency(Dependency const& lib, std::string const& origin, + Dependency& path, bool& resolved); }; From 728e6ce203fb2a4c3e3ccc524e8370311928e37a Mon Sep 17 00:00:00 2001 From: Stepanov Igor Date: Tue, 25 Aug 2026 14:50:11 +0300 Subject: [PATCH 6/6] file(GET_RUNTIME_DEPENDENCIES): Fix DLL case insensitivity for cross-compiling When cross-compiling to Windows from a (Linux) host with a case-sensitive filesystem, match DLL file names case-insensitively. Fixes: #28049 --- Source/cmBinUtilsWindowsPELinker.cxx | 46 ++++++++++++++++++++++----- Source/cmRuntimeDependencyArchive.cxx | 10 ++++-- Source/cmRuntimeDependencyArchive.h | 2 ++ 3 files changed, 48 insertions(+), 10 deletions(-) diff --git a/Source/cmBinUtilsWindowsPELinker.cxx b/Source/cmBinUtilsWindowsPELinker.cxx index 0c9c2a5fc4..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,11 +23,15 @@ # include # include "cmsys/Encoding.hxx" + +# include "cmStringAlgorithms.h" +#else +# include "cmsys/Directory.hxx" #endif -#ifdef _WIN32 namespace { +#ifdef _WIN32 std::string ReplaceWithActualNameCasing(std::string path) { WIN32_FIND_DATAW findData; @@ -39,9 +44,30 @@ std::string ReplaceWithActualNameCasing(std::string path) } 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) @@ -107,7 +133,7 @@ bool cmBinUtilsWindowsPELinker::ScanDependencies(std::string const& file, return false; } if (resolved) { - if (this->Archive->IsPostExcluded(path.LowerName)) { + if (this->Archive->IsPostExcluded(path.LowerName, path.CasedName)) { continue; } bool unique; @@ -146,19 +172,23 @@ bool cmBinUtilsWindowsPELinker::ResolveDependency(Dependency const& lib, dirs.insert(dirs.begin(), origin); for (auto const& searchPath : dirs) { +#ifdef _WIN32 path.LowerName = cmStrCat(searchPath, '/', lib.LowerName); if (!cmSystemTools::PathExists(path.LowerName)) { continue; } this->NormalizePath(path.LowerName); -#ifdef _WIN32 path.CasedName = ReplaceWithActualNameCasing(path.LowerName); #else - path.CasedName = [&lib](std::string libPath) -> std::string { - libPath.replace(libPath.end() - lib.CasedName.size(), libPath.end(), - lib.CasedName); + 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.LowerName); + }(path.CasedName); #endif resolved = true; return true; 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 = {});