Documentation/4.5/Developers/FAQ

From Slicer Wiki
Revision as of 22:14, 12 November 2015 by UpdateBot (talk | contribs) (Nightly -> 4.5)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search
Home < Documentation < 4.5 < Developers < FAQ


For the latest Slicer documentation, visit the read-the-docs.


Contents


Developer FAQ: General

What is Slicer ?

3D Slicer is a free open source extensible software application for medical image computing and visualization. Mainly written in C++ and based on the NA-MIC kit, 3D Slicer relies on a variety of libraries: VTK, ITK, CTK, CMake, Qt and Python.

To ensure the stability of the application, relying on a robust software process, the source code is compiled and tested on a daily basis on a variety of platform configurations. The testing results are summarized and reported using a web-based centralized CDash dashboard. Developers of 3D Slicer can also report issues on the open mailing list or using the web-based bug tracking system.

3D Slicer consists of both a lean application core and modules offering specific functionality. The core implements the user interface, provides support for data input/output (IO) and visualization and also exposes developer interfaces that support extension of the application with new modules.

Multiple types of modules are supported: CLI, Loadable module, Scripted module and Editor effect. While the developer has to choose between one of these types to implement its module, the end user won't notice the difference as they all share the same look & feel. The choice for a given type of module is usually based on the type of inputs/parameters for a given module.

These modules can be either built-in or installed on demand via the extensions manager.

How to setup for Git development ?

See Slicer Setup

How to contribute a patch ?

The following instructions describes the recommended workflow to contribute patch to Slicer code base.

It is assumed that you followed the New community member checklist, have a clone of https://github.com/Slicer/Slicer/ and have setup the development environment as described here.

  1. Create an issue in the tracker. For example, see issue #1906

  2. Make sure your clone has a git remote. After forking Slicer repository, replace jcfr with your git login.

    git remote add jcfr git@github.com:jcfr/Slicer.git
    
  3. Create a topic named <issuer_number>-a-descriptive-topic-name. For example:

    git checkout -b 1906-uninstall-extensions-on-restart
    
  4. Fix the code or implement your feature, then commit your change(s)

    1. Make sure to read the Slicer Coding and Commit Style Guide
  5. Publish the topic on your fork

    git push jcfr 1906-uninstall-extensions-on-restart
    
  6. Add a note to the issue with a link pointing to your topic. For example, see note 1906#c4578



What is our bug / feature request workflow ?

The following diagram illustrates Slicer issue workflow:

Mantis-workflow.png

Source: Adapted from http://www.warelab.org/blog/?p=24


How to schedule a Developer Hangout ?

See instruction here


Should core feature be implemented in C++ or Python ?

There is no one-size-fits-all answer to this. There are many examples of "core' features of Slicer implemented using a variety of programming languages and techniques.

  • MRML and most Logic operations are in C++, implemented as VTK subclasses
  • the Application and most GUI functionality is in C++, implemented as QWidget subclasses
  • most bundled modules are implemented as "loadable" modules, combining VTK and Qt parent classes
  • many important modules bundled with Slicer are implemented as python scripted modules (LabelStatistics, ExtensionWizard...) or with hybrid C++ and Python solutions (Editor, DICOM, DataProbe...)
  • other "core" features rely on JavaScript and web technologies (Charts, SceneViews, Extension Manager....)

The implementation choice depends heavily on the use case and the best judgement of the people who commit to maintain the code. If you are contributing an extension that you will maintain, you have a lot of flexibility. If you are hoping to pass off your code to others and you expect them to maintain it, then you should carefully follow the example of similar code that is already being maintained so that your code will be a pleasure to work with and not a misfit that causes trouble.


Original comment from Andras Lasso copied from PR#373 discussion.


There are many reasons for implementing Slicer core in C++, we just list here few reasons:

  • C++ rigor and extensive compile-time checks increases the chance of catching errors earlier. C++ enforces many things that in Python are managed by good programming practices (that are not enforced and in general not followed by Slicer developers).
  • C++ memory management is much more explicit, which is more difficult to learn than Python, but allows much better efficiency (you can prevent memory fragmentation, optimize memory reallocations, etc), which is useful for code that may run hundreds of times per second (this code does).
  • There are lots of good examples of solid, fast C++ displayable managers. Python displayable managers are more at the experimental level.
  • Accessibility of Python classes from C++ modules is cumbersome. Accessibility of C++ classes is very convenient from both Python and C++ modules.
  • Some projects don't use Python and don't want to use it (Python brings in huge amount of additional code, which is a problem if you want to minimize the amount of code that goes through regulatory approval)
  • Profiling and optimization of mixed C++/Python code is very difficult (both C++ and Python profilers treat the "other side" as black hole). Since all the rest of the Slicer core is implemented in C++ (with a few small exceptions), it is much easier to implement this in C++, too.


That said, we love Python programming, do it extensively, but implementing Slicer core features in Python has just too many disadvantages.

How to convert between ITK images and Slicer scalar volume nodes?

See discussion and relevant links at http://slicer-devel.65872.n3.nabble.com/Converting-ITK-image-to-Slicer-ScalarVolumeNode-td4035458.html

Steve Pieper's suggested architecture for using ITK code to process Slicer MRML data is as follows:

1) develop an ITK pipeline that implements the desired behavior

2) wrap the pipeline in a high level pure C++ ITK class that exposes the key inputs, output, parameters, and events

3) write a thin CLI wrapper around (2) using the Slicer Execution mode

4a) use the CLI in Slicer as-is

4b) write a scripted module that presents a higher level interface and calls the CLI

4c) if you need more interactivity, write a vtkITK wrapper around (2) that exposes the high level ITK class aspects using VTK conventions; expose this via a scripted or loadable module.

A nice thing about this approach is that (1) through (3) are all highly reusable in different contexts both in and out of Slicer.

