Difference between revisions of "Documentation/Nightly/Developers/Tutorials/MigrationGuide/SlicerExtension"

From Slicer Wiki
Jump to: navigation, search
(24 intermediate revisions by one other user not shown)
Line 1: Line 1:
 
<noinclude>__TOC__</noinclude>
 
<noinclude>__TOC__</noinclude>
 
==Slicer Extension updates==
 
==Slicer Extension updates==
 +
 +
===Slicer 5.0: ITKv4 to ITKv5===
 +
 +
To remove support for ITKv4 and only support ITKv5. See [[Documentation/Nightly/Developers/Tutorials/MigrationGuide#Transition_from_ITK4_to_ITK5]], it includes
 +
the following sections:
 +
* [[Documentation/Nightly/Developers/Tutorials/MigrationGuide#Upgrading_to_ITKv5_or_keep_using_ITKv4_GenerateThreadedData|Upgrading to ITKv5 or keep using ITKv4 GenerateThreadedData]]
 +
* [[Documentation/Nightly/Developers/Tutorials/MigrationGuide#itkMultiThreader_refactor|itkMultiThreader refactor]]
 +
* [[Documentation/Nightly/Developers/Tutorials/MigrationGuide#SimpleFastMutexLock.2C_FastMutexLock_and_MutexLock_are_deprecated|SimpleFastMutexLock, FastMutexLock and MutexLock are deprecated]]
 +
 +
If completely removing support for ITKv4 and only supporting ITKv5 is not possible.  It is possible to conditionally include the ITKv4 code.
 +
 +
For example:
 +
 +
<pre>
 +
#if ITK_VERSION_MAJOR >= 5
 +
  itk::ITK_THREAD_RETURN_TYPE
 +
#else
 +
  ITK_THREAD_RETURN_TYPE
 +
#endif
 +
</pre>
 +
 +
Example of commits:
 +
* ResampleDTIlogEuclidean
 +
** [https://github.com/NIRALUser/ResampleDTIlogEuclidean/commit/f779bf775aad3c4e1493ed8fa722b32623ac9561 ResampleDTIlogEuclidean@f779bf7]  COMP: Use std::mutex instead of deprecated ITK implementation
 +
** [https://github.com/NIRALUser/ResampleDTIlogEuclidean/commit/ed5093b15d0ded34db08978c6c5933c36e40b803 ResampleDTIlogEuclidean@ed5093b] BUG: ITKv5: Fix tests updating ITK filters to use ITKv5 dynamic multi-threading
 +
* PETTumorSegmentation
 +
** [https://github.com/QIICR/PETTumorSegmentation/pull/18/commits/4aead376ed1d909310d43496dd349e8f3b8c8210 PETTumorSegmentation PR#18] BUG: Add support for ITKv5 dynamic multithreader
 +
** [https://github.com/QIICR/PETTumorSegmentation/pull/18/commits/814a689501ab06d70d3ee3d561c14674e724a0d2 PETTumorSegmentation PR#18] COMP: Support ITKv5 refactored threading models
  
 
===Slicer 5.0: Python2 to Python3===
 
===Slicer 5.0: Python2 to Python3===
Line 6: Line 34:
 
Depending on the complexity of the extension, two approaches shall be considered:
 
Depending on the complexity of the extension, two approaches shall be considered:
 
* code base common to Slicer 4.10 and Slicer 5.0. This means backward compatibility with the latest release is maintained.
 
* code base common to Slicer 4.10 and Slicer 5.0. This means backward compatibility with the latest release is maintained.
* specific branch for each Slicer version (e.g <tt>master-4.10</tt> and <tt><master</tt>)
+
* specific branch for each Slicer version (e.g <tt>master-4.10</tt> and <tt>master</tt>)
 +
 
 +
 
 +
'''Example of commits'''
 +
 
 +
* [http://viewvc.slicer.org/viewvc.cgi/Slicer4?view=revision&revision=28079 Slicer r28079] STYLE: Update python classes to follow new-style
 +
* [https://github.com/fedorov/MultiVolumeImporter/commit/f9917b237c3bc3255e3c7677dc9af351dc2325e1 MultiVolumeImporter@f9917b2] STYLE: Apply lib2to3.fixes.fix_idioms to support python3
 +
* [https://github.com/fedorov/MultiVolumeImporter/commit/3edd1bc593f178f11aa92d9baa62685bc96ac540 MultiVolumeImporter@3edd1bc] ENH: Support for Python3
 +
* [https://github.com/slicersalt/ShapeVariationAnalyzer/commit/42343774c44dc78b8560fc0a9e33e3a6018cb6e1 ShapeVariationAnalyzer@4234377] STYLE: Update python scripts for python 3.x
 +
* [https://github.com/QIICR/PETTumorSegmentation/pull/18/commits/b298ab8e672e1ab52ae6b189a34d9930ccac19ba PETTumorSegmentation PR#18] BUG: Add support for Python 3
 +
 
 +
 
 +
'''Step 1'''
  
 
Understanding the scope of changes needed to support Python 3 can be done by:
 
Understanding the scope of changes needed to support Python 3 can be done by:
Line 16: Line 56:
 
${Slicer_DIR}/../python-install/bin/PythonSlicer -m pip install future
 
${Slicer_DIR}/../python-install/bin/PythonSlicer -m pip install future
 
</pre>
 
</pre>
<small>{{note}} Alternatively the <tt>future</tt> package could be installed in a regular python environment and used from there.</small>
 
 
</li>
 
</li>
 
<li>applying all fixes
 
<li>applying all fixes
Line 22: Line 61:
 
   for f in `find ./ -name "*.py"`; do \
 
   for f in `find ./ -name "*.py"`; do \
 
     ${Slicer_DIR}/../python-install/bin/PythonSlicer \
 
     ${Slicer_DIR}/../python-install/bin/PythonSlicer \
       --launch futurize -w $f; \
+
       --launch futurize --nobackups --write $f; \
 +
  done
 +
</pre>
 +
 
 +
<small>{{note}} Alternatively the <tt>future</tt> package could be installed in a regular python environment and used from there.
 +
 
 +
<pre>
 +
  for f in `find ./ -name "*.py"`; do \
 +
    futurize --nobackups --write $f; \
 
   done
 
   done
 
</pre>
 
</pre>
 +
</small>
 +
 
</li>
 
</li>
<li>reviewing the changes and updating as needed.</li>
 
 
</ol>
 
</ol>
 +
 +
This first step will apply the following transformations:
 +
<pre>
 +
lib2to3.fixes.fix_apply
 +
lib2to3.fixes.fix_dict
 +
lib2to3.fixes.fix_except
 +
lib2to3.fixes.fix_exec
 +
lib2to3.fixes.fix_exitfunc
 +
lib2to3.fixes.fix_filter
 +
lib2to3.fixes.fix_funcattrs
 +
lib2to3.fixes.fix_getcwdu
 +
lib2to3.fixes.fix_has_key
 +
lib2to3.fixes.fix_input
 +
lib2to3.fixes.fix_intern
 +
lib2to3.fixes.fix_isinstance
 +
lib2to3.fixes.fix_itertools
 +
lib2to3.fixes.fix_itertools_imports
 +
lib2to3.fixes.fix_long
 +
lib2to3.fixes.fix_map
 +
lib2to3.fixes.fix_methodattrs
 +
lib2to3.fixes.fix_ne
 +
lib2to3.fixes.fix_next
 +
lib2to3.fixes.fix_nonzero
 +
lib2to3.fixes.fix_numliterals
 +
lib2to3.fixes.fix_operator
 +
lib2to3.fixes.fix_paren
 +
lib2to3.fixes.fix_raw_input
 +
lib2to3.fixes.fix_reduce
 +
lib2to3.fixes.fix_renamesSlicer migration guide describes how to update the code. See https://www.slicer.org/wiki/Documentation/Nightly/Developers/Tutorials/MigrationGuide/SlicerExtension#Slicer_5.0:_Python2_to_Python3
 +
lib2to3.fixes.fix_repr
 +
lib2to3.fixes.fix_standarderror
 +
lib2to3.fixes.fix_sys_exc
 +
lib2to3.fixes.fix_throw
 +
lib2to3.fixes.fix_tuple_params
 +
lib2to3.fixes.fix_types
 +
lib2to3.fixes.fix_xreadlines
 +
lib2to3.fixes.fix_zip
 +
libfuturize.fixes.fix_absolute_import
 +
libfuturize.fixes.fix_basestring
 +
libfuturize.fixes.fix_cmp
 +
libfuturize.fixes.fix_division_safe
 +
libfuturize.fixes.fix_execfile
 +
libfuturize.fixes.fix_future_builtins
 +
libfuturize.fixes.fix_future_standard_library
 +
libfuturize.fixes.fix_future_standard_library_urllib
 +
libfuturize.fixes.fix_metaclass
 +
libfuturize.fixes.fix_next_call
 +
libfuturize.fixes.fix_object
 +
libfuturize.fixes.fix_print_with_import
 +
libfuturize.fixes.fix_raise
 +
libfuturize.fixes.fix_unicode_keep_u
 +
libfuturize.fixes.fix_xrange_with_import
 +
libpasteurize.fixes.fix_newstyle
 +
</pre>
 +
 +
expect these two:
 +
 +
<pre>
 +
lib2to3.fixes.fix_idioms
 +
lib2to3.fixes.fix_ws_comma
 +
</pre>
 +
 +
<small>{{note}} If the number of changes is large, you should consider applying each fixes independently.</small>
 +
 +
 +
'''Step 2'''
 +
 +
Not all changes applied automatically should be integrated. Most of the changes introducing imports from the <tt>future</tt> python package can simply be removed or removed after making use of <tt>try/except</tt> or check of <tt>sys.version_info[0]</tt>.
 +
 +
* Systematic conversion of keys, values or items from dictionaries do not need to be systematically converted from <tt>dict_keys</tt>/<tt>dict_values</tt>/<tt>dict_items</tt> to <tt>list</tt>. For example, this Slicer [http://viewvc.slicer.org/viewvc.cgi/Slicer4?view=revision&revision=28077 r28077] reverted some of the automatic changes applied by the future CLI.
 +
 +
* Unless python classes implement the object functions <tt>next</tt> and <tt>__unicode__</tt> specific to Python 2, nothing specific should be done and <tt><b>from builtins import object</b></tt> can be removed. Automatic removal of imports can also be automated doing:
 +
 +
  for f in `find ./ -name "*.py"`; do \
 +
    sed -i '/from builtins import object/ d' $f; \
 +
  done
 +
 +
* Unless there are performances issue associated with using <tt>range</tt> in Python 2, the <tt><b>from builtins import range</b></tt> can be removed:
 +
 +
  for f in `find ./ -name "*.py"`; do \
 +
    sed -i '/from builtins import range/ d' $f; \
 +
  done
 +
 +
* If there are performance issue with using <tt>range</tt> in Python 2, the following could also be done:
 +
 +
  import sys
 +
  if sys.version_info[0] == 2:
 +
    range = xrange
 +
 +
* Use of aliases can also be avoided by removing
 +
 +
  from future import standard_library
 +
  standard_library.install_aliases()
 +
 +
and instead doing something like this:
 +
 +
  try:
 +
    import queue
 +
  except ImportError:
 +
    import Queue as queue
 +
 +
For a complete list aliases, see https://python-future.org/reference.html#module-future.standard_library
 +
 +
* Use of <tt>old_div()</tt> function can generally be avoided by using <tt>int()</tt>
 +
 +
'''Step 3'''
 +
 +
The <tt>lib2to3.fixes.fix_idioms</tt> transformation should explicitly be applied:
 +
 +
<pre>
 +
  for f in `find ./ -name "*.py"`; do \
 +
    ${Slicer_DIR}/../python-install/bin/PythonSlicer \
 +
      --launch futurize -f lib2to3.fixes.fix_idioms --nobackups --write $f; \
 +
  done
 +
</pre>
 +
 +
===Slicer 5.0: Python2 to Python3 (EditorEffect imports)===
 +
 +
'''Error:'''
 +
 +
<pre>
 +
    from EditorLib import EditorLib
 +
ImportError: cannot import name 'EditorLib'
 +
</pre>
 +
 +
Import of Editor classes should be updated. For example, see [http://viewvc.slicer.org/viewvc.cgi/Slicer4/trunk/Utilities/Templates/Modules/ScriptedEditorEffect/TemplateKeyEffect.py?r1=28122&r2=28121&pathrev=28122 r28122].
 +
 +
 +
'''Before:'''
 +
 +
<pre>
 +
import EditorLib
 +
from EditorLib.EditOptions import HelpButton
 +
from EditorLib.EditOptions import EditOptions
 +
from EditorLib import EditUtil
 +
</pre>
 +
 +
<pre>
 +
class TemplateKeyEffectOptions(EditorLib.LabelEffectOptions):
 +
  [...]
 +
</pre>
 +
 +
 +
'''After:'''
 +
 +
<pre>
 +
import EditorLib
 +
from EditorLib import EditOptions, HelpButton
 +
from EditorLib import EditUtil
 +
from EditorLib import LabelEffectOptions, LabelEffectTool, LabelEffectLogic, LabelEffect
 +
</pre>
 +
 +
<pre>
 +
class TemplateKeyEffectOptions(LabelEffectOptions):
 +
  [...]
 +
</pre>
 +
 +
===Slicer 4.9: Explicit include of ExternalProject module not needed anymore===
 +
 +
Following [http://viewvc.slicer.org/viewvc.cgi/Slicer4?view=revision&revision=26984 r26984], calling <tt>find_package(Slicer REQUIRED)</tt> and <tt>include(${Slicer_USE_FILE})</tt> ensure the <tt>ExternalProject</tt> CMake module is included.
 +
 +
Note that <tt>ExternalProjectDependency</tt> CMake module is also included.
 +
 +
===Slicer 4.9: Explicit passing of CMAKE_OSX_* variables not needed anymore===
 +
 +
Following [http://viewvc.slicer.org/viewvc.cgi/Slicer4?view=revision&revision=26983 r26983], calling <tt>find_package(Slicer REQUIRED)</tt> and <tt>include(${Slicer_USE_FILE})</tt> initializes <tt>CMAKE_OSX_*</tt> variables and ensures the variables <tt>CMAKE_OSX_ARCHITECTURES</tt>, <tt>CMAKE_OSX_SYSROOT</tt> and <tt>CMAKE_OSX_DEPLOYMENT_TARGET</tt> are passed to all external projects when configuring SuperBuild based extension.
  
 
===Slicer 4.9: Explicit initialization of CMAKE_BUILD_TYPE not needed anymore===
 
===Slicer 4.9: Explicit initialization of CMAKE_BUILD_TYPE not needed anymore===
Line 33: Line 247:
 
Following [http://viewvc.slicer.org/viewvc.cgi/Slicer4?view=revision&revision=26978 r26978], calling <tt>find_package(Slicer REQUIRED)</tt> and <tt>include(${Slicer_USE_FILE})</tt> initializes <tt>CMAKE_BUILD_TYPE</tt> and ensures the variables <tt>CMAKE_BUILD_TYPE</tt> and <tt>CMAKE_CONFIGURATION_TYPES</tt> are passed to all external projects when configuring SuperBuild based extension.
 
Following [http://viewvc.slicer.org/viewvc.cgi/Slicer4?view=revision&revision=26978 r26978], calling <tt>find_package(Slicer REQUIRED)</tt> and <tt>include(${Slicer_USE_FILE})</tt> initializes <tt>CMAKE_BUILD_TYPE</tt> and ensures the variables <tt>CMAKE_BUILD_TYPE</tt> and <tt>CMAKE_CONFIGURATION_TYPES</tt> are passed to all external projects when configuring SuperBuild based extension.
  
The module <tt>SlicerInitializeBuildType</tt> is automatically included in <tt>UserSlicer</tt>.
+
The module <tt>SlicerInitializeBuildType</tt> is automatically included in <tt>UseSlicer</tt> CMake module.
  
 
===Slicer 4.9: Subversion not required anymore===
 
===Slicer 4.9: Subversion not required anymore===

Revision as of 21:00, 27 June 2019

Home < Documentation < Nightly < Developers < Tutorials < MigrationGuide < SlicerExtension

Slicer Extension updates

Slicer 5.0: ITKv4 to ITKv5

To remove support for ITKv4 and only support ITKv5. See Documentation/Nightly/Developers/Tutorials/MigrationGuide#Transition_from_ITK4_to_ITK5, it includes the following sections:

If completely removing support for ITKv4 and only supporting ITKv5 is not possible. It is possible to conditionally include the ITKv4 code.

For example:

#if ITK_VERSION_MAJOR >= 5
  itk::ITK_THREAD_RETURN_TYPE
#else
  ITK_THREAD_RETURN_TYPE
#endif

Example of commits:

Slicer 5.0: Python2 to Python3

Depending on the complexity of the extension, two approaches shall be considered:

  • code base common to Slicer 4.10 and Slicer 5.0. This means backward compatibility with the latest release is maintained.
  • specific branch for each Slicer version (e.g master-4.10 and master)


Example of commits


Step 1

Understanding the scope of changes needed to support Python 3 can be done by:

  1. installing future package (see https://python-future.org/)
    Slicer_DIR=/path/to/Slicer-SuperBuild/Slicer-build
    ${Slicer_DIR}/../python-install/bin/PythonSlicer -m pip install future
    
  2. applying all fixes
      for f in `find ./ -name "*.py"`; do \
        ${Slicer_DIR}/../python-install/bin/PythonSlicer \
          --launch futurize --nobackups --write $f; \
      done
    

    Note Alternatively the future package could be installed in a regular python environment and used from there.

      for f in `find ./ -name "*.py"`; do \
        futurize --nobackups --write $f; \
      done
    

This first step will apply the following transformations:

lib2to3.fixes.fix_apply
lib2to3.fixes.fix_dict
lib2to3.fixes.fix_except
lib2to3.fixes.fix_exec
lib2to3.fixes.fix_exitfunc
lib2to3.fixes.fix_filter
lib2to3.fixes.fix_funcattrs
lib2to3.fixes.fix_getcwdu
lib2to3.fixes.fix_has_key
lib2to3.fixes.fix_input
lib2to3.fixes.fix_intern
lib2to3.fixes.fix_isinstance
lib2to3.fixes.fix_itertools
lib2to3.fixes.fix_itertools_imports
lib2to3.fixes.fix_long
lib2to3.fixes.fix_map
lib2to3.fixes.fix_methodattrs
lib2to3.fixes.fix_ne
lib2to3.fixes.fix_next
lib2to3.fixes.fix_nonzero
lib2to3.fixes.fix_numliterals
lib2to3.fixes.fix_operator
lib2to3.fixes.fix_paren
lib2to3.fixes.fix_raw_input
lib2to3.fixes.fix_reduce
lib2to3.fixes.fix_renamesSlicer migration guide describes how to update the code. See https://www.slicer.org/wiki/Documentation/Nightly/Developers/Tutorials/MigrationGuide/SlicerExtension#Slicer_5.0:_Python2_to_Python3
lib2to3.fixes.fix_repr
lib2to3.fixes.fix_standarderror
lib2to3.fixes.fix_sys_exc
lib2to3.fixes.fix_throw
lib2to3.fixes.fix_tuple_params
lib2to3.fixes.fix_types
lib2to3.fixes.fix_xreadlines
lib2to3.fixes.fix_zip
libfuturize.fixes.fix_absolute_import
libfuturize.fixes.fix_basestring
libfuturize.fixes.fix_cmp
libfuturize.fixes.fix_division_safe
libfuturize.fixes.fix_execfile
libfuturize.fixes.fix_future_builtins
libfuturize.fixes.fix_future_standard_library
libfuturize.fixes.fix_future_standard_library_urllib
libfuturize.fixes.fix_metaclass
libfuturize.fixes.fix_next_call
libfuturize.fixes.fix_object
libfuturize.fixes.fix_print_with_import
libfuturize.fixes.fix_raise
libfuturize.fixes.fix_unicode_keep_u
libfuturize.fixes.fix_xrange_with_import
libpasteurize.fixes.fix_newstyle

expect these two:

lib2to3.fixes.fix_idioms
lib2to3.fixes.fix_ws_comma

Note If the number of changes is large, you should consider applying each fixes independently.


Step 2

Not all changes applied automatically should be integrated. Most of the changes introducing imports from the future python package can simply be removed or removed after making use of try/except or check of sys.version_info[0].

  • Systematic conversion of keys, values or items from dictionaries do not need to be systematically converted from dict_keys/dict_values/dict_items to list. For example, this Slicer r28077 reverted some of the automatic changes applied by the future CLI.
  • Unless python classes implement the object functions next and __unicode__ specific to Python 2, nothing specific should be done and from builtins import object can be removed. Automatic removal of imports can also be automated doing:
 for f in `find ./ -name "*.py"`; do \
   sed -i '/from builtins import object/ d' $f; \
 done
  • Unless there are performances issue associated with using range in Python 2, the from builtins import range can be removed:
 for f in `find ./ -name "*.py"`; do \
   sed -i '/from builtins import range/ d' $f; \
 done
  • If there are performance issue with using range in Python 2, the following could also be done:
 import sys
 if sys.version_info[0] == 2:
   range = xrange
  • Use of aliases can also be avoided by removing
 from future import standard_library
 standard_library.install_aliases()

and instead doing something like this:

 try:
   import queue
 except ImportError:
   import Queue as queue

For a complete list aliases, see https://python-future.org/reference.html#module-future.standard_library

  • Use of old_div() function can generally be avoided by using int()

Step 3

The lib2to3.fixes.fix_idioms transformation should explicitly be applied:

  for f in `find ./ -name "*.py"`; do \
    ${Slicer_DIR}/../python-install/bin/PythonSlicer \
      --launch futurize -f lib2to3.fixes.fix_idioms --nobackups --write $f; \
  done

Slicer 5.0: Python2 to Python3 (EditorEffect imports)

Error:

    from EditorLib import EditorLib
ImportError: cannot import name 'EditorLib'

Import of Editor classes should be updated. For example, see r28122.


Before:

import EditorLib
from EditorLib.EditOptions import HelpButton
from EditorLib.EditOptions import EditOptions
from EditorLib import EditUtil
class TemplateKeyEffectOptions(EditorLib.LabelEffectOptions):
  [...]


After:

import EditorLib
from EditorLib import EditOptions, HelpButton
from EditorLib import EditUtil
from EditorLib import LabelEffectOptions, LabelEffectTool, LabelEffectLogic, LabelEffect
class TemplateKeyEffectOptions(LabelEffectOptions):
  [...]

Slicer 4.9: Explicit include of ExternalProject module not needed anymore

Following r26984, calling find_package(Slicer REQUIRED) and include(${Slicer_USE_FILE}) ensure the ExternalProject CMake module is included.

Note that ExternalProjectDependency CMake module is also included.

Slicer 4.9: Explicit passing of CMAKE_OSX_* variables not needed anymore

Following r26983, calling find_package(Slicer REQUIRED) and include(${Slicer_USE_FILE}) initializes CMAKE_OSX_* variables and ensures the variables CMAKE_OSX_ARCHITECTURES, CMAKE_OSX_SYSROOT and CMAKE_OSX_DEPLOYMENT_TARGET are passed to all external projects when configuring SuperBuild based extension.

Slicer 4.9: Explicit initialization of CMAKE_BUILD_TYPE not needed anymore

Following r26978, calling find_package(Slicer REQUIRED) and include(${Slicer_USE_FILE}) initializes CMAKE_BUILD_TYPE and ensures the variables CMAKE_BUILD_TYPE and CMAKE_CONFIGURATION_TYPES are passed to all external projects when configuring SuperBuild based extension.

The module SlicerInitializeBuildType is automatically included in UseSlicer CMake module.

Slicer 4.9: Subversion not required anymore

Following r27060, Subversion is not required anymore.

Slicer 4.9: Support EP_GIT_PROTOCOL and use of ExternalProject_SetIfNotDefined for setting GIT_REPOSITORY, GIT_TAG and alike

Following r26957, extension may use the following convention to define GIT_REPOSITORY and GIT_TAG, this allows developer to override the value before the first configuration by setting the corresponding environment variable, or by explicitly configuring the project with that variable.

The option EP_GIT_PROTOCOL is also already set in ExternalProjectDependency module included by Slicer and its value is updated based on the <SUPERBUILD_TOPLEVEL_PROJECT>_USE_GIT_PROTOCOL option.

  ExternalProject_SetIfNotDefined(
    ${CMAKE_PROJECT_NAME}_${proj}_GIT_REPOSITORY
    "${EP_GIT_PROTOCOL}://github.com/jcfr/shape4D.git"
    QUIET
    )

  ExternalProject_SetIfNotDefined(
    ${CMAKE_PROJECT_NAME}_${proj}_GIT_TAG
    "12fef84ca2a56feffc59d8159bdadd2ce4a4138e" # slicersalt-2018-01-22-c74c766a4c
    QUIET
    )

See:

Slicer 4.9: Use ExternalProject_AlwaysConfigure to force reconfigure of inner project

Following r26551, the function ExternalProject_AlwaysConfigure may be used to ensure the inner project is always reconfigured.

Using the `BUILD_ALWAYS` option supported by ExternalProject_Add will not have the intended effect.

See https://cmake-artichoke.readthedocs.io/en/latest/ExternalProjectDependency.html#function:ExternalProject_AlwaysConfigure

Slicer 4.9: Specifying external projects to install in SuperBuild extension

Following r27267 and r27232, the following should be used to ensure the extension can also be bundled into a Slicer custom application. When bundled, the variable ${EXTENSION_NAME}_CPACK_INSTALL_CMAKE_PROJECTS is then used to update the application's list of project to install.

#-----------------------------------------------------------------------------
set(EXTENSION_CPACK_INSTALL_CMAKE_PROJECTS)
#list(APPEND EXTENSION_CPACK_INSTALL_CMAKE_PROJECTS "${Foo_DIR};Foo;RuntimeLibraries;/")
set(${EXTENSION_NAME}_CPACK_INSTALL_CMAKE_PROJECTS "${EXTENSION_CPACK_INSTALL_CMAKE_PROJECTS}" CACHE STRING "List of external projects to install" FORCE)

#-----------------------------------------------------------------------------
list(APPEND CPACK_INSTALL_CMAKE_PROJECTS "${CMAKE_BINARY_DIR};${EXTENSION_NAME};ALL;/")
list(APPEND CPACK_INSTALL_CMAKE_PROJECTS "${${EXTENSION_NAME}_CPACK_INSTALL_CMAKE_PROJECTS}")
include(${Slicer_EXTENSION_GENERATE_CONFIG})
include(${Slicer_EXTENSION_CPACK})

Slicer 4.9: Generating (Extension)Config.cmake

Initially introduced in r25944, and later improved in r25991, including ${Slicer_EXTENSION_GENERATE_CONFIG} ensure a config is generated and allow an extension to import targets from another extension by using find_package(ExtensionName REQUIRED).

[...]

include(${Slicer_EXTENSION_GENERATE_CONFIG})
include(${Slicer_EXTENSION_CPACK})

Slicer 4.9: Initializing <projectName>_BUILD_SLICER_EXTENSION option: Standalone vs Slicer extension build

The following snippet allows to automatically initialize <projectName>_BUILD_SLICER_EXTENSION to ON if Slicer_DIR is defined.

#-----------------------------------------------------------------------------
# Standalone vs Slicer extension option
#-----------------------------------------------------------------------------

# This option should be named after the project name, it corresponds to the
# option set to ON when the project is build by the Slicer Extension build
# system.

set(_default OFF)
set(_reason "${PROJECT_NAME}_BUILD_SLICER_EXTENSION is ON")
if(NOT DEFINED ${PROJECT_NAME}_BUILD_SLICER_EXTENSION AND DEFINED Slicer_DIR)
  set(_default ON)
  set(_reason "Slicer_DIR is SET")
endif()

option(${PROJECT_NAME}_BUILD_SLICER_EXTENSION "Build as a Slicer Extension" ${_default})

set(_msg "Checking if building as a Slicer extension")
message(STATUS ${_msg})
if(${PROJECT_NAME}_BUILD_SLICER_EXTENSION)
  message(STATUS "${_msg} - yes (${_reason})")
else()
  message(STATUS "${_msg} - no (${PROJECT_NAME}_BUILD_SLICER_EXTENSION is OFF)")
endif()
mark_as_superbuild(${PROJECT_NAME}_BUILD_SLICER_EXTENSION:BOOL)