diff options
author | Christian Heimlich <chris@pcserenity.com> | 2023-03-06 13:48:24 -0500 |
---|---|---|
committer | Christian Heimlich <chris@pcserenity.com> | 2023-03-23 15:19:26 -0400 |
commit | fa45594407c2650e9d350e04a534dd17314bf40a (patch) | |
tree | ece7462b15067412385c43b771f58c1ffc00a549 /Source/cmBinUtilsWindowsPELinker.cxx | |
parent | 14cfd6a1ebf12c043aa4b5031bf9621bde068eb3 (diff) | |
download | cmake-fa45594407c2650e9d350e04a534dd17314bf40a.tar.gz |
file(GET_RUNTIME_DEPENDENCIES): Preserve casing for Windows PE binaries
For Windows PE files the `file(GET_RUNTIME_DEPENDENCIES)` command
converts the name of all DLLs found during binary scanning to
lowercase in order to simplify the syntax requirements of its regex
filters; however, this has the side-effect of causing all DLL paths
returned via RESOLVED_DEPENDENCIES_VAR to be in lowercase, regardless
of their actual casing.
Instead, respect the original casing as closely as possible when
returning resolved dependencies after all filters have been
passed:
When evaluating a Windows PE format binary on a non-Windows host
the casing of dependencies recorded within the binary are
used. When the host is running Windows, the actual casing of the
dependencies on-disk are used instead.
Fixes: #23091
Diffstat (limited to 'Source/cmBinUtilsWindowsPELinker.cxx')
-rw-r--r-- | Source/cmBinUtilsWindowsPELinker.cxx | 58 |
1 files changed, 50 insertions, 8 deletions
diff --git a/Source/cmBinUtilsWindowsPELinker.cxx b/Source/cmBinUtilsWindowsPELinker.cxx index 79e39e9c52..918f563387 100644 --- a/Source/cmBinUtilsWindowsPELinker.cxx +++ b/Source/cmBinUtilsWindowsPELinker.cxx @@ -3,7 +3,10 @@ #include "cmBinUtilsWindowsPELinker.h" +#include <algorithm> +#include <iterator> #include <sstream> +#include <utility> #include <vector> #include <cm/memory> @@ -16,6 +19,27 @@ #ifdef _WIN32 # include <windows.h> + +# 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( @@ -60,29 +84,47 @@ bool cmBinUtilsWindowsPELinker::ScanDependencies( if (!this->Tool->GetFileInfo(file, needed)) { return false; } - for (auto& n : needed) { - n = cmSystemTools::LowerCase(n); - } + + struct WinPEDependency + { + WinPEDependency(std::string o) + : Original(std::move(o)) + , LowerCase(cmSystemTools::LowerCase(Original)) + { + } + std::string const Original; + std::string const LowerCase; + }; + + std::vector<WinPEDependency> 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 : needed) { - if (!this->Archive->IsPreExcluded(lib)) { + for (auto const& lib : depends) { + if (!this->Archive->IsPreExcluded(lib.LowerCase)) { std::string path; bool resolved = false; - if (!this->ResolveDependency(lib, origin, path, resolved)) { + 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, path, unique); + this->Archive->AddResolvedPath(lib.Original, path, unique); if (unique && !this->ScanDependencies(path, cmStateEnums::SHARED_LIBRARY)) { return false; } } } else { - this->Archive->AddUnresolvedPath(lib); + this->Archive->AddUnresolvedPath(lib.Original); } } } |