Also this path, steps (1) through (4b) all the data types and orientation mappings between itk::Image and vtkMRMLScalarVolumeNode are handled automatically with existing mechanisms. Since the CLI is built as a shared library by default there is no file system overhead, just a few memcpys which is not much different than using the ITK pipeline directly.

Another option is to implement the pipeline in SimpleITK, but adding custom C++ code into the SimpleITK is more complex and I don't think it's even possible to do this as an extension, whereas the path described above is completely compatible with our extension process.

Note that the use case for the code that Raul points to is the opposite case, using a VTK class inside of an ITK pipeline. In this case ITKVtkGlue is very appropriate. The IJKToRAS transforms are not relevant since vtkImageData class does not support orientation and all the operations need to be performed in pixel space.

If CLI route is not suitable for some reason, helper classes are available in SlicerRT that do conversion between itkImage and vtkMRMLScalarVolumeNode initializing IJKtoRAS matrix, see https://github.com/SlicerRt/SlicerRT/blob/master/SlicerRtCommon/SlicerRtCommon.h


Developer FAQ: Writing Documentation

How to reference module or extension documentation hosted on the Slicer wiki ?

The URL including the Nightly namespace should be used.

Good: http://wiki.slicer.org/wiki/Documentation/Nightly/Modules/GaussianBlurImageFilter

Poor: http://wiki.slicer.org/wiki/Documentation/4.4/Modules/GaussianBlurImageFilter

References to documentation hosted on the wiki usually occurs when:

  • writing module or extension description
  • setting the documentation URL in CMakeLists.txt, cpp or python source files.

Rational: This will facilitate maintenance and avoid to update source files after each release.


Developer FAQ: Building

How is organized the Slicer build tree ?

The Slicer build tree has two levels:

  • ~/Projects/Slicer-SuperBuild
  • ~/Projects/Slicer-SuperBuild/Slicer-build

The first level manages all the external dependencies of Slicer (VTK, ITK, Python, ...). The second level is the "traditional" build directory of Slicer.

See Slicer directory structure

What is a clean build ?

Doing a clean build means that

(1) all directories and files in the top-level build directory ~/Projects/Slicer-SuperBuild are removed.

and

(2) you updated your source checkout and have no locally modified files.

What to do if QtSDK installer hangs ?

If QtSDK installer hangs, use -style cleanlooks command line option. For details, see here.

Which minimum version of GLIBC is needed to build Slicer ?

The minimum version of GLIBC required to build Slicer is defined by the minimum version required by the pre-compiler binaries used when building Slicer. In our case, a small pre-compiled executable called the CTK AppLauncher is downloaded and used at configure and build time each time python has to be invoked.

The precompiled CTKAppLauncher imposes the following requirements regarding GLIBC and GLIBCXX libraries installed on your system:

$ strings CTKAppLauncher | ack GLIBC
GLIBC_2.2.5
GLIBCXX_3.4.11
GLIBCXX_3.4.9
GLIBCXX_3.4
GLIBC_2.3.3
GLIBC_2.3.2
GLIBC_2.4
GLIBC_2.3


To check that your system provides the required GLIBCXX and GLIB versions, you could run the following command and check that the requirement of the launcher can be satisfied:

$ strings /usr/lib/libstdc++.so.6 | grep GLIBCXX
GLIBCXX_3.4
GLIBCXX_3.4.1
GLIBCXX_3.4.2
GLIBCXX_3.4.3
GLIBCXX_3.4.4
GLIBCXX_3.4.5
GLIBCXX_3.4.6
GLIBCXX_3.4.7
GLIBCXX_3.4.8
GLIBCXX_3.4.9
GLIBCXX_3.4.10
GLIBCXX_3.4.11
GLIBCXX_3.4.12
GLIBCXX_3.4.13
GLIBCXX_3.4.14
GLIBCXX_3.4.15
GLIBCXX_3.4.16
GLIBCXX_3.4.17
$ strings /lib/libc.so.6 | grep GLIBC
GLIBC_2.2.5
GLIBC_2.2.6
GLIBC_2.3
GLIBC_2.3.2
GLIBC_2.3.3
GLIBC_2.3.4
GLIBC_2.4
GLIBC_2.5
GLIBC_2.6
GLIBC_2.7
GLIBC_2.8
GLIBC_2.9
GLIBC_2.10
GLIBC_2.11

What to do if Visual Studio compiler crashes ?

If the compiler crashes on Windows saying "Microsoft C/C++ Compiler Driver has stopped working", then it's most probably due to long build folder paths. To fix this the Slicer build directory should be moved and/or renamed. A typical build folder path is C:\S4D

How to build Slicer with SSL support ?

To build Slicer with SSL support, you need to build (or download) Qt with SSL support and configure Slicer with -DSlicer_USE_PYTHONQT_WITH_OPENSSL:BOOL=ON


Developer FAQ: Installing

Why building the 'install' target fail ?

Building the install target is not supported and is only used internally by the build system while generating the Slicer package. See Slicer packaging instructions


Developer FAQ: Debugging

How to print QString using GDB ?

See http://silmor.de/qtstuff.printqstring.php

More troubleshooting questions ?

See Troubleshooting


Developer FAQ: Python Scripting

How to systematically execute custom python code at startup ?

Each time Slicer starts, it will look up for a file named .slicerrc.py into your HOME folder.

See What is my HOME folder ?

How to save an image/volume using python ?

The module slicer.util provides methods allowing to save either a node or an entire scene:

  • saveNode
  • saveScene

For more details see:


How to assign a volume to a Slice view ?

Assuming the MRHead sample data has been loaded, you could do the following:

red_logic = slicer.app.layoutManager().sliceWidget("Red").sliceLogic()
red_cn = red_logic.GetSliceCompositeNode()
red_logic.GetSliceCompositeNode().SetBackgroundVolumeID(slicer.util.getNode('MRHead').GetID())

