diff --git a/Modules/Platform/CrayLinuxEnvironment.cmake b/Modules/Platform/CrayLinuxEnvironment.cmake index daff647591..56717e937d 100644 --- a/Modules/Platform/CrayLinuxEnvironment.cmake +++ b/Modules/Platform/CrayLinuxEnvironment.cmake @@ -40,9 +40,16 @@ endif() # The rest of this file is based on UnixPaths.cmake, adjusted for Cray # add the install directory of the running cmake to the search directories -# CMAKE_ROOT is CMAKE_INSTALL_PREFIX/share/cmake, so we need to go two levels up +# CMAKE_ROOT is CMAKE_INSTALL_PREFIX/share/cmake, so we need to go two levels up. +# When CMake runs from its build tree, CMAKE_ROOT is the source tree instead. get_filename_component(__cmake_install_dir "${CMAKE_ROOT}" PATH) get_filename_component(__cmake_install_dir "${__cmake_install_dir}" PATH) +get_property(__cmake_running_in_build_tree GLOBAL PROPERTY + _CMAKE_RUNNING_IN_BUILD_TREE) +if(__cmake_running_in_build_tree) + set(__cmake_install_dir "") +endif() +unset(__cmake_running_in_build_tree) # Note: Some Cray's have the SYSROOT_DIR variable defined, pointing to a copy # of the NIDs userland. If so, then we'll use it. Otherwise, just assume @@ -53,10 +60,13 @@ get_filename_component(__cmake_install_dir "${__cmake_install_dir}" PATH) list(APPEND CMAKE_SYSTEM_PREFIX_PATH # Standard $ENV{SYSROOT_DIR}/usr/local $ENV{SYSROOT_DIR}/usr $ENV{SYSROOT_DIR}/ - - # CMake install location - "${__cmake_install_dir}" ) +if(__cmake_install_dir) + list(APPEND CMAKE_SYSTEM_PREFIX_PATH + # CMake install location + "${__cmake_install_dir}" + ) +endif() if (NOT CMAKE_FIND_NO_INSTALL_PREFIX) list(APPEND CMAKE_SYSTEM_PREFIX_PATH # Project install destination. diff --git a/Modules/Platform/UnixPaths.cmake b/Modules/Platform/UnixPaths.cmake index e95da44ea4..9aa659e4fd 100644 --- a/Modules/Platform/UnixPaths.cmake +++ b/Modules/Platform/UnixPaths.cmake @@ -18,9 +18,16 @@ set(__UNIX_PATHS_INCLUDED 1) set(UNIX 1) # also add the install directory of the running cmake to the search directories -# CMAKE_ROOT is CMAKE_INSTALL_PREFIX/share/cmake, so we need to go two levels up +# CMAKE_ROOT is CMAKE_INSTALL_PREFIX/share/cmake, so we need to go two levels up. +# When CMake runs from its build tree, CMAKE_ROOT is the source tree instead. get_filename_component(_CMAKE_INSTALL_DIR "${CMAKE_ROOT}" PATH) get_filename_component(_CMAKE_INSTALL_DIR "${_CMAKE_INSTALL_DIR}" PATH) +get_property(_cmake_running_in_build_tree GLOBAL PROPERTY + _CMAKE_RUNNING_IN_BUILD_TREE) +if(_cmake_running_in_build_tree) + set(_CMAKE_INSTALL_DIR "") +endif() +unset(_cmake_running_in_build_tree) # List common installation prefixes. These will be used for all # search types. @@ -31,10 +38,13 @@ get_filename_component(_CMAKE_INSTALL_DIR "${_CMAKE_INSTALL_DIR}" PATH) list(APPEND CMAKE_SYSTEM_PREFIX_PATH # Standard /usr/local /usr / - - # CMake install location - "${_CMAKE_INSTALL_DIR}" ) +if(_CMAKE_INSTALL_DIR) + list(APPEND CMAKE_SYSTEM_PREFIX_PATH + # CMake install location + "${_CMAKE_INSTALL_DIR}" + ) +endif() if (NOT CMAKE_FIND_NO_INSTALL_PREFIX) list(APPEND CMAKE_SYSTEM_PREFIX_PATH # Project install destination. diff --git a/Modules/Platform/WindowsPaths.cmake b/Modules/Platform/WindowsPaths.cmake index c56dfaf9ac..0f19b95e85 100644 --- a/Modules/Platform/WindowsPaths.cmake +++ b/Modules/Platform/WindowsPaths.cmake @@ -50,9 +50,19 @@ endif() unset(_programfiles) # Add the CMake install location. +# CMAKE_ROOT is CMAKE_INSTALL_PREFIX/share/cmake, so we need to go two levels up. +# When CMake runs from its build tree, CMAKE_ROOT is the source tree instead. get_filename_component(_CMAKE_INSTALL_DIR "${CMAKE_ROOT}" PATH) get_filename_component(_CMAKE_INSTALL_DIR "${_CMAKE_INSTALL_DIR}" PATH) -list(APPEND CMAKE_SYSTEM_PREFIX_PATH "${_CMAKE_INSTALL_DIR}") +get_property(_cmake_running_in_build_tree GLOBAL PROPERTY + _CMAKE_RUNNING_IN_BUILD_TREE) +if(_cmake_running_in_build_tree) + set(_CMAKE_INSTALL_DIR "") +endif() +unset(_cmake_running_in_build_tree) +if(_CMAKE_INSTALL_DIR) + list(APPEND CMAKE_SYSTEM_PREFIX_PATH "${_CMAKE_INSTALL_DIR}") +endif() if (NOT CMAKE_FIND_NO_INSTALL_PREFIX) # Add other locations. @@ -88,8 +98,12 @@ if (NOT CMAKE_FIND_NO_INSTALL_PREFIX) ) endif() endif() +if(_CMAKE_INSTALL_DIR) + list(APPEND CMAKE_SYSTEM_LIBRARY_PATH + "${_CMAKE_INSTALL_DIR}/bin" + ) +endif() list(APPEND CMAKE_SYSTEM_LIBRARY_PATH - "${_CMAKE_INSTALL_DIR}/bin" /bin ) diff --git a/Source/cmState.cxx b/Source/cmState.cxx index 038fdde1bc..10d792ee43 100644 --- a/Source/cmState.cxx +++ b/Source/cmState.cxx @@ -673,6 +673,9 @@ cmValue cmState::GetGlobalProperty(std::string const& prop) this->SetGlobalProperty("ENABLED_LANGUAGES", langs); } else if (prop == "CMAKE_ROLE") { this->SetGlobalProperty("CMAKE_ROLE", this->GetRoleString()); + } else if (prop == "_CMAKE_RUNNING_IN_BUILD_TREE") { + this->SetGlobalProperty("_CMAKE_RUNNING_IN_BUILD_TREE", + cmSystemTools::GetCMakeInBuildTree() ? "1" : "0"); } #define STRING_LIST_ELEMENT(F) ";" #F if (prop == "CMAKE_C_KNOWN_FEATURES") { diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 485a72eb50..9fe72eecb0 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -2889,6 +2889,8 @@ std::string InitLogicalWorkingDirectory() return cwd; } +bool cmSystemToolsCMakeInBuildTree = false; + std::string cmSystemToolsLogicalWorkingDirectory = InitLogicalWorkingDirectory(); @@ -3013,6 +3015,7 @@ void FindCMakeResourcesInBuildTree(std::string const& exe_dir) if (fin && cmSystemTools::GetLineFromStream(fin, src_dir) && cmSystemTools::FileIsDirectory(src_dir)) { cmSystemToolsCMakeRoot = src_dir; + cmSystemToolsCMakeInBuildTree = true; } else { dir = cmSystemTools::GetFilenamePath(dir); src_dir_txt = cmStrCat(dir, "/CMakeFiles/CMakeSourceDir.txt"); @@ -3020,6 +3023,7 @@ void FindCMakeResourcesInBuildTree(std::string const& exe_dir) if (fin2 && cmSystemTools::GetLineFromStream(fin2, src_dir) && cmSystemTools::FileIsDirectory(src_dir)) { cmSystemToolsCMakeRoot = src_dir; + cmSystemToolsCMakeInBuildTree = true; } } if (!cmSystemToolsCMakeRoot.empty() && cmSystemToolsHTMLDoc.empty() && @@ -3037,6 +3041,7 @@ void cmSystemTools::FindCMakeResources(char const* argv0) #ifdef CMAKE_BOOTSTRAP // The bootstrap cmake knows its resource locations. cmSystemToolsCMakeRoot = CMAKE_BOOTSTRAP_SOURCE_DIR; + cmSystemToolsCMakeInBuildTree = true; cmSystemToolsCMakeCommand = exe; // The bootstrap cmake does not provide the other tools, // so use the directory where they are about to be built. @@ -3120,6 +3125,11 @@ std::string const& cmSystemTools::GetCMakeRoot() return cmSystemToolsCMakeRoot; } +bool cmSystemTools::GetCMakeInBuildTree() +{ + return cmSystemToolsCMakeInBuildTree; +} + std::string const& cmSystemTools::GetHTMLDoc() { return cmSystemToolsHTMLDoc; diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index 7eaee0ec5c..93e0ef6f5e 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -560,6 +560,7 @@ public: static std::string const& GetCMakeCursesCommand(); static std::string const& GetCMClDepsCommand(); static std::string const& GetCMakeRoot(); + static bool GetCMakeInBuildTree(); static std::string const& GetHTMLDoc(); /** Get the CMake config directory **/ diff --git a/Tests/RunCMake/find_library/BuildTreePrefixNoLeak.cmake b/Tests/RunCMake/find_library/BuildTreePrefixNoLeak.cmake new file mode 100644 index 0000000000..6a067600d4 --- /dev/null +++ b/Tests/RunCMake/find_library/BuildTreePrefixNoLeak.cmake @@ -0,0 +1,32 @@ +# Regression net for the build-tree prefix leak fixed in the Platform modules. +# When CMake runs from its build tree, CMAKE_ROOT is the source tree rather +# than an install-tree resource directory. In that case, the historical +# dirname(dirname(CMAKE_ROOT)) install-prefix calculation must not be added to +# CMAKE_SYSTEM_PREFIX_PATH. + +get_property(_cmake_running_in_build_tree GLOBAL PROPERTY + _CMAKE_RUNNING_IN_BUILD_TREE) + +if(_cmake_running_in_build_tree) + get_filename_component(_leak_root_dir "${CMAKE_ROOT}" PATH) + get_filename_component(_leak_prefix "${_leak_root_dir}" PATH) + + # Empty means there is no candidate. "/" is already a standard entry, not + # evidence of this leak. + if(_leak_prefix AND + NOT _leak_prefix STREQUAL "/" AND + _leak_prefix IN_LIST CMAKE_SYSTEM_PREFIX_PATH) + # Corner case intentionally not excluded: checking the CMake *source* tree + # out into a system prefix such as /usr/src or /opt/ would make + # _leak_prefix a standard root and trip this assertion. Those are + # install/system trees, not dev/CI workspaces, so the corner is treated as + # an unsupported layout. + message(FATAL_ERROR + "CMAKE_SYSTEM_PREFIX_PATH leaked dirname(dirname(CMAKE_ROOT))=\"${_leak_prefix}\" " + "(CMAKE_ROOT=\"${CMAKE_ROOT}\"); the Platform/*.cmake build-tree guard regressed.") + endif() +endif() + +unset(_cmake_running_in_build_tree) +unset(_leak_root_dir) +unset(_leak_prefix) diff --git a/Tests/RunCMake/find_library/RunCMakeTest.cmake b/Tests/RunCMake/find_library/RunCMakeTest.cmake index 32da627439..118ef9b26f 100644 --- a/Tests/RunCMake/find_library/RunCMakeTest.cmake +++ b/Tests/RunCMake/find_library/RunCMakeTest.cmake @@ -3,6 +3,7 @@ include(RunCMake) run_cmake(ConfigureLogTransitions) run_cmake(ConfigureLogTransitionsSuppressed) run_cmake(Created) +run_cmake(BuildTreePrefixNoLeak) run_cmake(FromPrefixPath) run_cmake(FromPATHEnv) run_cmake_with_options(IgnoreInstallPrefix "-DCMAKE_INSTALL_PREFIX=${RunCMake_BINARY_DIR}/IgnoreInstallPrefix-build/")