diff --git a/CMake/Utilities/imstkAddExternalProject.cmake b/CMake/Utilities/imstkAddExternalProject.cmake index 0e3bf1f8442afe654762765145d4fa3553d953b5..65d4af6dcb462bc5dbf387dd88b08f24be8725c9 100644 --- a/CMake/Utilities/imstkAddExternalProject.cmake +++ b/CMake/Utilities/imstkAddExternalProject.cmake @@ -78,14 +78,6 @@ macro(imstk_add_external_project extProj) # If needs to download and build #----------------------------------------------------------------------------- if(NOT DEFINED ${extProj}_DIR AND NOT ${USE_SYSTEM_${extProj}}) - #----------------------------------------------------------------------------- - # Ensure all generator info is passed to external library build - #----------------------------------------------------------------------------- - set (COMMON_CMAKE_EP_ARGS - CMAKE_GENERATOR ${CMAKE_GENERATOR} - CMAKE_GENERATOR_PLATFORM ${CMAKE_GENERATOR_PLATFORM} - CMAKE_GENERATOR_TOOLSET ${CMAKE_GENERATOR_TOOLSET} - ) imstk_define_external_dirs( ${extProj} ) @@ -98,7 +90,6 @@ macro(imstk_add_external_project extProj) BINARY_DIR ${${extProj}_BINARY_DIR} # from above or parsed argument TMP_DIR ${${extProj}_TMP_DIR} # from above STAMP_DIR ${${extProj}_STAMP_DIR} # from above - ${COMMON_CMAKE_EP_ARGS} # from above ${${extProj}_EP_ARGS} # from ExternalProject_Include_Dependencies ${${extProj}_UNPARSED_ARGUMENTS} # from unparsed arguments of this macro DEPENDS ${${extProj}_DEPENDENCIES} # from parsed argument diff --git a/CMake/Utilities/imstkSolveDependencies.cmake b/CMake/Utilities/imstkSolveDependencies.cmake index 361922c129bafd9147b7f64d68cdbcb4239e13fb..09de271878a9f549b134478dc28b1ac0294f17be 100644 --- a/CMake/Utilities/imstkSolveDependencies.cmake +++ b/CMake/Utilities/imstkSolveDependencies.cmake @@ -1,15 +1,22 @@ #.rst: # ExternalProjectDependency # ------------------------- +# +# .. only:: html +# +# .. contents:: ########################################################################### # -# Program: 3D Slicer +# Library: CTK # # Copyright (c) Kitware Inc. # -# See COPYRIGHT.txt -# or http://www.slicer.org/copyright/copyright.txt for details. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0.txt # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, @@ -17,37 +24,109 @@ # See the License for the specific language governing permissions and # limitations under the License. # -# This file was originally developed by Jean-Christophe Fillion-Robin, Kitware Inc. -# and was partially funded by NIH grant 3P41RR013218-12S1 -# ########################################################################### include(CMakeParseArguments) -if(NOT DEFINED EP_LIST_SEPARATOR) - set(EP_LIST_SEPARATOR "^^") -endif() +#.rst: +# Global Variables +# ^^^^^^^^^^^^^^^^ #.rst: # .. cmake:variable:: EXTERNAL_PROJECT_DIR # +# This variable describes the directory in which external project files +# matching ``<EXTERNAL_PROJECT_FILE_PREFIX><projectname>.cmake`` expression are globbed. +# if(NOT EXISTS "${EXTERNAL_PROJECT_DIR}") set(EXTERNAL_PROJECT_DIR ${CMAKE_SOURCE_DIR}/SuperBuild) endif() +#.rst: +# .. cmake:variable:: EXTERNAL_PROJECT_ADDITIONAL_DIR +# +# If set, this variable represents an other directory in which external project files +# are searched for if not already found in ``EXTERNAL_PROJECT_DIR``. + +#.rst: +# .. cmake:variable:: EXTERNAL_PROJECT_ADDITIONAL_DIRS +# +# If set, this variable represents additional directories in which external project files +# are searched for if not already found in ``EXTERNAL_PROJECT_DIR`` and +# ``EXTERNAL_PROJECT_ADDITIONAL_DIR``. + #.rst: # .. cmake:variable:: EXTERNAL_PROJECT_FILE_PREFIX # +# This variable describes the prefix of the external project files looked up in +# ``EXTERNAL_PROJECT_DIR``. It defaults to ``External_``. +# if(NOT DEFINED EXTERNAL_PROJECT_FILE_PREFIX) set(EXTERNAL_PROJECT_FILE_PREFIX "External_") endif() +#.rst: +# .. cmake:variable:: SUPERBUILD_TOPLEVEL_PROJECT +# +# This variable can be set to explicitly identify the name of the top-level project. +# If not set, it default to the value of ``CMAKE_PROJECT_NAME``. +if(NOT DEFINED SUPERBUILD_TOPLEVEL_PROJECT) + if(NOT DEFINED CMAKE_PROJECT_NAME) + message(FATAL_ERROR "Failed to initialize variable SUPERBUILD_TOPLEVEL_PROJECT. Variable CMAKE_PROJECT_NAME is not defined.") + endif() + set(SUPERBUILD_TOPLEVEL_PROJECT ${CMAKE_PROJECT_NAME}) +endif() + +#.rst: +# .. cmake:variable:: EP_LIST_SEPARATOR +# +# This variable is used to separate list items when passed in various external project +# ``..._COMMAND`` options. +# +# If defaults to ``^^``. +if(NOT DEFINED EP_LIST_SEPARATOR) + set(EP_LIST_SEPARATOR "^^") +endif() + + +#.rst: +# .. cmake:variable:: EP_GIT_PROTOCOL +# +# The value of this variable is controlled by the option ``<SUPERBUILD_TOPLEVEL_PROJECT>_USE_GIT_PROTOCOL`` +# automatically defined by including this CMake module. Setting this option allows to update the value of +# ``EP_GIT_PROTOCOL`` variable. +# +# If enabled, the variable ``EP_GIT_PROTOCOL`` is set to ``git``. Otherwise, it is set to ``https``. +# The option is enabled by default. +# +# The variable ``EP_GIT_PROTOCOL`` can be used when adding external project. For example: +# +# .. code-block:: cmake +# +# ExternalProject_Add(${proj} +# ${${proj}_EP_ARGS} +# GIT_REPOSITORY "${EP_GIT_PROTOCOL}://github.com/Foo/Foo.git" +# [...] +# ) +# +option(${SUPERBUILD_TOPLEVEL_PROJECT}_USE_GIT_PROTOCOL "If behind a firewall turn this off to use https instead." ON) +set(EP_GIT_PROTOCOL "git") +if(NOT ${SUPERBUILD_TOPLEVEL_PROJECT}_USE_GIT_PROTOCOL) + set(EP_GIT_PROTOCOL "https") +endif() + # Compute -G arg for configuring external projects with the same CMake generator: if(CMAKE_EXTRA_GENERATOR) set(EP_CMAKE_GENERATOR "${CMAKE_EXTRA_GENERATOR} - ${CMAKE_GENERATOR}") else() set(EP_CMAKE_GENERATOR "${CMAKE_GENERATOR}") endif() +set(EP_CMAKE_GENERATOR_PLATFORM "${CMAKE_GENERATOR_PLATFORM}") +set(EP_CMAKE_GENERATOR_TOOLSET "${CMAKE_GENERATOR_TOOLSET}") + +#.rst: +# Functions +# ^^^^^^^^^ #.rst: # .. cmake:function:: mark_as_superbuild @@ -67,8 +146,7 @@ endif() # .. code-block:: cmake # # PROJECTS corresponds to a list of <projectname> that will be added using 'ExternalProject_Add' function. -# If not specified and called within a project file, it defaults to the value of 'SUPERBUILD_TOPLEVEL_PROJECT' -# Otherwise, it defaults to 'CMAKE_PROJECT_NAME'. +# If not specified and called within a project file, it defaults to the value of 'SUPERBUILD_TOPLEVEL_PROJECT'. # If instead 'ALL_PROJECTS' is specified, the variables and labels will be passed to all projects. # # VARS is an expected list of variables specified as <varname>:<vartype> to pass to <projectname> @@ -200,9 +278,15 @@ function(_sb_cmakevar_to_cmakearg cmake_varname_and_type cmake_arg_var has_cfg_i _sb_extract_varname_and_vartype(${cmake_varname_and_type} _varname _vartype) set(_var_value "${${_varname}}") - get_property(_value_set_in_cache CACHE ${_varname} PROPERTY VALUE SET) - if(_value_set_in_cache) - get_property(_var_value CACHE ${_varname} PROPERTY VALUE) + + # Use cache value unless it is INTERNAL + if(_vartype STREQUAL "INTERNAL") + set(_vartype "STRING") + else() + get_property(_value_set_in_cache CACHE ${_varname} PROPERTY VALUE SET) + if(_value_set_in_cache) + get_property(_var_value CACHE ${_varname} PROPERTY VALUE) + endif() endif() set(_has_cfg_intdir FALSE) @@ -215,6 +299,10 @@ function(_sb_cmakevar_to_cmakearg cmake_varname_and_type cmake_arg_var has_cfg_i endif() endif() + if(NOT _has_cfg_intdir) + string(REPLACE "\"" "\\\"" _var_value "${_var_value}") + endif() + set(${cmake_arg_var} -D${_varname}:${_vartype}=${_var_value} PARENT_SCOPE) set(${has_cfg_intdir_var} ${_has_cfg_intdir} PARENT_SCOPE) @@ -230,14 +318,13 @@ set(_ALL_PROJECT_IDENTIFIER "ALLALLALL") # # _sb_append_to_cmake_args( -# VARS <varname1>:<vartype1> [<varname2>:<vartype2> [...]] +# [VARS <varname1>:<vartype1> [<varname2>:<vartype2> [...]]] # [PROJECTS <projectname> [<projectname> [...]] | ALL_PROJECTS] # [LABELS <label1> [<label2> [...]]] # ) # # PROJECTS corresponds to a list of <projectname> that will be added using 'ExternalProject_Add' function. -# If not specified and called within a project file, it defaults to the value of 'SUPERBUILD_TOPLEVEL_PROJECT' -# Otherwise, it defaults to 'CMAKE_PROJECT_NAME'. +# If not specified and called within a project file, it defaults to the value of 'SUPERBUILD_TOPLEVEL_PROJECT'. # If instead 'ALL_PROJECTS' is specified, the variables and labels will be passed to all projects. # # VARS is an expected list of variables specified as <varname>:<vartype> to pass to <projectname> @@ -255,11 +342,7 @@ function(_sb_append_to_cmake_args) cmake_parse_arguments(_sb "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) if(NOT _sb_PROJECTS AND NOT _sb_ALL_PROJECTS) - if(SUPERBUILD_TOPLEVEL_PROJECT) - set(_sb_PROJECTS ${SUPERBUILD_TOPLEVEL_PROJECT}) - else() - set(_sb_PROJECTS ${CMAKE_PROJECT_NAME}) - endif() + set(_sb_PROJECTS ${SUPERBUILD_TOPLEVEL_PROJECT}) endif() if(_sb_ALL_PROJECTS) @@ -288,6 +371,46 @@ function(_sb_append_to_cmake_args) endforeach() endfunction() +#.rst: +# .. cmake:function:: ExternalProject_DeclareLabels +# +# .. code-block:: cmake +# +# ExternalProject_DeclareLabels( +# [PROJECTS <projectname> [<projectname> [...]] | ALL_PROJECTS] +# LABELS <label1> [<label2> [...]] +# ) +# +# .. code-block:: cmake +# +# PROJECTS corresponds to a list of <projectname> that will be added using 'ExternalProject_Add' function. +# If not specified and called within a project file, it defaults to the value of 'SUPERBUILD_TOPLEVEL_PROJECT'. +# If instead 'ALL_PROJECTS' is specified, the variables and labels will be passed to all projects. +# +# LABELS is a list of label to pass to the <projectname> as CMake CACHE args of the +# form -D<projectname>_EP_LABEL_<label>= unless specific variables +# have been associated with the labels using mark_as_superbuild. +# +function(ExternalProject_DeclareLabels) + set(options ALL_PROJECTS) + set(oneValueArgs) + set(multiValueArgs PROJECTS LABELS) + cmake_parse_arguments(_sb "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(_sb_PROJECTS AND _sb_ALL_PROJECTS) + message(FATAL_ERROR "Arguments 'PROJECTS' and 'ALL_PROJECTS' are mutually exclusive !") + endif() + + if(_sb_ALL_PROJECTS) + set(optional_arg_ALL_PROJECTS "ALL_PROJECTS") + else() + set(optional_arg_ALL_PROJECTS PROJECTS ${_sb_PROJECTS}) + endif() + + _sb_append_to_cmake_args( + LABELS ${_sb_LABELS} ${optional_arg_ALL_PROJECTS}) +endfunction() + function(_sb_get_external_project_arguments proj varname) mark_as_superbuild(${SUPERBUILD_TOPLEVEL_PROJECT}_USE_SYSTEM_${proj}:BOOL) @@ -299,7 +422,9 @@ function(_sb_get_external_project_arguments proj varname) list(REMOVE_DUPLICATES _labels) foreach(label ${_labels}) get_property(${proj}_EP_LABEL_${label} GLOBAL PROPERTY ${proj}_EP_LABEL_${label}) - list(REMOVE_DUPLICATES ${proj}_EP_LABEL_${label}) + if(${proj}_EP_LABEL_${label}) + list(REMOVE_DUPLICATES ${proj}_EP_LABEL_${label}) + endif() _sb_append_to_cmake_args(PROJECTS ${proj} VARS ${proj}_EP_LABEL_${label}:STRING) endforeach() @@ -321,19 +446,46 @@ function(_sb_get_external_project_arguments proj varname) _sb_collect_args(${_ALL_PROJECT_IDENTIFIER}) set(_ep_arguments "") + + # Automatically propagate CMake options + foreach(_cmake_option IN ITEMS + CMAKE_EXPORT_COMPILE_COMMANDS + CMAKE_JOB_POOL_COMPILE + CMAKE_JOB_POOL_LINK + CMAKE_JOB_POOLS + ) + if(DEFINED ${_cmake_option}) + list(APPEND _ep_arguments CMAKE_CACHE_ARGS + -D${_cmake_option}:BOOL=${${_cmake_option}} + ) + endif() + endforeach() + foreach(property CMAKE_ARGS CMAKE_CACHE_ARGS) get_property(${proj}_EP_PROPERTY_${property} GLOBAL PROPERTY ${proj}_EP_PROPERTY_${property}) get_property(${_ALL_PROJECT_IDENTIFIER}_EP_PROPERTY_${property} GLOBAL PROPERTY ${_ALL_PROJECT_IDENTIFIER}_EP_PROPERTY_${property}) set(_all ${${proj}_EP_PROPERTY_${property}} ${${_ALL_PROJECT_IDENTIFIER}_EP_PROPERTY_${property}}) - if(_all) + list(LENGTH _all _num_properties) + if(_num_properties GREATER 0) list(APPEND _ep_arguments ${property} ${_all}) endif() endforeach() list(APPEND _ep_arguments LIST_SEPARATOR ${EP_LIST_SEPARATOR}) - list(APPEND _ep_arguments CMAKE_GENERATOR ${EP_CMAKE_GENERATOR}) - + list(APPEND _ep_arguments CMAKE_GENERATOR ${_sb_CMAKE_GENERATOR}) + if(CMAKE_VERSION VERSION_GREATER "3.0") + list(APPEND _ep_arguments CMAKE_GENERATOR_PLATFORM ${_sb_CMAKE_GENERATOR_PLATFORM}) + endif() + list(APPEND _ep_arguments CMAKE_GENERATOR_TOOLSET ${_sb_CMAKE_GENERATOR_TOOLSET}) + if(CMAKE_VERSION VERSION_EQUAL "3.4" OR CMAKE_VERSION VERSION_GREATER "3.4") + # USES_TERMINAL_* options were introduced in CMake 3.4 + foreach(step IN ITEMS DOWNLOAD UPDATE CONFIGURE BUILD TEST INSTALL) + list(APPEND _ep_arguments + USES_TERMINAL_${step} 1 + ) + endforeach() + endif() set(${varname} ${_ep_arguments} PARENT_SCOPE) endfunction() @@ -436,6 +588,41 @@ function(_sb_is_optional proj output_var) set(${output_var} ${optional} PARENT_SCOPE) endfunction() +#.rst: +# .. cmake:function:: ExternalProject_Add_Dependencies +# +# .. code-block:: cmake +# +# ExternalProject_Add_Dependencies(<project_name> +# DEPENDS <dep1> [<dep2> [...]] +# ) +# +# +# .. code-block:: cmake +# +# DEPENDS List of additional dependencies to associat with `<project_name>`. +# +macro(ExternalProject_Add_Dependencies project_name) + set(options) + set(oneValueArgs) + set(multiValueArgs DEPENDS) + cmake_parse_arguments(_epad "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + # Sanity checks + if(x${project_name} STREQUAL xDEPENDS) + message(FATAL_ERROR "Argument <project_name> is missing !") + endif() + if(_epad_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Invalid arguments: ${_epad_UNPARSED_ARGUMENTS}") + endif() + + if(NOT _epad_DEPENDS) + message(FATAL_ERROR "Argument DEPENDS is missing") + endif() + + set_property(GLOBAL PROPERTY SB_${project_name}_ADDITIONAL_DEPENDS ${_epad_DEPENDS}) +endmacro() + #.rst: # .. cmake:function:: ExternalProject_Include_Dependencies # @@ -447,11 +634,45 @@ endfunction() # [DEPENDS_VAR <depends_var>] # [USE_SYSTEM_VAR <use_system_var>] # [SUPERBUILD_VAR <superbuild_var>] +# [CMAKE_GENERATOR <cmake_generator>] +# [CMAKE_GENERATOR_PLATFORM <cmake_generator_platform>] +# [CMAKE_GENERATOR_TOOLSET <cmake_generator_toolset>] # ) # +# +# .. code-block:: cmake +# +# PROJECT_VAR Name of the variable containing the name of the included project. +# By default, it is `proj` and it is set to `<project_name>`. +# +# EP_ARGS_VAR Name of the variable listing arguments to pass to ExternalProject. +# If not specified, variable name default to `<project_name>_EP_ARGS`. +# +# DEPENDS_VAR Name of the variable containing the dependency of the included project. +# By default, it is `<project_name>_DEPENDS`. +# +# +# USE_SYSTEM_VAR Name of the variable indicating if the system version of <project_name> +# should be looked up. Lookup of the project is left to the developer implementing +# the external project file. +# By default, it is `<SUPERBUILD_TOPLEVEL_PROJECT>_USE_SYSTEM_<project_name>`. +# +# SUPERBUILD_VAR Name of the variable indicating if the top-level or inner project is being built. +# By default, it is `<SUPERBUILD_TOPLEVEL_PROJECT>_SUPERBUILD`. +# +# +# CMAKE_GENERATOR +# CMAKE_GENERATOR_PLATFORM +# CMAKE_GENERATOR_TOOLSET These three options allow to overwrite the values set in the top-level project that +# would otherwise automatically be propagated to dependent projects. +# macro(ExternalProject_Include_Dependencies project_name) set(options) - set(oneValueArgs PROJECT_VAR DEPENDS_VAR EP_ARGS_VAR USE_SYSTEM_VAR SUPERBUILD_VAR) + set(oneValueArgs PROJECT_VAR DEPENDS_VAR EP_ARGS_VAR USE_SYSTEM_VAR SUPERBUILD_VAR + CMAKE_GENERATOR + CMAKE_GENERATOR_PLATFORM + CMAKE_GENERATOR_TOOLSET + ) set(multiValueArgs) cmake_parse_arguments(_sb "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) @@ -461,6 +682,9 @@ macro(ExternalProject_Include_Dependencies project_name) OR x${project_name} STREQUAL xDEPENDS_VAR OR x${project_name} STREQUAL xUSE_SYSTEM_VAR OR x${project_name} STREQUAL xSUPERBUILD_VAR + OR x${project_name} STREQUAL xCMAKE_GENERATOR + OR x${project_name} STREQUAL xCMAKE_GENERATOR_PLATFORM + OR x${project_name} STREQUAL xCMAKE_GENERATOR_TOOLSET ) message(FATAL_ERROR "Argument <project_name> is missing !") endif() @@ -514,12 +738,31 @@ macro(ExternalProject_Include_Dependencies project_name) #message("[${project_name}] Setting _sb_SUPERBUILD_VAR with default value '${_sb_SUPERBUILD_VAR}'") endif() + # Set default for optional CMAKE_GENERATOR_* parameters + foreach(varname IN ITEMS + "CMAKE_GENERATOR" + "CMAKE_GENERATOR_PLATFORM" + "CMAKE_GENERATOR_TOOLSET" + ) + if(NOT _sb_${varname}) + set(_sb_${varname} ${EP_${varname}}) + #message("[${project_name}] Setting _sb_${varname} with default value '${_sb_${varname}}'") + else() + #message("[${project_name}] Setting _sb_${varname} to value '${_sb_${varname}}'") + endif() + endforeach() + # Keeping track of variable name independently of the recursion if(NOT DEFINED _sb_SB_VAR) set(_sb_SB_VAR ${_sb_SUPERBUILD_VAR}) #message("[${project_name}] Setting _sb_SB_VAR with default value '${_sb_SB_VAR}'") endif() + # Try to detect if superbuild variable was improperly passed + if("${_sb_SB_VAR}" STREQUAL "_SUPERBUILD") + message(FATAL_ERROR "SUPERBUILD_VAR value is incorrectly set to '_SUPERBUILD'") + endif() + # Set local variables set(_sb_DEPENDS ${${_sb_DEPENDS_VAR}}) set(_sb_USE_SYSTEM ${${_sb_USE_SYSTEM_VAR}}) @@ -541,6 +784,12 @@ macro(ExternalProject_Include_Dependencies project_name) set(SB_FIRST_PASS TRUE) endif() + # Extra dependencies specified using "ExternalProject_Add_Dependencies" + get_property(_sb_ADDITIONAL_DEPENDS GLOBAL PROPERTY SB_${_sb_proj}_ADDITIONAL_DEPENDS) + if(NOT "x${_sb_ADDITIONAL_DEPENDS}" STREQUAL "x") + list(APPEND _sb_DEPENDS ${_sb_ADDITIONAL_DEPENDS}) + endif() + set(_sb_REQUIRED_DEPENDS) foreach(dep ${_sb_DEPENDS}) if(NOT ${_sb_proj} STREQUAL ${SUPERBUILD_TOPLEVEL_PROJECT}) @@ -581,21 +830,38 @@ macro(ExternalProject_Include_Dependencies project_name) set_property(GLOBAL PROPERTY SB_${_sb_proj}_USE_SYSTEM ${_sb_USE_SYSTEM}) set_property(GLOBAL PROPERTY SB_${_sb_proj}_USE_SYSTEM_VAR ${_sb_USE_SYSTEM_VAR}) set_property(GLOBAL PROPERTY SB_${_sb_proj}_PROJECT_VAR ${_sb_PROJECT_VAR}) + foreach(varname IN ITEMS + "CMAKE_GENERATOR" + "CMAKE_GENERATOR_PLATFORM" + "CMAKE_GENERATOR_TOOLSET" + ) + set_property(GLOBAL PROPERTY SB_${_sb_proj}_${varname} ${_sb_${varname}}) + endforeach() superbuild_stack_push(SB_PROJECT_STACK ${_sb_proj}) # Include dependencies foreach(dep ${_sb_DEPENDS}) get_property(_included GLOBAL PROPERTY SB_${dep}_FILE_INCLUDED) if(NOT _included) - # XXX - Refactor - Add a single variable named 'EXTERNAL_PROJECT_DIRS' if(EXISTS "${EXTERNAL_PROJECT_DIR}/${EXTERNAL_PROJECT_FILE_PREFIX}${dep}.cmake") include(${EXTERNAL_PROJECT_DIR}/${EXTERNAL_PROJECT_FILE_PREFIX}${dep}.cmake) elseif(EXISTS "${${dep}_FILEPATH}") + # Originally implemented to support CTK buildsystem include(${${dep}_FILEPATH}) elseif(EXISTS "${EXTERNAL_PROJECT_ADDITIONAL_DIR}/${EXTERNAL_PROJECT_FILE_PREFIX}${dep}.cmake") include(${EXTERNAL_PROJECT_ADDITIONAL_DIR}/${EXTERNAL_PROJECT_FILE_PREFIX}${dep}.cmake) else() - message(FATAL_ERROR "Can't find ${EXTERNAL_PROJECT_FILE_PREFIX}${dep}.cmake") + set(_found_ep_cmake FALSE) + foreach(_external_project_additional_dir ${EXTERNAL_PROJECT_ADDITIONAL_DIRS}) + if(EXISTS "${_external_project_additional_dir}/${EXTERNAL_PROJECT_FILE_PREFIX}${dep}.cmake") + include(${_external_project_additional_dir}/${EXTERNAL_PROJECT_FILE_PREFIX}${dep}.cmake) + set(_found_ep_cmake TRUE) + break() + endif() + endforeach() + if(NOT _found_ep_cmake) + message(FATAL_ERROR "Can't find ${EXTERNAL_PROJECT_FILE_PREFIX}${dep}.cmake") + endif() endif() set_property(GLOBAL PROPERTY SB_${dep}_FILE_INCLUDED 1) endif() @@ -603,6 +869,13 @@ macro(ExternalProject_Include_Dependencies project_name) # Restore variables superbuild_stack_pop(SB_PROJECT_STACK _sb_proj) + foreach(varname IN ITEMS + "CMAKE_GENERATOR" + "CMAKE_GENERATOR_PLATFORM" + "CMAKE_GENERATOR_TOOLSET" + ) + get_property(_sb_${varname} GLOBAL PROPERTY SB_${_sb_proj}_${varname}) + endforeach() get_property(_sb_PROJECT_VAR GLOBAL PROPERTY SB_${_sb_proj}_PROJECT_VAR) get_property(_sb_USE_SYSTEM_VAR GLOBAL PROPERTY SB_${_sb_proj}_USE_SYSTEM_VAR) get_property(_sb_USE_SYSTEM GLOBAL PROPERTY SB_${_sb_proj}_USE_SYSTEM) @@ -635,12 +908,23 @@ macro(ExternalProject_Include_Dependencies project_name) set(${_sb_PROJECT_VAR} ${_sb_proj}) set(SB_SECOND_PASS TRUE) + set(_ep_include_deps_EXTRA_ARGS ) + foreach(varname IN ITEMS + "CMAKE_GENERATOR" + "CMAKE_GENERATOR_PLATFORM" + "CMAKE_GENERATOR_TOOLSET" + ) + list(APPEND _ep_include_deps_EXTRA_ARGS + ${varname} ${_sb_${varname}} + ) + endforeach() ExternalProject_Include_Dependencies(${_sb_proj} PROJECT_VAR ${_sb_PROJECT_VAR} DEPENDS_VAR ${_sb_DEPENDS_VAR} EP_ARGS_VAR ${_sb_EP_ARGS_VAR} USE_SYSTEM_VAR _sb_USE_SYSTEM SUPERBUILD_VAR ${_sb_SB_VAR} + ${_ep_include_deps_EXTRA_ARGS} ) set(SB_SECOND_PASS FALSE) endif() @@ -728,3 +1012,84 @@ function(ExternalProject_Install_CMake project_name) install(SCRIPT ${binary_dir}/cmake_install.cmake) endfunction() + +#.rst: +# .. cmake:function:: ExternalProject_SetIfNotDefined +# +# Set a variable to its default value if not already defined. +# +# .. code-block:: cmake +# +# ExternalProject_SetIfNotDefined(<var> <defaultvalue> [OBFUSCATE] [QUIET]) +# +# If *NOT* already defined, the variable <var> is set with: +# (1) the value of the environment variable <var>, if defined. +# (2) the value of the local variable variable <var>, if defined. +# (3) if none of the above is defined, the <defaultvalue> passed as a parameter. +# +# Passing the optional parameter 'OBFUSCATE' will display 'OBFUSCATED' instead of the real value. +# Passing the optional parameter 'QUIET' will not display any message. +# +# For convenience, the value of the cache variable named <var> will +# be displayed if it was set and if QUIET has not been passed. +macro(ExternalProject_SetIfNotDefined var defaultvalue) + set(_obfuscate FALSE) + set(_quiet FALSE) + foreach(arg ${ARGN}) + if(arg STREQUAL "OBFUSCATE") + set(_obfuscate TRUE) + endif() + if(arg STREQUAL "QUIET") + set(_quiet TRUE) + endif() + endforeach() + if(DEFINED ENV{${var}} AND NOT DEFINED ${var}) + set(_value "$ENV{${var}}") + if(_obfuscate) + set(_value "OBFUSCATED") + endif() + if(NOT _quiet) + message(STATUS "Setting '${var}' variable with environment variable value '${_value}'") + endif() + set(${var} $ENV{${var}}) + endif() + if(NOT DEFINED ${var}) + set(_value "${defaultvalue}") + if(_obfuscate) + set(_value "OBFUSCATED") + endif() + if(NOT _quiet) + message(STATUS "Setting '${var}' variable with default value '${_value}'") + endif() + set(${var} "${defaultvalue}") + endif() + get_property(_is_set CACHE ${var} PROPERTY VALUE SET) + if(_is_set AND NOT _quiet) + set(_value "${${var}}") + if(_obfuscate) + set(_value "OBFUSCATED") + endif() + message(STATUS "Cache variable '${var}' set to '${_value}'") + endif() +endmacro() + +#.rst: +# .. cmake:function:: ExternalProject_AlwaysConfigure +# +# Add a external project step named `forceconfigure` to `project_name` ensuring +# the project will always be reconfigured. +# +# .. code-block:: cmake +# +# ExternalProject_AlwaysConfigure(<project_name>) +function(ExternalProject_AlwaysConfigure proj) + # This custom external project step forces the configure and later + # steps to run. + _ep_get_step_stampfile(${proj} "configure" stampfile) + ExternalProject_Add_Step(${proj} forceconfigure + COMMAND ${CMAKE_COMMAND} -E remove ${stampfile} + COMMENT "Forcing configure step for '${proj}'" + DEPENDEES build + ALWAYS 1 + ) +endfunction()