Discussion: http://slicer-devel.65872.n3.nabble.com/Assign-volumes-to-views-tt4028694.html

How to access vtkRenderer in Slicer 3D view ?

renderer = slicer.app.layoutManager().threeDWidget(0).threeDView().renderWindow().GetRenderers().GetFirstRenderer()

How to access displayable manager associated with a Slicer 2D or 3D view ?

As originally explained here, you could use the method getDisplayableManagers() available in any qMRMLThreeDView and qMRMLSliceView.

lm = slicer.app.layoutManager()
for v in range(lm.threeDViewCount):
  td = lm.threeDWidget(v)
  ms = vtk.vtkCollection()
  td.getDisplayableManagers(ms)
  for i in range(ms.GetNumberOfItems()):
   m = ms.GetItemAsObject(i)
   if m.GetClassName() == "vtkMRMLModelDisplayableManager":
     print(m)

How to center the 3D view on the scene ?

layoutManager = slicer.app.layoutManager()
threeDWidget = layoutManager.threeDWidget(0)
threeDView = threeDWidget.threeDView()
threeDView.resetFocalPoint()

Should I use 'old style' or 'new style' python classes in my scripted module ?

When python classes have no superclass specified they are 'old style' as described here [1].

In general it doesn't matter for the classes in a scripted module, since they won't be subclassed either old or new style should be the same.

For other python code in slicer where you might be subclassing, it's better to use new style classes. See the class hierarchies in the EditorLib and the DICOMLib for examples.

How to harden a transform ?

>>> n = getNode('Bone')
>>> logic = slicer.vtkSlicerTransformLogic()
>>> logic.hardenTransform(n)

Discussion: http://slicer-devel.65872.n3.nabble.com/Scripting-hardened-transforms-tt4029456.html

Where can I find example scripts?

Have a look at Documentation/4.5/ScriptRepository.

How can I use a visual debugger for step-by-step debugging

Debugging using PyCharm or PyDev

Visual debugging (setting breakpoints, execute code step-by-step, view variables, stack, etc.) of Python scripted module is possible by using PyCharm or PyDev by using the Python debugger module Debugging tools extension.

See detailed instructions at the Debugging tools extension page.

Visual debugging of Python modules in Slicer

Debugging using Visual Studio

On Windows, Python Tools for Visual Studio (PTVS) enables debugging Python inside Visual Studio. Its remote debugging capability allows attaching the debugger to Slicer's embedded Python environment.

See Debugging Python in Visual Studio for details.

Debugging using remote-pdb

A command line debugging session with a pdb interface can be achieved with python-remote-pdb.

Install python-remote-pdb into Slicer's Python:

 git clone https://github.com/ionelmc/python-remote-pdb.git
 cd python-remote-pdb
 /path/to/Slicer-build/Slicer-build/Slicer ./setup.py install

Then, call set_trace() where you want to start the debugger.

 from remote_pdb import set_trace; set_trace()

In the console where Slicer was started, a message like the following will be printed:

 RemotePdb session open at 127.0.0.1:1234, waiting for connection

In another terminal, connect with telnet:

 telnet 127.0.0.1 1234

or socat (has history, readline support):

 socat readline tcp:127.0.0.1:1234

Why can't I access my C++ Qt class from python

  • Python wrapping of a Qt class requires a Qt style constructor with QObject as argument (it can be defaulted to null though), which is public. If one of these are missing, python wrapping will fail for that class
  • [Other reasons go here]

How can I access callData argument in a VTK object observer callback function

To get notification about an event emitted by a VTK object you can simply use the AddObserver method, for example:

def sceneModifiedCallback(caller, eventId):
  print("Scene modified")
  print("There are {0} nodes in the scene". format(slicer.mrmlScene.GetNumberOfNodes()))

sceneModifiedObserverTag = slicer.mrmlScene.AddObserver(vtk.vtkCommand.ModifiedEvent, sceneModifiedCallback)

If an event also contains additional information as CallData then the type of this argument has to be specified as well, for example:

@vtk.calldata_type(vtk.VTK_OBJECT)
def nodeAddedCallback(caller, eventId, callData):
  print("Node added")
  print("New node: {0}".format(callData.GetName()))

nodeAddedModifiedObserverTag = slicer.mrmlScene.AddObserver(slicer.vtkMRMLScene.NodeAddedEvent, nodeAddedCallback)

Note: @vtk.calldata_type is a Python decorator, which modifies properties of a function that is declared right after the decorator. The decorator is defined in VTK (in Wrapping\Python\vtk\util\misc.py).

Usage from a class requires an extra step of creating the callback in the class __init__ function, as Python2 by default does some extra wrapping (http://stackoverflow.com/questions/9523370/adding-attributes-to-instance-methods-in-python):

class MyClass:
  def __init__(self):
    from functools import partial
    def nodeAddedCallback(self, caller, eventId, callData):
      print("Node added")
      print("New node: {0}".format(callData.GetName()))
    self.nodeAddedCallback = partial(nodeAddedCallback, self)
    self.nodeAddedCallback.CallDataType = vtk.VTK_OBJECT
  def registerCallbacks(self):
    self.nodeAddedModifiedObserverTag = slicer.mrmlScene.AddObserver(slicer.vtkMRMLScene.NodeAddedEvent, self.nodeAddedCallback)
  def unregisterCallbacks(self):
    slicer.mrmlScene.RemoveObserver(self.nodeAddedModifiedObserverTag)
        
myObject = MyClass()
myObject.registerCallbacks()

Allowed CallDataType values: VTK_STRING, VTK_OBJECT, VTK_INT, VTK_LONG, VTK_DOUBLE, VTK_FLOAT, "string0". See more information here: https://github.com/Kitware/VTK/blob/master/Wrapping/PythonCore/vtkPythonCommand.cxx

A simplified syntax is available by using a mix-in:

from slicer.util import VTKObservationMixin

class MyClass(VTKObservationMixin):
  def __init__(self):
    VTKObservationMixin.__init__(self)
    self.addObserver(slicer.mrmlScene, slicer.vtkMRMLScene.NodeAddedEvent, self.nodeAddedCallback)
  
  @vtk.calldata_type(vtk.VTK_OBJECT)
  def nodeAddedCallback(self, caller, eventId, callData):
    print("Node added")
    print("New node: {0}".format(callData.GetName()))

myObject = MyClass()

Note: VTKObservationMixin is a Python mix-in that allows adding a set of methods to a class by inheritance. VTKObservationMixin includes addObserver, hasObserver, observer, removeObserver, removeObservers methods, defined in Slicer (in Base\Python\slicer\util.py). For example of usage, see test_slicer_util_VTKObservationMixin.py

How to run CLI module from Python?

See here.

How can I run slicer operations from a batch script?

Slicer --no-main-window --python-script /tmp/test.py

Contents of /tmp/test.py

# use a slicer scripted module logic
from SampleData import SampleDataLogic
SampleDataLogic().downloadMRHead()
head = slicer.util.getNode('MRHead')

# use a vtk class
threshold = vtk.vtkImageThreshold()
threshold.SetInputData(head.GetImageData())
threshold.ThresholdBetween(100, 200)
threshold.SetInValue(255)
threshold.SetOutValue(0)

#  use a slicer-specific C++ class
erode = slicer.vtkImageErode()
erode.SetInputConnection(threshold.GetOutputPort())
erode.SetNeighborTo4()  
erode.Update()          

head.SetAndObserveImageData(erode.GetOutputDataObject(0))

slicer.util.saveNode(head, "/tmp/eroded.nrrd")

exit()

How can I run Slicer on a headless compute node?

Many cluster nodes are installed with minimal linux systems that don't include X servers. X servers, particularly those with hardware acceleration traditionally needed to be installed with root privileges, making it impossible to run applications that rendered using X or OpenGL.

But there is a workaround which allows everything in slicer to work normally so you could even do headless rendering.

You can use a modern version of X that supports running a dummy framebuffer. This can be installed in user mode so you don't even need to have root on the system.

See [2] for details.

There's a thread here with more discussion: [3]

Here is a working example of the approach running on a headless compute node running CTK tests (which also use Qt and VTK)

[4]


Developer FAQ: MRML

How to add a MRML node into the scene ?

  • Generic pattern

vtkNew<vtkMRML???Node> nodeToAdd;
...
mrmlScene->AddNode(nodeToAdd.GetPointer());

  • Add a polydata to the scene

vtkNew<vtkMRMLModelNode> modelNode;
modelNode->SetPolyData(polyData);
mrmlScene->AddNode(modelNode.GetPointer());

  • Load a polyData from file

vtkSlicerModelsLogic* modelsLogic = ...;
//modelsLogic->SetMRMLScene(mrmlScene);
modelsLogic->AddModel(polyDataFileName);

What to do if you get 'No LookupTable was set but number of components in input doesn't match OutputFormat' when loading a MRML scene ?

If you get the following error messages:

ERROR: In /path/to/VTK/Imaging/vtkImageMapToColors.cxx, line 153
vtkImageMapToColors (0x268f190): RequestInformation: No LookupTable was set but number of components in input doesn't match OutputFormat, therefore input can't be passed through!

ERROR: In /path/to/VTK/Imaging/vtkImageExtractComponents.cxx, line 239
vtkImageExtractComponents (0x26947e0): Execute: Component 1 is not in input.

ERROR: In /path/to/VTK/Imaging/vtkImageExtractComponents.cxx, line 239
vtkImageExtractComponents (0x26947e0): Execute: Component 1 is not in input.

[...]

Make sure the colorNodeRef attribute is set on each VolumeDisplay node.

How to change the volumes in the 2D views ?

appLogic = slicer.app.applicationLogic()
selectionNode = appLogic.GetSelectionNode()
selectionNode.SetReferenceActiveVolumeID(bg)
selectionNode.SetReferenceSecondaryVolumeID(fg)
appLogic.PropagateVolumeSelection()

Source: https://github.com/fedorov/ChangeTrackerPy/blob/master/Wizard/Helper.py#L82


Developer FAQ: IO

Why is my node writer not showing up in the Save dialog ?

You have implemented a loadable module with a new MRML node, its storage node, and the qSlicerNodeWriter needed to save your node on your system file. If the writer is not showing up for your node in the qSlicerSaveDataDialog, it could be one of those following reasons :

  • You need to register your writer in the qSlicerIOManager in qSlicerYourModule::setup().

Example: qSlicerMarkupsModule writer registration


Developer FAQ: Modules

Within a Slicer build-tree, where are located Slicer modules ?

Slicer module executables and libraries are located in your main Slicer build directory Slicer-Superbuild/Slicer-build. Refer to Directory Structure description for more details.

How to build module outside of Slicer source tree

Follow developers guide for building modules

How to modify local version of External module

Some Slicer modules (such as OpenIGTLink and OpenIGTLinkIF) are built as External git projects by CMake scripts in the Slicer/SuperBuild directory. The SuperBuild process may refresh from the repository unexpectedly, overwriting any local changes. To avoid this, comment out the git settings in the appropriate external build file while making local edits. For example, in SuperBuild/External_OpenIGTLinkIF.cmake:

     GIT_REPOSITORY "${git_protocol}://github.com/openigtlink/OpenIGTLinkIF.git"
     GIT_TAG "f9b65b1ffd2992862025f3c6ec5fe30e6f5dd395"
     SOURCE_DIR ${CMAKE_BINARY_DIR}/${proj}
     # GIT_REPOSITORY "${git_protocol}://github.com/openigtlink/OpenIGTLinkIF.git"
     # GIT_TAG "f9b65b1ffd2992862025f3c6ec5fe30e6f5dd395"
     SOURCE_DIR ${CMAKE_BINARY_DIR}/${proj}

How to call a CLI module from a C++ loadable module ?

Discussion: http://slicer-devel.65872.n3.nabble.com/Calling-CLI-module-from-a-C-loadable-module-tt4031930.html

Example: vtkSlicerCropVolumeLogic.cxx#L318-351


Developer FAQ: Extensions

What is an extension ?

Extensions in the Extension manager.

An extension could be seen as a delivery package bundling together one or more Slicer modules. After installing an extension, the associated modules will be presented to the user as built-in ones

The Slicer community maintains a website referred to as the Slicer Extensions Catalog to support finding, downloading and installing of extensions. Access to this website is integral to Slicer and facilitated by the Extensions Manager functionality built into the distributed program.

The Catalog classifies extensions into three levels of compliance:

  1. Category 1: Fully compliant Slicer Extensions: Slicer license, open source, maintained.
  2. Category 2: Open source, contact exists.
  3. Category 3: All other extensions (work in progress, beta, closed source etc).

To publish extensions, developers should consider reading the following pages:

What is the extensions catalog ?

The extensions catalog provides Slicer users with a convenient way to access the extensions previously uploaded on the extensions server:

Why there are no windows 32-bit extensions available ?

  • Win 32 has a very limited amount of memory available to an application.
  • Many registration and segmentation algorithms fail on that platform because they run out of memory, when used with state of large data.
  • Some of these failures are just that, some can crash slicer. Even though the "real" failure is caused by overextending the capabilities of the hardware (in a way the users fault), it appears to the user that Slicer does not work.
  • If you search the archives of slicer-users there are several such complaints until we started to discourage people to use 32 bit.

Discussion: http://massmail.spl.harvard.edu/public-archives/slicer-users/2013/006703.html

Should I install the nightly version to access to last extension updates ?

If the extension developers contributed updates for the current stable release, you don't have to install the nightly version of Slicer. You can simply update the extension. Consider reading How to update an already installed extension ?.

On the other hand, if the extension developers stopped to maintain the version of their extension built against the stable release (so that we can use the latest feature that will be in the next Slicer release), downloading the nightly is the only way to get the latest version of the extension.

How to update an already installed extension?

Assuming updates extensions are available for your version of Slicer, extensions can either be updated manually or automatically.

See Updating installed extensions

How to manually download an extension package?

1) Get revision associated with your install or built Slicer (Menu -> Help -> About). The revision is a number preceded by r character, for example: if the complete version string is 4.3.1-2014-09-14 r23677 the revision is 23677

