Commit 1ebfa5bc authored by Max Smolens's avatar Max Smolens

python: Add wrapping of kits when VTK_ENABLE_KITS is ON

If VTK_ENABLE_KITS is ON, VTK kits and modules that are not associated with any
kit will be wrapped. The effect is that drastically fewer libraries are created.

Take vtkCommon as an example. When VTK_ENABLE_KITS is OFF, a library is
generated for each wrapped module:

    vtkCommonColorPython27D-x.y.dll
    vtkCommonComputationalGeometryPython27D-x.y.dll
    vtkCommonCorePython27D-x.y.dll
    vtkCommonDataModelPython27D-x.y.dll
    vtkCommonExecutionModelPython27D-x.y.dll
    vtkCommonMathPython27D-x.y.dll
    vtkCommonMiscPython27D-x.y.dll
    vtkCommonSystemPython27D-x.y.dll
    vtkCommonTransformsPython27D-x.y.dll

When VTK_ENABLE_KITS is ON, a single "kit" library is generated:

    vtkCommonKitPython27D-x.y.dll

The wrapped kits have the suffix "Kit" to avoid naming conflicts with existing
libraries like "vtkFilterPython".

As part of this change, the Python wrapping function has been split into two
functions, one which wraps the code and another which builds the wrapped code.
The new function is backwards compatible, but to update client code, replace
calls like:

    vtk_add_python_wrapping(${module})

with:

    vtk_add_python_wrapping(${module} module_srcs)
    vtk_add_python_wrapping_library(${module} module_srcs ${module})

