Difference between revisions of "Documentation/Nightly/Developers/Tutorials/MigrationGuide/SlicerExtension"
(38 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=== | ||
+ | |||
+ | 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 <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: | ||
+ | |||
+ | <ol start="1" style="list-style-type: decimal;"> | ||
+ | <li>installing future package (see https://python-future.org/) | ||
+ | <pre> | ||
+ | Slicer_DIR=/path/to/Slicer-SuperBuild/Slicer-build | ||
+ | ${Slicer_DIR}/../python-install/bin/PythonSlicer -m pip install future | ||
+ | </pre> | ||
+ | </li> | ||
+ | <li>applying all fixes | ||
+ | <pre> | ||
+ | for f in `find ./ -name "*.py"`; do \ | ||
+ | ${Slicer_DIR}/../python-install/bin/PythonSlicer \ | ||
+ | --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 | ||
+ | </pre> | ||
+ | </small> | ||
+ | |||
+ | </li> | ||
+ | </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=== | ||
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> | + | 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=== | ||
Line 13: | Line 255: | ||
===Slicer 4.9: Support EP_GIT_PROTOCOL and use of ExternalProject_SetIfNotDefined for setting GIT_REPOSITORY, GIT_TAG and alike=== | ===Slicer 4.9: Support EP_GIT_PROTOCOL and use of ExternalProject_SetIfNotDefined for setting GIT_REPOSITORY, GIT_TAG and alike=== | ||
− | Following [http://viewvc.slicer.org/viewvc.cgi/Slicer4?view=revision&revision=26957 r26957], extension may use the following convention to define <tt>GIT_REPOSITORY</tt> and <tt>< | + | Following [http://viewvc.slicer.org/viewvc.cgi/Slicer4?view=revision&revision=26957 r26957], extension may use the following convention to define <tt>GIT_REPOSITORY</tt> and <tt>GIT_TAG</tt>, 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 <tt>EP_GIT_PROTOCOL</tt> is also already set in <tt>ExternalProjectDependency</tt> module included by Slicer and its value is updated based on the <tt><SUPERBUILD_TOPLEVEL_PROJECT>_USE_GIT_PROTOCOL</tt> option. | ||
+ | |||
+ | <pre> | ||
+ | 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 | ||
+ | ) | ||
+ | </pre> | ||
+ | |||
+ | See: | ||
+ | * https://cmake-artichoke.readthedocs.io/en/latest/ExternalProjectDependency.html#variable:EP_GIT_PROTOCOL | ||
+ | * https://cmake-artichoke.readthedocs.io/en/latest/ExternalProjectDependency.html#function:ExternalProject_SetIfNotDefined | ||
+ | |||
+ | ===Slicer 4.9: Use ExternalProject_AlwaysConfigure to force reconfigure of inner project=== | ||
+ | |||
+ | Following [http://viewvc.slicer.org/viewvc.cgi/Slicer4?view=revision&revision=26551 r26551], the function <tt>ExternalProject_AlwaysConfigure</tt> may be used to ensure the inner project is always reconfigured. | ||
+ | |||
+ | Using the `BUILD_ALWAYS` option supported by <tt>ExternalProject_Add</tt> 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 [http://viewvc.slicer.org/viewvc.cgi/Slicer4?view=revision&revision=27267 r27267] and [http://viewvc.slicer.org/viewvc.cgi/Slicer4?view=revision&revision=27232 r27232], the following should be used to ensure | ||
+ | the extension can also be bundled into a Slicer custom application. When bundled, the variable <tt>${EXTENSION_NAME}_CPACK_INSTALL_CMAKE_PROJECTS</tt> is then used to update the application's list of project to install. | ||
+ | |||
+ | <pre> | ||
+ | #----------------------------------------------------------------------------- | ||
+ | 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}) | ||
+ | </pre> | ||
+ | |||
+ | ===Slicer 4.9: Generating (Extension)Config.cmake=== | ||
+ | |||
+ | Initially introduced in [http://viewvc.slicer.org/viewvc.cgi/Slicer4?view=revision&revision=25944 r25944], and later improved in [http://viewvc.slicer.org/viewvc.cgi/Slicer4?view=revision&revision=25991 r25991], including <tt>${Slicer_EXTENSION_GENERATE_CONFIG}</tt> ensure a config is generated and allow an extension to import targets from another extension by using <tt>find_package(ExtensionName REQUIRED)</tt>. | ||
+ | |||
+ | <pre> | ||
+ | [...] | ||
+ | |||
+ | include(${Slicer_EXTENSION_GENERATE_CONFIG}) | ||
+ | include(${Slicer_EXTENSION_CPACK}) | ||
+ | </pre> | ||
+ | |||
+ | ===Slicer 4.9: Initializing <projectName>_BUILD_SLICER_EXTENSION option: Standalone vs Slicer extension build=== | ||
+ | |||
+ | The following snippet allows to automatically initialize <tt><projectName>_BUILD_SLICER_EXTENSION</tt> to <tt>ON</tt> if <tt>Slicer_DIR</tt> is defined. | ||
+ | |||
+ | <pre> | ||
+ | #----------------------------------------------------------------------------- | ||
+ | # 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) | ||
+ | </pre> |
Revision as of 21:00, 27 June 2019
Home < Documentation < Nightly < Developers < Tutorials < MigrationGuide < SlicerExtensionContents
- 1 Slicer Extension updates
- 1.1 Slicer 5.0: ITKv4 to ITKv5
- 1.2 Slicer 5.0: Python2 to Python3
- 1.3 Slicer 5.0: Python2 to Python3 (EditorEffect imports)
- 1.4 Slicer 4.9: Explicit include of ExternalProject module not needed anymore
- 1.5 Slicer 4.9: Explicit passing of CMAKE_OSX_* variables not needed anymore
- 1.6 Slicer 4.9: Explicit initialization of CMAKE_BUILD_TYPE not needed anymore
- 1.7 Slicer 4.9: Subversion not required anymore
- 1.8 Slicer 4.9: Support EP_GIT_PROTOCOL and use of ExternalProject_SetIfNotDefined for setting GIT_REPOSITORY, GIT_TAG and alike
- 1.9 Slicer 4.9: Use ExternalProject_AlwaysConfigure to force reconfigure of inner project
- 1.10 Slicer 4.9: Specifying external projects to install in SuperBuild extension
- 1.11 Slicer 4.9: Generating (Extension)Config.cmake
- 1.12 Slicer 4.9: Initializing <projectName>_BUILD_SLICER_EXTENSION option: Standalone vs Slicer extension build
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:
- Upgrading to ITKv5 or keep using ITKv4 GenerateThreadedData
- itkMultiThreader refactor
- 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:
#if ITK_VERSION_MAJOR >= 5 itk::ITK_THREAD_RETURN_TYPE #else ITK_THREAD_RETURN_TYPE #endif
Example of commits:
- ResampleDTIlogEuclidean
- ResampleDTIlogEuclidean@f779bf7 COMP: Use std::mutex instead of deprecated ITK implementation
- ResampleDTIlogEuclidean@ed5093b BUG: ITKv5: Fix tests updating ITK filters to use ITKv5 dynamic multi-threading
- PETTumorSegmentation
- PETTumorSegmentation PR#18 BUG: Add support for ITKv5 dynamic multithreader
- PETTumorSegmentation PR#18 COMP: Support ITKv5 refactored threading models
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
- Slicer r28079 STYLE: Update python classes to follow new-style
- MultiVolumeImporter@f9917b2 STYLE: Apply lib2to3.fixes.fix_idioms to support python3
- MultiVolumeImporter@3edd1bc ENH: Support for Python3
- ShapeVariationAnalyzer@4234377 STYLE: Update python scripts for python 3.x
- 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:
- 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
- applying all fixes
for f in `find ./ -name "*.py"`; do \ ${Slicer_DIR}/../python-install/bin/PythonSlicer \ --launch futurize --nobackups --write $f; \ done
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
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:
- https://cmake-artichoke.readthedocs.io/en/latest/ExternalProjectDependency.html#variable:EP_GIT_PROTOCOL
- https://cmake-artichoke.readthedocs.io/en/latest/ExternalProjectDependency.html#function:ExternalProject_SetIfNotDefined
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.
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)