Packaging SlicerVMTK extension with custom Slicer build

Slicer build process automatically finds ExternalX.cmake files to build dependencies and rely on their correct implementation to find potential additional dependencies, build, and install them.

SlicerIGT, SlicerOpenIGTLink, and SlicerVirtualReality extensions are all superbuild extensions that are tested to work well when used in a custom Slicer application. Test if they work correctly for you and if they do then compare what is different in VMTK.

1 Like

Thanks, I’ll try those ones.

I’m still trying to identify differences between the CMake scripts for SlicerOpenIGTLink and SlicerVMTK, but looking at the CDash results for the three extensions you suggested, I see that SlicerVirtualReality is not able to build for Mac, and the build error relates to finding an include file from its external package OpenVR. I’m not sure if this is related, but SlicerVirtualReality, SlicerVMTK, and SlicerElastix are all failing to build on Mac, and Mac only. I may start a separate thread about this.

First you need to make sure that the extension builds without problems when it is built standalone. Once it works, you can try to build it as part of a custom Slicer application. There may be additional complications in superbuild extensions, because if the extension is built as part of Slicer then Slicer’s build system must build and package all the third-party libraries that the extension depends on.

Absolutely. I just re-tested the up-to-date extension and VMTK, with the most recent Slicer’s VTK and ITK, and it is able to build on its own. The problem is when I try to include it in a custom application, either by referencing the pre-downloaded extension source directory, or using the FetchContent_Populate macro to fetch the source.

The SuperBuild seems able to recognize the dependence on VMTK and build it, then it puts the shared object libraries from VMTK in the main SuperBuild directory, but then when running the ExternalProject_Include_Dependencies macro when building Slicer itself, it can’t find External_VMTK.cmake.
Other than that, I ran into a minor issue when doing a completely fresh build because VMTK’s dependence on ITK and VTK wasn’t specified, but that was a quick fix.

The extension must store External_(dependency).cmake files in SuperBuild subfolder.

That’s the confusing thing - it does. The file is in SlicerExtension-VMTK/SuperBuild, but the ExternalProject_Include_Dependencies macro doesn’t check there when building Slicer. If I print out where it tries to access the file when building Slicer, it tries:

  • ~/app-SuperBuild/slicersources-src/SuperBuild/External_VMTK.cmake
  • (blank)
  • /External_VMTK.cmake
  • a foreach statement that’s not entered

The last two are supposed to use values from EXTERNAL_PROJECT_ADDITIONAL_DIR and a list called EXTERNAL_PROJECT_ADDITIONAL_DIRS, but they are blank.
The relevant code is here: https://github.com/Slicer/Slicer/blob/master/CMake/ExternalProjectDependency.cmake#L858
For some reason, the values of EXTERNAL_PROJECT_ADDITIONAL_DIR and the EXTERNAL_PROJECT_ADDITIONAL_DIRS list aren’t being set, or are being cleared? At the Configure stage for the superbuild, these values are present, though.

Try to add SlicerOpenIGTLink extension to your project, too, and see if there is any difference between where OpenIGTLink library shows up and VMTK library shows up. We would then have a better idea where the problem might be.

I’m having trouble getting SlicerOpenIGTLink to compile, but it’s a different problem, and I can’t tell if it’s getting past the place where SlicerExtension-VMTK stops. Here’s the error:

[ 97%] Performing configure step for ‘Slicer’

– Configuring extension directory: SlicerOpenIGTLink
– Checking EXTENSION_NAME variable
– Checking EXTENSION_NAME variable - NOTDEFINED
– Checking MODULE_NAME variable
– Checking MODULE_NAME variable - NOTDEFINED
– Checking PROJECT_NAME variable
– Checking PROJECT_NAME variable - SlicerOpenIGTLink
– Setting EXTENSION_NAME …: SlicerOpenIGTLink
– Checking EXTENSION_NAME variable
– Checking EXTENSION_NAME variable - SlicerOpenIGTLink
– Looking for decorator header qSlicerOpenIGTLinkIFModuleWidgetsPythonQtDecorators.h

– Looking for decorator header qSlicerOpenIGTLinkIFModuleWidgetsPythonQtDecorators.h - Not found

– Configuring Loadable module: OpenIGTLinkIF [qSlicerOpenIGTLinkIFModuleExport.h]

CMake Error at /short/pack/PADPlanner-SB/SlicerOpenIGTLink/OpenIGTLinkIF/Testing/CMakeLists.txt:29 (list):
list sub-command INSERT requires at least three arguments.

I’m still not certain about what’s happening, but something that may be interesting is that with OpenIGTLink, I don’t see the message output lines that I added to ExternalProjectDependency.cmake in the build output. In both cases, I see them in the Configure stage in the CMake GUI, but with SlicerExtension-VMTK, I see them again in the Slicer build configuration phase. It makes me think that OpenIGTLink doesn’t re-run the macro during the build.

Here’s the build output leading up to the error when I try adding SlicerExtension-VMTK to Slicer. The four lines after “SuperBuild - First pass” are my additions.

[ 97%] Performing configure step for ‘Slicer’

