ctkMacroCheckExternalProjectDependency.cmake 30 KB

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