How to release an extension

When creating a purely scripted (i.e. python only) Slicer extension, what is a good release “object” to create and how do I create it?

Ideally I want something that I can use with the extension manager’s Install from file button

image

I see it’s looking for some kind of zip or tarball, but IDK what exactly

what is a good release “object” to create and how do I create it?
for some kind of zip or tarball, but IDK what exactly

These .tar.gz or .zip files correspond to the extension package generated by building the extension. See Developer Guide/ Extensions Build an extension

Usually, the official Slicer build machine take care of generting the “package” and uploading it to https://slicer-packages.kitware.com/

start Slicer with your python module

This can be done specifying an additional module path. See Application settings — 3D Slicer documentation

1 Like

Thanks. So the extension manager’s Install from file button cannot be used to install a purely scripted module? It has to be done by specifying an additional module path?

The install from file button is intended to install extension packages, which are as @jcfr says are the tar/zip files. When we distribute extensions on the factory machines, pure python extensions are still “built” i.e. cmake and the build system are used to copy and zip the files into the appropriate structure.

The best and most repeatable way to generate the release object is to build and package the extension so that it is compatible with the Slicer extension ecosystem.

1 Like

Here is an example of a “pure python” extension that is built on the factory: GitHub - acetylsalicyl/SlicerRawImageGuess

The important thing is that it must be an extension (and have the appropriate CMake files), not just a module file.

1 Like

And here is the extension package created from the RawImageGuess extension by building the PACKAGE target: https://slicer-packages.kitware.com/api/v1/item/62871f65e8408647b39feaba/download

As you can see, the files are mostly just copied from the source tree, but exactly which files are included in the package and where they are placed and extension metadata (that is saved in the s4ext file in the package) are specified in CMakeLists.txt files, and the package structure is slightly different on macOS than on Linux and Windows.

It would be nice to build extension package from Python-only extensions without having to build Slicer. There could be several options:

  • Option A: Use the build tree in slicer/slicer-base docker image. It may be just a single-line command that you need to write to build a package from your extension’s source tree. Unfortunately, it would only create Linux package.
  • Option B: Create some sham CMake files that would provide an empty Slicer package for find_package and various CMake macros and functions that are used for building an extension. Then CMake could be pip-installed and used for building the package, without a real Slicer build tree and without the need for any additional build tools.
  • Option C: Create an alternative packaging method for Python-only packages. It could be based on a manifest file that would specify extension metadata and list of files to include in the package. We would then need 1. some Python scripts that could create an extension package based on this manifest, and 2. CMake functions, which would allow building and testing the extension based on information in the manifest file.
1 Like

Thank you everyone for the responses. So in the end it is possible to install a purely scripted extension using the “Install from file” button. Piecing it together from the replies above, here is what finally worked for me:

mkdir build
cd build
cmake .. -DSlicer_DIR=path/to/my/slicer/inner/build -DCMAKE_BUILD_TYPE:STRING=Release
make package

This created a tar.gz file that I was then able to use with the “Install from file” button.

(This is sort of explained in a scattered way in the extension guide, but was not very straight forward to tease out for me, partly because I have a poor understanding of build systems :sweat_smile: , so ty for the help)

2 Likes

Ebrahim,

I used the following script to create installation packages for Windows, Mac, and Linux from the created package for a linux machine.

#!/bin/bash
build_dir=../Code/slicerflywheelcaseiterator/build
cp $build_dir/*git*tar.gz ./

# 30822: Slicer-5.0.2
# 30893: Slicer-5.0.3
# 31122: Slicer-5.1.0 (draft)
# 31314: Slicer-5.2.0
# 31317: Slicer-5.2.1
# 31382: Slicer-5.2.2
# 31734: Slicer-5.3.0

declare -A slicer_versions=(
    [5.0.2]="30822"
    [5.0.3]="30893"
    [5.1.0]="31122" # draft
    [5.2.0]="31314"
    [5.2.1]="31317"
    [5.2.2]="31382"
    [5.3.0]="31734"
)

linux_build_tar=*git*.tar.gz
linux_build=`basename --suffix=.tar.gz ${linux_build_tar%%.*}`
ext_num=`echo $linux_build | awk -F'-' '{print $1}'`
ext_name=`echo $linux_build | awk -F'64-' '{print $2}'| awk -F'-git' '{print $1}'`
slicer_base_version=5.3


echo $linux_build_tar
echo $linux_build
echo $ext_num
echo $ext_name

tar xzvf $linux_build_tar

for i in 0 1 2;do
    cp -rf $linux_build/lib/Slicer-$slicer_base_version $linux_build/lib/Slicer-5.$i;
    cp -rf $linux_build/share/Slicer-$slicer_base_version $linux_build/share/Slicer-5.$i;
done

tar czvf $linux_build_tar $linux_build

# create windows build
windows_build=${linux_build/linux/win}
cp -rf $linux_build $windows_build

tar czvf $windows_build.tar.gz $windows_build

## create mac build
mac_build=${linux_build/linux/mac}
for key in "${!slicer_versions[@]}"; do
    slicer_dest_version=${key:0:3}
    dest_ext_num=${slicer_versions[$key]}
    mac_dir=$mac_build/Slicer.app/Contents/Extensions-$dest_ext_num/$ext_name
    echo $mac_dir
    mkdir -p $mac_dir/{lib,share}
    cp -rf $linux_build/lib/Slicer-$slicer_base_version \
           $mac_dir/lib/Slicer-$slicer_dest_version
    cp -rf $linux_build/share/Slicer-$slicer_base_version \
           $mac_dir/share/Slicer-$slicer_dest_version       
done

zip -r $mac_build.zip $mac_build

# # clean up
rm -rf $linux_build
rm -rf $windows_build
rm -rf $mac_build
1 Like