Medical Imaging Interaction Toolkit  2026.06.00
Medical Imaging Interaction Toolkit
Packaging and Installation

Overview

MITK uses CMake's native install and packaging infrastructure to produce redistributable packages on Windows, Linux, and macOS. The system is built around runtime dependency sets that collect all targets during configuration and resolve their transitive shared-library dependencies at install time. On Windows and Linux, a single set (mitk_deps) is used. On macOS, each app bundle gets its own set (e.g. mitk_deps_MitkWorkbench, mitk_deps_MitkFlowBench) so that dependency resolution is fully independent per bundle.

The high-level flow is:

  1. Each target creation site (mitk_create_module(), mitk_create_executable(), mitkFunctionInstallCTKPlugin()) registers its target with all dependency sets and installs into all bundle directories. BlueBerry applications are not registered with the dependency sets because their transitive dependencies are already covered by the modules they link to.
  2. At the end of the top-level CMakeLists.txt, mitkInstallRules.cmake is included. It installs special-case targets (CppMicroServices, Python), resolves all transitive dependencies, and deploys Qt.
  3. CPack picks up the resulting install tree and produces platform-specific packages.

Two-Phase Build Recap

MITK uses a SuperBuild pattern with two distinct CMake phases:

  1. SuperBuild phase (SuperBuild.cmake): Downloads, configures, builds, and installs (most) external dependencies (ITK, VTK, CTK, DCMTK, Boost, Python3, pybind11, etc.) into an external project prefix (ep/). Each external project is configured with a shared CMAKE_INSTALL_RPATH so its libraries can find each other at runtime.
  2. MITK build phase (top-level CMakeLists.txt): Builds MITK modules, plugins, and applications. Uses find_package() to locate the externals installed by the SuperBuild. All install rules target this phase.

External projects are built and installed into the SuperBuild prefix. The MITK build itself lives in MITK-superbuild/MITK-build/. Only the MITK build phase generates install/package rules — the SuperBuild phase does not install anything into the final package directly. Instead, the runtime dependency resolution in mitkInstallRules.cmake finds and copies external libraries from the SuperBuild prefix.

Install Architecture

The RUNTIME_DEPENDENCY_SET Approach

CMake 3.21+ provides install(RUNTIME_DEPENDENCY_SET), which collects targets and resolves their transitive shared-library dependencies at install time.

The dependency set names are stored in the MITK_RUNTIME_DEPENDENCY_SETS list variable. On Windows/Linux this contains a single entry (mitk_deps). On macOS, there is one entry per bundle (e.g. mitk_deps_MitkWorkbench, mitk_deps_MitkFlowBench). This list is parallel to MITK_INSTALL_BINDIR and MITK_INSTALL_FRAMEWORKSDIR — all three have matching indices.

Every installable target registers with all dependency sets and installs into all bundle directories using foreach(... IN ZIP_LISTS ...):

foreach(_bindir _depset IN ZIP_LISTS MITK_INSTALL_BINDIR MITK_RUNTIME_DEPENDENCY_SETS)
install(TARGETS MyTarget
RUNTIME_DEPENDENCY_SET ${_depset}
RUNTIME DESTINATION ${_bindir}
LIBRARY DESTINATION ${_bindir})
endforeach()

At the end of configuration, mitkInstallRules.cmake resolves each dependency set independently:

foreach(_bindir _fwdir _depset IN ZIP_LISTS MITK_INSTALL_BINDIR MITK_INSTALL_FRAMEWORKSDIR MITK_RUNTIME_DEPENDENCY_SETS)
install(RUNTIME_DEPENDENCY_SET ${_depset}
PRE_EXCLUDE_REGEXES ... # Skip Windows system DLLs
POST_EXCLUDE_REGEXES ... # Skip system libraries, Python, plugin dirs, Qt frameworks (macOS)
DIRECTORIES ${_search_dirs}
RUNTIME DESTINATION ${_bindir}
LIBRARY DESTINATION ${_fwdir}
FRAMEWORK DESTINATION ${_fwdir})
endforeach()

Note that LIBRARY DESTINATION uses the Frameworks directory, not the binary directory. On Windows and Linux both resolve to bin/, so there is no difference. On macOS, this places resolved transitive dependencies (external dylibs) into Contents/Frameworks/ rather than Contents/MacOS/. This is necessary because macdeployqt (called by qt_generate_deploy_app_script()) hardcodes Contents/Frameworks/ as the destination for all non-framework dylibs and rewrites binary references accordingly. Using the same destination for both mechanisms avoids duplication. MITK modules in Contents/MacOS/ find these dependencies via their @loader_path/../Frameworks RPATH entry.

This replaces the legacy approach of manually walking targets with BundleUtilities or hand-maintained install loops.

Install Destination Variables

All install destinations use three parallel list variables defined in CMakeLists.txt after MACOSX_BUNDLE_NAMES is populated:

Variable macOS (with bundles) Windows / Linux
MITK_INSTALL_BINDIR <Bundle>.app/Contents/MacOS (one per bundle) bin
MITK_INSTALL_FRAMEWORKSDIR <Bundle>.app/Contents/Frameworks (one per bundle) bin
MITK_RUNTIME_DEPENDENCY_SETS mitk_deps_<Bundle> (one per bundle) mitk_deps