2) Open the extension catalog (app store). The default Slicer extension catalog is available at: http://slicer.kitware.com/midas3/slicerappstore

3) Select operating system, bitness and enter revision in the empty textbox between the bitness selector and the searchbox. If no revision is entered then the No extensions found message will be displayed.

4) Click Download button of the selected extension to download the extension package.

How to manually install an extension?

1) Get the extension package matching your Slicer version.

2.a) Either install the extension package using the Slicer extension called "DeveloperToolsForExtensions"

2.b.i) Or extract the archive (zip or tar.gz) in a folder. You should then have a folder like:

/path/to/<slicer_revision>-<os>-<bitness>-<extension_name>-<extension_scm><extension_revision>-YYYY-MM-DD

containing one or more of the following folders:

lib/Slicer-X.Y/cli-modules
lib/Slicer-X.Y/qt-loadable-modules
lib/Slicer-X.Y/qt-scripted-modules

For more details: Documentation/4.5/Developers/DirectoryStructure

2.b.ii) There are two options:

2.b.ii.a) In the Module settings (Menu -> Edit -> Settings), add all existing paths ending with:

lib/Slicer-X.Y/cli-modules
lib/Slicer-X.Y/qt-loadable-modules
lib/Slicer-X.Y/qt-scripted-modules

2.b.ii.b) Start Slicer specifying the option --additional-module-paths with all existing paths listed in 4.a.

How to create a custom Slicer version with selected extensions pre-installed?

1) Download and install Slicer

2) Install all necessary extensions manually (as described above) in <slicer_install_dir>/lib/Slicer-X.Y/...

3) If all the files in <slicer_install_dir> are copied to any other folder/computer/USB drive/portable storage device then Slicer can be launched by running the Slicer executable in the main directory. No installation or administrative access rights are necessary. Slicer can even be launched directly from a USB drive, without copying files to the computer.

What is an extension description file ?

See Description file description

Can an extension contain different types of modules ?

Yes. Extensions are used to package together all types of Slicer modules.

See also What_is_an_extension ?

Should the name of the source repository match the name of the extension ?

Assuming your extension is named AwesomeFilter, generally, we suggest to name the extension repository either SlicerAwesomeFilter, Slicer-AwesomeFilter, Slicer_AwesomeFilter, SlicerExtension-AwesomeFilter, SlicerExtension_AwesomeFilter.

Doing so will minimize confusion by clearly stating that the code base is associated with Slicer.

What is the Extensions Index ?

Think of the ExtensionsIndex as a repository containing a list of extension description files *.s4ext used by the Slicer extensions build system to build, test, package and upload extensions on the extensions server.

Once uploaded on an extensions server, within Slicer, extensions can be installed using the extensions manager.

The extensions catalog provides Slicer users with a convenient way to access the extensions previously uploaded.

There are multiple branches on the ExtensionsIndex:

  • master: This branch contain description files of extensions that will be built against Slicer nightly.
  • [...]
  • 4.10: This branch contain description files of extensions that will be built against latest Slicer 4.10 available patch release.

