Problem with using absolute pathways in Slicer scripted modules

Hi there.

While implementing my own scripted module, I was required to add a specific executable to the python resources in its cmake file:

  set(MODULE_PYTHON_RESOURCES
  ${ALPHA_SHAPES_3_EXECUTABLE}
  Resources/Icons/${MODULE_NAME}.png
  )

The path of ${ALPHA_SHAPES_3_EXECUTABLE} is absolute, I double checked using the IS_ABSOLUTE function.

However, upon execution, it misreads this absolute path as a relative path, which causes build errors. I’ve narrowed down the problem to ctkMacroCompilePythonScript.cmake.

  if(DEFINED MY_RESOURCES)
    set(resource_input_files)
    foreach(file ${MY_RESOURCES})
      if(NOT IS_ABSOLUTE ${file})
        set(src "${MY_SOURCE_DIR}/${file}")
      else()
        set(src "${file}")
      endif()
      set_property(GLOBAL APPEND PROPERTY
      _CTK_${target}_PYTHON_RESOURCES "${src}|${file}|${MY_DESTINATION_DIR}")
    endforeach()
  endif()

The code runs into the problem upon setting the tgt:

list(GET tuple 0 src)
list(GET tuple 1 tgt_file)
list(GET tuple 2 dest_dir)
set(tgt ${dest_dir}/${tgt_file})

where tgt_file is taken as the entire filepath, not just the file name - even for absolute paths.

In an attempt to fix the issue, I made the following changes, but it seems to crash CTK:

if(DEFINED MY_RESOURCES)
    set(resource_input_files)
    foreach(file ${MY_RESOURCES})
      if(NOT IS_ABSOLUTE ${file})
        set(src "${MY_SOURCE_DIR}/${file}")
	set_property(GLOBAL APPEND PROPERTY
        _CTK_${target}_PYTHON_RESOURCES "${src}|${file}|${MY_DESTINATION_DIR}")
      else()
	set(src "${file}")
	get_filename_component(tgt_file_only ${file} NAME)
	set_property(GLOBAL APPEND PROPERTY
        _CTK_${target}_PYTHON_RESOURCES "${src}|${tgt_file_only}|${MY_DESTINATION_DIR}")
      endif()
    endforeach()
  endif()

Any guidance would me much appreciated.

Thanks,

Purav

Executable is not really a resource file, as it has to be placed in specific location to allow it to run, maybe fix up rpath (for MacOSX), etc. Do you build the executable? Is that open-source? If yes, then follow the pattern used by SlicerElastix.

Yup, the executable is built from open source code that I modified. I find the .exe using cmake, by having it as one of the flags, and the reason I wish to list it as a resource is to have it copied to the destination directory (where the .py files of the extension are copied to).

The cmake and source code changes I made work locally without having slicer rebuilt, however the code edit seems to break CTK.

OK, then follow what is done in SlicerElastix - it does exactly what you need (downloads & builds the external library, passes targets to the Slicer extension, adds it to the extension package, etc.). Another example is SegmentMesher.

I would prefer not to download and build the external library every time, given its size, and given that it has hundreds of executables, only 1 of which I wish to use. If there is a way to tackle this issue using the code I wrote/modified, please let me know. Otherwise I’ll resort to the extensions you mentioned above.

If you just need alpha shapes algorithm, then you can use Markups To Model extension. It can create a 3D surface mesh from a sparse set of points. It uses vtkDelaunay3D filter. To enable alpha shapes, set Convexity (Alpha) parameter to >0.

There may be other relevant modules, so in general, before writing any custom extension it is useful to write to the forum what your goal is and ask if anyone has implemented a similar solution already.

If you need to use a specific alpha shapes implementation and not the one in VTK then there are a couple of options:

  • A. Building it as part of your module. It is the proper way, it ensures that the library is built and packaged properly for any platform that Slicer uses. If the library build system uses CMake and it is modularized then you can configure to build only the components that you need. See SlicerElastix, SegmentMesher extensions as examples.
  • B. If an algorithm is in a widely used library (such as OpenCV, CGAL, …) then an option is to build that library with all commonly needed features enabled as a Slicer extension. Then, other extensions that need features from this library can depend on this extension. This has already been implemented for OpenCV but it can be done for other libraries, too. See SlicerOpenCV extension as an example.
  • C. Download binaries. See how ScreenCapture module downloads ffmpeg executable.
  • D. Add compiled binaries to your extension. Create a target that “builds” the binary by simply copying the file corresponding to the current platform. Add the binary to the extension package by appending installation information to CPACK_INSTALL_CMAKE_PROJECTS variable.
2 Likes

Thanks Andras, I ended up creating a module using the vtkDelaunay3D filter - I didn’t even realize it existed.

1 Like