From d568b3fa47e19e0163aa2264b366a29f390fc899 Mon Sep 17 00:00:00 2001 From: Alexandru Croitor Date: Tue, 6 Jan 2026 15:43:23 +0100 Subject: [PATCH] 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 --- Source/cmFindCommon.cxx | 5 +- .../emptydir/.gitkeep | 0 ...ootPathAndPrefixPathWithCommonSubdir.cmake | 50 +++++++++++++++++++ .../RunCMake/find_package/RunCMakeTest.cmake | 1 + 4 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 Tests/RunCMake/find_package/FindRootPathAndPrefixPathAreEqual/emptydir/.gitkeep create mode 100644 Tests/RunCMake/find_package/FindRootPathAndPrefixPathWithCommonSubdir.cmake diff --git a/Source/cmFindCommon.cxx b/Source/cmFindCommon.cxx index fb7cc9f43a..444c0403bd 100644 --- a/Source/cmFindCommon.cxx +++ b/Source/cmFindCommon.cxx @@ -301,8 +301,9 @@ void cmFindCommon::RerootPaths(std::vector& 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) { diff --git a/Tests/RunCMake/find_package/FindRootPathAndPrefixPathAreEqual/emptydir/.gitkeep b/Tests/RunCMake/find_package/FindRootPathAndPrefixPathAreEqual/emptydir/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Tests/RunCMake/find_package/FindRootPathAndPrefixPathWithCommonSubdir.cmake b/Tests/RunCMake/find_package/FindRootPathAndPrefixPathWithCommonSubdir.cmake new file mode 100644 index 0000000000..5231e302d1 --- /dev/null +++ b/Tests/RunCMake/find_package/FindRootPathAndPrefixPathWithCommonSubdir.cmake @@ -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() diff --git a/Tests/RunCMake/find_package/RunCMakeTest.cmake b/Tests/RunCMake/find_package/RunCMakeTest.cmake index 3cd4ab9906..f0fc80b3a7 100644 --- a/Tests/RunCMake/find_package/RunCMakeTest.cmake +++ b/Tests/RunCMake/find_package/RunCMakeTest.cmake @@ -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)