The reasoning behind this approach is that since both the Slicer API and ABI associated with Slicer base libraries are changing often, compatibility of the extensions available for download is guaranteed by building extensions against every Slicer revisions.

It means that developer willing to have their extensions available on the different versions of Slicer will have to submit pull requests for each version.

What is an API Key ?

See http://en.wikipedia.org/wiki/Application_programming_interface_key

How to obtain an API key to submit on the extension server ?

In order to upload extensions on the slicer extensions server, it is required to:


  1. Create an account on the extension server: http://slicer.kitware.com by clicking on the Register link in the top right corner

  2. Slicer-midas-extensions-server-registration.png

    This image shows the top portion of http://slicer.kitware.com after it has been expanded by clicking the Register button.

  3. Go to NA-MIC community and click on Join community

  4. Retrieve your API key looking at your account details:

    1. Go to http://slicer.kitware.com. If needed, signin by clicking on Login in the top right corner.
    2. Click on your name in the top right corner.
    3. Click on My account.
    4. Click on API tab.
    5. Copy the API Key associated with Default application.

      1. There is currently a bug preventing api key containing non alpanumeric characters from being used.
        If your Default api key contain for example a /, try to delete the api key and regenerate one that is not containing "/" and is named Default.
        We are working on the issue to update the build system so that it properly escape "/" and also get in touch with Midas team so that api key containing just number and letter are generated.

  5. Slicer-midas-extensions-server-obtaining-api-key.png

How to cache API credentials ?

There is now a new feature that allow you to "cache" your credential [1]. If you set the two environment variables, MIDAS_PACKAGE_EMAIL and MIDAS_PACKAGE_API_KEY, you would simply need to configure your extension using:

cd MyExtension-build
cmake -DCMAKE_BUILD_TYPE:STRING=Release -DSlicer_DIR:PATH=/path/to/Slicer-Superbuild/Slicer-build ../MyExtension
make ExperimentalUpload

[1] http://viewvc.slicer.org/viewvc.cgi/Slicer4?view=revision&revision=22457

Where can I find the extension templates ?

The module and extension templates are available in the Slicer source tree: https://github.com/Slicer/Slicer/tree/master/Utilities/Templates/

Using the Extension Wizard, you could easily create a new extension without having to copy, rename and update manually every files.

How to build an extension ?

Assuming that the source code of your extension is located in folder MyExtension, this could be achieved doing:

Makefile Visual Studio
$ mkdir MyExtension-build
$ cd MyExtension-build
$ cmake -DCMAKE_BUILD_TYPE:STRING=Release -DSlicer_DIR:PATH=/path/to/Slicer-Superbuild/Slicer-build ../MyExtension
$ make
  1. Start CMake, select source and build directory
  2. Add Slicer_DIR entry to the cache
  3. Click on Configure, select generator, then click on Generate button.
  4. Open MyExtension.sln, select Release configuration, then menu Project -> Build Solution.

How to package an extension ?

Assuming your extension has been built into folder MyExtension-build, this could be achieved doing:

Makefile Visual Studio
$ make package
  1. Open MyExtension.sln
  2. Select PACKAGES project, then right click and select Build

How are Superbuild extension packaged ?

Extensions using the Superbuild mechanism build projects in two steps:

  • First, the project dependencies are built in an outer-build directory.
  • Then, the project itself is built in an inner-build directory

Extensions can use the Superbuild mechanism. However, developers have to be careful that the packaging macros clean the project before reconfiguring it. This means that if ones uses the Slicer extension packaging macros inside the inner-build directory, when packaging and uploading the extension package, the project will be reconfigured, and variables passed from the outer-build directory will be lost. If the project only depends on libraries that Slicer builds, this is not an issue. If the project has specific dependencies that Slicer does not compile on its own, the developer should be careful to instantiate the Slicer extension packaging macros only in the outer-build directory. This only means that in the latter case, tests should be instantiated in the outer-build directory to allow the Slicer extension building process to test the extension before uploading the extension and the tests results.

How to upload an extension ?

  1. If not already done, send an email on the slicer developers list asking to be granted write permission on the experimental folder.

    To: slicer-devel@bwh.harvard.edu
    Subject: Extension NAME-OF-YOUR-EXTENSION - Asking permission to write to the Experimental folder
    Hi, 
    
    This extension will allow to [...]
    
    Could you grant user YourUserName write access to the Experimental folder ?
    
    

Assuming your extension has been built and packaged into folder MyExtension-build, this could be achieved by first re-configuring the project providing your midas credentials and then building the ExperimentalUploadOnly target:

Makefile Visual Studio
$ cmake -DMIDAS_PACKAGE_EMAIL:STRING=<YOUR-MIDAS-LOGIN> -DMIDAS_PACKAGE_API_KEY:STRING=<YOUR-MIDAS-APIKEY> .
$ make ExperimentalUploadOnly
  1. Start CMake, select source and build directory
  2. Add MIDAS_PACKAGE_EMAIL and MIDAS_PACKAGE_API_KEY entries to the cache
  3. Open MyExtension.sln
  4. Select Release configuration
  5. Select ExperimentalUploadOnly project, then right click and select Build

Can an extension depend on other extensions ?

Yes. An ExtensionFoo can depend on ExtensionBar

The dependency should be specified as a list by setting the variable EXTENSION_DEPENDS in the extension CMakeLists.txt.

For example, if you have ModuleA, ModuleB and ModuleC and ModuleA can be used as standalone one. You could create the following extensions:

  • Extension1 containing ModuleA
  • Extension2 containing ModuleB and ModuleC

and add the following variable to Extension2/CMakeLists.txt:

set(EXTENSION_DEPENDS Extension1)

User:

  • If user installs Extension2, Extension1 will automatically be installed first.

Developer:

  • The generated extension description file have a depends field. See here for details.
  • The extension framework will build the extension in order. When building Extension2, it will pass the CMake option -DExtension1_DIR:PATH=/path/to/Extension1-build.

