cmFindCommon::RerootPaths() mishandles case where CMAKE_PREFIX_PATH matches one of the roots
If an entry in CMAKE_PREFIX_PATH
happens to point to the same directory as one of the entries in CMAKE_FIND_ROOT_PATH
or CMAKE_STAGING_PREFIX
, then cmFindCommon::RerootPaths()
ends up concatenating them instead of just using the path as is (i.e. it appends the path to itself). Here is the relevant part of the code:
for (std::string const& r : roots) {
for (std::string const& up : unrootedPaths) {
// Place the unrooted path under the current root if it is not
// already inside. Skip the unrooted path if it is relative to
// a user home directory or is empty.
std::string rootedDir;
if (cmSystemTools::IsSubDirectory(up, r) ||
(stagePrefix && cmSystemTools::IsSubDirectory(up, *stagePrefix))) {
rootedDir = up;
} else if (!up.empty() && up[0] != '~') {
// Start with the new root.
rootedDir = cmStrCat(r, '/');
// Append the original path with its old root removed.
rootedDir += cmSystemTools::SplitPathRootComponent(up);
}
// Store the new path.
paths.push_back(rootedDir);
}
}
The cmSystemTools::IsSubdirectory()
calls look like they should actually be "is the same or a subdirectory".
A scenario where this can arise is where something sets CMAKE_FIND_ROOT_PATH_PACKAGE
to ONLY
(e.g. the NDK toolchain file does this), so anything specified by a CMAKE_PREFIX_PATH
will only be used in a re-rooted form. Users may wonder why the CMAKE_PREFIX_PATH
they gave was ignored, not realising that CMAKE_FIND_ROOT_PATH_PACKAGE
has been set to ONLY
and therefore their CMAKE_PREFIX_PATH
will always be re-rooted. So they then go and set CMAKE_FIND_ROOT_PATH
to the same value as CMAKE_PREFIX_PATH
, hoping that will work, but it doesn't. They then set CMAKE_PREFIX_PATH
to a subdirectory of CMAKE_FIND_ROOT_PATH
and it does work. This is confusing for users and was actually what happened with the Qt project in the toolchain file it provides as a convenience when cross-compiling.