cmFindCommon: Fix cmFindCommon::RerootPaths to use real paths

When comparing if a candidate path is already a subdirectory of a root
path, we should compare the real paths, to ensure we canonicalize the
paths.

Fixes: #27493
This commit is contained in:
Alexandru Croitor
2026-01-07 11:24:40 +01:00
parent 047e5855f9
commit d568b3fa47
4 changed files with 54 additions and 2 deletions
+3 -2
View File
@@ -301,8 +301,9 @@ void cmFindCommon::RerootPaths(std::vector<std::string>& paths,
auto isSameDirectoryOrSubDirectory = [](std::string const& l,
std::string const& r) {
return (cmSystemTools::GetRealPath(l) == cmSystemTools::GetRealPath(r)) ||
cmSystemTools::IsSubDirectory(l, r);
std::string const lReal = cmSystemTools::GetRealPath(l);
std::string const rReal = cmSystemTools::GetRealPath(r);
return (lReal == rReal) || cmSystemTools::IsSubDirectory(lReal, rReal);
};
for (auto const& r : roots) {
@@ -0,0 +1,50 @@
set(regular_root "${CMAKE_CURRENT_SOURCE_DIR}/FindRootPathAndPrefixPathAreEqual")
set(regular_prefix "${regular_root}/lib/cmake")
# 'emptydir' must be a real dir on the file system, otherwise CMake
# won't canonicalize the path when getting resolving the real path.
set(dotted_root "${regular_root}/emptydir/..")
set(dotted_prefix "${dotted_root}/lib/cmake")
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE "ONLY")
# Case with no '..' in the paths
set(CMAKE_FIND_ROOT_PATH "${regular_root}")
set(CMAKE_PREFIX_PATH "${regular_prefix}")
message(STATUS "Looking for Foo without '..' in the paths")
find_package(Foo
REQUIRED
CONFIG
NO_CMAKE_ENVIRONMENT_PATH
NO_SYSTEM_ENVIRONMENT_PATH
# Important because CMAKE_SYSTEM_PREFIX_PATH might contain "/" as a prefix
# And when "/" is rerooted onto the root above, the package is found even if
# CMAKE_PREFIX_PATH is empty. We want to ensure that we hit
# the CMAKE_FIND_ROOT_PATH == CMAKE_PREFIX_PATH code path.
NO_CMAKE_SYSTEM_PATH
)
if(Foo_FOUND)
message(STATUS "Foo found for case without '..' in the paths")
endif()
# Unset the cache variable to find the package again.
unset(Foo_DIR CACHE)
# Case with '..' in the paths
set(CMAKE_FIND_ROOT_PATH "${dotted_root}")
set(CMAKE_PREFIX_PATH "${dotted_prefix}")
message(STATUS "Looking for Foo with '..' in the paths")
find_package(Foo
REQUIRED
CONFIG
NO_CMAKE_ENVIRONMENT_PATH
NO_SYSTEM_ENVIRONMENT_PATH
# Important because CMAKE_SYSTEM_PREFIX_PATH might contain "/" as a prefix
# And when "/" is rerooted onto the root above, the package is found even if
# CMAKE_PREFIX_PATH is empty. We want to ensure that we hit
# the CMAKE_FIND_ROOT_PATH == CMAKE_PREFIX_PATH code path.
NO_CMAKE_SYSTEM_PATH
)
if(Foo_FOUND)
message(STATUS "Foo found for case with '..' in the paths")
endif()
@@ -48,6 +48,7 @@ run_cmake(RequiredOptionalKeywordsClash)
run_cmake(RequiredVarOptional)
run_cmake(RequiredVarNested)
run_cmake(FindRootPathAndPrefixPathAreEqual)
run_cmake(FindRootPathAndPrefixPathWithCommonSubdir)
run_cmake(SetFoundFALSE)
run_cmake(UnwindIncludeBlock)
run_cmake(UnwindIncludeFunction)