Packaging SlicerVMTK extension with custom Slicer build

Before building, I added Slicer_EXTENSION_SOURCE_DIRS

Also, the download of the module or extension source can be automatic using an approach similar to this one:

I’m making progress with an application started with cookiecutter, and including my scripted modules. One question I have is about additional files for a module. I have some tables in plist files in the Resources directory of a scripted module. How do I make sure these will be copied to the qt-scripted-modules/Resources directory when building?

Another minor thing I noticed is a problem with the version numbers and dates that appear in the compiled application. In the Mac menu bar, the version number and date are for Slicer, while at the top of the application window, the version number is what I defined, but the date is all zeros. I’ve included an image. Is this a bug, or is there something I need to do?
Thanks!

This is because you do not yet have a git repository associated with your custom application source code. In that case, the there is now way to know the date associated with the last commit.

This is indeed a bug, for now the following lines need to be changed to use Slicer_MAIN_PROJECT_VERSION_FULL. (Note that ideally it should SLICER_APP_VERSION_FULL but this is not yet possible because repository info are only extracted for Slicer itself and the main application only)

Could you create a Slicer PR to address this ? Thanks

https://github.com/Slicer/Slicer/blob/ad3fcd4ddf367363f9fb258b6dc2fcee06cd2039/CMake/SlicerMacroBuildApplication.cmake#L449-L450

Ok, I’ve submitted a PR with those lines changed.

Ok, thanks. I put the application code in a sub-directory of a project, so the .git directory is two levels up. I’ll reorganize things once I have a better idea what I’m doing.

I also had this question:

Thanks!

Thanks for the contribution. PR#1003 has just been integrated as 27343

What do you mean exactly by some tables in plist files ?

There are two approaches for associated resources with scripted module:

Oh… the answer was in my own previous post! :man_facepalming:
I hadn’t added the files to the MODULE_PYTHON_RESOURCES list.
Property list (.plist) files are an XML-based data format on Mac/iOS. Python has a plistlib library to read them. I’m using some color look-up tables that are stored that way.

Property list (.plist) files are an XML-based data format on Mac/iOS. Python has a plistlib library to read them.

I see. The Slicer build system currently provides its one template for the plist file integrated in the Slicer.app (or `Custom.app):

https://github.com/Slicer/Slicer/blob/87e8a89274eca8c0a249df8785ded16a060006ab/CMake/SlicerMacroBuildApplication.cmake#L451

This was done back in 2014 to ensure the application would work with High DPI monitor. See https://github.com/Slicer/Slicer/commit/a913ea9af8705fc766d5acd7d9689a8202ba2310

If really needed, we could provide custom application with a way to provide their own template, would that help you ?

That said, using a more traditional approach would ensure the work you do is portable on windows, linux, …

Thanks, that’s probably more work than necessary. Reading them isn’t a problem, it’s that I forgot that I should include them in the CMakeLists file. :flushed: I just tested that, and it worked.
I’m finding the files by starting from the path of the module’s Python script, then the function plistlib.readPlist reads a file and generates a dictionary. It should still be portable to other systems. Here’s what I’m doing:

    self.moduleDir = os.path.dirname(slicer.util.modulePath(self.__module__))
    ...
    clutDir = "Resources/CLUT"
    NIHFile = "NIH.plist"
    NIHFullPath = self.moduleDir+"/"+clutDir+"/"+NIHFile

    import plistlib
    plistOutput = plistlib.readPlist(NIHFullPath)
    plistRed = plistOutput['Red']
    plistGreen = plistOutput['Green']
    plistBlue = plistOutput['Blue']

Then I build a vtkMRMLColorTableNode from these arrays.

Thanks for your previous assistance.
I’m back to trying to get SlicerVMTK to build with my application. I’m working from an application started using cookiecutter. The build is able to identify a dependency on VMTK and build it, but when it gets to building SlicerVMTK via the ExternalProjectDependency.cmake script, it can’t find SuperBuild/External_VMTK.cmake. The line that produces the error message I get is at:

The error I get is:

– Setting EXTENSION_NAME …: SlicerVMTK
– SuperBuild - First pass
CMake Error at /short/pack/PADPlanner-SB/slicersources-src/CMake/ExternalProjectDependency.cmake:858 (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)

I’m fetching the extension code from a repository, and so the extension source is being placed in SlicerExtension-VMTK in the main project-SuperBuild directory. I need help with how to get the build script to find the External_VMTK.cmake file.

It looks like when the build is at the stage of configuring the extension directory for SlicerExtension-VMTK, the value of EXTERNAL_PROJECT_DIR is /short/pack/PADPlanner-SB/slicersources-src/SuperBuild/External_VMTK.cmake, rather than the location of the extension.

@lassoan, @jcfr, any thoughts on this? I may test another extension, because I’m not sure if this is a general problem with including extensions that have dependencies via Slicer_EXTENSION_SOURCE_DIRS, or just with SlicerVMTK. I looked at the elastix extension to see if I could see something SlicerVMTK was missing, and it looked about the same, but apparently that wasn’t the best choice for comparison.

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.