What are the extension specific targets: ExperimentalUpload, ExperimentalUploadOnly, ... ?

Slicer extension build system provides the developer with a set of convenient targets allowing to build and upload extensions.

Target name Description
Experimental Configure, build, test the extension and publish result on CDash.
ExperimentalUpload Equivalent to Experimental target followed by packaging and upload of the extension on the extension server.
ExperimentalUploadOnly Only proceed to the upload of the extension on the extension server.
test or BUILD_TESTS Locally execute the test
package or PACKAGE Locally package the extension

Is --launch flag available for a MacOSX installed Slicer.app ?

On MacOSx, running Slicer with the --help argument does NOT list the usual launcher related options.

$ ./Slicer.app/Contents/MacOS/Slicer --help
Usage
 Slicer [options]
 
 Options
   --, --ignore-rest                     Ignores the rest of the labeled arguments following this flag. (default: false)
   -h, --help                            Display available command line arguments.
   [...]
   --version                             Displays version information and exits.

To provide some background information, when generating the package that will be distributed, an application bundle Slicer.app is created. As explained here, a bundle is a directory with a standardized hierarchical structure that holds executable code and the resources used by that code. It means that since all libraries contained within a bundle are referenced relatively to the location of either the CLI or the Slicer executable, the use of launcher does NOT make sens.

To help fixing-up the libraries, executables and plugins so that they reference each other in a relative way, CMake provides us with the BundleUtilities module.

This module is used in two situations:

  1. Fixup of Slicer application itself. See SlicerCPack.cmake#L36-68 and SlicerCPackBundleFixup.cmake.in
  2. Fixup of an extension package. See SlicerExtensionCPack.cmake#L126-143 and SlicerExtensionCPackBundleFixup.cmake.in


What is the difference between Documentation/Nightly/Modules and Documentation/Nightly/Extensions ?

As suggested by the namespace names:

  • All module documentation pages should be located under Documentation/Nightly/Modules
  • All extension documentation pages should be located under Documentation/Nightly/Extensions


For example, if an an extension named DoSomethingGreat bundles three modules ModuleA, ModuleB and ModuleC. The following pages should be created:

  • Documentation/Nightly/Extensions/DoSomethingGreat
  • Documentation/Nightly/Modules/ModuleA
  • Documentation/Nightly/Modules/ModuleB
  • Documentation/Nightly/Modules/ModuleC


In case your extension bundles only one module, the extension name is expected to match the module name. For example, if your extension is named DoSomethingAwesome, the associated module is expected to be named DoSomethingAwesome. The following pages will then be created:

  • Documentation/Nightly/Extensions/DoSomethingAwesome
  • Documentation/Nightly/Modules/DoSomethingAwesome

where page Extensions/DoSomethingAwesome redirect to page Modules/DoSomethingAwesome.


To setup a redirection, simply add the following text to page Extensions/DoSomethingAwesome:

#REDIRECT [[Documentation/Nightly/Modules/DoSomethingAwesome]]

For an example, see here

More details about redirection are available here: http://www.mediawiki.org/wiki/Help:Redirects


Which URL should be associated with EXTENSION_HOMEPAGE metadata ?

Extensions available through the Slicer Extensions Catalog are expected to have a page created under the Nightly documentation namespace. The corresponding URL should be associated with the EXTENSION_HOMEPAGE metadata.

For example:

  • set(EXTENSION_HOMEPAGE "http://slicer.org/wiki/Documentation/Nightly/Extensions/DoSomethingGreat")
  • set(EXTENSION_HOMEPAGE "http://slicer.org/wiki/Documentation/Nightly/Extensions/DoSomethingAwesome")

Note that this also apply for extension bundling only one module. Indeed, in this case the page will redirect to the appropriate module page. For example: http://www.slicer.org/wiki/Documentation/Nightly/Extensions/SkullStripper

How to rename an extension to add new features ?

If you created an extension to perform Task1, but later on, your module is getting more generic and you add some other tasks, the name of your extension might change. In order to rename, your extension, you should:

  • Remove your old extension from the ExtensionsIndex
  • Then, submit your extension again (including new features) with a new name
  • Make also sure to add redirection from the "deprecated" module documentation to the "new" pages. On the Slicer wiki, this could be using the #REDIRECT instruction.

How to check if an extension is built by Slicer Extensions build system ?

Sometimes an extension could be built either as a standalone package or as a Slicer extension.

To differenciate the two cases, the developer could check for the value of:

<ExtensionName>_BUILD_SLICER_EXTENSION

This variable will be set to ON when the extension is built by the Slicer Extensions build system.

For details: https://github.com/Slicer/Slicer/blob/ff5f5a866d8afcaa0f2e6f615cc8f8cf07361741/Extensions/CMake/SlicerBlockBuildPackageAndUploadExtension.cmake#L95

How often extensions are uploaded on the extensions server ?

Slicer extensions are built and uploaded on the extensions server every day.

To be more specific, the frequency of extensions build and upload associated with:

  • Slicer nightly package occurs every night and also continuously during the day.
  • Slicer 4.10 lastest stable release package occurs every night.

Will an extension be uploaded if associated tests are failing ?

Independently of the extension test results, if the extension could be successfully packaged, it will be uploaded on the extensions server.

How do I associate a remote with my local extension git source directory ?

1) Start a terminal (or Git Bash on Windows)

2) Get the associated SSH remote url. Need help ?

3) Associate the remote URL with your local git source tree

git remote add origin git://github.com/<username>/MyExtension

Which remote name is expected for extension git checkout ?

When packaging an extension and generating the associated description file, the system will look for a remote named origin.

In case you get the error reported below, you will have to either rename or add a remote. Need help ?

