mirror of
https://github.com/Kitware/CMake.git
synced 2025-12-31 10:50:16 -06:00
ExternalProject/FetchContent: Support relative remote URLs
Teach `ExternalProject_Add` and `FetchContent_Declare` to resolve relative remote URLs provided via `GIT_REPOSITORY`. Add policy CMP0150 to maintain compatibility. Fixes: #24211 Co-Authored-By: Craig Scott <craig.scott@crascit.com>
This commit is contained in:
committed by
Craig Scott
parent
e256e35daa
commit
550f63447d
@@ -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>
|
||||
|
||||
39
Help/policy/CMP0150.rst
Normal file
39
Help/policy/CMP0150.rst
Normal file
@@ -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
|
||||
@@ -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`.
|
||||
@@ -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
|
||||
|
||||
182
Modules/ExternalProject/shared_internal_commands.cmake
Normal file
182
Modules/ExternalProject/shared_internal_commands.cmake
Normal file
@@ -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()
|
||||
@@ -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
|
||||
|
||||
@@ -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) \
|
||||
|
||||
7
Tests/RunCMake/CMP0150/CMP0150-NEW-build-stdout.txt
Normal file
7
Tests/RunCMake/CMP0150/CMP0150-NEW-build-stdout.txt
Normal file
@@ -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
|
||||
107
Tests/RunCMake/CMP0150/CMP0150-NEW-resolve.cmake
Normal file
107
Tests/RunCMake/CMP0150/CMP0150-NEW-resolve.cmake
Normal file
@@ -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"
|
||||
)
|
||||
4
Tests/RunCMake/CMP0150/CMP0150-NEW-stdout.txt
Normal file
4
Tests/RunCMake/CMP0150/CMP0150-NEW-stdout.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
-- Configured bottom project
|
||||
-- Completed configuring project middle
|
||||
-- Completed configuring project top
|
||||
-- Configuring done
|
||||
45
Tests/RunCMake/CMP0150/CMP0150-NEW.cmake
Normal file
45
Tests/RunCMake/CMP0150/CMP0150-NEW.cmake
Normal file
@@ -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)
|
||||
3
Tests/RunCMake/CMP0150/CMP0150-OLD-build-stdout.txt
Normal file
3
Tests/RunCMake/CMP0150/CMP0150-OLD-build-stdout.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
.*-- Configured bottom project
|
||||
.*ExternalProject for ep-bottom
|
||||
.*Non-ep top project
|
||||
21
Tests/RunCMake/CMP0150/CMP0150-OLD-common.cmake
Normal file
21
Tests/RunCMake/CMP0150/CMP0150-OLD-common.cmake
Normal file
@@ -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)
|
||||
3
Tests/RunCMake/CMP0150/CMP0150-OLD-stdout.txt
Normal file
3
Tests/RunCMake/CMP0150/CMP0150-OLD-stdout.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
-- Configured bottom project
|
||||
-- Completed configuring project top
|
||||
-- Configuring done
|
||||
2
Tests/RunCMake/CMP0150/CMP0150-OLD.cmake
Normal file
2
Tests/RunCMake/CMP0150/CMP0150-OLD.cmake
Normal file
@@ -0,0 +1,2 @@
|
||||
set(policyCommand "cmake_policy(SET CMP0150 OLD)")
|
||||
include(CMP0150-OLD-common.cmake)
|
||||
3
Tests/RunCMake/CMP0150/CMP0150-WARN-build-stdout.txt
Normal file
3
Tests/RunCMake/CMP0150/CMP0150-WARN-build-stdout.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
.*-- Configured bottom project
|
||||
.*ExternalProject for ep-bottom
|
||||
.*Non-ep top project
|
||||
25
Tests/RunCMake/CMP0150/CMP0150-WARN-stderr.txt
Normal file
25
Tests/RunCMake/CMP0150/CMP0150-WARN-stderr.txt
Normal file
@@ -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\)
|
||||
3
Tests/RunCMake/CMP0150/CMP0150-WARN-stdout.txt
Normal file
3
Tests/RunCMake/CMP0150/CMP0150-WARN-stdout.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
-- Configured bottom project
|
||||
-- Completed configuring project top
|
||||
-- Configuring done
|
||||
2
Tests/RunCMake/CMP0150/CMP0150-WARN.cmake
Normal file
2
Tests/RunCMake/CMP0150/CMP0150-WARN.cmake
Normal file
@@ -0,0 +1,2 @@
|
||||
set(policyCommand "")
|
||||
include(CMP0150-OLD-common.cmake)
|
||||
27
Tests/RunCMake/CMP0150/CMakeLists.txt
Normal file
27
Tests/RunCMake/CMP0150/CMakeLists.txt
Normal file
@@ -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)
|
||||
23
Tests/RunCMake/CMP0150/CMakeLists.txt.in
Normal file
23
Tests/RunCMake/CMP0150/CMakeLists.txt.in
Normal file
@@ -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@")
|
||||
17
Tests/RunCMake/CMP0150/RunCMakeTest.cmake
Normal file
17
Tests/RunCMake/CMP0150/RunCMakeTest.cmake
Normal file
@@ -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)
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user