diff options
23 files changed, 575 insertions, 1 deletions
diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst index 8c7189a..ff57390 100644 --- a/Help/manual/cmake-policies.7.rst +++ b/Help/manual/cmake-policies.7.rst @@ -57,6 +57,7 @@ Policies Introduced by CMake 3.27 .. toctree:: :maxdepth: 1 + CMP0150: ExternalProject_Add and FetchContent_Declare treat relative git repository paths as being relative to parent project's remote. </policy/CMP0150> CMP0149: Visual Studio generators select latest Windows SDK by default. </policy/CMP0149> CMP0148: The FindPythonInterp and FindPythonLibs modules are removed. </policy/CMP0148> CMP0147: Visual Studio generators build custom commands in parallel. </policy/CMP0147> diff --git a/Help/policy/CMP0150.rst b/Help/policy/CMP0150.rst new file mode 100644 index 0000000..fe646d9 --- /dev/null +++ b/Help/policy/CMP0150.rst @@ -0,0 +1,39 @@ +CMP0150 +------- + +.. versionadded:: 3.27 + +:command:`ExternalProject_Add` and :command:`FetchContent_Declare` commands +treat relative ``GIT_REPOSITORY`` paths as being relative to the parent +project's remote. + +Earlier versions of these commands always treated relative paths in +``GIT_REPOSITORY`` as local paths, but the base directory it was treated +as relative to was both undocumented and unintuitive. The ``OLD`` behavior +for this policy is to interpret relative paths used for ``GIT_REPOSITORY`` +as local paths relative to the following: + +* The parent directory of ``SOURCE_DIR`` for :command:`ExternalProject_Add`. +* ``FETCHCONTENT_BASE_DIR`` for :command:`FetchContent_Declare`. + +The ``NEW`` behavior is to determine the remote from the parent project and +interpret the path relative to that remote. The value of +:variable:`CMAKE_CURRENT_SOURCE_DIR` when :command:`ExternalProject_Add` or +:command:`FetchContent_Declare` is called determines the parent project. +The remote is selected according to the following (the first match is used): + +* If the parent project is checked out on a branch with an upstream remote + defined, use that remote. +* If only one remote is defined, use that remote. +* If multiple remotes are defined and one of them is named ``origin``, use + ``origin``'s remote but also issue a warning. + +If an appropriate remote cannot be determined from the above, a fatal error +will be raised. + +This policy was introduced in CMake version 3.27. CMake version |release| +warns when a relative path is encountered and the policy is not set, +falling back to using ``OLD`` behavior. Use the :command:`cmake_policy` +command to set it to ``OLD`` or ``NEW`` explicitly. + +.. include:: DEPRECATED.txt diff --git a/Help/release/dev/ExternalProject-FetchContent-relative-git-remotes.rst b/Help/release/dev/ExternalProject-FetchContent-relative-git-remotes.rst new file mode 100644 index 0000000..d467620 --- /dev/null +++ b/Help/release/dev/ExternalProject-FetchContent-relative-git-remotes.rst @@ -0,0 +1,7 @@ +ExternalProject-FetchContent-Relative-git-remotes +------------------------------------------------- + +* The :module:`ExternalProject` and :module:`FetchContent` modules + now resolve relative `GIT_REPOSITORY` paths as relative to the + parent project's remote, not as a relative local file system path. + See :policy:`CMP0150`. diff --git a/Modules/ExternalProject.cmake b/Modules/ExternalProject.cmake index 9a6cbd6..e2cc497 100644 --- a/Modules/ExternalProject.cmake +++ b/Modules/ExternalProject.cmake @@ -278,6 +278,13 @@ External Project Definition URL of the git repository. Any URL understood by the ``git`` command may be used. + .. versionchanged:: 3.27 + A relative URL will be resolved based on the parent project's + remote, subject to :policy:`CMP0150`. See the policy documentation + for how the remote is selected, including conditions where the + remote selection can fail. Local filesystem remotes should + always use absolute paths. + ``GIT_TAG <tag>`` Git branch name, tag or commit hash. Note that branch names and tags should generally be specified as remote names (i.e. ``origin/myBranch`` @@ -1188,6 +1195,8 @@ The custom step could then be triggered from the main build like so:: #]=======================================================================] +include(${CMAKE_CURRENT_LIST_DIR}/ExternalProject/shared_internal_commands.cmake) + cmake_policy(PUSH) cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced cmake_policy(SET CMP0057 NEW) # if() supports IN_LIST @@ -4159,6 +4168,17 @@ function(ExternalProject_Add name) set_property(TARGET ${name} PROPERTY EXCLUDE_FROM_ALL TRUE) endif() + get_property(repo TARGET ${name} PROPERTY _EP_GIT_REPOSITORY) + if(NOT repo STREQUAL "") + cmake_policy(GET CMP0150 cmp0150 + PARENT_SCOPE # undocumented, do not use outside of CMake + ) + get_property(source_dir TARGET ${name} PROPERTY _EP_SOURCE_DIR) + get_filename_component(work_dir "${source_dir}" PATH) + _ep_resolve_git_remote(resolved_git_repository "${repo}" "${cmp0150}" "${work_dir}") + set_property(TARGET ${name} PROPERTY _EP_GIT_REPOSITORY ${resolved_git_repository}) + endif() + # The 'complete' step depends on all other steps and creates a # 'done' mark. A dependent external project's 'configure' step # depends on the 'done' mark so that it rebuilds when this project diff --git a/Modules/ExternalProject/shared_internal_commands.cmake b/Modules/ExternalProject/shared_internal_commands.cmake new file mode 100644 index 0000000..ca3cd9f --- /dev/null +++ b/Modules/ExternalProject/shared_internal_commands.cmake @@ -0,0 +1,182 @@ +cmake_policy(VERSION 3.25) + +# Determine the remote URL of the project containing the working_directory. +# This will leave output_variable unset if the URL can't be determined. +function(_ep_get_git_remote_url output_variable working_directory) + set("${output_variable}" "" PARENT_SCOPE) + + find_package(Git QUIET REQUIRED) + + execute_process( + COMMAND ${GIT_EXECUTABLE} symbolic-ref --short HEAD + WORKING_DIRECTORY "${working_directory}" + OUTPUT_VARIABLE git_symbolic_ref + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + + if(NOT git_symbolic_ref STREQUAL "") + # We are potentially on a branch. See if that branch is associated with + # an upstream remote (might be just a local one or not a branch at all). + execute_process( + COMMAND ${GIT_EXECUTABLE} config branch.${git_symbolic_ref}.remote + WORKING_DIRECTORY "${working_directory}" + OUTPUT_VARIABLE git_remote_name + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + endif() + + if(NOT git_remote_name) + # Can't select a remote based on a branch. If there's only one remote, + # or we have multiple remotes but one is called "origin", choose that. + execute_process( + COMMAND ${GIT_EXECUTABLE} remote + WORKING_DIRECTORY "${working_directory}" + OUTPUT_VARIABLE git_remote_list + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + string(REPLACE "\n" ";" git_remote_list "${git_remote_list}") + list(LENGTH git_remote_list git_remote_list_length) + + if(git_remote_list_length EQUAL 0) + message(FATAL_ERROR "Git remote not found in parent project.") + elseif(git_remote_list_length EQUAL 1) + list(GET git_remote_list 0 git_remote_name) + else() + set(base_warning_msg "Multiple git remotes found for parent project") + if("origin" IN_LIST git_remote_list) + message(WARNING "${base_warning_msg}, defaulting to origin.") + set(git_remote_name "origin") + else() + message(FATAL_ERROR "${base_warning_msg}, none of which are origin.") + endif() + endif() + endif() + + if(GIT_VERSION VERSION_LESS 1.7.5) + set(_git_remote_url_cmd_args config remote.${git_remote_name}.url) + elseif(GIT_VERSION VERSION_LESS 2.7) + set(_git_remote_url_cmd_args ls-remote --get-url ${git_remote_name}) + else() + set(_git_remote_url_cmd_args remote get-url ${git_remote_name}) + endif() + + execute_process( + COMMAND ${GIT_EXECUTABLE} ${_git_remote_url_cmd_args} + WORKING_DIRECTORY "${working_directory}" + OUTPUT_VARIABLE git_remote_url + OUTPUT_STRIP_TRAILING_WHITESPACE + COMMAND_ERROR_IS_FATAL LAST + ENCODING UTF-8 # Needed to handle non-ascii characters in local paths + ) + + set("${output_variable}" "${git_remote_url}" PARENT_SCOPE) +endfunction() + +function(_ep_is_relative_git_remote output_variable remote_url) + if(remote_url MATCHES "^\\.\\./") + set("${output_variable}" TRUE PARENT_SCOPE) + else() + set("${output_variable}" FALSE PARENT_SCOPE) + endif() +endfunction() + +# Return an absolute remote URL given an existing remote URL and relative path. +# The output_variable will be set to an empty string if an absolute URL +# could not be computed (no error message is output). +function(_ep_resolve_relative_git_remote + output_variable + parent_remote_url + relative_remote_url +) + set("${output_variable}" "" PARENT_SCOPE) + + if(parent_remote_url STREQUAL "") + return() + endif() + + string(REGEX MATCH + "^(([A-Za-z0-9][A-Za-z0-9+.-]*)://)?(([^/@]+)@)?(\\[[A-Za-z0-9:]+\\]|[^/:]+)?([/:]/?)(.+(\\.git)?/?)$" + git_remote_url_components + "${parent_remote_url}" + ) + + set(protocol "${CMAKE_MATCH_1}") + set(auth "${CMAKE_MATCH_3}") + set(host "${CMAKE_MATCH_5}") + set(separator "${CMAKE_MATCH_6}") + set(path "${CMAKE_MATCH_7}") + + string(REPLACE "/" ";" remote_path_components "${path}") + string(REPLACE "/" ";" relative_path_components "${relative_remote_url}") + + foreach(relative_path_component IN LISTS relative_path_components) + if(NOT relative_path_component STREQUAL "..") + break() + endif() + + list(LENGTH remote_path_components remote_path_component_count) + + if(remote_path_component_count LESS 1) + return() + endif() + + list(POP_BACK remote_path_components) + list(POP_FRONT relative_path_components) + endforeach() + + list(APPEND final_path_components ${remote_path_components} ${relative_path_components}) + list(JOIN final_path_components "/" path) + + set("${output_variable}" "${protocol}${auth}${host}${separator}${path}" PARENT_SCOPE) +endfunction() + +# The output_variable will be set to the original git_repository if it +# could not be resolved (no error message is output). The original value is +# also returned if it doesn't need to be resolved. +function(_ep_resolve_git_remote + output_variable + git_repository + cmp0150 + cmp0150_old_base_dir +) + if(git_repository STREQUAL "") + set("${output_variable}" "" PARENT_SCOPE) + return() + endif() + + _ep_is_relative_git_remote(_git_repository_is_relative "${git_repository}") + + if(NOT _git_repository_is_relative) + set("${output_variable}" "${git_repository}" PARENT_SCOPE) + return() + endif() + + if(cmp0150 STREQUAL "NEW") + _ep_get_git_remote_url(_parent_git_remote_url "${CMAKE_CURRENT_SOURCE_DIR}") + _ep_resolve_relative_git_remote(_resolved_git_remote_url "${_parent_git_remote_url}" "${git_repository}") + + if(_resolved_git_remote_url STREQUAL "") + message(FATAL_ERROR + "Failed to resolve relative git remote URL:\n" + " Relative URL: ${git_repository}\n" + " Parent URL: ${_parent_git_remote_url}" + ) + endif() + set("${output_variable}" "${_resolved_git_remote_url}" PARENT_SCOPE) + return() + elseif(cmp0150 STREQUAL "") + cmake_policy(GET_WARNING CMP0150 _cmp0150_warning) + message(AUTHOR_WARNING + "${_cmp0150_warning}\n" + "A relative GIT_REPOSITORY path was detected. " + "This will be interpreted as a local path to where the project is being cloned. " + "Set GIT_REPOSITORY to an absolute path or set policy CMP0150 to NEW to avoid " + "this warning." + ) + endif() + + set("${output_variable}" "${cmp0150_old_base_dir}/${git_repository}" PARENT_SCOPE) +endfunction() diff --git a/Modules/FetchContent.cmake b/Modules/FetchContent.cmake index dd5f617..74ac8aa 100644 --- a/Modules/FetchContent.cmake +++ b/Modules/FetchContent.cmake @@ -1076,6 +1076,8 @@ current working directory. #]=======================================================================] +include(${CMAKE_CURRENT_LIST_DIR}/ExternalProject/shared_internal_commands.cmake) + #======================================================================= # Recording and retrieving content details for later population #======================================================================= @@ -1223,6 +1225,7 @@ function(FetchContent_Declare contentName) # cannot check for multi-value arguments with this method. We will have to # handle the URL keyword differently. set(oneValueArgs + GIT_REPOSITORY SVN_REPOSITORY DOWNLOAD_NO_EXTRACT DOWNLOAD_EXTRACT_TIMESTAMP @@ -1242,6 +1245,30 @@ function(FetchContent_Declare contentName) set(ARG_SOURCE_DIR "${FETCHCONTENT_BASE_DIR}/${contentNameLower}-src") endif() + if(ARG_GIT_REPOSITORY) + # We resolve the GIT_REPOSITORY here so that we get the right parent in the + # remote selection logic. In the sub-build, ExternalProject_Add() would see + # the private sub-build directory as the parent project, but the parent + # project should be the one that called FetchContent_Declare(). We resolve + # a relative repo here so that the sub-build's ExternalProject_Add() only + # ever sees a non-relative repo. + # Since these checks may be non-trivial on some platforms (notably Windows), + # don't perform them if we won't be using these details. This also allows + # projects to override calls with relative URLs when they have checked out + # the parent project in an unexpected way, such as from a mirror or fork. + set(savedDetailsPropertyName "_FetchContent_${contentNameLower}_savedDetails") + get_property(alreadyDefined GLOBAL PROPERTY ${savedDetailsPropertyName} DEFINED) + if(NOT alreadyDefined) + cmake_policy(GET CMP0150 cmp0150 + PARENT_SCOPE # undocumented, do not use outside of CMake + ) + _ep_resolve_git_remote(_resolved_git_repository + "${ARG_GIT_REPOSITORY}" "${cmp0150}" "${FETCHCONTENT_BASE_DIR}" + ) + set(ARG_GIT_REPOSITORY "${_resolved_git_repository}") + endif() + endif() + if(ARG_SVN_REPOSITORY) # Add a hash of the svn repository URL to the source dir. This works # around the problem where if the URL changes, the download would diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index fe88382..23e50a9 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -450,7 +450,12 @@ class cmMakefile; 27, 0, cmPolicies::WARN) \ SELECT(POLICY, CMP0149, \ "Visual Studio generators select latest Windows SDK by default.", 3, \ - 27, 0, cmPolicies::WARN) + 27, 0, cmPolicies::WARN) \ + SELECT(POLICY, CMP0150, \ + "ExternalProject_Add and FetchContent_Declare commands " \ + "treat relative GIT_REPOSITORY paths as being relative " \ + "to the parent project's remote.", \ + 3, 27, 0, cmPolicies::WARN) #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1) #define CM_FOR_EACH_POLICY_ID(POLICY) \ diff --git a/Tests/RunCMake/CMP0150/CMP0150-NEW-build-stdout.txt b/Tests/RunCMake/CMP0150/CMP0150-NEW-build-stdout.txt new file mode 100644 index 0000000..9e71b73 --- /dev/null +++ b/Tests/RunCMake/CMP0150/CMP0150-NEW-build-stdout.txt @@ -0,0 +1,7 @@ +.*-- Configured bottom project +.*ExternalProject for ep-Y +.*-- Configured bottom project +[^\n]*-- Completed configuring project middle +.*-- Configured bottom project +.*ExternalProject for ep-X +.*Non-ep top project diff --git a/Tests/RunCMake/CMP0150/CMP0150-NEW-resolve.cmake b/Tests/RunCMake/CMP0150/CMP0150-NEW-resolve.cmake new file mode 100644 index 0000000..f43f3d5 --- /dev/null +++ b/Tests/RunCMake/CMP0150/CMP0150-NEW-resolve.cmake @@ -0,0 +1,107 @@ +include(ExternalProject/shared_internal_commands) + +function(test_resolve parentUrl relativeUrl expectedResult) + _ep_resolve_relative_git_remote(result "${parentUrl}" "${relativeUrl}") + if(NOT result STREQUAL expectedResult) + message(SEND_ERROR "URL resolved to unexpected result:\n" + " Expected: ${expectedResult}\n" + " Actual : ${result}" + ) + endif() +endfunction() + +test_resolve( + "https://example.com/group/parent" + "../other" + "https://example.com/group/other" +) +test_resolve( + "https://example.com/group/parent" + "../../alt/other" + "https://example.com/alt/other" +) + +test_resolve( + "git@example.com:group/parent" + "../other" + "git@example.com:group/other" +) +test_resolve( + "git@example.com:group/parent" + "../../alt/other" + "git@example.com:alt/other" +) +test_resolve( + "git@example.com:/group/parent" + "../other" + "git@example.com:/group/other" +) +test_resolve( + "git@example.com:/group/parent" + "../../alt/other" + "git@example.com:/alt/other" +) +test_resolve( + "git+ssh://git@example.com:group/parent" + "../other" + "git+ssh://git@example.com:group/other" +) +test_resolve( + "ssh://git@example.com:1234/group/parent" + "../../alt/other" + "ssh://git@example.com:1234/alt/other" +) + +test_resolve( + "file:///group/parent" + "../other" + "file:///group/other" +) +test_resolve( + "file:///group/parent" + "../../alt/other" + "file:///alt/other" +) +test_resolve( + "file:///~/group/parent" + "../../other" + "file:///~/other" +) +test_resolve( + "/group/parent" + "../other" + "/group/other" +) +test_resolve( + "/group/parent" + "../../alt/other" + "/alt/other" +) +test_resolve( + "C:/group/parent" + "../other" + "C:/group/other" +) +test_resolve( + "C:/group/parent" + "../../alt/other" + "C:/alt/other" +) + +test_resolve( + "x-Test+v1.0://example.com/group/parent" + "../other" + "x-Test+v1.0://example.com/group/other" +) + +# IPv6 literals +test_resolve( + "http://[::1]/group/parent" + "../../alt/other" + "http://[::1]/alt/other" +) +test_resolve( + "git@[::1]:group/parent" + "../../alt/other" + "git@[::1]:alt/other" +) diff --git a/Tests/RunCMake/CMP0150/CMP0150-NEW-stdout.txt b/Tests/RunCMake/CMP0150/CMP0150-NEW-stdout.txt new file mode 100644 index 0000000..0f25fab --- /dev/null +++ b/Tests/RunCMake/CMP0150/CMP0150-NEW-stdout.txt @@ -0,0 +1,4 @@ +-- Configured bottom project +-- Completed configuring project middle +-- Completed configuring project top +-- Configuring done diff --git a/Tests/RunCMake/CMP0150/CMP0150-NEW.cmake b/Tests/RunCMake/CMP0150/CMP0150-NEW.cmake new file mode 100644 index 0000000..c1c5607 --- /dev/null +++ b/Tests/RunCMake/CMP0150/CMP0150-NEW.cmake @@ -0,0 +1,45 @@ +set(policyCommand "cmake_policy(SET CMP0150 NEW)") + +# Need to keep paths and file names short to avoid hitting limits on Windows. +# Directory names "a" through to "g" are used here according to the following: +# a = Top project +# b/c = Middle project +# d = Bottom project +# e/f = Cloned Top project +# g = Build directory for cloned Top project +# +# Dependency names map as follows: +# X = middle dependency +# Y = bottom dependency + +set(projName top) +set(depName X) +set(epRelativeGitRepo ../b/c) +set(fcRelativeGitRepo ../b/c) +configure_file(CMakeLists.txt.in a/CMakeLists.txt @ONLY) +initGitRepo("${CMAKE_CURRENT_BINARY_DIR}/a") + +set(projName middle) +set(depName Y) +set(epRelativeGitRepo ../../d) +set(fcRelativeGitRepo ../../d) +configure_file(CMakeLists.txt.in b/c/CMakeLists.txt @ONLY) +initGitRepo("${CMAKE_CURRENT_BINARY_DIR}/b/c") + +file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/d") +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/d/CMakeLists.txt" [[ +cmake_minimum_required(VERSION 3.26) +project(bottom LANGUAGES NONE) +message(STATUS "Configured bottom project") +]]) +initGitRepo("${CMAKE_CURRENT_BINARY_DIR}/d") + +set(clonedTopDir "${CMAKE_CURRENT_BINARY_DIR}/e/f") +file(MAKE_DIRECTORY "${clonedTopDir}") +execGitCommand(${CMAKE_CURRENT_BINARY_DIR} clone --quiet "file://${CMAKE_CURRENT_BINARY_DIR}/a" "${clonedTopDir}") +add_subdirectory("${clonedTopDir}" "${CMAKE_CURRENT_BINARY_DIR}/g") + +# Ensure build order is predictable +add_custom_target(non-ep-top ALL COMMAND ${CMAKE_COMMAND} -E echo "Non-ep top project") +add_dependencies(non-ep-top ep-X) +add_dependencies(ep-X ep-Y) diff --git a/Tests/RunCMake/CMP0150/CMP0150-OLD-build-stdout.txt b/Tests/RunCMake/CMP0150/CMP0150-OLD-build-stdout.txt new file mode 100644 index 0000000..0150af7 --- /dev/null +++ b/Tests/RunCMake/CMP0150/CMP0150-OLD-build-stdout.txt @@ -0,0 +1,3 @@ +.*-- Configured bottom project +.*ExternalProject for ep-bottom +.*Non-ep top project diff --git a/Tests/RunCMake/CMP0150/CMP0150-OLD-common.cmake b/Tests/RunCMake/CMP0150/CMP0150-OLD-common.cmake new file mode 100644 index 0000000..69748f7 --- /dev/null +++ b/Tests/RunCMake/CMP0150/CMP0150-OLD-common.cmake @@ -0,0 +1,21 @@ +# There's no point testing more than one level for OLD, since the behavior only +# depends on the current build, not anything about the parent git repo, etc. +set(projName top) +set(depName bottom) +set(epRelativeGitRepo ../../../Bottom) +set(fcRelativeGitRepo ../Bottom) +configure_file(CMakeLists.txt.in Top/CMakeLists.txt @ONLY) + +file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Bottom") +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/Bottom/CMakeLists.txt" [[ +cmake_minimum_required(VERSION 3.26) +project(bottom LANGUAGES NONE) +message(STATUS "Configured bottom project") +]]) +initGitRepo("${CMAKE_CURRENT_BINARY_DIR}/Bottom") + +add_subdirectory("${CMAKE_CURRENT_BINARY_DIR}/Top" "${CMAKE_CURRENT_BINARY_DIR}/Top-build") + +# Ensure build order is predictable +add_custom_target(non-ep-top ALL COMMAND ${CMAKE_COMMAND} -E echo "Non-ep top project") +add_dependencies(non-ep-top ep-bottom) diff --git a/Tests/RunCMake/CMP0150/CMP0150-OLD-stdout.txt b/Tests/RunCMake/CMP0150/CMP0150-OLD-stdout.txt new file mode 100644 index 0000000..680f9c1 --- /dev/null +++ b/Tests/RunCMake/CMP0150/CMP0150-OLD-stdout.txt @@ -0,0 +1,3 @@ +-- Configured bottom project +-- Completed configuring project top +-- Configuring done diff --git a/Tests/RunCMake/CMP0150/CMP0150-OLD.cmake b/Tests/RunCMake/CMP0150/CMP0150-OLD.cmake new file mode 100644 index 0000000..6b58e70 --- /dev/null +++ b/Tests/RunCMake/CMP0150/CMP0150-OLD.cmake @@ -0,0 +1,2 @@ +set(policyCommand "cmake_policy(SET CMP0150 OLD)") +include(CMP0150-OLD-common.cmake) diff --git a/Tests/RunCMake/CMP0150/CMP0150-WARN-build-stdout.txt b/Tests/RunCMake/CMP0150/CMP0150-WARN-build-stdout.txt new file mode 100644 index 0000000..0150af7 --- /dev/null +++ b/Tests/RunCMake/CMP0150/CMP0150-WARN-build-stdout.txt @@ -0,0 +1,3 @@ +.*-- Configured bottom project +.*ExternalProject for ep-bottom +.*Non-ep top project diff --git a/Tests/RunCMake/CMP0150/CMP0150-WARN-stderr.txt b/Tests/RunCMake/CMP0150/CMP0150-WARN-stderr.txt new file mode 100644 index 0000000..74c932a --- /dev/null +++ b/Tests/RunCMake/CMP0150/CMP0150-WARN-stderr.txt @@ -0,0 +1,25 @@ +CMake Warning \(dev\) at .*/Modules/ExternalProject/shared_internal_commands\.cmake:[0-9]+ \(message\): + Policy CMP0150 is not set: ExternalProject_Add and FetchContent_Declare + commands treat relative GIT_REPOSITORY paths as being relative to the + parent project's remote\. Run "cmake --help-policy CMP0150" for policy + details\. Use the cmake_policy command to set the policy and suppress this + warning\. + + A relative GIT_REPOSITORY path was detected\. This will be interpreted as a + local path to where the project is being cloned\. Set GIT_REPOSITORY to an + absolute path or set policy CMP0150 to NEW to avoid this warning\. +Call Stack \(most recent call first\): + .*/Modules/ExternalProject\.cmake:[0-9]+ \(_ep_resolve_git_remote\) +.* +CMake Warning \(dev\) at .*/Modules/ExternalProject/shared_internal_commands\.cmake:[0-9]+ \(message\): + Policy CMP0150 is not set: ExternalProject_Add and FetchContent_Declare + commands treat relative GIT_REPOSITORY paths as being relative to the + parent project's remote\. Run "cmake --help-policy CMP0150" for policy + details\. Use the cmake_policy command to set the policy and suppress this + warning\. + + A relative GIT_REPOSITORY path was detected\. This will be interpreted as a + local path to where the project is being cloned\. Set GIT_REPOSITORY to an + absolute path or set policy CMP0150 to NEW to avoid this warning\. +Call Stack \(most recent call first\): + .*/Modules/FetchContent\.cmake:[0-9]+ \(_ep_resolve_git_remote\) diff --git a/Tests/RunCMake/CMP0150/CMP0150-WARN-stdout.txt b/Tests/RunCMake/CMP0150/CMP0150-WARN-stdout.txt new file mode 100644 index 0000000..680f9c1 --- /dev/null +++ b/Tests/RunCMake/CMP0150/CMP0150-WARN-stdout.txt @@ -0,0 +1,3 @@ +-- Configured bottom project +-- Completed configuring project top +-- Configuring done diff --git a/Tests/RunCMake/CMP0150/CMP0150-WARN.cmake b/Tests/RunCMake/CMP0150/CMP0150-WARN.cmake new file mode 100644 index 0000000..20fd45d --- /dev/null +++ b/Tests/RunCMake/CMP0150/CMP0150-WARN.cmake @@ -0,0 +1,2 @@ +set(policyCommand "") +include(CMP0150-OLD-common.cmake) diff --git a/Tests/RunCMake/CMP0150/CMakeLists.txt b/Tests/RunCMake/CMP0150/CMakeLists.txt new file mode 100644 index 0000000..371dccc --- /dev/null +++ b/Tests/RunCMake/CMP0150/CMakeLists.txt @@ -0,0 +1,27 @@ +cmake_minimum_required(VERSION 3.25) +project(${RunCMake_TEST} NONE) + +find_package(Git REQUIRED) + +function(execGitCommand workDir) + execute_process( + WORKING_DIRECTORY "${workDir}" + COMMAND "${GIT_EXECUTABLE}" ${ARGN} + COMMAND_ECHO STDOUT + COMMAND_ERROR_IS_FATAL ANY + ) +endfunction() + +function(initGitRepo workDir) + # init.defaultBranch only works with git 2.28 or later, so we must use the + # historical default branch name "master". Force the old default in case test + # sites have overridden the default to something else. + execGitCommand("${workDir}" -c init.defaultBranch=master init) + execGitCommand("${workDir}" config user.email "testauthor@cmake.org") + execGitCommand("${workDir}" config user.name testauthor) + execGitCommand("${workDir}" config core.autocrlf false) + execGitCommand("${workDir}" add CMakeLists.txt) + execGitCommand("${workDir}" commit -m "Initial commit") +endfunction() + +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/CMP0150/CMakeLists.txt.in b/Tests/RunCMake/CMP0150/CMakeLists.txt.in new file mode 100644 index 0000000..db6cfc7 --- /dev/null +++ b/Tests/RunCMake/CMP0150/CMakeLists.txt.in @@ -0,0 +1,23 @@ +cmake_minimum_required(VERSION 3.25) +project(@projName@ LANGUAGES NONE) + +@policyCommand@ + +include(ExternalProject) +ExternalProject_Add(ep-@depName@ + GIT_REPOSITORY @epRelativeGitRepo@ + GIT_TAG master + GIT_CONFIG init.defaultBranch=master + TEST_COMMAND "" + INSTALL_COMMAND "${CMAKE_COMMAND}" -E echo "ExternalProject for ep-@depName@" +) + +include(FetchContent) +FetchContent_Declare(@depName@ + GIT_REPOSITORY @fcRelativeGitRepo@ + GIT_TAG master + GIT_CONFIG init.defaultBranch=master +) +FetchContent_MakeAvailable(@depName@) + +message(STATUS "Completed configuring project @projName@") diff --git a/Tests/RunCMake/CMP0150/RunCMakeTest.cmake b/Tests/RunCMake/CMP0150/RunCMakeTest.cmake new file mode 100644 index 0000000..940c33e --- /dev/null +++ b/Tests/RunCMake/CMP0150/RunCMakeTest.cmake @@ -0,0 +1,17 @@ +include(RunCMake) + +function(test_CMP0150 val) + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${val}-build) + run_cmake(CMP0150-${val}) + set(RunCMake_TEST_NO_CLEAN TRUE) + # Some git versions write clone messages to stderr. These would cause the + # test to fail, so we need to merge them into stdout. + set(RunCMake_TEST_OUTPUT_MERGE TRUE) + run_cmake_command(CMP0150-${val}-build ${CMAKE_COMMAND} --build .) +endfunction() + +test_CMP0150(WARN) +test_CMP0150(OLD) +test_CMP0150(NEW) + +run_cmake_script(CMP0150-NEW-resolve) diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index f05f784..bd41ff8 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -160,6 +160,7 @@ endif() add_RunCMake_test(CMP0132) add_RunCMake_test(CMP0135) add_RunCMake_test(CMP0139) +add_RunCMake_test(CMP0150) # The test for Policy 65 requires the use of the # CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS variable, which both the VS and Xcode |