CMake Warning at /path/to/Slicer/CMake/FindGit.cmake:144 (message):
No remote origin set for git repository: /path/to/MyExtension
Call Stack (most recent call first):
/path/to/Slicer/CMake/SlicerMacroExtractRepositoryInfo.cmake:99 (GIT_WC_INFO)
/path/to/Slicer/CMake/SlicerExtensionCPack.cmake:55 (SlicerMacroExtractRepositoryInfo)
CMakeLists.txt:25 (include)

Why ExtensionWizard failed to describe extension: "script does not set 'EXTENSION_HOMEPAGE'" ?

The issue is that the your extension has a "non standard" layout and the wizard was now way of extracting the expected information.

Similar issue has been discussed and reported for the "SPHARM-PDM" or UKF extension.

First half of the solution would be to move the metadata from Common.cmake to CMakeLists.txt as it is done in [1]

Then, you could make sure there is a project() statement by following what is suggested in [2]

If you prefer not to re-organize your extension, you could still contribute extension description file. See here for details.

[1] http://www.nitrc.org/plugins/scmsvn/viewcvs.php?view=rev&root=spharm-pdm&revision=228

[2] http://www.na-mic.org/Bug/view.php?id=3737#c12081

Is project() statement allowed in extension CMakeLists.txt ?

Following Slicer r22038, the project statement is required.

Is call to "if(NOT Slicer_SOURCE_DIR)" required to protect "find_package(Slicer)" in extension CMakeLists.txt ?

Following Slicer r22063, protecting call to find_package(Slicer) with if(NOT Slicer_SOURCE_DIR) is optional and should be removed to keep code simpler and easier to maintain.

Before:

cmake_minimum_required(VERSION 2.8.9)

if(NOT Slicer_SOURCE_DIR)
  find_package(Slicer COMPONENTS ConfigurePrerequisites)
endif()

if(NOT Slicer_SOURCE_DIR)
  set(EXTENSION_NAME EmptyExtensionTemplate)
  set(EXTENSION_HOMEPAGE "http://www.slicer.org/wiki/Documentation/Nightly/Extensions/EmptyExtensionTemplate")
  set(EXTENSION_CATEGORY "Examples")
  set(EXTENSION_CONTRIBUTORS "Jean-Christophe Fillion-Robin (Kitware)")
  set(EXTENSION_DESCRIPTION "This is an example of extension bundling N module(s)")
  set(EXTENSION_ICONURL "http://viewvc.slicer.org/viewvc.cgi/Slicer4/trunk/Extensions/Testing/EmptyExtensionTemplate/EmptyExtensionTemplate.png?revision=21746&view=co")
  set(EXTENSION_SCREENSHOTURLS "http://www.slicer.org/w/img_auth.php/4/42/Slicer-r19441-EmptyExtensionTemplate-screenshot.png")
endif()

if(NOT Slicer_SOURCE_DIR)
  find_package(Slicer REQUIRED)
  include(${Slicer_USE_FILE})
endif()

add_subdirectory(ModuleA)

if(NOT Slicer_SOURCE_DIR)
  include(${Slicer_EXTENSION_CPACK})
endif()

After:

cmake_minimum_required(VERSION 2.8.9)

find_package(Slicer COMPONENTS ConfigurePrerequisites)

project(EmptyExtensionTemplate)

set(EXTENSION_HOMEPAGE "http://www.slicer.org/wiki/Documentation/Nightly/Extensions/EmptyExtensionTemplate")
set(EXTENSION_CATEGORY "Examples")
set(EXTENSION_CONTRIBUTORS "Jean-Christophe Fillion-Robin (Kitware)")
set(EXTENSION_DESCRIPTION "This is an example of empty extension")
set(EXTENSION_ICONURL "http://viewvc.slicer.org/viewvc.cgi/Slicer4/trunk/Extensions/Testing/EmptyExtensionTemplate/EmptyExtensionTemplate.png?revision=21746&view=co")
set(EXTENSION_SCREENSHOTURLS "http://www.slicer.org/w/img_auth.php/4/42/Slicer-r19441-EmptyExtensionTemplate-screenshot.png")

find_package(Slicer REQUIRED)
include(${Slicer_USE_FILE})

add_subdirectory(ModuleA)

include(${Slicer_EXTENSION_CPACK})

Why is the --contribute option is not available with the ExtensionWizard ?

Wizard contribute option is available only (1) if Slicer is built with OpenSSL support or (2) directly from the nightly.

To build Slicer with SSL support, you need to build (or download) Qt with SSL support and configure Slicer with -DSlicer_USE_PYTHONQT_WITH_OPENSSL:BOOL=ON

How dependent extensions are configured and built ?

If an ExtensionB depends on an ExtensionA, ExtensionA should be listed as dependency in the metadata of ExtensionB.

This can be done setting EXTENSION_DEPENDS in the CMakeLists.txt or by specifying depends field in the description file.

Doing so will ensure that:

  • (1) the extension build system configure the extensions in the right order
  • (2) ExtensionB is configured with option ExtensionA_DIR.


Developer FAQ: Dashboard

What time the nightly dashboard starts ?

The nightly build are expected to start every day after 3am UTC (22pm EST) and should be available in the morning. If no build error occurred, the latest packages can be downloaded using on of these links:


How can I setup a dashboard ?

See dashboard setup instruction.


Developer FAQ: Device interoperability

Can Oculus Rift be used with Slicer ?

Some preliminary integration work has been done. See http://slicer-devel.65872.n3.nabble.com/Oculus-Rift-td4032779.html

Can Oculus Rift be connected with Slicer through OpenIGTLink ?

Oculus requires very tight integration with the rendering pipeline, so probably the current approach of using a C++ loadable module that directly communicates with the Oculus SDK to get pose and send images is better than going through OpenIGTLink.

Source: http://slicer-devel.65872.n3.nabble.com/OpenIGT-and-Slicer-tp4032868p4032875.html