– Configuring extension directory: SlicerExtension-VMTK
CMake Warning (dev) at /short/pack/PADPlanner-SB/SlicerExtension-VMTK/CMakeLists.txt:4 (project):
Policy CMP0048 is not set: project() command manages VERSION variables.
Run “cmake --help-policy CMP0048” for policy details. Use the cmake_policy
command to set the policy and suppress this warning.

The following variable(s) would be set to empty:

PROJECT_VERSION
PROJECT_VERSION_MAJOR
PROJECT_VERSION_MINOR
PROJECT_VERSION_PATCH

This warning is for project developers. Use -Wno-dev to suppress it.

– Checking EXTENSION_NAME variable
– Checking EXTENSION_NAME variable - NOTDEFINED
– Checking MODULE_NAME variable
– Checking MODULE_NAME variable - NOTDEFINED
– Checking PROJECT_NAME variable
– Checking PROJECT_NAME variable - SlicerVMTK
– Setting EXTENSION_NAME …: SlicerVMTK
– SuperBuild - First pass
EXTERNAL_PROJECT_DIR location is /short/pack/PADPlanner-SB/slicersources-src/SuperBuild/External_VMTK.cmake
dep_FILEPATH location is
EXTERNAL_PROJECT_ADDITIONAL_DIR location is /External_VMTK.cmake
This is the whole EXTERNAL_PROJECT_ADDITIONAL_DIRS list:
CMake Error at /short/pack/PADPlanner-SB/slicersources-src/CMake/ExternalProjectDependency.cmake:862 (message):
Can’t find External_VMTK.cmake
Call Stack (most recent call first):
/short/pack/PADPlanner-SB/SlicerExtension-VMTK/SuperBuild.cmake:32 (ExternalProject_Include_Dependencies)
/short/pack/PADPlanner-SB/SlicerExtension-VMTK/CMakeLists.txt:33 (include)

-- Configuring incomplete, errors occurred!
See also “/short/pack/PADPlanner-SB/Slicer-build/CMakeFiles/CMakeOutput.log”.
See also “/short/pack/PADPlanner-SB/Slicer-build/CMakeFiles/CMakeError.log”.
make[2]: *** [slicersources-build/Slicer-prefix/src/Slicer-stamp/Slicer-configure] Error 1
make[1]: *** [slicersources-build/CMakeFiles/Slicer.dir/all] Error 2
make: *** [all] Error 2

Actually, I tried commenting out the line OpenIGTLink was failing on, the list sub-command, and the configuration carries on, and completes, without writing the messages I added to ExternalProjectDependency.cmake. Here’s the new extension configuration output for OpenIGTLink:

– Configuring extension directory: SlicerOpenIGTLink
– Checking EXTENSION_NAME variable
– Checking EXTENSION_NAME variable - NOTDEFINED
– Checking MODULE_NAME variable
– Checking MODULE_NAME variable - NOTDEFINED
– Checking PROJECT_NAME variable
– Checking PROJECT_NAME variable - SlicerOpenIGTLink
– Setting EXTENSION_NAME …: SlicerOpenIGTLink
– Checking EXTENSION_NAME variable
– Checking EXTENSION_NAME variable - SlicerOpenIGTLink
– Looking for decorator header qSlicerOpenIGTLinkIFModuleWidgetsPythonQtDecorators.h
– Looking for decorator header qSlicerOpenIGTLinkIFModuleWidgetsPythonQtDecorators.h - Not found
– Configuring Loadable module: OpenIGTLinkIF [qSlicerOpenIGTLinkIFModuleExport.h]
– Looking for decorator header qSlicerOpenIGTLinkRemoteModuleWidgetsPythonQtDecorators.h
– Looking for decorator header qSlicerOpenIGTLinkRemoteModuleWidgetsPythonQtDecorators.h - Not found
– Configuring Loadable module: OpenIGTLinkRemote [qSlicerOpenIGTLinkRemoteModuleExport.h]
– Looking for decorator header qSlicerPlusRemoteModuleWidgetsPythonQtDecorators.h
– Looking for decorator header qSlicerPlusRemoteModuleWidgetsPythonQtDecorators.h - Not found
– Configuring Loadable module: PlusRemote [qSlicerPlusRemoteModuleExport.h]
– Looking for decorator header qSlicerUltrasoundRemoteControlModuleWidgetsPythonQtDecorators.h
– Looking for decorator header qSlicerUltrasoundRemoteControlModuleWidgetsPythonQtDecorators.h - Not found
– Configuring Scripted module: UltrasoundRemoteControl
– Skipping extension packaging: SlicerOpenIGTLink - Slicer_SOURCE_DIR is defined.
CMake Warning at Utilities/Scripts/SlicerWizard/doc/CMakeLists.txt:41 (message):
Warning: sphinx-build not found: Python documentation will not be created

