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 #.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 
29 include(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 #
41 if(NOT EXISTS "${EXTERNAL_PROJECT_DIR}")
42  set(EXTERNAL_PROJECT_DIR ${CMAKE_SOURCE_DIR}/SuperBuild)
43 endif()
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 #
57 if(NOT DEFINED EXTERNAL_PROJECT_FILE_PREFIX)
58  set(EXTERNAL_PROJECT_FILE_PREFIX "External_")
59 endif()
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``.
66 if(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})
71 endif()
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 ``^^``.
80 if(NOT DEFINED EP_LIST_SEPARATOR)
81  set(EP_LIST_SEPARATOR "^^")
82 endif()
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 #
105 option(${SUPERBUILD_TOPLEVEL_PROJECT}_USE_GIT_PROTOCOL "If behind a firewall turn this off to use https instead." ON)
106 set(EP_GIT_PROTOCOL "git")
107 if(NOT ${SUPERBUILD_TOPLEVEL_PROJECT}_USE_GIT_PROTOCOL)
108  set(EP_GIT_PROTOCOL "https")
109 endif()
110 
111 # Compute -G arg for configuring external projects with the same CMake generator:
112 if(CMAKE_EXTRA_GENERATOR)
113  set(EP_CMAKE_GENERATOR "${CMAKE_EXTRA_GENERATOR} - ${CMAKE_GENERATOR}")
114 else()
115  set(EP_CMAKE_GENERATOR "${CMAKE_GENERATOR}")
116 endif()
117 set(EP_CMAKE_GENERATOR_PLATFORM "${CMAKE_GENERATOR_PLATFORM}")
118 set(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 #
153 function(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})
202 endfunction()
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 #
213 function(_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()
222 endfunction()
223 
224 
225 function(_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)
248 endfunction()
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 #
267 function(_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()
308 endfunction()
309 
310 set(_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 #
331 function(_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()
365 endfunction()
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 #
387 function(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})
405 endfunction()
406 
407 function(_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)
483 endfunction()
484 
485 function(_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})
494 endfunction()
495 
496 #.rst:
497 # .. cmake:function:: ExternalProject_Message
498 #
499 # .. code-block:: cmake
500 #
501 # ExternalProject_Message(<project_name> <msg> [condition])
502 #
503 function(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()
512 endfunction()
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 #
522 function(superbuild_stack_content stack_name output_var)
523  get_property(_stack GLOBAL PROPERTY ${stack_name})
524  set(${output_var} ${_stack} PARENT_SCOPE)
525 endfunction()
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 #
535 function(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)
539 endfunction()
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 #
548 function(superbuild_stack_push stack_name value)
549  set_property(GLOBAL APPEND PROPERTY ${stack_name} ${value})
550 endfunction()
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 #
560 function(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()
570 endfunction()
571 
572 function(_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)
582 endfunction()
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 #
627 macro(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}")
898 endmacro()
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 #
909 macro(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  )
932 endmacro()
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 #
947 function(ExternalProject_Install_CMake project_name)
948  ExternalProject_Get_Property(${project_name} binary_dir)
949 
950  install(SCRIPT ${binary_dir}/cmake_install.cmake)
951 endfunction()
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.
969 macro(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()
1000 endmacro()
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>)
1011 function(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  )
1021 endfunction()