ExternalProject: Preserve colons and semicolons in the path

The _ep_set_directories() function needs to ensure paths passed in
are in the expected CMake path form. The special character that
file(TO_CMAKE_PATH) interprets as a path separator must be
masked to prevent it splitting paths that contain that character
(semicolons on Windows, colons on other platforms).

Fixes: #26490
This commit is contained in:
Craig Scott
2025-01-19 22:30:46 +11:00
parent 49ffce754e
commit b1ff216656

View File

@@ -1310,6 +1310,26 @@ define_property(DIRECTORY PROPERTY "EP_STEP_TARGETS" INHERITED)
define_property(DIRECTORY PROPERTY "EP_INDEPENDENT_STEP_TARGETS" INHERITED)
define_property(DIRECTORY PROPERTY "EP_UPDATE_DISCONNECTED" INHERITED)
# file(TO_CMAKE_PATH) will interpret a platform-specific character as a path
# separator, and if its input contains that character, it will treat the input
# as a list. Sometimes we have a string that we know is always a single path,
# but it may contain the separator character. To prevent it being treated as a
# list of paths, this function masks the separator character while calling
# file(TO_CMAKE_PATH).
function(_ep_to_single_cmake_path out_var input)
if(WIN32)
set(unsafe_char ";")
else()
set(unsafe_char ":")
endif()
string(REPLACE "${unsafe_char}" "__EP_MARKER__" safe_input "${input}")
file(TO_CMAKE_PATH "${safe_input}" converted_input)
string(REPLACE "__EP_MARKER__" "${unsafe_char}" output "${converted_input}")
set(${out_var} "${output}" PARENT_SCOPE)
endfunction()
function(_ep_set_directories name)
get_property(prefix TARGET ${name} PROPERTY _EP_PREFIX)
if(NOT prefix)
@@ -1322,7 +1342,7 @@ function(_ep_set_directories name)
endif()
endif()
if(prefix)
file(TO_CMAKE_PATH "${prefix}" prefix)
_ep_to_single_cmake_path(prefix "${prefix}")
set(tmp_default "${prefix}/tmp")
set(download_default "${prefix}/src")
set(source_default "${prefix}/src/${name}")
@@ -1330,7 +1350,7 @@ function(_ep_set_directories name)
set(stamp_default "${prefix}/src/${name}-stamp")
set(install_default "${prefix}")
else()
file(TO_CMAKE_PATH "${base}" base)
_ep_to_single_cmake_path(base "${base}")
set(tmp_default "${base}/tmp/${name}")
set(download_default "${base}/Download/${name}")
set(source_default "${base}/Source/${name}")
@@ -1360,7 +1380,7 @@ function(_ep_set_directories name)
if(NOT IS_ABSOLUTE "${${var}_dir}")
get_filename_component(${var}_dir "${top}/${${var}_dir}" ABSOLUTE)
endif()
file(TO_CMAKE_PATH "${${var}_dir}" ${var}_dir)
_ep_to_single_cmake_path(${var}_dir "${${var}_dir}")
set_property(TARGET ${name} PROPERTY _EP_${VAR}_DIR "${${var}_dir}")
set(_EP_${VAR}_DIR "${${var}_dir}" PARENT_SCOPE)
endforeach()
@@ -1373,7 +1393,7 @@ function(_ep_set_directories name)
if(NOT IS_ABSOLUTE "${log_dir}")
get_filename_component(log_dir "${top}/${log_dir}" ABSOLUTE)
endif()
file(TO_CMAKE_PATH "${log_dir}" log_dir)
_ep_to_single_cmake_path(log_dir "${log_dir}")
set_property(TARGET ${name} PROPERTY _EP_LOG_DIR "${log_dir}")
set(_EP_LOG_DIR "${log_dir}" PARENT_SCOPE)
@@ -1388,7 +1408,7 @@ function(_ep_set_directories name)
else()
# Prefix with a slash so that when appended to the source directory, it
# behaves as expected.
file(TO_CMAKE_PATH "${source_subdir}" source_subdir)
_ep_to_single_cmake_path(source_subdir "${source_subdir}")
set_property(TARGET ${name} PROPERTY _EP_SOURCE_SUBDIR "/${source_subdir}")
set(_EP_SOURCE_SUBDIR "/${source_subdir}" PARENT_SCOPE)
endif()