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