diff options
Diffstat (limited to 'Modules/ExternalProject.cmake')
-rw-r--r-- | Modules/ExternalProject.cmake | 203 |
1 files changed, 170 insertions, 33 deletions
diff --git a/Modules/ExternalProject.cmake b/Modules/ExternalProject.cmake index b34a35b..605908d 100644 --- a/Modules/ExternalProject.cmake +++ b/Modules/ExternalProject.cmake @@ -232,7 +232,12 @@ External Project Definition measure. .. versionchanged:: 3.6 - This option also applies to ``git clone`` invocations. + This option also applies to ``git clone`` invocations, although the + default behavior is different. If ``TLS_VERIFY`` is not given and + :variable:`CMAKE_TLS_VERIFY` is not set, the behavior will be + determined by git's defaults. Normally, the ``sslVerify`` git + config setting defaults to true, but the user may have overridden + this at a global level. ``TLS_CAINFO <file>`` Specify a custom certificate authority file to use if ``TLS_VERIFY`` @@ -278,6 +283,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`` @@ -441,13 +453,23 @@ External Project Definition ``UPDATE_DISCONNECTED <bool>`` .. versionadded:: 3.2 - When enabled, this option causes the update step to be skipped. It does - not, however, prevent the download step. The update step can still be + When enabled, this option causes the update step to be skipped (but see + below for changed behavior where this is not the case). It does not + prevent the download step. The update step can still be added as a step target (see :command:`ExternalProject_Add_StepTargets`) and called manually. This is useful if you want to allow developers to build the project when disconnected from the network (the network may still be needed for the download step though). + .. versionchanged:: 3.27 + + When ``UPDATE_DISCONNECTED`` is true, the update step will be executed + if any details about the update or download step are changed. + Furthermore, if using the git download/update method, the update + logic will be modified to skip attempts to contact the remote. + If the ``GIT_TAG`` mentions a ref that is not known locally, the + update step will halt with a fatal error. + When this option is present, it is generally advisable to make the value a cache variable under the developer's control rather than hard-coding it. If this option is not present, the default value is taken from the @@ -1188,6 +1210,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 @@ -1309,6 +1333,8 @@ function(_ep_write_gitclone_script message(FATAL_ERROR "Tag for git checkout should not be empty.") endif() + set(git_submodules_config_options "") + if(GIT_VERSION_STRING VERSION_LESS 2.20 OR 2.21 VERSION_LESS_EQUAL GIT_VERSION_STRING) set(git_clone_options "--no-checkout") @@ -1331,18 +1357,26 @@ function(_ep_write_gitclone_script if(NOT ${git_remote_name} STREQUAL "origin") list(APPEND git_clone_options --origin \"${git_remote_name}\") endif() + if(NOT "x${tls_verify}" STREQUAL "x") + # The clone config option is sticky, it will apply to all subsequent git + # update operations. The submodules config option is not sticky, because + # git doesn't provide any way to do that. Thus, we will have to pass the + # same config option in the update step too for submodules, but not for + # the main git repo. + if(tls_verify) + # Default git behavior is "true", but the user might have changed the + # global default to "false". Since TLS_VERIFY was given, ensure we honor + # the specified setting regardless of what the global default might be. + list(APPEND git_clone_options -c http.sslVerify=true) + set(git_submodules_config_options -c http.sslVerify=true) + else() + list(APPEND git_clone_options -c http.sslVerify=false) + set(git_submodules_config_options -c http.sslVerify=false) + endif() + endif() string (REPLACE ";" " " git_clone_options "${git_clone_options}") - set(git_options) - # disable cert checking if explicitly told not to do it - if(NOT "x${tls_verify}" STREQUAL "x" AND NOT tls_verify) - set(git_options - -c http.sslVerify=false - ) - endif() - string (REPLACE ";" " " git_options "${git_options}") - configure_file( ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ExternalProject/gitclone.cmake.in ${script_filename} @@ -1385,6 +1419,7 @@ function(_ep_write_gitupdate_script git_repository work_dir git_update_strategy + tls_verify ) if("${git_tag}" STREQUAL "") @@ -1399,6 +1434,22 @@ function(_ep_write_gitupdate_script list(APPEND git_stash_save_options --all) endif() + set(git_submodules_config_options "") + if(NOT "x${tls_verify}" STREQUAL "x") + # The submodules config option is not sticky, git doesn't provide any way + # to do that. We have to pass this config option for the update step too. + # We don't need to set it for the non-submodule update because it gets + # recorded as part of the clone operation in a sticky manner. + if(tls_verify) + # Default git behavior is "true", but the user might have changed the + # global default to "false". Since TLS_VERIFY was given, ensure we honor + # the specified setting regardless of what the global default might be. + set(git_submodules_config_options -c http.sslVerify=true) + else() + set(git_submodules_config_options -c http.sslVerify=false) + endif() + endif() + configure_file( "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ExternalProject/gitupdate.cmake.in" "${script_filename}" @@ -2090,13 +2141,7 @@ function(_ep_get_configuration_subdir_genex suffix_var) set(suffix "") get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if(_isMultiConfig) - if(CMAKE_GENERATOR STREQUAL "Xcode") - # The Xcode generator does not support per-config sources, - # so use the underlying build system's placeholder instead. - set(suffix "/${CMAKE_CFG_INTDIR}") - else() - set(suffix "/$<CONFIG>") - endif() + set(suffix "/$<CONFIG>") endif() set(${suffix_var} "${suffix}" PARENT_SCOPE) endfunction() @@ -2444,7 +2489,7 @@ function(ExternalProject_Add_Step name step) PROPERTY _EP_${step}_ALWAYS ) if(always) - set(touch) + set(maybe_COMMAND_touch "") # Mark stamp files for all configs as SYMBOLIC since we do not create them. # Remove any existing stamp in case the option changed in an existing tree. get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) @@ -2466,7 +2511,7 @@ function(ExternalProject_Add_Step name step) file(REMOVE ${stamp_file}) endif() else() - set(touch ${CMAKE_COMMAND} -E touch ${stamp_file}) + set(maybe_COMMAND_touch "COMMAND \${CMAKE_COMMAND} -E touch \${stamp_file}") endif() # Wrap with log script? @@ -2494,7 +2539,7 @@ function(ExternalProject_Add_Step name step) BYPRODUCTS \${byproducts} COMMENT \${comment} COMMAND ${__cmdQuoted} - COMMAND \${touch} + ${maybe_COMMAND_touch} DEPENDS \${depends} WORKING_DIRECTORY \${work_dir} VERBATIM @@ -3213,7 +3258,7 @@ function(_ep_get_update_disconnected var name) endfunction() function(_ep_add_update_command name) - ExternalProject_Get_Property(${name} source_dir tmp_dir) + ExternalProject_Get_Property(${name} source_dir stamp_dir tmp_dir) get_property(cmd_set TARGET ${name} PROPERTY _EP_UPDATE_COMMAND SET) get_property(cmd TARGET ${name} PROPERTY _EP_UPDATE_COMMAND) @@ -3227,6 +3272,7 @@ function(_ep_add_update_command name) set(work_dir) set(comment) set(always) + set(file_deps) if(cmd_set) set(work_dir ${source_dir}) @@ -3288,6 +3334,7 @@ function(_ep_add_update_command name) endif() set(work_dir ${source_dir}) set(comment "Performing update step for '${name}'") + set(comment_disconnected "Performing disconnected update step for '${name}'") get_property(git_tag TARGET ${name} @@ -3341,8 +3388,15 @@ function(_ep_add_update_command name) _ep_get_git_submodules_recurse(git_submodules_recurse) + get_property(tls_verify TARGET ${name} PROPERTY _EP_TLS_VERIFY) + if("x${tls_verify}" STREQUAL "x" AND DEFINED CMAKE_TLS_VERIFY) + set(tls_verify "${CMAKE_TLS_VERIFY}") + endif() + + set(update_script "${tmp_dir}/${name}-gitupdate.cmake") + list(APPEND file_deps ${update_script}) _ep_write_gitupdate_script( - "${tmp_dir}/${name}-gitupdate.cmake" + "${update_script}" "${GIT_EXECUTABLE}" "${git_tag}" "${git_remote_name}" @@ -3352,8 +3406,10 @@ function(_ep_add_update_command name) "${git_repository}" "${work_dir}" "${git_update_strategy}" + "${tls_verify}" ) - set(cmd ${CMAKE_COMMAND} -P ${tmp_dir}/${name}-gitupdate.cmake) + set(cmd ${CMAKE_COMMAND} -Dcan_fetch=YES -P ${update_script}) + set(cmd_disconnected ${CMAKE_COMMAND} -Dcan_fetch=NO -P ${update_script}) set(always 1) elseif(hg_repository) if(NOT HG_EXECUTABLE) @@ -3361,6 +3417,7 @@ function(_ep_add_update_command name) endif() set(work_dir ${source_dir}) set(comment "Performing update step (hg pull) for '${name}'") + set(comment_disconnected "Performing disconnected update step for '${name}'") get_property(hg_tag TARGET ${name} @@ -3386,9 +3443,23 @@ Update to Mercurial >= 2.1.1. ${HG_EXECUTABLE} pull COMMAND ${HG_EXECUTABLE} update ${hg_tag} ) + set(cmd_disconnected ${HG_EXECUTABLE} update ${hg_tag}) set(always 1) endif() + # We use configure_file() to write the update_info_file so that the file's + # timestamp is not updated if we don't change the contents + if(NOT DEFINED cmd_disconnected) + set(cmd_disconnected "${cmd}") + endif() + set(update_info_file ${stamp_dir}/${name}-update-info.txt) + list(APPEND file_deps ${update_info_file}) + configure_file( + "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ExternalProject/UpdateInfo.txt.in" + "${update_info_file}" + @ONLY + ) + get_property(log TARGET ${name} PROPERTY _EP_LOG_UPDATE @@ -3422,16 +3493,39 @@ Update to Mercurial >= 2.1.1. EXCLUDE_FROM_MAIN \${update_disconnected} WORKING_DIRECTORY \${work_dir} DEPENDEES download + DEPENDS \${file_deps} ${log} ${uses_terminal} )" ) + if(update_disconnected) + if(NOT DEFINED comment_disconnected) + set(comment_disconnected "${comment}") + endif() + set(__cmdQuoted) + foreach(__item IN LISTS cmd_disconnected) + string(APPEND __cmdQuoted " [==[${__item}]==]") + endforeach() + + cmake_language(EVAL CODE " + ExternalProject_Add_Step(${name} update_disconnected + INDEPENDENT TRUE + COMMENT \${comment_disconnected} + COMMAND ${__cmdQuoted} + WORKING_DIRECTORY \${work_dir} + DEPENDEES download + DEPENDS \${file_deps} + ${log} + ${uses_terminal} + )" + ) + endif() endfunction() function(_ep_add_patch_command name) - ExternalProject_Get_Property(${name} source_dir) + ExternalProject_Get_Property(${name} source_dir stamp_dir) get_property(cmd_set TARGET ${name} PROPERTY _EP_PATCH_COMMAND SET) get_property(cmd TARGET ${name} PROPERTY _EP_PATCH_COMMAND) @@ -3442,6 +3536,15 @@ function(_ep_add_patch_command name) set(work_dir ${source_dir}) endif() + # We use configure_file() to write the patch_info_file so that the file's + # timestamp is not updated if we don't change the contents + set(patch_info_file ${stamp_dir}/${name}-patch-info.txt) + configure_file( + "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ExternalProject/PatchInfo.txt.in" + "${patch_info_file}" + @ONLY + ) + get_property(log TARGET ${name} PROPERTY _EP_LOG_PATCH @@ -3463,11 +3566,6 @@ function(_ep_add_patch_command name) endif() _ep_get_update_disconnected(update_disconnected ${name}) - if(update_disconnected) - set(patch_dep download) - else() - set(patch_dep update) - endif() set(__cmdQuoted) foreach(__item IN LISTS cmd) @@ -3478,11 +3576,28 @@ function(_ep_add_patch_command name) INDEPENDENT TRUE COMMAND ${__cmdQuoted} WORKING_DIRECTORY \${work_dir} - DEPENDEES \${patch_dep} + EXCLUDE_FROM_MAIN \${update_disconnected} + DEPENDEES update + DEPENDS \${patch_info_file} ${log} ${uses_terminal} )" ) + + if(update_disconnected) + cmake_language(EVAL CODE " + ExternalProject_Add_Step(${name} patch_disconnected + INDEPENDENT TRUE + COMMAND ${__cmdQuoted} + WORKING_DIRECTORY \${work_dir} + DEPENDEES update_disconnected + DEPENDS \${patch_info_file} + ${log} + ${uses_terminal} + )" + ) + endif() + endfunction() function(_ep_get_file_deps var name) @@ -3692,6 +3807,13 @@ function(_ep_add_configure_command name) list(APPEND file_deps ${tmp_dir}/${name}-cfgcmd.txt) list(APPEND file_deps ${_ep_cache_args_script}) + _ep_get_update_disconnected(update_disconnected ${name}) + if(update_disconnected) + set(dependees patch_disconnected) + else() + set(dependees patch) + endif() + get_property(log TARGET ${name} PROPERTY _EP_LOG_CONFIGURE @@ -3721,7 +3843,7 @@ function(_ep_add_configure_command name) INDEPENDENT FALSE COMMAND ${__cmdQuoted} WORKING_DIRECTORY \${binary_dir} - DEPENDEES patch + DEPENDEES \${dependees} DEPENDS \${file_deps} ${log} ${uses_terminal} @@ -4144,6 +4266,10 @@ function(ExternalProject_Add name) # Miscellaneous options # LIST_SEPARATOR + # + # Internal options (undocumented) + # + EXTERNALPROJECT_INTERNAL_ARGUMENT_SEPARATOR ) _ep_parse_arguments( ExternalProject_Add @@ -4165,6 +4291,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 |