ExternalProject,FetchContent: Avoid CMAKE_DISABLE_SOURCE_CHANGES error

The file(MAKE_DIRECTORY) implementation checks whether a path is
allowed to be written to before it checks if it already exists. For the
scenario where a SOURCE_DIR is an existing directory within the main
project's source directory, this triggers a fatal error if
CMAKE_DISABLE_SOURCE_CHANGES is set to true for ExternalProject,
and some FetchContent scenarios. Therefore, add an explicit check for
existence first to avoid making such error-triggering calls.

Fixes: #21872
This commit is contained in:
Craig Scott
2024-05-31 17:38:10 +10:00
parent 140766867b
commit 0cc1b550dd
6 changed files with 49 additions and 2 deletions

View File

@@ -3,8 +3,13 @@
cmake_minimum_required(VERSION 3.5)
# If CMAKE_DISABLE_SOURCE_CHANGES is set to true and the source directory is an
# existing directory in our source tree, calling file(MAKE_DIRECTORY) on it
# would cause a fatal error, even though it would be a no-op.
if(NOT EXISTS "@source_dir@")
file(MAKE_DIRECTORY "@source_dir@")
endif()
file(MAKE_DIRECTORY
"@source_dir@"
"@binary_dir@"
"@install_dir@"
"@tmp_dir@"

View File

@@ -1657,8 +1657,13 @@ function(__FetchContent_populateDirect)
set(_EP_TMP_DIR "${FETCHCONTENT_BASE_DIR}/${contentNameLower}-tmp")
set(_EP_DOWNLOAD_DIR "${_EP_TMP_DIR}")
# If CMAKE_DISABLE_SOURCE_CHANGES is set to true and _EP_SOURCE_DIR is an
# existing directory in our source tree, calling file(MAKE_DIRECTORY) on it
# would cause a fatal error, even though it would be a no-op.
if(NOT EXISTS "${_EP_SOURCE_DIR}")
file(MAKE_DIRECTORY "${_EP_SOURCE_DIR}")
endif()
file(MAKE_DIRECTORY
"${_EP_SOURCE_DIR}"
"${_EP_BINARY_DIR}"
"${_EP_STAMP_DIR}"
"${_EP_TMP_DIR}"

View File

@@ -21,6 +21,7 @@ run_cmake(TLSVersionBadEnv)
run_cmake(NoOptions)
run_cmake(SourceEmpty)
run_cmake(SourceMissing)
run_cmake(SourceDirExisting)
run_cmake(CMAKE_CACHE_ARGS)
run_cmake(CMAKE_CACHE_DEFAULT_ARGS)
run_cmake(CMAKE_CACHE_mix)

View File

@@ -0,0 +1,16 @@
# We're providing a pre-existing source directory. Make sure we don't trigger
# an error if the undocumented but used-in-the-wild CMAKE_DISABLE_SOURCE_CHANGES
# variable is set.
set(CMAKE_DISABLE_SOURCE_CHANGES TRUE)
include(ExternalProject)
ExternalProject_Add(source_dir_existing
SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/Foo"
DOWNLOAD_COMMAND "${CMAKE_COMMAND}" -E echo "Download command executed"
UPDATE_COMMAND ""
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
TEST_COMMAND ""
INSTALL_COMMAND ""
)

View File

@@ -0,0 +1,18 @@
cmake_policy(SET CMP0168 NEW)
# Undocumented variable used to catch attempts to write to anywhere under the
# source directory that isn't under the build directory. In order for this
# code path to be checked for direct population mode, we need a non-empty
# download, update, or patch command so that the population code path is used.
# Custom commands might not write to the source directory and instead just
# print messages or other non-modifying tasks, like is done here.
set(CMAKE_DISABLE_SOURCE_CHANGES TRUE)
include(FetchContent)
FetchContent_Declare(
WithProject
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/WithProject # This exists
DOWNLOAD_COMMAND ${CMAKE_COMMAND} -E echo "Download command executed"
)
FetchContent_MakeAvailable(WithProject)

View File

@@ -106,3 +106,5 @@ run_cmake_command(ScriptMode-direct
-DCMP0168=NEW
-P ${CMAKE_CURRENT_LIST_DIR}/ScriptMode.cmake
)
run_cmake(DisableSourceChanges)