Additionally, the functions "vtk_wrap_python" and "vtk_add_python_wrapping" have
been updated to understand a list of modules as input.
Co-authored-by: Jean-Christophe Fillion-Robin's avatarJean-Christophe Fillion-Robin <jchris.fillionr@kitware.com>
Co-authored-by: Max Smolens's avatarMax Smolens <max.smolens@kitware.com>
Co-authored-by: Ben Boeckel's avatarBen Boeckel <ben.boeckel@kitware.com>
parent 3a0ed04e
......@@ -83,6 +83,7 @@ SET(VTK_WRAP_PYTHON "@VTK_WRAP_PYTHON@")
SET(VTK_WRAP_TCL "@VTK_WRAP_TCL@")
SET(VTK_WRAP_JAVA "@VTK_WRAP_JAVA@")
SET(VTK_QT_VERSION "@VTK_QT_VERSION@")
SET(VTK_ENABLE_KITS "@VTK_ENABLE_KITS@")
# Do not add options or information here that is specific to a
# particular module. Instead set <module>_EXPORT_OPTIONS and/or
......
......@@ -238,6 +238,8 @@ if(VTK_ENABLE_KITS)
endforeach()
endforeach()
list(REMOVE_DUPLICATES vtk_kits)
# Put all kits in the list (if they are not dependencies of any module, they
# will be dropped otherwise).
list(APPEND vtk_modules_and_kits ${vtk_kits})
......
......@@ -8,7 +8,34 @@ if(PYTHONINTERP_FOUND AND PYTHONLIBS_FOUND)
endif()
endif()
function(vtk_add_python_wrapping module_name)
# To support wrapping of either module or kit, this function
# has two signatures:
# 1) vtk_add_python_wrapping(<module_name> <sources_var>)
# 2) vtk_add_python_wrapping("<module_name>[ <module_name>]" <sources_var> <kit_name>)
#
# Legacy code may call this function with a single argument. In that case,
# vtk_add_python_wrapping_library() is called internally to maintain backwards
# compatibility.
function(vtk_add_python_wrapping module_names)
if(${ARGC} EQUAL 1)
set(_legacy TRUE)
message(AUTHOR_WARNING
"Calling vtk_add_python_wrapping() with a single argument is deprecated.\n"
"Replace calls like:\n"
" vtk_add_python_wrapping(\${module})\n"
"with:\n"
" vtk_add_python_wrapping(\${module} module_srcs)\n"
" vtk_add_python_wrapping_library(\${module} module_srcs \${module})")
endif()
if("${ARGV1}" MATCHES ".+")
set(sources_var ${ARGV1})
endif()
if("${ARGV2}" MATCHES ".+")
list(REMOVE_AT ARGN 0)
set(target ${ARGN})
else()
set(target ${module_names})
endif()
if(NOT VTK_WRAP_PYTHON_INIT_EXE)
if(TARGET vtkWrapPythonInit)
set (VTK_WRAP_PYTHON_INIT_EXE vtkWrapPythonInit)
......@@ -16,6 +43,37 @@ function(vtk_add_python_wrapping module_name)
message(FATAL_ERROR "VTK must be built with Python wrapping turned on.")
endif()
endif()
set(EXTRA_PYTHON_INCLUDE_DIRS)
set(KIT_HIERARCHY_FILE)
set(VTK_WRAP_HINTS_FILES)
foreach(module_name IN LISTS module_names)
list(APPEND EXTRA_PYTHON_INCLUDE_DIRS ${${module_name}_PYTHON_INCLUDE_DIRS})
if(NOT ${module_name}_EXCLUDE_FROM_WRAP_HIERARCHY)
list(APPEND KIT_HIERARCHY_FILE ${${module_name}_WRAP_HIERARCHY_FILE})
endif()
if(${module_name}_WRAP_HINTS AND EXISTS "${${module_name}_WRAP_HINTS}")
list(APPEND VTK_WRAP_HINTS_FILES "${${module_name}_WRAP_HINTS}")
endif()
endforeach()
if(VTK_WRAP_HINTS_FILES)
set(VTK_WRAP_HINTS ${VTK_WRAP_HINTS_FILES})
endif()
vtk_wrap_python(${target}Python Python_SRCS "${module_names}")
if(_legacy)
set(_sources "${Python_SRCS}" "${extra_srcs}")
vtk_add_python_wrapping_library(${module_names} _sources ${module_names})
else()
set(${sources_var} "${Python_SRCS}" "${extra_srcs}" PARENT_SCOPE)
endif()
endfunction()
function(vtk_add_python_wrapping_library module srcs)
# Need to add the Wrapping/Python to the include directory
set(_python_include_dirs
${VTK_SOURCE_DIR}/Wrapping/Python
......@@ -23,57 +81,52 @@ function(vtk_add_python_wrapping module_name)
${VTK_SOURCE_DIR}/Utilities/Python
${VTK_BINARY_DIR}/Utilities/Python
${PYTHON_INCLUDE_DIRS})
set(XY ${PYTHON_MAJOR_VERSION}${PYTHON_MINOR_VERSION})
if(NOT CMAKE_HAS_TARGET_INCLUDES)
include_directories(${_python_include_dirs})
endif()
if(NOT ${module_name}_EXCLUDE_FROM_WRAP_HIERARCHY)
set(KIT_HIERARCHY_FILE ${${module_name}_WRAP_HIERARCHY_FILE})
endif()
string(REGEX REPLACE "^vtk" "" kit_name "${module_name}")
set(KIT ${kit_name})
set(XY ${PYTHON_MAJOR_VERSION}${PYTHON_MINOR_VERSION})
# Figure out the dependent PythonXYD libraries for the module
unset(extra_links)
set(EXTRA_PYTHON_INCLUDE_DIRS ${${module_name}_PYTHON_INCLUDE_DIRS})
foreach(dep ${${module_name}_DEPENDS})
if(NOT "${module_name}" STREQUAL "${dep}" AND TARGET ${dep}PythonD)
set(extra_links)
foreach(dep IN LISTS ${module}_DEPENDS)
if(NOT "${module}" STREQUAL "${dep}" AND TARGET ${dep}PythonD)
list(APPEND extra_links ${dep}PythonD)
endif()
endforeach()
if(${module_name}_WRAP_HINTS AND EXISTS "${${module_name}_WRAP_HINTS}")
set(VTK_WRAP_HINTS "${${module_name}_WRAP_HINTS}")
endif()
vtk_wrap_python(${module_name}Python Python_SRCS ${module_name})
vtk_add_library(${module_name}PythonD ${Python_SRCS} ${extra_srcs})
get_property(output_name TARGET ${module_name}PythonD PROPERTY OUTPUT_NAME)
vtk_add_library(${module}PythonD ${${srcs}})
get_property(output_name TARGET ${module}PythonD PROPERTY OUTPUT_NAME)
string(REPLACE "PythonD" "Python${XY}D" output_name "${output_name}")
set_property(TARGET ${module_name}PythonD PROPERTY OUTPUT_NAME ${output_name})
set_property(TARGET ${module}PythonD PROPERTY OUTPUT_NAME ${output_name})
if(CMAKE_HAS_TARGET_INCLUDES)
set_property(TARGET ${module_name}PythonD APPEND
set_property(TARGET ${module}PythonD APPEND
PROPERTY INCLUDE_DIRECTORIES ${_python_include_dirs})
endif()
if(${module_name}_IMPLEMENTS)
set_property(TARGET ${module_name}PythonD PROPERTY COMPILE_DEFINITIONS
"${module_name}_AUTOINIT=1(${module_name})")
endif()
target_link_libraries(${module_name}PythonD LINK_PUBLIC ${module_name}
target_link_libraries(${module}PythonD LINK_PUBLIC
vtkWrappingPythonCore ${extra_links} ${VTK_PYTHON_LIBRARIES})
if (MSVC)
set_target_properties(${module_name}PythonD
set_target_properties(${module}PythonD
PROPERTIES STATIC_LIBRARY_FLAGS ${CMAKE_MODULE_LINKER_FLAGS})
endif()
_vtk_add_python_module(${module_name}Python ${module_name}PythonInit.cxx)
target_link_libraries(${module_name}Python ${module_name}PythonD)
foreach (submodule IN LISTS ARGN)
if(${submodule}_IMPLEMENTS)
set_property(TARGET ${module}PythonD APPEND PROPERTY COMPILE_DEFINITIONS
"${submodule}_AUTOINIT=1(${submodule})")
endif()
target_link_libraries(${module}PythonD LINK_PUBLIC ${submodule})
endforeach ()
set(prefix ${module})
if(_${module}_is_kit)
set(prefix ${prefix}${VTK_KIT_SUFFIX})
endif()
_vtk_add_python_module(${module}Python ${prefix}PythonInit.cxx)
target_link_libraries(${module}Python ${module}PythonD)
if(CMAKE_HAS_TARGET_INCLUDES)
set_property(TARGET ${module_name}Python APPEND
set_property(TARGET ${module}Python APPEND
PROPERTY INCLUDE_DIRECTORIES ${_python_include_dirs})
endif()
endfunction()
......
......@@ -36,12 +36,12 @@ macro(VTK_WRAP_PYTHON3 TARGET SRC_LIST_NAME SOURCES)
# collect the common wrapper-tool arguments
set(_common_args)
if(VTK_WRAP_HINTS)
set(_common_args "${_common_args}--hints \"${VTK_WRAP_HINTS}\"\n")
endif()
if(KIT_HIERARCHY_FILE)
set(_common_args "${_common_args}--types \"${KIT_HIERARCHY_FILE}\"\n")
endif()
foreach(file IN LISTS VTK_WRAP_HINTS)
set(_common_args "${_common_args}--hints \"${file}\"\n")
endforeach()
foreach(file IN LISTS KIT_HIERARCHY_FILE)
set(_common_args "${_common_args}--types \"${file}\"\n")
endforeach()
if(NOT CMAKE_VERSION VERSION_LESS 3.1 AND NOT VTK_ENABLE_KITS)
# write wrapper-tool arguments to a file
......@@ -56,13 +56,21 @@ $<$<BOOL:$<TARGET_PROPERTY:${TARGET},INCLUDE_DIRECTORIES>>:
")
else()
# all the include directories
string(REGEX REPLACE "Python\$" "" module "${TARGET}")
if(${module}_INCLUDE_DIRS)
set(TMP_INCLUDE_DIRS ${${module}_INCLUDE_DIRS})
elseif(VTK_WRAP_INCLUDE_DIRS)
set(TMP_INCLUDE_DIRS ${VTK_WRAP_INCLUDE_DIRS})
set(TMP_INCLUDE_DIRS)
set(_modules ${ARGN})
if(NOT _modules)
string(REGEX REPLACE "Python\$" "" module "${TARGET}")
set(_modules ${module})
endif()
foreach(module IN LISTS ${_modules})
if(${module}_INCLUDE_DIRS)
list(APPEND TMP_INCLUDE_DIRS ${${module}_INCLUDE_DIRS})
endif()
endforeach()
if(VTK_WRAP_INCLUDE_DIRS)
list(APPEND TMP_INCLUDE_DIRS ${VTK_WRAP_INCLUDE_DIRS})
else()
set(TMP_INCLUDE_DIRS ${VTK_INCLUDE_DIRS})
list(APPEND TMP_INCLUDE_DIRS ${VTK_INCLUDE_DIRS})
endif()
if(EXTRA_PYTHON_INCLUDE_DIRS)
list(APPEND TMP_INCLUDE_DIRS ${EXTRA_PYTHON_INCLUDE_DIRS})
......@@ -220,11 +228,13 @@ macro(vtk_find_header header include_dirs full_path)
endforeach()
endmacro()
# Macro that just takes the name of the module, figure the rest out from there.
macro(vtk_wrap_python TARGET SRC_LIST_NAME module)
# Macro that just takes the a list of module names, figure the rest out from there.
macro(vtk_wrap_python TARGET SRC_LIST_NAME)
# List of all headers to wrap.
set(headers_to_wrap)
foreach(module ${ARGN})
# Decide what to do for each header.
foreach(header ${${module}_HEADERS})
# Everything in this block is for headers that will be wrapped.
......@@ -241,6 +251,8 @@ macro(vtk_wrap_python TARGET SRC_LIST_NAME module)
endif()
endforeach()
endforeach() # end ARGN loop
# Delegate to vtk_wrap_python3
vtk_wrap_python3(${TARGET} ${SRC_LIST_NAME} "${headers_to_wrap}")
vtk_wrap_python3(${TARGET} ${SRC_LIST_NAME} "${headers_to_wrap}" ${ARGN})
endmacro()
......@@ -29,21 +29,143 @@ macro(vtk_include_recurse module)
include_directories(${${module}_PYTHON_INCLUDE_DIRS})
endmacro()
# Loop through all modules that should be wrapped, and wrap them.
foreach(module ${VTK_PYTHON_MODULES})
vtk_module_load(${module})
vtk_module_headers_load(${module})
vtk_include_recurse(${module})
vtk_add_python_wrapping(${module})
endforeach()
set(VTK_PYTHON_MODULES_AND_KITS ${VTK_PYTHON_MODULES})
set(_vtk_python_modules_only ${VTK_PYTHON_MODULES})
if(VTK_ENABLE_KITS)
set(_vtk_kits_with_suffix)
set(VTK_KIT_SUFFIX "Kit") # Required to avoid conflict with targets like vtkFiltersPython
# Create list of module that do not belong to any kits
foreach(kit IN LISTS vtk_kits)
# XXX Variable '_${kit}_modules' is set in vtkModuleTop.cmake
list(REMOVE_ITEM _vtk_python_modules_only ${_${kit}_modules})
list(APPEND _vtk_kits_with_suffix ${kit}${VTK_KIT_SUFFIX})
endforeach()
set(VTK_PYTHON_MODULES_AND_KITS ${_vtk_kits_with_suffix} ${_vtk_python_modules_only})
# Create dependency lists for kits (suffix: _DEPENDS). The function
# vtk_add_python_wrapping_libary uses these lists.
#
# Additionally, create subsets of the full dependency lists that contain only
# Python-wrapped kits and modules (suffix: _PYTHON_DEPENDS). These lists are
# used to topologically sort the dependency graph.
foreach(kit IN LISTS vtk_kits)
set(_module_depends)
foreach(module IN LISTS _${kit}_modules)
vtk_module_load(${module})
list(APPEND _module_depends ${${module}_DEPENDS})
endforeach()
set(_kit_depends)
foreach(dep IN LISTS _module_depends)
if(${dep}_KIT)
list(APPEND _kit_depends ${${dep}_KIT}${VTK_KIT_SUFFIX})
else()
list(APPEND _kit_depends ${dep})
endif()
endforeach()
list(REMOVE_DUPLICATES _kit_depends)
set(${kit}${VTK_KIT_SUFFIX}_DEPENDS ${_kit_depends})
set(_kit_python_depends)
foreach(module IN LISTS ${kit}${VTK_KIT_SUFFIX}_DEPENDS)
list(FIND VTK_PYTHON_MODULES_AND_KITS ${module} _module_index)
if (_module_index GREATER -1)
list(APPEND _kit_python_depends ${module})
endif()
endforeach()
list(REMOVE_DUPLICATES _kit_python_depends)
set(${kit}${VTK_KIT_SUFFIX}_PYTHON_DEPENDS ${_kit_python_depends})
endforeach()
# Create dependency lists for modules that also consider any dependent kits
# (suffix: _DEPENDS_WITH_KITS). These lists are used to override
# <module>_DEPENDS when calling vtk_add_python_wrapping_library.
#
# Additionally, create subsets of the full dependency lists that contain only
# Python-wrapped kits and modules (suffix: _PYTHON_DEPENDS). These lists are
# used to topologically sort the dependency graph.
foreach(module IN LISTS _vtk_python_modules_only)
vtk_module_load(${module})
set(_saved_${module}_DEPENDS ${${module}_DEPENDS})
set(_module_depends_with_kits)
foreach(dep IN LISTS ${module}_DEPENDS)
if(${dep}_KIT)
list(APPEND _module_depends_with_kits ${${dep}_KIT}${VTK_KIT_SUFFIX})
else()
list(APPEND _module_depends_with_kits ${dep})
endif()
endforeach()
list(REMOVE_DUPLICATES _module_depends_with_kits)
set(${module}_DEPENDS_WITH_KITS ${_module_depends_with_kits})
set(_module_python_depends)
foreach(module IN LISTS ${module}_DEPENDS_WITH_KITS)
list(FIND VTK_PYTHON_MODULES_AND_KITS ${module} _module_index)
if (_module_index GREATER -1)
list(APPEND _module_python_depends ${module})
endif()
endforeach()
list(REMOVE_DUPLICATES _module_python_depends)
set(${module}_PYTHON_DEPENDS ${_module_python_depends})
endforeach()
# Create list of kits and modules to wrap, ordered to satisfy dependencies.
include(${VTK_CMAKE_DIR}/TopologicalSort.cmake)
set(_vtk_python_wrapping_work_list ${VTK_PYTHON_MODULES_AND_KITS})
topological_sort(_vtk_python_wrapping_work_list "" _PYTHON_DEPENDS)
# Wrap kits and modules.
foreach(target IN LISTS _vtk_python_wrapping_work_list)
# Determine whether target is a kit or module
string(REGEX REPLACE "(.+)${VTK_KIT_SUFFIX}\$" "\\1" _stripped_target ${target})
if(_${_stripped_target}_is_kit)
# Wrap kit
set(kit ${_stripped_target})
set(kit_srcs)
foreach(module IN LISTS _${kit}_modules)
vtk_module_headers_load(${module})
vtk_include_recurse(${module})
endforeach()
vtk_add_python_wrapping("${_${kit}_modules}" kit_srcs ${kit}${VTK_KIT_SUFFIX})
vtk_add_python_wrapping_library(${kit}${VTK_KIT_SUFFIX} kit_srcs ${_${kit}_modules})
else()
# Wrap module
set(module ${_stripped_target})
vtk_module_headers_load(${module})
vtk_include_recurse(${module})
vtk_add_python_wrapping(${module} module_srcs)
# Override module dependency list for vtk_add_python_wrapping_library
set(${module}_DEPENDS ${${module}_DEPENDS_WITH_KITS})
vtk_add_python_wrapping_library(${module} module_srcs ${module})
set(${module}_DEPENDS ${_saved_${module}_DEPENDS})
endif()
endforeach()
# Ensure that original module dependency lists are restored
foreach(module IN LISTS _vtk_python_modules_only)
set(${module}_DEPENDS ${_saved_${module}_DEPENDS})
unset(_saved_${module}_DEPENDS)
endforeach()
else(VTK_ENABLE_KITS)
# Loop through all modules that should be wrapped, and wrap them.
foreach(module IN LISTS _vtk_python_modules_only)
vtk_module_load(${module})
vtk_module_headers_load(${module})
vtk_include_recurse(${module})
vtk_add_python_wrapping(${module} module_srcs)
vtk_add_python_wrapping_library(${module} module_srcs ${module})
endforeach()
endif(VTK_ENABLE_KITS)
option(VTK_ENABLE_VTKPYTHON "Enable vtkpython and pvtkpython binaries" ON)
mark_as_advanced(VTK_ENABLE_VTKPYTHON)
if(VTK_ENABLE_VTKPYTHON)
# Now to build the vtkPython executable, configure the .py files etc.
get_property(VTK_PYTHON_MODULES GLOBAL PROPERTY VTK_PYTHON_WRAPPED)
vtk_module_load(vtkWrappingPythonCore)
vtk_module_load(vtkPython)
include_directories(${CMAKE_CURRENT_BINARY_DIR}
......@@ -166,7 +288,7 @@ if(PYTHON_EXECUTABLE)
# Wrapping/Python/vtk/*.py
unset(VTK_PYTHON_FILES)
unset(VTK_PYTHON_IMPORT_ALL)
foreach(module ${VTK_PYTHON_MODULES})
foreach(module IN LISTS VTK_PYTHON_MODULES_AND_KITS)
set(VTK_PYTHON_IMPORT_ALL
"${VTK_PYTHON_IMPORT_ALL}from .${module} import *\n")
configure_file(vtk/module.py.in vtk/${module}.py @ONLY)
......@@ -295,7 +417,7 @@ if(PYTHON_EXECUTABLE)
# Install python extension library that backs the modules
if (BUILD_SHARED_LIBS AND NOT VTK_INSTALL_NO_LIBRARIES)
foreach(module ${VTK_PYTHON_MODULES})
foreach(module IN LISTS VTK_PYTHON_MODULES_AND_KITS)
install(TARGETS ${module}Python
RUNTIME DESTINATION ${VTK_INSTALL_RUNTIME_DIR} COMPONENT RuntimeLibraries
LIBRARY DESTINATION ${VTK_INSTALL_PYTHON_MODULE_DIR}/vtk COMPONENT RuntimeLibraries
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment