1#.rst: 2# ExternalProjectDependency 3# ------------------------- 4# 5# .. only:: html 6# 7# .. contents:: 8 9########################################################################### 10# 11# Library: CTK 12# 13# Copyright (c) Kitware Inc. 14# 15# Licensed under the Apache License, Version 2.0 (the "License"); 16# you may not use this file except in compliance with the License. 17# You may obtain a copy of the License at 18# 19# http://www.apache.org/licenses/LICENSE-2.0.txt 20# 21# Unless required by applicable law or agreed to in writing, software 22# distributed under the License is distributed on an "AS IS" BASIS, 23# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 24# See the License for the specific language governing permissions and 25# limitations under the License. 26# 27########################################################################### 28 29include(CMakeParseArguments) 30 31#.rst: 32# Global Variables 33# ^^^^^^^^^^^^^^^^ 34 35#.rst: 36# .. cmake:variable:: EXTERNAL_PROJECT_DIR 37# 38# This variable describes the directory in which external project files 39# matching ``<EXTERNAL_PROJECT_FILE_PREFIX><projectname>.cmake`` expression are globbed. 40# 41if(NOT EXISTS "${EXTERNAL_PROJECT_DIR}") 42 set(EXTERNAL_PROJECT_DIR ${CMAKE_SOURCE_DIR}/SuperBuild) 43endif() 44 45#.rst: 46# .. cmake:variable:: EXTERNAL_PROJECT_ADDITIONAL_DIR 47# 48# If set, this variable represents an other directory in which external project files 49# are searched for if not already found in ``EXTERNAL_PROJECT_DIR``. 50 51#.rst: 52# .. cmake:variable:: EXTERNAL_PROJECT_FILE_PREFIX 53# 54# This variable describes the prefix of the external project files looked up in 55# ``EXTERNAL_PROJECT_DIR``. It defaults to ``External_``. 56# 57if(NOT DEFINED EXTERNAL_PROJECT_FILE_PREFIX) 58 set(EXTERNAL_PROJECT_FILE_PREFIX "External_") 59endif() 60 61#.rst: 62# .. cmake:variable:: SUPERBUILD_TOPLEVEL_PROJECT 63# 64# This variable can be set to explicitly identify the name of the top-level project. 65# If not set, it default to the value of ``CMAKE_PROJECT_NAME``. 66if(NOT DEFINED SUPERBUILD_TOPLEVEL_PROJECT) 67 if(NOT DEFINED CMAKE_PROJECT_NAME) 68 message(FATAL_ERROR "Failed to initialize variable SUPERBUILD_TOPLEVEL_PROJECT. Variable CMAKE_PROJECT_NAME is not defined.") 69 endif() 70 set(SUPERBUILD_TOPLEVEL_PROJECT ${CMAKE_PROJECT_NAME}) 71endif() 72 73#.rst: 74# .. cmake:variable:: EP_LIST_SEPARATOR 75# 76# This variable is used to separate list items when passed in various external project 77# ``..._COMMAND`` options. 78# 79# If defaults to ``^^``. 80if(NOT DEFINED EP_LIST_SEPARATOR) 81 set(EP_LIST_SEPARATOR "^^") 82endif() 83 84 85#.rst: 86# .. cmake:variable:: EP_GIT_PROTOCOL 87# 88# The value of this variable is controled by the option ``<SUPERBUILD_TOPLEVEL_PROJECT>_USE_GIT_PROTOCOL`` 89# automatically defined by including this CMake module. Setting this option allows to update the value of 90# ``EP_GIT_PROTOCOL`` variable. 91# 92# If enabled, the variable ``EP_GIT_PROTOCOL`` is set to ``git``. Otherwise, it is set to ``https``. 93# The option is enabled by default. 94# 95# The variable ``EP_GIT_PROTOCOL`` can be used when adding external project. For example: 96# 97# .. code-block:: cmake 98# 99# ExternalProject_Add(${proj} 100# ${${proj}_EP_ARGS} 101# GIT_REPOSITORY "${EP_GIT_PROTOCOL}://github.com/Foo/Foo.git" 102# [...] 103# ) 104# 105option(${SUPERBUILD_TOPLEVEL_PROJECT}_USE_GIT_PROTOCOL "If behind a firewall turn this off to use https instead." ON) 106set(EP_GIT_PROTOCOL "git") 107if(NOT ${SUPERBUILD_TOPLEVEL_PROJECT}_USE_GIT_PROTOCOL) 108 set(EP_GIT_PROTOCOL "https") 109endif() 110 111# Compute -G arg for configuring external projects with the same CMake generator: 112if(CMAKE_EXTRA_GENERATOR) 113 set(EP_CMAKE_GENERATOR "${CMAKE_EXTRA_GENERATOR} - ${CMAKE_GENERATOR}") 114else() 115 set(EP_CMAKE_GENERATOR "${CMAKE_GENERATOR}") 116endif() 117set(EP_CMAKE_GENERATOR_PLATFORM "${CMAKE_GENERATOR_PLATFORM}") 118set(EP_CMAKE_GENERATOR_TOOLSET "${CMAKE_GENERATOR_TOOLSET}") 119 120#.rst: 121# Functions 122# ^^^^^^^^^ 123 124#.rst: 125# .. cmake:function:: mark_as_superbuild 126# 127# .. code-block:: cmake 128# 129# mark_as_superbuild(<varname1>[:<vartype1>] [<varname2>[:<vartype2>] [...]]) 130# 131# .. code-block:: cmake 132# 133# mark_as_superbuild( 134# VARS <varname1>[:<vartype1>] [<varname2>[:<vartype2>] [...]] 135# [PROJECTS <projectname> [<projectname> [...]] | ALL_PROJECTS] 136# [LABELS <label1> [<label2> [...]]] 137# ) 138# 139# .. code-block:: cmake 140# 141# PROJECTS corresponds to a list of <projectname> that will be added using 'ExternalProject_Add' function. 142# If not specified and called within a project file, it defaults to the value of 'SUPERBUILD_TOPLEVEL_PROJECT'. 143# If instead 'ALL_PROJECTS' is specified, the variables and labels will be passed to all projects. 144# 145# VARS is an expected list of variables specified as <varname>:<vartype> to pass to <projectname> 146# 147# 148# LABELS is an optional list of label to associate with the variable names specified using 'VARS' and passed to 149# the <projectname> as CMake CACHE args of the form: 150# -D<projectname>_EP_LABEL_<label1>=<varname1>;<varname2>[...] 151# -D<projectname>_EP_LABEL_<label2>=<varname1>;<varname2>[...] 152# 153function(mark_as_superbuild) 154 set(options ALL_PROJECTS CMAKE_CMD) 155 set(oneValueArgs) 156 set(multiValueArgs VARS PROJECTS LABELS) 157 cmake_parse_arguments(_sb "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) 158 159 set(_vars ${_sb_UNPARSED_ARGUMENTS}) 160 161 set(_named_parameters_expected 0) 162 if(_sb_PROJECTS OR _sb_ALL_PROJECTS OR _sb_LABELS OR _sb_VARS) 163 set(_named_parameters_expected 1) 164 set(_vars ${_sb_VARS}) 165 endif() 166 167 if(_named_parameters_expected AND _sb_UNPARSED_ARGUMENTS) 168 message(FATAL_ERROR "Arguments '${_sb_UNPARSED_ARGUMENTS}' should be associated with VARS parameter !") 169 endif() 170 171 if(_sb_PROJECTS AND _sb_ALL_PROJECTS) 172 message(FATAL_ERROR "Arguments 'PROJECTS' and 'ALL_PROJECTS' are mutually exclusive !") 173 endif() 174 175 foreach(var ${_vars}) 176 set(_type_specified 0) 177 if(var MATCHES ":") 178 set(_type_specified 1) 179 endif() 180 # XXX Display warning with variable type is also specified for cache variable. 181 set(_var ${var}) 182 if(NOT _type_specified) 183 get_property(_type_set_in_cache CACHE ${_var} PROPERTY TYPE SET) 184 set(_var_name ${_var}) 185 set(_var_type "STRING") 186 if(_type_set_in_cache) 187 get_property(_var_type CACHE ${_var_name} PROPERTY TYPE) 188 endif() 189 set(_var ${_var_name}:${_var_type}) 190 endif() 191 list(APPEND _vars_with_type ${_var}) 192 endforeach() 193 194 if(_sb_ALL_PROJECTS) 195 set(optional_arg_ALL_PROJECTS "ALL_PROJECTS") 196 else() 197 set(optional_arg_ALL_PROJECTS PROJECTS ${_sb_PROJECTS}) 198 endif() 199 200 _sb_append_to_cmake_args( 201 VARS ${_vars_with_type} LABELS ${_sb_LABELS} ${optional_arg_ALL_PROJECTS}) 202endfunction() 203 204# 205# _sb_extract_varname_and_vartype(<cmake_varname_and_type> <varname_var> [<vartype_var>]) 206# 207# <cmake_varname_and_type> corresponds to variable name and variable type passed as "<varname>:<vartype>" 208# 209# <varname_var> will be set to "<varname>" 210# 211# <vartype_var> is an optional variable name that will be set to "<vartype>" 212# 213function(_sb_extract_varname_and_vartype cmake_varname_and_type varname_var) 214 set(_vartype_var "${ARGV2}") 215 string(REPLACE ":" ";" varname_and_vartype ${cmake_varname_and_type}) 216 list(GET varname_and_vartype 0 _varname) 217 list(GET varname_and_vartype 1 _vartype) 218 set(${varname_var} ${_varname} PARENT_SCOPE) 219 if(_vartype_var MATCHES ".+") 220 set(${_vartype_var} ${_vartype} PARENT_SCOPE) 221 endif() 222endfunction() 223 224 225function(_sb_list_to_string separator input_list output_string_var) 226 set(_string "") 227 # Get list length 228 list(LENGTH input_list list_length) 229 # If the list has 0 or 1 element, there is no need to loop over. 230 if(list_length LESS 2) 231 set(_string "${input_list}") 232 else() 233 math(EXPR last_element_index "${list_length} - 1") 234 foreach(index RANGE ${last_element_index}) 235 # Get current item_value 236 list(GET input_list ${index} item_value) 237 if(NOT item_value STREQUAL "") 238 # .. and append non-empty value to output string 239 set(_string "${_string}${item_value}") 240 # Append separator if current element is NOT the last one. 241 if(NOT index EQUAL last_element_index) 242 set(_string "${_string}${separator}") 243 endif() 244 endif() 245 endforeach() 246 endif() 247 set(${output_string_var} ${_string} PARENT_SCOPE) 248endfunction() 249 250# 251# _sb_cmakevar_to_cmakearg(<cmake_varname_and_type> <cmake_arg_var> <has_cfg_intdir_var> [<varname_var> [<vartype_var>]]) 252# 253# <cmake_varname_and_type> corresponds to variable name and variable type passed as "<varname>:<vartype>" 254# 255# <cmake_arg_var> is a variable name that will be set to "-D<varname>:<vartype>=${<varname>}" 256# 257# <has_int_dir_var> is set to either TRUE or FALSE. 258# FALSE means that the value does NOT reference ${CMAKE_CFG_INTDIR} and 259# the generated cmake argument should be passed to ExternalProject_Add as CMAKE_CACHE_ARGS. 260# TRUEmeans that the value does reference ${CMAKE_CFG_INTDIR} and 261# the generated cmake argument should be passed to ExternalProject_Add as CMAKE_ARGS. 262# 263# <varname_var> is an optional variable name that will be set to "<varname>" 264# 265# <vartype_var> is an optional variable name that will be set to "<vartype>" 266# 267function(_sb_cmakevar_to_cmakearg cmake_varname_and_type cmake_arg_var has_cfg_intdir_var) 268 set(_varname_var "${ARGV3}") 269 set(_vartype_var "${ARGV4}") 270 271 _sb_extract_varname_and_vartype(${cmake_varname_and_type} _varname _vartype) 272 273 set(_var_value "${${_varname}}") 274 275 # Use cache value unless it is INTERNAL 276 if(_vartype STREQUAL "INTERNAL") 277 set(_vartype "STRING") 278 else() 279 get_property(_value_set_in_cache CACHE ${_varname} PROPERTY VALUE SET) 280 if(_value_set_in_cache) 281 get_property(_var_value CACHE ${_varname} PROPERTY VALUE) 282 endif() 283 endif() 284 285 set(_has_cfg_intdir FALSE) 286 if(CMAKE_CONFIGURATION_TYPES) 287 string(FIND "${_var_value}" ${CMAKE_CFG_INTDIR} _index) 288 if(NOT _index EQUAL -1) 289 # Separate list item with <EP_LIST_SEPARATOR> 290 _sb_list_to_string(${EP_LIST_SEPARATOR} "${_var_value}" _var_value) 291 set(_has_cfg_intdir TRUE) 292 endif() 293 endif() 294 295 if(NOT _has_cfg_intdir) 296 string(REPLACE "\"" "\\\"" _var_value "${_var_value}") 297 endif() 298 299 set(${cmake_arg_var} -D${_varname}:${_vartype}=${_var_value} PARENT_SCOPE) 300 set(${has_cfg_intdir_var} ${_has_cfg_intdir} PARENT_SCOPE) 301 302 if(_varname_var MATCHES ".+") 303 set(${_varname_var} ${_varname} PARENT_SCOPE) 304 endif() 305 if(_vartype_var MATCHES ".+") 306 set(${_vartype_var} ${_vartype} PARENT_SCOPE) 307 endif() 308endfunction() 309 310set(_ALL_PROJECT_IDENTIFIER "ALLALLALL") 311 312# 313# _sb_append_to_cmake_args( 314# [VARS <varname1>:<vartype1> [<varname2>:<vartype2> [...]]] 315# [PROJECTS <projectname> [<projectname> [...]] | ALL_PROJECTS] 316# [LABELS <label1> [<label2> [...]]] 317# ) 318# 319# PROJECTS corresponds to a list of <projectname> that will be added using 'ExternalProject_Add' function. 320# If not specified and called within a project file, it defaults to the value of 'SUPERBUILD_TOPLEVEL_PROJECT'. 321# If instead 'ALL_PROJECTS' is specified, the variables and labels will be passed to all projects. 322# 323# VARS is an expected list of variables specified as <varname>:<vartype> to pass to <projectname> 324# 325# 326# LABELS is an optional list of label to associate with the variable names specified using 'VARS' and passed to 327# the <projectname> as CMake CACHE args of the form: 328# -D<projectname>_EP_LABEL_<label1>=<varname1>;<varname2>[...] 329# -D<projectname>_EP_LABEL_<label2>=<varname1>;<varname2>[...] 330# 331function(_sb_append_to_cmake_args) 332 set(options ALL_PROJECTS) 333 set(oneValueArgs) 334 set(multiValueArgs VARS PROJECTS LABELS) 335 cmake_parse_arguments(_sb "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) 336 337 if(NOT _sb_PROJECTS AND NOT _sb_ALL_PROJECTS) 338 set(_sb_PROJECTS ${SUPERBUILD_TOPLEVEL_PROJECT}) 339 endif() 340 341 if(_sb_ALL_PROJECTS) 342 set(_sb_PROJECTS ${_ALL_PROJECT_IDENTIFIER}) 343 endif() 344 345 foreach(_sb_PROJECT ${_sb_PROJECTS}) 346 347 set(_ep_varnames "") 348 foreach(varname_and_vartype ${_sb_VARS}) 349 if(NOT TARGET ${_sb_PROJECT}) 350 set_property(GLOBAL APPEND PROPERTY ${_sb_PROJECT}_EP_CMAKE_ARGS ${varname_and_vartype}) 351 _sb_extract_varname_and_vartype(${varname_and_vartype} _varname) 352 else() 353 message(FATAL_ERROR "Function _sb_append_to_cmake_args not allowed because project '${_sb_PROJECT}' already added !") 354 endif() 355 list(APPEND _ep_varnames ${_varname}) 356 endforeach() 357 358 if(_sb_LABELS) 359 set_property(GLOBAL APPEND PROPERTY ${_sb_PROJECT}_EP_LABELS ${_sb_LABELS}) 360 foreach(label ${_sb_LABELS}) 361 set_property(GLOBAL APPEND PROPERTY ${_sb_PROJECT}_EP_LABEL_${label} ${_ep_varnames}) 362 endforeach() 363 endif() 364 endforeach() 365endfunction() 366 367#.rst: 368# .. cmake:function:: ExternalProject_DeclareLabels 369# 370# .. code-block:: cmake 371# 372# ExternalProject_DeclareLabels( 373# [PROJECTS <projectname> [<projectname> [...]] | ALL_PROJECTS] 374# LABELS <label1> [<label2> [...]] 375# ) 376# 377# .. code-block:: cmake 378# 379# PROJECTS corresponds to a list of <projectname> that will be added using 'ExternalProject_Add' function. 380# If not specified and called within a project file, it defaults to the value of 'SUPERBUILD_TOPLEVEL_PROJECT'. 381# If instead 'ALL_PROJECTS' is specified, the variables and labels will be passed to all projects. 382# 383# LABELS is a list of label to pass to the <projectname> as CMake CACHE args of the 384# form -D<projectname>_EP_LABEL_<label>= unless specific variables 385# have been associated with the labels using mark_as_superbuild. 386# 387function(ExternalProject_DeclareLabels) 388 set(options ALL_PROJECTS) 389 set(oneValueArgs) 390 set(multiValueArgs PROJECTS LABELS) 391 cmake_parse_arguments(_sb "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) 392 393 if(_sb_PROJECTS AND _sb_ALL_PROJECTS) 394 message(FATAL_ERROR "Arguments 'PROJECTS' and 'ALL_PROJECTS' are mutually exclusive !") 395 endif() 396 397 if(_sb_ALL_PROJECTS) 398 set(optional_arg_ALL_PROJECTS "ALL_PROJECTS") 399 else() 400 set(optional_arg_ALL_PROJECTS PROJECTS ${_sb_PROJECTS}) 401 endif() 402 403 _sb_append_to_cmake_args( 404 LABELS ${_sb_LABELS} ${optional_arg_ALL_PROJECTS}) 405endfunction() 406 407function(_sb_get_external_project_arguments proj varname) 408 409 mark_as_superbuild(${SUPERBUILD_TOPLEVEL_PROJECT}_USE_SYSTEM_${proj}:BOOL) 410 411 function(_sb_collect_args proj) 412 # Set list of CMake args associated with each label 413 get_property(_labels GLOBAL PROPERTY ${proj}_EP_LABELS) 414 if(_labels) 415 list(REMOVE_DUPLICATES _labels) 416 foreach(label ${_labels}) 417 get_property(${proj}_EP_LABEL_${label} GLOBAL PROPERTY ${proj}_EP_LABEL_${label}) 418 if(${proj}_EP_LABEL_${label}) 419 list(REMOVE_DUPLICATES ${proj}_EP_LABEL_${label}) 420 endif() 421 _sb_append_to_cmake_args(PROJECTS ${proj} 422 VARS ${proj}_EP_LABEL_${label}:STRING) 423 endforeach() 424 endif() 425 426 get_property(_args GLOBAL PROPERTY ${proj}_EP_CMAKE_ARGS) 427 foreach(var ${_args}) 428 _sb_cmakevar_to_cmakearg(${var} cmake_arg _has_cfg_intdir) 429 set(_ep_property "CMAKE_CACHE_ARGS") 430 if(_has_cfg_intdir) 431 set(_ep_property "CMAKE_ARGS") 432 endif() 433 set_property(GLOBAL APPEND PROPERTY ${proj}_EP_PROPERTY_${_ep_property} ${cmake_arg}) 434 endforeach() 435 436 endfunction() 437 438 _sb_collect_args(${proj}) 439 _sb_collect_args(${_ALL_PROJECT_IDENTIFIER}) 440 441 set(_ep_arguments "") 442 443 # Automatically propagate CMake options 444 foreach(_cmake_option IN ITEMS 445 CMAKE_EXPORT_COMPILE_COMMANDS 446 CMAKE_JOB_POOL_COMPILE 447 CMAKE_JOB_POOL_LINK 448 CMAKE_JOB_POOLS 449 ) 450 if(DEFINED ${_cmake_option}) 451 list(APPEND _ep_arguments CMAKE_CACHE_ARGS 452 -D${_cmake_option}:BOOL=${${_cmake_option}} 453 ) 454 endif() 455 endforeach() 456 457 foreach(property CMAKE_ARGS CMAKE_CACHE_ARGS) 458 get_property(${proj}_EP_PROPERTY_${property} GLOBAL PROPERTY ${proj}_EP_PROPERTY_${property}) 459 get_property(${_ALL_PROJECT_IDENTIFIER}_EP_PROPERTY_${property} GLOBAL PROPERTY ${_ALL_PROJECT_IDENTIFIER}_EP_PROPERTY_${property}) 460 set(_all ${${proj}_EP_PROPERTY_${property}} ${${_ALL_PROJECT_IDENTIFIER}_EP_PROPERTY_${property}}) 461 list(LENGTH _all _num_properties) 462 if(_num_properties GREATER 0) 463 list(APPEND _ep_arguments ${property} ${_all}) 464 endif() 465 endforeach() 466 467 list(APPEND _ep_arguments LIST_SEPARATOR ${EP_LIST_SEPARATOR}) 468 469 list(APPEND _ep_arguments CMAKE_GENERATOR ${_sb_CMAKE_GENERATOR}) 470 if(CMAKE_VERSION VERSION_GREATER "3.0") 471 list(APPEND _ep_arguments CMAKE_GENERATOR_PLATFORM ${_sb_CMAKE_GENERATOR_PLATFORM}) 472 endif() 473 list(APPEND _ep_arguments CMAKE_GENERATOR_TOOLSET ${_sb_CMAKE_GENERATOR_TOOLSET}) 474 if(CMAKE_VERSION VERSION_EQUAL "3.4" OR CMAKE_VERSION VERSION_GREATER "3.4") 475 # USES_TERMINAL_* options were introduced in CMake 3.4 476 foreach(step IN ITEMS DOWNLOAD UPDATE CONFIGURE BUILD TEST INSTALL) 477 list(APPEND _ep_arguments 478 USES_TERMINAL_${step} 1 479 ) 480 endforeach() 481 endif() 482 set(${varname} ${_ep_arguments} PARENT_SCOPE) 483endfunction() 484 485function(_sb_update_indent proj) 486 superbuild_stack_size(SB_PROJECT_STACK _stack_size) 487 set(_indent "") 488 if(_stack_size GREATER 0) 489 foreach(not_used RANGE 1 ${_stack_size}) 490 set(_indent " ${_indent}") 491 endforeach() 492 endif() 493 set_property(GLOBAL PROPERTY SUPERBUILD_${proj}_INDENT ${_indent}) 494endfunction() 495 496#.rst: 497# .. cmake:function:: ExternalProject_Message 498# 499# .. code-block:: cmake 500# 501# ExternalProject_Message(<project_name> <msg> [condition]) 502# 503function(ExternalProject_Message proj msg) 504 set(_display 1) 505 if(NOT "x${ARGV2}" STREQUAL "x") 506 set(_display ${ARGN}) 507 endif() 508 if(${_display}) 509 get_property(_indent GLOBAL PROPERTY SUPERBUILD_${proj}_INDENT) 510 message(STATUS "SuperBuild - ${_indent}${msg}") 511 endif() 512endfunction() 513 514# 515# superbuild_stack_content(<stack_name> <output_var>) 516# 517# <stack_name> corresponds to the name of stack. 518# 519# <output_var> is the name of CMake variable that will be set with the content 520# of the stack identified by <stack_name>. 521# 522function(superbuild_stack_content stack_name output_var) 523 get_property(_stack GLOBAL PROPERTY ${stack_name}) 524 set(${output_var} ${_stack} PARENT_SCOPE) 525endfunction() 526 527# 528# superbuild_stack_size(<stack_name> <output_var>) 529# 530# <stack_name> corresponds to the name of stack. 531# 532# <output_var> is the name of CMake variable that will be set with the size 533# of the stack identified by <stack_name>. 534# 535function(superbuild_stack_size stack_name output_var) 536 get_property(_stack GLOBAL PROPERTY ${stack_name}) 537 list(LENGTH _stack _stack_size) 538 set(${output_var} ${_stack_size} PARENT_SCOPE) 539endfunction() 540 541# 542# superbuild_stack_push(<stack_name> <value>) 543# 544# <stack_name> corresponds to the name of stack. 545# 546# <value> is appended to the stack identified by <stack_name>. 547# 548function(superbuild_stack_push stack_name value) 549 set_property(GLOBAL APPEND PROPERTY ${stack_name} ${value}) 550endfunction() 551 552# 553# superbuild_stack_pop(<stack_name> <item_var>) 554# 555# <stack_name> corresponds to the name of stack. 556# 557# <item_var> names a CMake variable that will be set with the item 558# removed from the stack identified by <stack_name> 559# 560function(superbuild_stack_pop stack_name item_var) 561 get_property(_stack GLOBAL PROPERTY ${stack_name}) 562 list(LENGTH _stack _stack_size) 563 if(_stack_size GREATER 0) 564 math(EXPR _index_to_remove "${_stack_size} - 1") 565 list(GET _stack ${_index_to_remove} _item) 566 list(REMOVE_AT _stack ${_index_to_remove}) 567 set_property(GLOBAL PROPERTY ${stack_name} ${_stack}) 568 set(${item_var} ${_item} PARENT_SCOPE) 569 endif() 570endfunction() 571 572function(_sb_is_optional proj output_var) 573 set(_include_project 1) 574 if(COMMAND superbuild_is_external_project_includable) 575 superbuild_is_external_project_includable("${proj}" _include_project) 576 endif() 577 set(optional 1) 578 if(_include_project) 579 set(optional 0) 580 endif() 581 set(${output_var} ${optional} PARENT_SCOPE) 582endfunction() 583 584#.rst: 585# .. cmake:function:: ExternalProject_Include_Dependencies 586# 587# .. code-block:: cmake 588# 589# ExternalProject_Include_Dependencies(<project_name> 590# [PROJECT_VAR <project_var>] 591# [EP_ARGS_VAR <external_project_args_var>] 592# [DEPENDS_VAR <depends_var>] 593# [USE_SYSTEM_VAR <use_system_var>] 594# [SUPERBUILD_VAR <superbuild_var>] 595# [CMAKE_GENERATOR <cmake_generator>] 596# [CMAKE_GENERATOR_PLATFORM <cmake_generator_platform>] 597# [CMAKE_GENERATOR_TOOLSET <cmake_generator_toolset>] 598# ) 599# 600# 601# .. code-block:: cmake 602# 603# PROJECT_VAR Name of the variable containing the name of the included project. 604# By default, it is `proj` and it is set to `<project_name>`. 605# 606# EP_ARGS_VAR Name of the variable listing arguments to pass to ExternalProject. 607# If not specified, variable name default to `<project_name>_EP_ARGS`. 608# 609# DEPENDS_VAR Name of the variable containing the dependency of the included project. 610# By default, it is `<project_name>_DEPENDS`. 611# 612# 613# USE_SYSTEM_VAR Name of the variable indicating if the system version of <project_name> 614# should be looked up. Lookup of the project is left to the developer implementing 615# the external project file. 616# By default, it is `<SUPERBUILD_TOPLEVEL_PROJECT>_USE_SYSTEM_<project_name>`. 617# 618# SUPERBUILD_VAR Name of the variable indicating if the top-level or inner project is being built. 619# By default, it is `<SUPERBUILD_TOPLEVEL_PROJECT>_SUPERBUILD`. 620# 621# 622# CMAKE_GENERATOR 623# CMAKE_GENERATOR_PLATFORM 624# CMAKE_GENERATOR_TOOLSET These three options allow to overwrite the values set in the top-level project that 625# would otherwise automatically be propagated to dependent projects. 626# 627macro(ExternalProject_Include_Dependencies project_name) 628 set(options) 629 set(oneValueArgs PROJECT_VAR DEPENDS_VAR EP_ARGS_VAR USE_SYSTEM_VAR SUPERBUILD_VAR 630 CMAKE_GENERATOR 631 CMAKE_GENERATOR_PLATFORM 632 CMAKE_GENERATOR_TOOLSET 633 ) 634 set(multiValueArgs) 635 cmake_parse_arguments(_sb "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) 636 637 # Sanity checks 638 if(x${project_name} STREQUAL xPROJECT_VAR 639 OR x${project_name} STREQUAL xEP_ARGS_VAR 640 OR x${project_name} STREQUAL xDEPENDS_VAR 641 OR x${project_name} STREQUAL xUSE_SYSTEM_VAR 642 OR x${project_name} STREQUAL xSUPERBUILD_VAR 643 OR x${project_name} STREQUAL xCMAKE_GENERATOR 644 OR x${project_name} STREQUAL xCMAKE_GENERATOR_PLATFORM 645 OR x${project_name} STREQUAL xCMAKE_GENERATOR_TOOLSET 646 ) 647 message(FATAL_ERROR "Argument <project_name> is missing !") 648 endif() 649 if(_sb_UNPARSED_ARGUMENTS) 650 message(FATAL_ERROR "Invalid arguments: ${_sb_UNPARSED_ARGUMENTS}") 651 endif() 652 653 # Set default for optional PROJECT_VAR parameter 654 if(NOT _sb_PROJECT_VAR) 655 set(_sb_PROJECT_VAR proj) 656 set(${_sb_PROJECT_VAR} ${project_name}) 657 #message("[${project_name}] Setting _sb_PROJECT_VAR with default value '${_sb_PROJECT_VAR}'") 658 endif() 659 660 if(_sb_PROJECT_VAR AND NOT x${project_name} STREQUAL x${${_sb_PROJECT_VAR}}) 661 message(FATAL_ERROR 662 "Argument <project_name>:${project_name} and PROJECT_VAR:${_sb_PROJECT_VAR}:${${_sb_PROJECT_VAR}} are different !") 663 endif() 664 665 set(_sb_proj ${project_name}) 666 667 # Skip if project already included 668 get_property(_is_included GLOBAL PROPERTY SB_${_sb_proj}_FILE_INCLUDED) 669 if(_is_included) 670 return() 671 endif() 672 673 # Set default for optional DEPENDS_VAR and EP_ARGS parameters 674 foreach(param DEPENDS EP_ARGS) 675 if(NOT _sb_${param}_VAR) 676 set(_sb_${param}_VAR ${_sb_proj}_${param}) 677 #message("[${project_name}] Setting _sb_${param}_VAR with default value '${_sb_${param}_VAR}'") 678 endif() 679 endforeach() 680 681 # Set top level project 682 superbuild_stack_size(SB_PROJECT_STACK _stack_size) 683 if(_stack_size EQUAL 0) 684 set(SUPERBUILD_TOPLEVEL_PROJECT ${_sb_proj}) 685 endif() 686 687 # Set default for optional USE_SYSTEM_VAR parameter 688 if(NOT _sb_USE_SYSTEM_VAR) 689 set(_sb_USE_SYSTEM_VAR ${SUPERBUILD_TOPLEVEL_PROJECT}_USE_SYSTEM_${_sb_proj}) 690 #message("[${project_name}] Setting _sb_USE_SYSTEM_VAR with default value '${_sb_USE_SYSTEM_VAR}'") 691 endif() 692 693 # Set default for optional SUPERBUILD_VAR parameter 694 if(NOT _sb_SUPERBUILD_VAR) 695 set(_sb_SUPERBUILD_VAR ${SUPERBUILD_TOPLEVEL_PROJECT}_SUPERBUILD) 696 #message("[${project_name}] Setting _sb_SUPERBUILD_VAR with default value '${_sb_SUPERBUILD_VAR}'") 697 endif() 698 699 # Set default for optional CMAKE_GENERATOR_* parameters 700 foreach(varname IN ITEMS 701 "CMAKE_GENERATOR" 702 "CMAKE_GENERATOR_PLATFORM" 703 "CMAKE_GENERATOR_TOOLSET" 704 ) 705 if(NOT _sb_${varname}) 706 set(_sb_${varname} ${EP_${varname}}) 707 #message("[${project_name}] Setting _sb_${varname} with default value '${_sb_${varname}}'") 708 else() 709 #message("[${project_name}] Setting _sb_${varname} to value '${_sb_${varname}}'") 710 endif() 711 endforeach() 712 713 # Keeping track of variable name independently of the recursion 714 if(NOT DEFINED _sb_SB_VAR) 715 set(_sb_SB_VAR ${_sb_SUPERBUILD_VAR}) 716 #message("[${project_name}] Setting _sb_SB_VAR with default value '${_sb_SB_VAR}'") 717 endif() 718 719 # Set local variables 720 set(_sb_DEPENDS ${${_sb_DEPENDS_VAR}}) 721 set(_sb_USE_SYSTEM ${${_sb_USE_SYSTEM_VAR}}) 722 723 _sb_update_indent(${_sb_proj}) 724 725 # Keep track of the projects 726 list(APPEND SB_${SUPERBUILD_TOPLEVEL_PROJECT}_POSSIBLE_DEPENDS ${_sb_proj}) 727 728 # Use system ? 729 get_property(_use_system_set GLOBAL PROPERTY SB_${_sb_proj}_USE_SYSTEM SET) 730 if(_use_system_set) 731 get_property(_sb_USE_SYSTEM GLOBAL PROPERTY SB_${_sb_proj}_USE_SYSTEM) 732 endif() 733 734 # Is this the first run ? 735 if(${_sb_proj} STREQUAL ${SUPERBUILD_TOPLEVEL_PROJECT} AND NOT DEFINED SB_FIRST_PASS) 736 message(STATUS "SuperBuild - First pass") 737 set(SB_FIRST_PASS TRUE) 738 endif() 739 740 set(_sb_REQUIRED_DEPENDS) 741 foreach(dep ${_sb_DEPENDS}) 742 if(NOT ${_sb_proj} STREQUAL ${SUPERBUILD_TOPLEVEL_PROJECT}) 743 # Set "use system" variable if it has NOT already been explicitly set 744 get_property(_sb_${dep}_USE_SYSTEM_VAR GLOBAL PROPERTY SB_${dep}_USE_SYSTEM_VAR) 745 if(_sb_USE_SYSTEM AND NOT DEFINED ${_sb_${dep}_USE_SYSTEM_VAR}) 746 set_property(GLOBAL PROPERTY SB_${dep}_USE_SYSTEM ${_sb_USE_SYSTEM}) 747 #message(${_sb_proj} "Property SB_${dep}_USE_SYSTEM set to [${_sb_USE_SYSTEM_VAR}:${_sb_USE_SYSTEM}]") 748 endif() 749 endif() 750 _sb_is_optional(${dep} _optional) 751 set_property(GLOBAL PROPERTY SB_${dep}_OPTIONAL ${_optional}) 752 #message(${_sb_proj} "[${_sb_proj}] Property SB_${dep}_OPTIONAL set to ${_optional}") 753 if(NOT _optional) 754 list(APPEND _sb_REQUIRED_DEPENDS ${dep}) 755 endif() 756 endforeach() 757 758 # Display dependency of project being processed 759 if(_sb_REQUIRED_DEPENDS AND SB_SECOND_PASS AND ${_sb_SB_VAR}) 760 set(dependency_str "") 761 foreach(dep ${_sb_REQUIRED_DEPENDS}) 762 get_property(_is_included GLOBAL PROPERTY SB_${dep}_FILE_INCLUDED) 763 set(_include_status "") 764 if(_is_included) 765 set(_include_status "[INCLUDED]") 766 endif() 767 set(dependency_str "${dependency_str}${dep}${_include_status}, ") 768 endforeach() 769 ExternalProject_Message(${_sb_proj} "${_sb_proj} => Requires ${dependency_str}") 770 endif() 771 772 # Save variables 773 set_property(GLOBAL PROPERTY SB_${_sb_proj}_REQUIRED_DEPENDS ${_sb_REQUIRED_DEPENDS}) 774 set_property(GLOBAL PROPERTY SB_${_sb_proj}_DEPENDS ${_sb_DEPENDS}) 775 set_property(GLOBAL PROPERTY SB_${_sb_proj}_DEPENDS_VAR ${_sb_DEPENDS_VAR}) 776 set_property(GLOBAL PROPERTY SB_${_sb_proj}_EP_ARGS_VAR ${_sb_EP_ARGS_VAR}) 777 set_property(GLOBAL PROPERTY SB_${_sb_proj}_USE_SYSTEM ${_sb_USE_SYSTEM}) 778 set_property(GLOBAL PROPERTY SB_${_sb_proj}_USE_SYSTEM_VAR ${_sb_USE_SYSTEM_VAR}) 779 set_property(GLOBAL PROPERTY SB_${_sb_proj}_PROJECT_VAR ${_sb_PROJECT_VAR}) 780 foreach(varname IN ITEMS 781 "CMAKE_GENERATOR" 782 "CMAKE_GENERATOR_PLATFORM" 783 "CMAKE_GENERATOR_TOOLSET" 784 ) 785 set_property(GLOBAL PROPERTY SB_${_sb_proj}_${varname} ${_sb_${varname}}) 786 endforeach() 787 superbuild_stack_push(SB_PROJECT_STACK ${_sb_proj}) 788 789 # Include dependencies 790 foreach(dep ${_sb_DEPENDS}) 791 get_property(_included GLOBAL PROPERTY SB_${dep}_FILE_INCLUDED) 792 if(NOT _included) 793 # XXX - Refactor - Add a single variable named 'EXTERNAL_PROJECT_DIRS' 794 if(EXISTS "${EXTERNAL_PROJECT_DIR}/${EXTERNAL_PROJECT_FILE_PREFIX}${dep}.cmake") 795 include(${EXTERNAL_PROJECT_DIR}/${EXTERNAL_PROJECT_FILE_PREFIX}${dep}.cmake) 796 elseif(EXISTS "${${dep}_FILEPATH}") 797 include(${${dep}_FILEPATH}) 798 elseif(EXISTS "${EXTERNAL_PROJECT_ADDITIONAL_DIR}/${EXTERNAL_PROJECT_FILE_PREFIX}${dep}.cmake") 799 include(${EXTERNAL_PROJECT_ADDITIONAL_DIR}/${EXTERNAL_PROJECT_FILE_PREFIX}${dep}.cmake) 800 else() 801 message(FATAL_ERROR "Can't find ${EXTERNAL_PROJECT_FILE_PREFIX}${dep}.cmake") 802 endif() 803 set_property(GLOBAL PROPERTY SB_${dep}_FILE_INCLUDED 1) 804 endif() 805 endforeach() 806 807 # Restore variables 808 superbuild_stack_pop(SB_PROJECT_STACK _sb_proj) 809 foreach(varname IN ITEMS 810 "CMAKE_GENERATOR" 811 "CMAKE_GENERATOR_PLATFORM" 812 "CMAKE_GENERATOR_TOOLSET" 813 ) 814 get_property(_sb_${varname} GLOBAL PROPERTY SB_${_sb_proj}_${varname}) 815 endforeach() 816 get_property(_sb_PROJECT_VAR GLOBAL PROPERTY SB_${_sb_proj}_PROJECT_VAR) 817 get_property(_sb_USE_SYSTEM_VAR GLOBAL PROPERTY SB_${_sb_proj}_USE_SYSTEM_VAR) 818 get_property(_sb_USE_SYSTEM GLOBAL PROPERTY SB_${_sb_proj}_USE_SYSTEM) 819 get_property(_sb_EP_ARGS_VAR GLOBAL PROPERTY SB_${_sb_proj}_EP_ARGS_VAR) 820 get_property(_sb_DEPENDS_VAR GLOBAL PROPERTY SB_${_sb_proj}_DEPENDS_VAR) 821 get_property(_sb_DEPENDS GLOBAL PROPERTY SB_${_sb_proj}_DEPENDS) 822 get_property(_sb_REQUIRED_DEPENDS GLOBAL PROPERTY SB_${_sb_proj}_REQUIRED_DEPENDS) 823 824 # Use system ? 825 set(_include_type "") 826 if(_sb_USE_SYSTEM) 827 set(_include_type " (SYSTEM)") 828 endif() 829 get_property(_optional GLOBAL PROPERTY SB_${_sb_proj}_OPTIONAL) 830 ExternalProject_Message(${_sb_proj} "${_sb_proj}[OK]${_include_type}" SB_SECOND_PASS AND ${_sb_SB_VAR} AND NOT _optional) 831 832 if(${_sb_proj} STREQUAL ${SUPERBUILD_TOPLEVEL_PROJECT} AND SB_FIRST_PASS) 833 set(SB_FIRST_PASS FALSE) 834 ExternalProject_Message(${_sb_proj} "First pass - done") 835 836 if(${_sb_SB_VAR}) 837 foreach(possible_proj ${SB_${SUPERBUILD_TOPLEVEL_PROJECT}_POSSIBLE_DEPENDS}) 838 get_property(_optional GLOBAL PROPERTY SB_${possible_proj}_OPTIONAL) 839 if(_optional) 840 ExternalProject_Message(${_sb_proj} "${possible_proj}[OPTIONAL]") 841 endif() 842 set_property(GLOBAL PROPERTY SB_${possible_proj}_FILE_INCLUDED 0) 843 endforeach() 844 845 set(${_sb_PROJECT_VAR} ${_sb_proj}) 846 847 set(SB_SECOND_PASS TRUE) 848 set(_ep_include_deps_EXTRA_ARGS ) 849 foreach(varname IN ITEMS 850 "CMAKE_GENERATOR" 851 "CMAKE_GENERATOR_PLATFORM" 852 "CMAKE_GENERATOR_TOOLSET" 853 ) 854 list(APPEND _ep_include_deps_EXTRA_ARGS 855 ${varname} ${_sb_${varname}} 856 ) 857 endforeach() 858 ExternalProject_Include_Dependencies(${_sb_proj} 859 PROJECT_VAR ${_sb_PROJECT_VAR} 860 DEPENDS_VAR ${_sb_DEPENDS_VAR} 861 EP_ARGS_VAR ${_sb_EP_ARGS_VAR} 862 USE_SYSTEM_VAR _sb_USE_SYSTEM 863 SUPERBUILD_VAR ${_sb_SB_VAR} 864 ${_ep_include_deps_EXTRA_ARGS} 865 ) 866 set(SB_SECOND_PASS FALSE) 867 endif() 868 endif() 869 870 if(SB_FIRST_PASS OR _optional) 871 if(NOT ${_sb_proj} STREQUAL ${SUPERBUILD_TOPLEVEL_PROJECT}) 872 return() 873 endif() 874 endif() 875 876 if(SB_SECOND_PASS) 877 _sb_get_external_project_arguments(${_sb_proj} ${_sb_EP_ARGS_VAR}) 878 endif() 879 880 if(NOT SB_FIRST_PASS AND NOT SB_SECOND_PASS 881 AND ${_sb_proj} STREQUAL ${SUPERBUILD_TOPLEVEL_PROJECT}) 882 #ExternalProject_Message(${_sb_proj} "Clean up") 883 unset(_sb_SB_VAR) 884 unset(SB_FIRST_PASS) 885 unset(SB_SECOND_PASS) 886 endif() 887 888 # Set public variables 889 set(${_sb_PROJECT_VAR} ${_sb_proj}) 890 set(${_sb_DEPENDS_VAR} ${_sb_REQUIRED_DEPENDS}) 891 set(${_sb_USE_SYSTEM_VAR} ${_sb_USE_SYSTEM}) 892 893 #message("[${_sb_proj}] #################################") 894 #message("[${_sb_proj}] Setting ${_sb_PROJECT_VAR}:${_sb_proj}") 895 #message("[${_sb_proj}] Setting ${_sb_EP_ARGS_VAR}:${${_sb_EP_ARGS_VAR}}") 896 #message("[${_sb_proj}] Setting ${_sb_DEPENDS_VAR}:${${_sb_DEPENDS_VAR}}") 897 #message("[${_sb_proj}] Setting ${_sb_USE_SYSTEM_VAR}:${_sb_USE_SYSTEM}") 898endmacro() 899 900#.rst: 901# .. cmake:function:: ExternalProject_Add_Empty 902# 903# .. code-block:: cmake 904# 905# ExternalProject_Add_Empty(<project_name> 906# DEPENDS <depends> 907# ) 908# 909macro(ExternalProject_Add_Empty project_name) 910 set(options) 911 set(oneValueArgs) 912 set(multiValueArgs DEPENDS) 913 cmake_parse_arguments(_sb "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) 914 915 # Sanity checks 916 if(x${project_name} STREQUAL xDEPENDS) 917 message(FATAL_ERROR "Argument <project_name> is missing !") 918 endif() 919 if(_sb_UNPARSED_ARGUMENTS) 920 message(FATAL_ERROR "Invalid arguments: ${_sb_UNPARSED_ARGUMENTS}") 921 endif() 922 923 ExternalProject_Add(${project_name} 924 SOURCE_DIR ${CMAKE_BINARY_DIR}/${project_name} 925 BINARY_DIR ${project_name}-build 926 DOWNLOAD_COMMAND "" 927 CONFIGURE_COMMAND "" 928 BUILD_COMMAND "" 929 INSTALL_COMMAND "" 930 DEPENDS ${_sb_DEPENDS} 931 ) 932endmacro() 933 934#.rst: 935# .. cmake:function:: ExternalProject_Install_CMake 936# 937# Install an external CMake-based project as part of the ``install`` target. 938# 939# .. code-block:: cmake 940# 941# ExternalProject_Install_CMake(<project_name>) 942# 943# This causes building the main project's ``install`` target to also execute 944# the CMake install script for the specified external project. The project must 945# be previously declared with :command:`ExternalProject_Add`. 946# 947function(ExternalProject_Install_CMake project_name) 948 ExternalProject_Get_Property(${project_name} binary_dir) 949 950 install(SCRIPT ${binary_dir}/cmake_install.cmake) 951endfunction() 952 953#.rst: 954# .. cmake:function:: ExternalProject_SetIfNotDefined 955# 956# Set a variable to its default value if not already defined. 957# 958# .. code-block:: cmake 959# 960# ExternalProject_SetIfNotDefined(<var> <defaultvalue> [OBFUSCATE] [QUIET]) 961# 962# The default value is set with: 963# (1) if set, the value environment variable <var>. 964# (2) if set, the value of local variable variable <var>. 965# (3) if none of the above, the value passed as a parameter. 966# 967# Setting the optional parameter 'OBFUSCATE' will display 'OBFUSCATED' instead of the real value. 968# Setting the optional parameter 'QUIET' will not display any message. 969macro(ExternalProject_SetIfNotDefined var defaultvalue) 970 set(_obfuscate FALSE) 971 set(_quiet FALSE) 972 foreach(arg ${ARGN}) 973 if(arg STREQUAL "OBFUSCATE") 974 set(_obfuscate TRUE) 975 endif() 976 if(arg STREQUAL "QUIET") 977 set(_quiet TRUE) 978 endif() 979 endforeach() 980 if(DEFINED ENV{${var}} AND NOT DEFINED ${var}) 981 set(_value "$ENV{${var}}") 982 if(_obfuscate) 983 set(_value "OBFUSCATED") 984 endif() 985 if(NOT _quiet) 986 message(STATUS "Setting '${var}' variable with environment variable value '${_value}'") 987 endif() 988 set(${var} $ENV{${var}}) 989 endif() 990 if(NOT DEFINED ${var}) 991 set(_value "${defaultvalue}") 992 if(_obfuscate) 993 set(_value "OBFUSCATED") 994 endif() 995 if(NOT _quiet) 996 message(STATUS "Setting '${var}' variable with default value '${_value}'") 997 endif() 998 set(${var} "${defaultvalue}") 999 endif() 1000endmacro() 1001 1002#.rst: 1003# .. cmake:function:: ExternalProject_AlwaysConfigure 1004# 1005# Add a external project step named `forceconfigure` to `project_name` ensuring 1006# the project will always be reconfigured. 1007# 1008# .. code-block:: cmake 1009# 1010# ExternalProject_AlwaysConfigure(<project_name>) 1011function(ExternalProject_AlwaysConfigure proj) 1012 # This custom external project step forces the configure and later 1013 # steps to run. 1014 _ep_get_step_stampfile(${proj} "configure" stampfile) 1015 ExternalProject_Add_Step(${proj} forceconfigure 1016 COMMAND ${CMAKE_COMMAND} -E remove ${stampfile} 1017 COMMENT "Forcing configure step for '${proj}'" 1018 DEPENDEES build 1019 ALWAYS 1 1020 ) 1021endfunction() 1022