– Setting ‘CTEST_MODEL’ variable with default value ‘Experimental’
– Setting ‘MIDAS_PACKAGE_URL’ variable with default value ‘http://slicer.kitware.com/midas3
– Setting ‘MIDAS_PACKAGE_EMAIL’ variable with default value ‘OBFUSCATED’
– Setting ‘MIDAS_PACKAGE_API_KEY’ variable with default value ‘OBFUSCATED’
– Setting CPACK_PACKAGE_NAME to ‘PADPlanner’
– Setting CPACK_PACKAGE_VENDOR to ‘Sunnybrook Research Institute’
– Setting CPACK_PACKAGE_VERSION_MAJOR to ‘4’
– Setting CPACK_PACKAGE_VERSION_MINOR to ‘9’
– Setting CPACK_PACKAGE_VERSION_PATCH to ‘0’
– Setting CPACK_PACKAGE_VERSION to ‘4.9.0-2018-08-28’
– Setting CPACK_PACKAGE_INSTALL_DIRECTORY to ‘PADPlanner 4.9.0-2018-08-28’
– Setting CPACK_PACKAGE_DESCRIPTION_FILE to ‘/short/pack/PADPlanner-SB/slicersources-src/README.txt’
– Setting CPACK_RESOURCE_FILE_LICENSE to ‘/short/pack/PADPlanner-SB/slicersources-src/License.txt’
– Setting CPACK_PACKAGE_DESCRIPTION_SUMMARY to ‘Surgical planning tool for Peripheral Artery Disease’
– Setting CPACK_PACKAGE_ICON to ‘/Users/michaelschumaker/Development/mschumaker/Slicelets/PADFusion/CustomAppTemplateConfig/PADPlanner/Applications/PADPlannerApp/Resources/App.icns’
– Configuring done
– Generating done
– Build files have been written to: /short/pack/PADPlanner-SB/Slicer-build
[ 98%] Performing build step for ‘Slicer’

We tried the bundling of SlicerOpenIGTLink with BUILD_TESTING set to OFF, this explain why you see this error. In the following bloc:

The fix is most likely to change it if with:

# Add '--launcher-additional-settings' to launch command unless it is bundled in Slicer
if(NOT DEFINED Slicer_SOURCE_DIR)
  list(FIND Slicer_LAUNCH_COMMAND "--launch" launch_index)
  list(INSERT Slicer_LAUNCH_COMMAND ${launch_index} ${Slicer_ADDITIONAL_LAUNCHER_SETTINGS}) 
endif()
1 Like

Thanks, that makes sense. With those lines omitted, it’s able to carry on past the configuration stage.

Now the bundling of the SlicerVMTK should be done doing something like this:

# SlicerVMTK
set(extension_name "SlicerVMTK")
set(${extension_name}_SOURCE_DIR "${CMAKE_BINARY_DIR}/${extension_name}")
FetchContent_Populate(${extension_name}
  SOURCE_DIR     ${${extension_name}_SOURCE_DIR}
  GIT_REPOSITORY ${EP_GIT_PROTOCOL}://github.com/vmtk/SlicerExtension-VMTK.git
  GIT_TAG        c5dd07e2df6834342035cbdb1e0c461b452009d4
  GIT_PROGRESS   1
  QUIET
  )
list(APPEND Slicer_EXTENSION_SOURCE_DIRS ${${extension_name}_SOURCE_DIR})

Few things would have to be updated in the extension:

As a side note, it would be great if you could search for other occurrence that pattern and submit a PR fixing OpenIGTLinkIF.

1 Like

Ok, I can update the block dealing with CPack, and I’ll make sure to specify a commit. Once all this is sorted out, I can make that change to OpenIGTLinkIF as well.

One thing that’s confusing is the different naming of the extension. In a number of places it’s SlicerVMTK, but the repository is SlicerExtension-VMTK. I’m not sure when to use which name.

1 Like

In doubt, use the name of the project found in the project(NameOfProject) statement.

1 Like

So after everything… the problem has been solved by setting the extension_name to be SlicerVMTK. At the point where it was failing, the project name was being assigned as the expected extension name, and so the extension source files couldn’t be found.

As discussed, I’ve revised the block dealing with CPack, and I’ll submit a PR, though I would also like to add ITK and VTK as dependencies of the extension. When I tried a completely fresh superbuild, it attempted to build VMTK before ITK, and stopped. How can I add those dependencies correctly?

Sounds great!

You should be able to define dependencies by setting ${proj}_DEPENDS in External_(yourlibrary).cmake, as it is done for example for this external library:

Ok, thanks, I’ll do that.

Thank you for your help, @lassoan and @jcfr!

It’s almost there… but not quite. Everything compiles, but I’m unable to access the Python libraries for VMTK from the interpreter. Also, there was a problem when I attempted to package the app. The VMTK-build directory is in ~/app-SuperBuild/slicersources-build, but the script was expecting it to be in ~/app-SuperBuild, so “make package” failed.

Do you have any suggestions?

This section

should be updated based on

https://github.com/Slicer/Slicer/blob/f08936e114b0cff769d6e4cb196d697848f29194/Utilities/Templates/Extensions/SuperBuild/SuperBuild/External_Foo.cmake#L23-L45

consider also removing git_protocol and instead using EP_GIT_PROTOCOL as well as ExternalProject_SetIfNotDefined

1 Like