VTK  9.0.20210115
Module Migration

VTK 8.2 and older contained a module system which was based on variables and informed CMake's migration to target-based properties and interactions. This was incompatible with the way VTK ended up doing it. With VTK 9, its module system has been reworked to use CMake's targets.

This document may be used as a guide to updating code using old VTK modules into code using new VTK modules.

Using modules

If your project is just using VTK's modules and not declaring any of your own modules, porting involves a few changes to the way VTK is found and used.

The old module system made variables available for using VTK.

find_package(VTK
REQUIRED
COMPONENTS
vtkCommonCore
vtkRenderingOpenGL2)
include(${VTK_USE_FILE})
add_library(usesvtk ...)
target_link_libraries(usesvtk ${visibility} ${VTK_LIBRARIES})
target_include_directories(usesvtk ${visibility} ${VTK_INCLUDE_DIRS})
# Pass any VTK autoinit defines to the target.
target_compile_definitions(usesvtk PRIVATE ${VTK_DEFINITIONS})

This causes problems if VTK is found multiple times within a source tree with different components. The new pattern is:

find_package(VTK
#9.0 # Compatibility support is not provided if 9.0 is requested.
REQUIRED
COMPONENTS
# Old component names are OK, but deprecated.
#vtkCommonCore
#vtkRenderingOpenGL2
# New names reflect the target names in use.
CommonCore
RenderingOpenGL2)
# No longer needed; warns or errors depending on the version requested when
# finding VTK.
#include(${VTK_USE_FILE})
add_library(usesvtk ...)
# VTK_LIBRARIES is provided for compatibility, but not recommended.
#target_link_libraries(usesvtk ${visibility} ${VTK_LIBRARIES})
target_link_libraries(usesvtk ${visibility} VTK::CommonCore VTK::RenderingOpenGL2)
# Rather than defining a single `VTK_DEFINITIONS` for use by all relevant
# targets, the definitions are made as needed with the exact set needed for the
# listed modules.
vtk_module_autoinit(
TARGETS usesvtk
#MODULES ${VTK_LIBRARIES} # Again, works, but is not recommended.
MODULES VTK::CommonCore VTK::RenderingOpenGL2)

Module declaration

The old module system had CMake code declare modules in module.cmake files. This allowed logic and other things to happen within them which could cause module dependencies to be hard to follow. The new module system now provides facilities for disabling modules in certain configurations (using CONDITION) and for optionally depending on modules (using OPTIONAL_DEPENDS).

if (NOT SOME_OPTION)
set(depends)
if (SOME_OTHER_OPTION)
list(APPEND depends vtkSomeDep)
endif ()
vtk_module(vtkModuleName
GROUPS
# groups the module belongs to
KIT
# the kit the module belongs to
IMPLEMENTS
# modules containing vtkObjectFactory instances that are implemented here
DEPENDS
# public dependencies
#${depends} # no analogy in the new system
PRIVATE_DEPENDS
# private dependencies
${depends}
COMPILE_DEPENDS
# modules which must be built before this one but which are not actually
# linked.
TEST_DEPENDS
# test dependencies
TEST_OPTIONAL_DEPENDS
# optional test dependencies
${depends}
#EXCLUDE_FROM_WRAPPING
# present for modules which cannot be wrapped
)
endif ()

This is now replaced with a declarative file named vtk.module. This file is not CMake code and is instead parsed as an argument list in CMake (variable expansions are also not allowed). The above example would translate into:

MODULE
vtkModuleName
CONDITION
SOME_OPTION
GROUPS
# groups the module belongs to
KIT
# the kit the module belongs to
#IMPLEMENTABLE # Implicit in the old build system. Now explicit.
IMPLEMENTS
# modules containing vtkObjectFactory instances that are implemented here
DEPENDS
# public dependencies
PRIVATE_DEPENDS
# private dependencies
OPTIONAL_DEPENDS
vtkSomeDep
ORDER_DEPENDS
# modules which must be built before this one but which are not actually
# linked.
TEST_DEPENDS
# test dependencies
TEST_OPTIONAL_DEPENDS
# optional test dependencies
vtkSomeDep
#EXCLUDE_WRAP
# present for modules which cannot be wrapped

Modules may also now be provided by the current project or by an external project found by find_package as well.

Declaring sources

Sources used to be listed just as .cxx files. The module system would then search for a corresponding .h file, then add it to the list. Some source file properties could be used to control header-only or private headers.

In this example, we have a module with the following sources:

  • vtkPublicClass.cxx and vtkPublicClass.h: Public VTK class meant to be wrapped and its header installed.
  • vtkPrivateClass.cxx and vtkPrivateClass.h: Priavte VTK class not meant for use outside of the module.
  • helper.cpp and helper.h: Private API, but not following VTK's naming conventions.
  • public_helper.cpp and public_helper.h: Public API, but not following VTK's naming conventions.
  • vtkImplSource.cxx: A source file without a header.
  • public_header.h: A public header without a source file.
  • template.tcc and template.h: Public API, but not following VTK's naming conventions.
  • private_template.tcc and private_template.h: Private API, but not following VTK's naming conventions.
  • vtkPublicTemplate.txx and vtkPublicTemplate.h: Public template sources. Wrapped and installed.
  • vtkPrivateTemplate.txx and vtkPrivateTemplate.h: Private template sources.
  • vtkOptional.cxx and vtkOptional.h: Private API which requires an optional dependency.

The old module's way of building these sources is:

set(Module_SRCS
vtkPublicClass.cxx
vtkPrivateClass.cxx
helper.cpp
helper.h
public_helper.cpp
public_helper.h
public_header.h
vtkImplSource.cxx
vtkPublicTemplate.txx
vtkPrivateTemplate.txx
template.tcc # Not detected as a template, so not installed.
template.h
private_template.tcc
private_template.h
)
# Mark some files as only being header files.
set_source_files_properties(
public_header.h
HEADER_FILE_ONLY
)
# Mark some headers as being private.
set_source_files_properties(
helper.h
private_template.h
public_header.h
template.h
vtkImplSource.cxx # no header
vtkPrivateTemplate.h
PROPERTIES SKIP_HEADER_INSTALL 1
)
set(${vtk-module}_HDRS # Magic variable
public_helper.h
template.h
#helper.h # private headers just go ignored.
)
# Optional dependencies are detected through variables.
if (Module_vtkSomeDep)
list(APPEND Module_SRCS
# Some optional file.
vtkOptional.cxx)
endif ()
vtk_module_library(vtkModuleName ${Module_SRCS})

While with the new system, source files are explicitly declared using argument parsing.

set(classes
vtkPublicClass)
set(private_classes
vtkPrivateClass)
set(sources
helper.cpp
public_helper.cpp
vtkImplSource.cxx)
set(headers
public_header.h
public_helper.h
template.h)
set(private_headers
helper.h
private_template.h)
set(template_classes
vtkPublicTemplate)
set(private_template_classes
vtkPrivateTemplate)
set(templates
template.tcc)
set(private_templates
private_template.tcc)
# Optional dependencies are detected as targets.
if (TARGET vtkSomeDep)
# Optional classes may not be public (though there's no way to actually
# enforce it, optional dependencies are always treated as private.
list(APPEND private_classes
vtkOptional)
endif ()
vtk_module_add_module(vtkModuleName
# File pairs which follow VTK's conventions. The headers will be wrapped and
# installed.
CLASSES ${classes}
# File pairs which follow VTK's conventions, but are not for use outside the
# module.
PRIVATE_CLASSES ${private_classes}
# Standalone sources (those without headers or which do not follow VTK's
# conventions).
SOURCES ${sources}
# Standalone headers (those without sources or which do not follow VTK's
# conventions). These will be installed.
HEADERS ${public_headers}
# Standalone headers (those without sources or which do not follow VTK's
# conventions), but are not for use outside the module.
PRIVATE_HEADERS ${private_headers}
# Templates are also supported.
# Template file pairs which follow VTK's conventions. Both files will be
# installed (only the headers will be wrapped).
TEMPLATE_CLASSES ${template_classes}
# Template file pairs which follow VTK's conventions, but are not for use
# outside the module.
PRIVATE_TEMPLATE_CLASSES ${private_template_classes}
# Standalone template files (those without headers or which do not follow
# VTK's conventions). These will be installed.
TEMPLATES ${templates}
# Standalone template files (those without headers or which do not follow
# VTK's conventions), but are not for use outside the module.
PRIVATE_TEMPLATES ${private_templates}
)

Note that the arguments with CLASSES in their name expand to pairs of files with the .h and either .cxx or .txx extension based on whether it is a template or not. Projects not using this convention may use the HEADERS, SOURCES, and TEMPLATES arguments instead.

Object Factories

Previously, object factories were made using implicit variable declaration magic behind the scenes. This is no longer the case and proper CMake APIs for them are available.

set(sources
vtkObjectFactoryImpl.cxx
# This path is made by `vtk_object_factory_configure` later.
"${CMAKE_CURRENT_BINARY_DIR}/${vtk-module}ObjectFactory.cxx")
# Make a list of base classes we will be overriding.
set(overrides vtkObjectFactoryBase)
# Make a variable declaring what the override for the class is.
set(vtk_module_vtkObjectFactoryBase_override "vtkObjectFactoryImpl")
# Generate a source using the list of base classes overridden.
vtk_module_library("${vtk-module}" "${sources}")

This is now handled using proper APIs instead of variable lookups.

set(classes
vtkObjectFactoryImpl)
# Explicitly declare the override relationship.
BASE vtkObjectFactoryBase
OVERRIDE vtkObjectFactoryImpl)
# Collects the set of declared overrides and writes out a source file.
# The path to the source is returned as a variable.
SOURCE_FILE factory_source
# As is its header file.
HEADER_FILE factory_header
# The export macro is now explicitly passed (instead of assumed based on the
# current module context).
EXPORT_MACRO MODULE_EXPORT)
vtk_module_add_module(vtkModuleName
CLASSES ${classes}
SOURCES "${factory_source}"
PRIVATE_HEADERS "${factory_header}")

Building a group of modules

This was not well supported in the old module system. Basically, it involved setting up the source tree like VTK expects and then including the vtkModuleTop file. This is best just rewritten using the following CMake APIs:

vtk_object_factory_configure
function vtk_object_factory_configure()
Generate source for overrides in a module.
Definition: vtkObjectFactory.cmake:91
vtkX3D::component
Definition: vtkX3D.h:181
vtk_object_factory_declare
function vtk_object_factory_declare()
Declare a factory override.
Definition: vtkObjectFactory.cmake:35
vtkX3D::on
Definition: vtkX3D.h:445
target
boost::graph_traits< vtkGraph * >::vertex_descriptor target(boost::graph_traits< vtkGraph * >::edge_descriptor e, vtkGraph *)
Definition: vtkBoostGraphAdapter.h:965
vtk
Specialization of tuple ranges and iterators for vtkAOSDataArrayTemplate.
Definition: vtkCollectionRange.h:28
source
boost::graph_traits< vtkGraph * >::vertex_descriptor source(boost::graph_traits< vtkGraph * >::edge_descriptor e, vtkGraph *)
Definition: vtkBoostGraphAdapter.h:959
vtk_module_add_module
function vtk_module_add_module(name)
Create a module library.
Definition: vtkModule.cmake:3239