From c393300e2bd02892950331d6c88458429614323f Mon Sep 17 00:00:00 2001 From: Brad King Date: Mon, 23 Jun 2025 10:29:47 -0400 Subject: [PATCH] cmake: Restore acceptance of -DCMAKE_TOOLCHAIN_FILE=//... on non-Windows POSIX specifies that two leading slashes have implementation-defined interpretation, so CMake 3.31 and below did not normalize away leading double slashes. However, most implementations simply treat a leading `//` as just `/`, so CMake 4.0 now normalizes them away when they do not correspond to a network path on Windows. This change exposed that we were not normalizing `CMAKE_TOOLCHAIN_FILE` before passing its value to `include()` the first time if it was not passed with the `FILEPATH` or `PATH` cache entry type. Fix that. Fixes: #27010 --- Modules/CMakeDetermineSystem.cmake | 27 ++++++++++++------- Tests/RunCMake/CommandLine/RunCMakeTest.cmake | 4 +++ .../toolchain-D-abs-path-stdout.txt | 1 + .../toolchain-D-slash-abs-path-stdout.txt | 1 + 4 files changed, 23 insertions(+), 10 deletions(-) create mode 100644 Tests/RunCMake/CommandLine/toolchain-D-abs-path-stdout.txt create mode 100644 Tests/RunCMake/CommandLine/toolchain-D-slash-abs-path-stdout.txt diff --git a/Modules/CMakeDetermineSystem.cmake b/Modules/CMakeDetermineSystem.cmake index 80db89c35f..dc26258eac 100644 --- a/Modules/CMakeDetermineSystem.cmake +++ b/Modules/CMakeDetermineSystem.cmake @@ -139,17 +139,24 @@ endif() # variables around so they can be used in CMakeLists.txt. # In all other cases, the host and target platform are the same. if(CMAKE_TOOLCHAIN_FILE) - # at first try to load it as path relative to the directory from which cmake has been run - include("${CMAKE_BINARY_DIR}/${CMAKE_TOOLCHAIN_FILE}" OPTIONAL RESULT_VARIABLE _INCLUDED_TOOLCHAIN_FILE) - if(NOT _INCLUDED_TOOLCHAIN_FILE) - # if the file isn't found there, check the default locations - include("${CMAKE_TOOLCHAIN_FILE}" OPTIONAL RESULT_VARIABLE _INCLUDED_TOOLCHAIN_FILE) - endif() - - if(_INCLUDED_TOOLCHAIN_FILE) - set(CMAKE_TOOLCHAIN_FILE "${_INCLUDED_TOOLCHAIN_FILE}" CACHE FILEPATH "The CMake toolchain file" FORCE) + if(IS_ABSOLUTE "${CMAKE_TOOLCHAIN_FILE}" AND EXISTS "${CMAKE_TOOLCHAIN_FILE}") + # Normalize the absolute path. + set(CMAKE_TOOLCHAIN_FILE "${CMAKE_TOOLCHAIN_FILE}" CACHE FILEPATH "The CMake toolchain file" FORCE) + set(CMAKE_TOOLCHAIN_FILE "$CACHE{CMAKE_TOOLCHAIN_FILE}") + include("${CMAKE_TOOLCHAIN_FILE}" OPTIONAL RESULT_VARIABLE _INCLUDED_TOOLCHAIN_FILE) else() - message(FATAL_ERROR "Could not find toolchain file: ${CMAKE_TOOLCHAIN_FILE}") + # at first try to load it as path relative to the directory from which cmake has been run + include("${CMAKE_BINARY_DIR}/${CMAKE_TOOLCHAIN_FILE}" OPTIONAL RESULT_VARIABLE _INCLUDED_TOOLCHAIN_FILE) + if(NOT _INCLUDED_TOOLCHAIN_FILE) + # if the file isn't found there, check the default locations + include("${CMAKE_TOOLCHAIN_FILE}" OPTIONAL RESULT_VARIABLE _INCLUDED_TOOLCHAIN_FILE) + endif() + if(_INCLUDED_TOOLCHAIN_FILE) + set(CMAKE_TOOLCHAIN_FILE "${_INCLUDED_TOOLCHAIN_FILE}" CACHE FILEPATH "The CMake toolchain file" FORCE) + endif() + endif() + if(NOT _INCLUDED_TOOLCHAIN_FILE) + message(FATAL_ERROR "Could not find toolchain file:\n \"${CMAKE_TOOLCHAIN_FILE}\"") endif() endif() diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake index efdf075a06..9fda9eb5b1 100644 --- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake +++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake @@ -264,6 +264,10 @@ function(run_Toolchain) run_cmake_with_options(toolchain-no-arg -S ${source_dir} --toolchain=) run_cmake_with_options(toolchain-valid-abs-path -S ${source_dir} --toolchain "${source_dir}/toolchain.cmake") run_cmake_with_options(toolchain-valid-rel-src-path -S ${source_dir} --toolchain=toolchain.cmake) + run_cmake_with_options(toolchain-D-abs-path -S ${source_dir} -DCMAKE_TOOLCHAIN_FILE=${source_dir}/toolchain.cmake) + if(CMAKE_HOST_UNIX AND NOT CMAKE_SYSTEM_NAME STREQUAL "CYGWIN" AND NOT CMAKE_SYSTEM_NAME STREQUAL "MSYS") + run_cmake_with_options(toolchain-D-slash-abs-path -S ${source_dir} -DCMAKE_TOOLCHAIN_FILE=/${source_dir}/toolchain.cmake) + endif() set(RunCMake_TEST_NO_CLEAN 1) set(binary_dir ${RunCMake_BINARY_DIR}/Toolchain-build) diff --git a/Tests/RunCMake/CommandLine/toolchain-D-abs-path-stdout.txt b/Tests/RunCMake/CommandLine/toolchain-D-abs-path-stdout.txt new file mode 100644 index 0000000000..753f00b5ad --- /dev/null +++ b/Tests/RunCMake/CommandLine/toolchain-D-abs-path-stdout.txt @@ -0,0 +1 @@ +CMAKE_TOOLCHAIN_FILE='[^']*/Tests/RunCMake/CommandLine/Toolchain/toolchain\.cmake' diff --git a/Tests/RunCMake/CommandLine/toolchain-D-slash-abs-path-stdout.txt b/Tests/RunCMake/CommandLine/toolchain-D-slash-abs-path-stdout.txt new file mode 100644 index 0000000000..9e9781f38a --- /dev/null +++ b/Tests/RunCMake/CommandLine/toolchain-D-slash-abs-path-stdout.txt @@ -0,0 +1 @@ +CMAKE_TOOLCHAIN_FILE='/[^/][^']*/Tests/RunCMake/CommandLine/Toolchain/toolchain\.cmake'