On macOS, these are lists with one entry per app bundle. On Windows/Linux, they are single-element lists. Install sites loop over them with foreach(... IN ZIP_LISTS ...) so the same code handles both cases. MITK's own targets (modules, executables, CppMicroServices) are installed to each MITK_INSTALL_BINDIR (Contents/MacOS/), while resolved transitive dependencies (external libraries) and frameworks go to each MITK_INSTALL_FRAMEWORKSDIR (Contents/Frameworks/).

Dependency Filtering

The single resolution call uses two layers of filtering:

PRE_EXCLUDE_REGEXES (matched against the dependency filename before searching):

  • api-ms-*, ext-ms-* — Windows API sets
  • msvcp*, vcruntime*, concrt*, vcomp*, ucrtbase — Visual C++ runtime (deployed separately via InstallRequiredSystemLibraries)

POST_EXCLUDE_REGEXES (matched against the full resolved path):

  • [/\\]Windows[/\\] — Windows system directory (case-insensitive)
  • /usr/lib, /lib, /System — Linux/macOS system libraries
  • python3[0-9]+. — Python shared library (installed separately)
  • .*/plugins/.* — Qt/CTK plugins (deployed by Qt deployment or CTK plugin install)
  • .*Qt[A-Z].*\.framework.* — Qt frameworks on macOS (deployed by qt_generate_deploy_app_script())
  • .*/Qt[A-Z].*\.dylib$ — Qt dylibs in non-framework form (same reason)

Search Directories

The DIRECTORIES argument tells CMake where to look for dependencies. These are provided by mitkFunctionGetLibrarySearchPaths(), which collects:

  • MITK runtime and library output directories
  • External project prefix (ep/bin, ep/lib)
  • OpenSSL binary directory
  • Additional module library search paths (from MITK_ADDITIONAL_LIBRARY_SEARCH_PATHS global property)
  • Python directories
  • CTK library directories
  • Qt library directory (via qmake -query QT_INSTALL_LIBS / QT_INSTALL_BINS)
  • Per-external-project paths from MITK-AdditionalLibPaths/*.cmake files

Ordering in CMakeLists.txt

The include(mitkInstallRules) call must appear after all targets have been created (Modules, Plugins, Applications, Examples) so that the dependency set is complete:

add_subdirectory(Utilities)
add_subdirectory(Modules)
# ... Plugins, Applications, Examples ...
include(mitkInstallRules) # Must come last

Target Types and Their Install Rules

Modules (Shared Libraries)

Created by mitk_create_module() in mitkFunctionCreateModule.cmake. Non-static, non-executable modules are installed to each bundle's binary directory and registered with each dependency set:

foreach(_bindir _depset IN ZIP_LISTS MITK_INSTALL_BINDIR MITK_RUNTIME_DEPENDENCY_SETS)
install(TARGETS ${MODULE_TARGET}
RUNTIME_DEPENDENCY_SET ${_depset}
RUNTIME DESTINATION ${_bindir}
LIBRARY DESTINATION ${_bindir})
endforeach()

Autoload Modules

Modules that specify AUTOLOAD_WITH <ParentModule> are installed into a subdirectory named after the parent module:

foreach(_bindir _depset IN ZIP_LISTS MITK_INSTALL_BINDIR MITK_RUNTIME_DEPENDENCY_SETS)
install(TARGETS ${MODULE_TARGET}
RUNTIME_DEPENDENCY_SET ${_depset}
RUNTIME DESTINATION ${_bindir}/${MODULE_AUTOLOAD_WITH}
LIBRARY DESTINATION ${_bindir}/${MODULE_AUTOLOAD_WITH})
endforeach()

At runtime, CppMicroServices automatically loads these modules when the parent module is loaded.

On Linux, autoload modules get INSTALL_RPATH "$ORIGIN/.." so they can find libraries in the parent bin/ directory. On macOS, they get INSTALL_RPATH "@loader_path/.." for the same reason.

Plugins (CTK/BlueBerry)

MITK plugins are installed by mitkFunctionInstallCTKPlugin(), called from mitkFunctionCreatePlugin(). Non-imported plugins register with the dependency set:

install(TARGETS ${_install_target}
RUNTIME_DEPENDENCY_SET ${_depset}
RUNTIME DESTINATION ${install_subdir}
LIBRARY DESTINATION ${install_subdir})

The plugin install function receives the dependency set name and destination per bundle from its caller, which loops over MACOSX_BUNDLE_NAMES.

Third-party (imported) CTK plugins are installed via install(FILES ...) since they are not CMake targets in the current project. On Linux, their RPATH is set post-install using file(RPATH_SET). On macOS, install_name_tool -add_rpath is used instead because file(RPATH_SET) only supports ELF and XCOFF formats, not Mach-O.

Plugins get INSTALL_RPATH "$ORIGIN/.." on Linux and INSTALL_RPATH "@loader_path/.." on macOS to resolve libraries in the parent directory (bin/ or Contents/MacOS/).

The CTK core libraries (libCTKCore, libCTKWidgets, libCTKPluginFramework, libCTKDICOMCore, libCTKDICOMWidgets, libCTKXNATCore) are not installed by any of the CTK-aware helpers above. They are pulled into the package as transitive dependencies of MITK plugins by install(RUNTIME_DEPENDENCY_SET). Because CTK has INSTALL_COMMAND "" (see CMakeExternals/CTK.cmake), CTK_DIR points directly at the CTK build tree, and those libraries retain their build-tree RPATH — which on Linux contains absolute paths from the build host (Qt install prefix and the CTK build directory itself). install(RUNTIME_DEPENDENCY_SET) does not rewrite RPATHs on copied files, so without further action the packaged bundle is non-relocatable: on another machine, the loader may follow the baked-in paths into unrelated library trees and trigger ABI mismatches. To prevent this, mitkInstallRules.cmake runs a post-install install(CODE ...) step on Linux that globs libCTK*.so* in each bundle's bin/ and resets their RUNPATH to $ORIGIN using file(RPATH_SET). macOS does not need the equivalent because macdeployqt rewrites library references during Qt deployment, and Windows has no RPATH.

Executables

Created by mitk_create_executable() (in mitkMacroCreateExecutable.cmake), which wraps mitk_create_module() with the EXECUTABLE option. Executables are installed to each bundle's binary directory with a wrapper script (Linux/Windows only — macOS executables are inside the bundle):

foreach(_bindir _depset IN ZIP_LISTS MITK_INSTALL_BINDIR MITK_RUNTIME_DEPENDENCY_SETS)
install(TARGETS ${EXECUTABLE_TARGET}
RUNTIME_DEPENDENCY_SET ${_depset}
RUNTIME DESTINATION ${_bindir})
endforeach()

Command-line apps (created via mitkFunctionCreateCommandLineApp()) follow the same path but their wrapper scripts go into apps/ instead of the install root.

BlueBerry Applications

Created by mitkFunctionCreateBlueBerryApplication(). These are Qt-based GUI applications that additionally:

  • Set the MITK_DEPLOY_QT target property to TRUE
  • Install third-party CTK plugins via mitkFunctionInstallThirdPartyCTKPlugins()
  • Create and install provisioning files
  • Get a platform-specific wrapper script
install(TARGETS ${_APP_NAME}
RUNTIME DESTINATION bin # Windows/Linux
BUNDLE DESTINATION .) # macOS .app bundle

BlueBerry applications are not registered with the dependency sets because they only link to MITK modules that are themselves registered — their transitive dependencies are fully covered.

CppMicroServices

The CppMicroServices library is a special case. It is built via usMacroCreateModule() (not mitk_create_module()), is not tracked in MITK_MODULE_TARGETS, and has US_NO_INSTALL=1 to disable its own install rules. It must be explicitly installed in mitkInstallRules.cmake:

foreach(_bindir _depset IN ZIP_LISTS MITK_INSTALL_BINDIR MITK_RUNTIME_DEPENDENCY_SETS)
install(TARGETS CppMicroServices
RUNTIME_DEPENDENCY_SET ${_depset}
RUNTIME DESTINATION ${_bindir}
LIBRARY DESTINATION ${_bindir}
PUBLIC_HEADER DESTINATION include/CppMicroServices EXCLUDE_FROM_ALL
PRIVATE_HEADER DESTINATION include/CppMicroServices EXCLUDE_FROM_ALL)
endforeach()

The EXCLUDE_FROM_ALL on header destinations suppresses warnings about the unused header install components.

See also the dedicated CppMicroServices Resource Embedding section below for how CppMicroServices resource embedding affects packaging.

Python

When MITK_USE_Python3 is enabled, the entire Python distribution from the build tree is copied into the package, and the MITK Python bindings (mitk_python_bindings target) are installed into the appropriate site-packages directory:

foreach(_fwdir _depset IN ZIP_LISTS MITK_INSTALL_FRAMEWORKSDIR MITK_RUNTIME_DEPENDENCY_SETS)
if(APPLE)
set(_python_dest "${_fwdir}/Python.framework")
else()
set(_python_dest "python")
endif()
install(DIRECTORY "${MITK_BINARY_DIR}/python/"
DESTINATION ${_python_dest}
USE_SOURCE_PERMISSIONS)
install(TARGETS mitk_python_bindings
RUNTIME_DEPENDENCY_SET ${_depset}
RUNTIME DESTINATION ${_python_dest}/${_rel_sitearch}/mitk
LIBRARY DESTINATION ${_python_dest}/${_rel_sitearch}/mitk)
endforeach()

On macOS, the destination is ${_fwdir}/Python.framework which resolves to <Bundle>.app/Contents/Frameworks/Python.framework for each bundle.

Qt Deployment

Qt deployment is handled by mitkFunctionDeployQt() in mitkFunctionDeployQt.cmake. It runs after the runtime dependency resolution, so that tools like windeployqt can see all MITK DLLs already present in bin/ and correctly trace their transitive Qt dependencies.

Only targets with the MITK_DEPLOY_QT property set to TRUE trigger Qt deployment. Currently, only BlueBerry applications set this property.

Why Two Different Qt Deploy Functions?

Qt provides two deployment entry points:

  • qt_generate_deploy_app_script() — designed for structured application layouts, specifically macOS .app bundles. It handles the Contents/Frameworks/, Contents/PlugIns/, Contents/Resources/ layout automatically.
  • qt_generate_deploy_script() — a lower-level function that generates a custom CMake install script. It accepts a CONTENT parameter with arbitrary CMake code, giving full control over deployment behavior.

MITK uses qt_generate_deploy_app_script() only on macOS (for .app bundles). On Windows and Linux, MITK uses qt_generate_deploy_script() with qt_deploy_runtime_dependencies() embedded in the CONTENT because:

  1. There are no app bundles on these platforms — the install layout is a flat bin/ directory.
  2. Qt's default FHS-style paths (lib/, libexec/, plugins/) do not match MITK's portable bin/-centric layout.
  3. Platform-specific options (e.g. windeployqt flags) must be passed through.

Platform-Specific Behavior

macOS: Uses qt_generate_deploy_app_script() which delegates to macdeployqt. This tool scans all binaries in the bundle, copies their non-system dependencies into Contents/Frameworks/, rewrites library references, and deploys Qt plugins to Contents/PlugIns/. Because macdeployqt hardcodes Contents/Frameworks/ as the destination for all non-framework dylibs (with no option to override this), the install(RUNTIME_DEPENDENCY_SET) resolution also targets Contents/Frameworks/ via LIBRARY DESTINATION ${MITK_INSTALL_FRAMEWORKSDIR}. This way macdeployqt overwrites (via -always-overwrite) rather than creating duplicates. Qt frameworks are excluded from install(RUNTIME_DEPENDENCY_SET) via POST_EXCLUDE_REGEXES to avoid conflicting with macdeployqt's framework deployment.

Windows: Uses qt_generate_deploy_script() with qt_deploy_runtime_dependencies(). The --no-opengl-sw option is passed to windeployqt to skip the software OpenGL fallback. If OpenSSL is available, its root directory is passed via --openssl-root.

After deployment, a post-install step moves resources/ and translations/ directories from the install prefix root into bin/, because windeployqt places them at the prefix root level and provides no option to change this.

Linux: Uses qt_generate_deploy_script() with overridden QT_DEPLOY_* variables so that everything goes under bin/ instead of the default FHS-style directories:

set(QT_DEPLOY_BIN_DIR "bin")
set(QT_DEPLOY_LIB_DIR "bin")
set(QT_DEPLOY_LIBEXEC_DIR "bin")
set(QT_DEPLOY_PLUGINS_DIR "bin/plugins")
set(QT_DEPLOY_QML_DIR "bin/qml")
set(QT_DEPLOY_TRANSLATIONS_DIR "bin/translations")
set(QT_DEPLOY_DATA_DIR "bin")

Without these overrides, Qt would deploy libraries to lib/, executables to libexec/, plugins to plugins/ at the prefix root, etc. — scattering files across the install tree and breaking MITK's RPATH-based portable layout.

These overrides also affect internal deployment hooks (e.g. the WebEngine deployment hook), which is critical: it ensures that QtWebEngineProcess, resource .pak files, and locale data all land under bin/ rather than at the prefix root.

The qt.conf Problem on Linux

After the Qt deploy script runs on Linux, qt.conf is overwritten. The reason: Qt's WebEngine deployment hook generates qt.conf with an absolute staging path as the prefix (e.g. /tmp/cpack-staging/install/bin). This makes the deployment non-relocatable.

The fixup overwrites it with a correct relative prefix:

[Paths]
Prefix = .

Since qt.conf lives in bin/ and the prefix is ., Qt looks for plugins at bin/plugins/, QML modules at bin/qml/, etc. — all relative to bin/.

This fixup is fragile. If Qt's internal deployment hooks change their qt.conf generation behavior in a future version, the overwrite may need to be adjusted.

RPATH Configuration

RPATH is configured per platform to ensure that shared libraries can find each other at runtime.

Global RPATH (MITK Build)

Set in the top-level CMakeLists.txt for all MITK targets:

if(LINUX)
set(CMAKE_INSTALL_RPATH "$ORIGIN;$ORIGIN/plugins")
elseif(APPLE)
set(CMAKE_INSTALL_RPATH "@loader_path;@loader_path/plugins;@loader_path/../Frameworks")
set(CMAKE_MACOSX_RPATH TRUE)
endif()

This means most installed binaries look for libraries in their own directory, in plugins/ relative to their location, and on macOS additionally in ../Frameworks/ (for external dependencies and Qt frameworks in Contents/Frameworks/). On macOS, @rpath entries propagate up the dynamic loader chain: when the executable loads a plugin, the plugin can resolve @rpath references using the executable's RPATHs in addition to its own. This is why plugins with only @loader_path/.. can still find libraries in Contents/Frameworks/ — via the executable's @loader_path/../Frameworks entry.

SuperBuild RPATH (External Projects)

External projects are configured with a separate RPATH in SuperBuild.cmake:

# macOS
set(_install_rpath "@loader_path/../lib")
# Linux
set(_install_rpath "$ORIGIN:$ORIGIN/../lib")
if(Qt6_DIR)
set(_install_rpath "${_install_rpath}:${Qt6_DIR}/../..")
endif()

This ensures external project libraries can find each other within the SuperBuild prefix during the build. At package time, these RPATHs are irrelevant since the dependency resolver copies all needed libraries into bin/ (Windows/Linux) or Contents/Frameworks/ (macOS).

Per-Target RPATH Overrides

Target type RPATH (Linux) RPATH (macOS) Reason
Regular modules $ORIGIN;$ORIGIN/plugins @loader_path;@loader_path/plugins;@loader_path/../Frameworks Global default — find peers, plugins, and Qt frameworks
Autoload modules $ORIGIN/.. @loader_path/.. Installed in <parent>/ subdir, must find libs in parent dir
Plugins $ORIGIN/.. @loader_path/.. Installed in plugins/, must find libs in parent dir
Imported CTK plugins $ORIGIN/.. (via file(RPATH_SET)) @loader_path/.. (via install_name_tool) Same as plugins, but set post-install since they are imported targets
Executables $ORIGIN;$ORIGIN/plugins @loader_path;@loader_path/plugins;@loader_path/../Frameworks Global default

On Windows, RPATH does not apply. DLLs are found via the executable's directory and PATH.

Wrapper Scripts

Wrapper scripts launch MITK executables from the install root. They exist because executables are installed in bin/ but the user runs them from the install root (or a start menu shortcut).

Windows

Script Used by Behavior
RunInstalledWin32App.bat BlueBerry apps start "" /B "%~dp0bin\%~n0.exe" -style windowsvista %* — launches detached with Qt style
RunInstalledApp.bat Regular executables "%~dp0bin\%~n0.exe" %* — direct launch from root
RunInstalledCmdLineApp.bat Command-line apps "%~dp0..\bin\%~n0.exe" %* — launch from apps/ subdirectory

Linux

Script Used by Behavior
RunInstalledApp.sh Regular executables and BlueBerry apps Sets LD_LIBRARY_PATH to include bin/ and python/lib, then launches bin/<name>
RunInstalledCmdLineApp.sh Command-line apps Same but resolves paths from apps/ subdirectory

On Linux, the wrapper scripts prepend bin/ and python/lib to LD_LIBRARY_PATH. python/lib is required for the Python shared library to be found at runtime. bin/ is a defensive layer: LD_LIBRARY_PATH takes precedence over a library's RUNPATH, so even if a bundled external .so carries a stale build-tree RPATH entry that happens to match a real directory on the user's machine, the bundled libraries in bin/ are loaded first. The CTK RUNPATH fixup in mitkInstallRules.cmake addresses the root cause for CTK specifically; this wrapper-script layer protects against the same class of failure for other externals and for the case of running the raw executable directly through the wrapper.

CPack Configuration

CPack configuration is in mitkSetupCPack.cmake.

Generators

Platform Generator(s)
Windows ZIP (always), NSIS (optional, if makensis is found)
macOS DragNDrop
Linux TGZ

Versioning and Naming

The package version is derived from MITK_REVISION_DESC (a git-based version string). If not available, it falls back to MITK_VERSION_MAJOR.MINOR.PATCH.

The package filename follows the pattern:

MITK-<version>-<platform-arch>

Platform-arch examples: windows-x86_64, ubuntu-22.04-x86_64, macos-14.0-arm64.

On Linux, the distribution name and version are read from /etc/os-release.

NSIS Settings

  • Install root defaults to $PROGRAMFILES64 on 64-bit Windows
  • Start menu shortcuts are collected in MITK_CPACK_PACKAGE_EXECUTABLES by mitkFunctionCreateBlueBerryApplication()

Strip Policy

Stripping is disabled globally (CPACK_STRIP_FILES OFF). See the CppMicroServices Resource Embedding section for the detailed explanation of why this is necessary and how it could be improved in the future.

macOS Post-Build Script

On macOS, CPack runs FixMacOSInstaller.cmake (generated from FixMacOSInstaller.cmake.in) as a post-build step. This script:

  1. Converts the Python directory into a proper Python.framework (required for code signing)
  2. Fixes @executable_path references in the mitk Python module to use @loader_path
  3. Signs the app bundle with codesign

Library Search Paths

mitkFunctionGetLibrarySearchPaths() serves a dual purpose:

  1. Build time: Provides directories for PATH / LD_LIBRARY_PATH in batch scripts and test runners
  2. Install time: Provides DIRECTORIES for install(RUNTIME_DEPENDENCY_SET) to locate dependencies

The function collects paths from:

Source Paths
MITK build tree Runtime and library output directories
External project prefix ep/bin, ep/lib
OpenSSL Derived from IMPORTED_LOCATION of OpenSSL::SSL
Module additional libs MITK_ADDITIONAL_LIBRARY_SEARCH_PATHS global property
Python python/ (Windows) or python/lib (Linux/macOS)
CTK CTK_LIBRARY_DIRS and per-library dirs
Qt QT_INSTALL_BINS (Windows) or QT_INSTALL_LIBS (Linux/macOS)
SuperBuild external projects MITK-AdditionalLibPaths/*.cmake files (via mitkFunctionAddLibrarySearchPaths())

External projects register their library paths via mitkFunctionAddLibrarySearchPaths(), which writes per-configuration path info into MITK-AdditionalLibPaths/<name>.cmake files. These are picked up automatically by mitkFunctionGetLibrarySearchPaths().

Directory Layout

Windows / Linux

<install-root>/
├── MitkWorkbench.bat/.sh # Wrapper scripts (install root)
├── apps/
│ └── MitkFileConverter.bat/.sh # Command-line app wrappers
├── bin/
│ ├── MitkWorkbench.exe # Executables
│ ├── MitkFileConverter.exe
│ ├── MitkWorkbench.provisioning # Provisioning files
│ ├── *.dll / *.so # MITK modules + resolved dependencies
│ ├── mitk.ico, mitk.bmp # Icons (Windows only)
│ ├── qt.conf # Qt configuration
│ ├── CppMicroServices.dll/.so # CppMicroServices library
│ ├── MitkCore/ # Autoload module subdirectories
│ │ └── MitkPreloadPython.dll/.so
│ ├── plugins/ # CTK/BlueBerry and Qt plugins
│ │ ├── org_mitk_gui_qt_*.dll/.so
│ │ ├── org_blueberry_*.dll/.so
│ │ ├── imageformats/ # Qt plugin subdirectories
│ │ └── platforms/
│ ├── resources/ # Qt WebEngine resources
│ │ └── *.pak
│ └── translations/ # Qt translations
└── python/ # Python distribution (if enabled)
├── bin/ or python.exe
└── lib/
└── python3.X/
└── site-packages/
└── mitk/ # MITK Python bindings

macOS

<install-root>/
└── MitkWorkbench.app/
└── Contents/
├── MacOS/
│ ├── MitkWorkbench # Main executable
│ ├── MitkWorkbench.provisioning # Provisioning file
│ ├── libMitk*.dylib # MITK modules
│ ├── libCppMicroServices.dylib # CppMicroServices
│ ├── MitkCore/ # Autoload module subdirectories
│ │ └── libMitkPreloadPython.dylib
│ └── plugins/ # CTK/BlueBerry plugins
│ ├── liborg_mitk_gui_qt_*.dylib
│ └── liborg_blueberry_*.dylib
├── Frameworks/
│ ├── Qt*.framework/ # Qt frameworks (deployed by macdeployqt)
│ ├── qwt.framework
│ ├── lib*.dylib # External dependencies (ITK, VTK, DCMTK, CTK, Boost, etc.)
│ └── Python.framework/ # Python (converted from directory)
│ └── Versions/
│ ├── A/
│ │ ├── Python # Python shared library
│ │ ├── bin/
│ │ ├── lib/
│ │ ├── Headers/
│ │ └── Resources/
│ │ └── Info.plist
│ └── Current -> A
├── PlugIns/ # Qt plugins (deployed by macdeployqt)
│ ├── platforms/
│ ├── imageformats/
│ ├── sqldrivers/
│ ├── styles/
│ └── ...
└── Resources/
└── icon.icns

MITK's own code (modules, executables, CppMicroServices, CTK/BlueBerry plugins) lives in Contents/MacOS/. Third-party dependencies and frameworks live in Contents/Frameworks/. This separation follows Apple's bundle conventions and avoids duplication with macdeployqt, which hardcodes Contents/Frameworks/ as the destination for all non-system shared libraries.

External Project Special Cases

Boost DLL Relocation (Windows)

Boost builds its DLLs into lib/. A post-install step (Boost-post_install-WIN32.cmake) moves them to bin/ so they are found alongside other DLLs:

file(GLOB boost_dlls boost_*.dll)
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ../bin)
foreach(boost_dll ${boost_dlls})
execute_process(COMMAND ${CMAKE_COMMAND} -E copy ${boost_dll} ../bin)
execute_process(COMMAND ${CMAKE_COMMAND} -E remove ${boost_dll})
endforeach()

Boost macOS RPATH

Boost does not follow the common practice of using @rpath for inter-library references on macOS. A post-install step (Boost-post_install-APPLE.cmake) fixes this with install_name_tool:

foreach(boost_dylib ${boost_dylibs})
execute_process(COMMAND install_name_tool -id @rpath/${boost_dylib} ${boost_dylib})
foreach(other_boost_dylib ${boost_dylibs})
execute_process(COMMAND install_name_tool -change ${other_boost_dylib}
@rpath/${other_boost_dylib} ${boost_dylib})
endforeach()
endforeach()

External CMake Project Installation

mitkFunctionInstallExternalCMakeProject() allows running an external project's install script directly:

function(mitkFunctionInstallExternalCMakeProject ep_name)
ExternalProject_Get_Property(${ep_name} binary_dir)
install(SCRIPT ${binary_dir}/cmake_install.cmake)
endfunction()

This is used for external projects that need their own install logic beyond what the dependency resolver handles.

macOS-Specific Details

App Bundles

On macOS, BlueBerry applications are built as .app bundles (MACOSX_BUNDLE). The bundle properties (name, identifier, version, icon) are set in mitkFunctionCreateBlueBerryApplication().

Python Framework Conversion

For code signing, macOS requires frameworks to follow a specific directory structure. The FixMacOSInstaller.cmake script converts the flat Python directory into Python.framework with the standard versioned layout:

Python.framework/
├── Versions/
│ ├── A/
│ │ ├── Python # Renamed from lib/libpython3.X.dylib
│ │ ├── bin/
│ │ ├── lib/
│ │ │ └── libpython3.X.dylib -> ../Python # Symlink back
│ │ ├── Headers/ # Moved from include/python3.X
│ │ ├── share/
│ │ └── Resources/
│ │ └── Info.plist
│ └── Current -> A
├── Headers -> Versions/Current/Headers
├── Python -> Versions/Current/Python
└── Resources -> Versions/Current/Resources

Code Signing and Entitlements

All app bundles are signed with codesign using the identity specified by MITK_CODESIGN_IDENTITY. The entitlements file (CMake/entitlements.plist) grants:

  • com.apple.security.cs.disable-library-validation — allows loading unsigned or differently-signed shared libraries (needed for plugins and Python modules)
  • com.apple.security.cs.allow-jit — allows JIT compilation (needed for some Python operations)

Python Module <tt>@loader_path</tt> Fix

The FixMacOSInstaller.cmake script fixes library dependency paths in the mitk Python module. macdeployqt rewrites dependency references to use @executable_path/../MacOS/, which works for binaries loaded by the main application but breaks when the Python interpreter in Frameworks/Python.framework/Versions/A/bin tries to load the mitk package. The fix rewrites these paths to use @loader_path instead.

Provisioning Files

Provisioning files tell the BlueBerry framework which plugins to load at startup. They use a simple text format:

READ file:///path/to/other.provisioning
START file:///path/to/plugin.so

mitkFunctionCreateProvisioningFile() creates two variants:

  1. Build-time (<AppName>.provisioning): Uses absolute file:/// URLs pointing to the build tree
  2. Install-time (<AppName>.provisioning.install): Uses @EXECUTABLE_DIR placeholders that resolve relative to the executable at runtime

The install-time variant is installed to each bundle's binary directory and renamed to drop the .install suffix. For example:

START file://@EXECUTABLE_DIR/plugins/liborg_mitk_gui_qt_common.so

CppMicroServices Resource Embedding

CppMicroServices allows modules to embed resources (XML descriptors, icons, etc.) as ZIP archives inside the shared library file itself. This mechanism has a direct impact on packaging because it constrains whether binaries can be stripped.

Two Embedding Modes: APPEND vs LINK

The usFunctionEmbedResources() function in Modules/CppMicroServices/cmake/usFunctionEmbedResources.cmake supports two modes:

APPEND mode (default on Windows and Linux):

The ZIP archive is literally appended as raw bytes after the end of the ELF/PE binary structure:

add_custom_command(
TARGET ${US_RESOURCE_TARGET}
POST_BUILD
COMMAND ${resource_compiler} --append $<TARGET_FILE:${US_RESOURCE_TARGET}> ${_zip_archive}
...)

The usResourceCompiler opens the shared library in binary append mode and writes the ZIP at the end. At runtime, CppMicroServices uses the miniz library to search for the ZIP central directory signature from the end of the file — standard ZIP behavior that works even when the ZIP is concatenated after other data.

LINK mode (default on macOS):

The ZIP archive is compiled into a proper object file section using platform-specific linker techniques:

Platform Technique Section
macOS ld -r -sectcreate __TEXT us_resources <zip> stub.o __TEXT/us_resources
Linux ld -r -b binary + objcopy --rename-section .data=.rodata .rodata
Windows Windows Resource Compiler (.rc file with US_RESOURCE type) PE resource section

The resulting .o or .rc file is linked into the target as a regular object file, making the ZIP part of the binary's official section table.

Default Mode Selection

usFunctionCheckResourceLinking.cmake determines the defaults:

  • macOS: LINK mode (required because codesign validates the binary structure and rejects appended data)
  • Windows: APPEND mode (even though LINK is available via RC compiler)
  • Linux: APPEND mode (even though LINK is available via ld -r -b binary)

The check sets US_DEFAULT_RESOURCE_MODE and US_RESOURCE_LINKING_AVAILABLE as cache variables.

Why Stripping Breaks APPEND Mode

When strip processes an ELF binary, it rewrites the file based on the ELF headers' recorded sections. Everything beyond the official ELF structure — including the appended ZIP archive — is discarded. The stripped binary loads fine, but all CppMicroServices resources are gone, causing runtime failures when modules try to access their embedded resources.

LINK mode survives stripping because the ZIP is stored inside a proper ELF section (.rodata). The strip command preserves allocated sections like .rodata since they are needed at runtime.

Current Impact and Future Improvement

Because MITK uses APPEND mode on Windows and Linux (the default), CPACK_STRIP_FILES must be set to OFF in mitkSetupCPack.cmake. This means all binaries in the package are unstripped, resulting in significantly larger packages.

A future improvement would be to switch CppMicroServices resource embedding to LINK mode on all platforms. This would:

  1. Allow re-enabling CPACK_STRIP_FILES ON to strip debug symbols from all binaries
  2. Eliminate the fragile dependency on file-append ordering
  3. Align all platforms with the same embedding strategy

The trade-off documented in the CppMicroServices source is that LINK mode "may result in slower module initialization and bigger object files." In practice, the initialization overhead is negligible, and the object file size increase is far outweighed by the package size savings from being able to strip debug symbols.

To switch, set US_DEFAULT_RESOURCE_MODE to "LINK" for all platforms in usFunctionCheckResourceLinking.cmake, or pass LINK explicitly in each usFunctionEmbedResources() call.

However, first tests on Windows and Linux revealed, that the LINK mode seems to be broken on these platforms.

Changes from Legacy System

The current install system replaced several legacy approaches:

Legacy Current Why
BundleUtilities / fixup_bundle() install(RUNTIME_DEPENDENCY_SET) BundleUtilities is deprecated in CMake 3.23+; the new approach is declarative and handles edge cases better
Central install loops walking MITK_MODULE_TARGETS Per-target install() at creation site Each target knows its own install destination; no need for a central loop to classify targets
mitkFunctionInstallAutoLoadModules() Inline install in mitk_create_module() Autoload install is now part of module creation; the legacy function has been removed
Manual DLL copying scripts RUNTIME_DEPENDENCY_SET with DIRECTORIES CMake resolves transitive dependencies automatically
Per-target Qt deployment calls Centralized loop in mitkInstallRules.cmake Qt deployment must run after all dependencies are in place

Known Issues and Future Work

  • CPACK_STRIP_FILES is OFF globally: Packages are larger than necessary because all binaries retain debug symbols. The root cause is CppMicroServices APPEND-mode resource embedding. Switching to LINK mode (see CppMicroServices Resource Embedding) would allow re-enabling stripping.
  • macOS autoload modules in Python: The FixMacOSInstaller.cmake @loader_path fix does not cover autoload modules. Importing mitk in a standalone Python interpreter on macOS will not load autoload modules. Running Python as a subprocess of an MITK application works correctly.
  • Qt WebEngine qt.conf on Linux: The Qt WebEngine deployment hook writes qt.conf with an absolute staging path. A post-install step overwrites it, but this is fragile and depends on the hook's behavior not changing across Qt versions.

File Reference

File Purpose
CMake/mitkInstallRules.cmake Central install orchestration: CppMicroServices, Python, dependency resolution, Qt deployment loop
CMake/mitkFunctionDeployQt.cmake mitkFunctionDeployQt() — Qt plugin, qt.conf, and WebEngine deployment
CMake/mitkFunctionCreateModule.cmake mitk_create_module() — module install rules and RPATH overrides
CMake/mitkMacroCreateExecutable.cmake mitk_create_executable() — executable install rules and wrapper scripts
CMake/mitkFunctionCreateCommandLineApp.cmake mitkFunctionCreateCommandLineApp() — wraps mitk_create_executable() with MitkCommandLine dependency
CMake/mitkFunctionCreateBlueBerryApplication.cmake mitkFunctionCreateBlueBerryApplication() — BB app creation, Qt deployment flag, provisioning
CMake/mitkFunctionCreatePlugin.cmake mitkFunctionCreatePlugin() — plugin install rules and RPATH
CMake/mitkFunctionInstallCTKPlugin.cmake mitkFunctionInstallCTKPlugin() — CTK plugin install with dependency set registration
CMake/mitkFunctionInstallThirdPartyCTKPlugins.cmake mitkFunctionInstallThirdPartyCTKPlugins() — installs third-party CTK plugins for an application
CMake/mitkFunctionInstallExternalCMakeProject.cmake mitkFunctionInstallExternalCMakeProject() — runs external project install scripts
CMake/mitkFunctionGetLibrarySearchPaths.cmake mitkFunctionGetLibrarySearchPaths() — collects library search dirs for build and install time
CMake/mitkFunctionAddLibrarySearchPaths.cmake mitkFunctionAddLibrarySearchPaths() — registers external project library paths
CMake/mitkFunctionCreateProvisioningFile.cmake mitkFunctionCreateProvisioningFile() — creates build-time and install-time provisioning files
CMake/mitkSetupCPack.cmake CPack generator selection, versioning, NSIS settings, strip policy
CMake/FixMacOSInstaller.cmake.in macOS post-CPack script: Python framework conversion, @loader_path fix, code signing
CMake/entitlements.plist macOS code signing entitlements
CMake/RunInstalledApp.bat Windows wrapper for regular executables
CMake/RunInstalledWin32App.bat Windows wrapper for BlueBerry (GUI) applications
CMake/RunInstalledCmdLineApp.bat Windows wrapper for command-line apps
CMake/RunInstalledApp.sh Linux wrapper for regular executables and BlueBerry apps
CMake/RunInstalledCmdLineApp.sh Linux wrapper for command-line apps
CMakeExternals/Boost-post_install-WIN32.cmake Moves Boost DLLs from lib/ to bin/
CMakeExternals/Boost-post_install-APPLE.cmake Fixes Boost inter-library references to use @rpath
Modules/CppMicroServices/cmake/usFunctionEmbedResources.cmake APPEND and LINK mode resource embedding into shared libraries
Modules/CppMicroServices/cmake/usFunctionAddResources.cmake Creates ZIP archives from resource files for embedding
Modules/CppMicroServices/cmake/usFunctionCheckResourceLinking.cmake Platform capability detection for LINK mode; sets US_DEFAULT_RESOURCE_MODE
SuperBuild.cmake SuperBuild RPATH configuration for external projects