#========================================================================== # # Copyright NumFOCUS # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0.txt # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # #==========================================================================*/ cmake_minimum_required(VERSION 3.16.3...3.19.7 FATAL_ERROR) project(WrapITK) enable_testing() # Set the module prefix once upon loading this files # Case 1: An external module is loading this file from # ${ITK_SOURCE_DIR}/CMake/ITKModuleExternal.cmake # Case 2: ITK is including this file from # ${ITK_SOURCE_DIR}/CMakeLists.txt # module_prefix is a global variable if(EXTERNAL_WRAP_ITK_PROJECT) set(module_prefix ${itk-module}) else() set(module_prefix ITK) endif() ############################################################################### # Configure installation ############################################################################### if(ITK_INSTALL_PACKAGE_DIR) string( REGEX REPLACE "^/" "" path "${ITK_INSTALL_PACKAGE_DIR}/WrapITK/") else() set(path "lib/InsightToolkit/WrapITK/") endif() set(WRAP_ITK_INSTALL_PREFIX "${path}" CACHE INTERNAL "subpath where where most of WrapITK files will be installed") # Output directories. set(WRAP_ITK_CONFIG_DIR "${WrapITK_SOURCE_DIR}/") set(WRAP_ITK_CMAKE_DIR "${WrapITK_SOURCE_DIR}") set(WRAPPER_MASTER_INDEX_OUTPUT_DIR "${ITK_DIR}/Wrapping/Typedefs" CACHE INTERNAL "typedefs dir") if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY) # See ITK/CMakeLists.txt for rational for overwriting multi-config default behavior of appending $ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "$<1:${WrapITK_BINARY_DIR}/lib>" CACHE INTERNAL "Single output directory for building all libraries.") endif() if(NOT EXECUTABLE_OUTPUT_PATH) set(EXECUTABLE_OUTPUT_PATH ${WrapITK_BINARY_DIR}/bin CACHE INTERNAL "Single output directory for building all executables.") endif() # Set WRAP_ITK_INSTALL_COMPONENT_IDENTIFIER to a non-null value, like # "Wrapping", which will be inserted into the wrapping install component name. # This can be used to split installation package components. if(NOT WRAP_ITK_INSTALL_COMPONENT_IDENTIFIER) set(WRAP_ITK_INSTALL_COMPONENT_IDENTIFIER "") endif() unset(GLOBAL_IdxFilesList) unset(GLOBAL_IdxFilesList CACHE) # Set WRAP_ITK_INSTALL_COMPONENT_PER_MODULE to 1 to have wrapping install # component names prefixed with their respective module name. # This can be used to have fine-control over the split of installation. if(NOT DEFINED WRAP_ITK_INSTALL_COMPONENT_PER_MODULE) set(WRAP_ITK_INSTALL_COMPONENT_PER_MODULE 0) endif() mark_as_advanced(CMAKE_LIBRARY_OUTPUT_DIRECTORY EXECUTABLE_OUTPUT_PATH WRAP_ITK_INSTALL_PREFIX) set(CXX_TEST_PATH ${EXECUTABLE_OUTPUT_PATH}) ############################################################################### # Additional files for installation ############################################################################### # See https://peps.python.org/pep-0561/#stub-only-packages # Packaging typehints with package so use "itk", if making separate typehint # package use "itk-stubs" set(ITK_STUB_BASENAME "itk") # ITK_STUB_DIR: all stub files are stored in this directory set(ITK_STUB_DIR "${ITK_DIR}/Wrapping/Generators/Python/${ITK_STUB_BASENAME}" CACHE INTERNAL "where python interface files are stored.") file(MAKE_DIRECTORY ${ITK_STUB_DIR}) # ITK_PKL_DIR: all temporary pickled object AST representations stored here set(ITK_PKL_DIR "${ITK_DIR}/Wrapping/Generators/Python/itk-pkl" CACHE INTERNAL "where temp pkl files are stored") file(MAKE_DIRECTORY ${ITK_PKL_DIR}) set(WRAP_ITK_TYPEDEFS_DIRECTORY "${ITK_DIR}/Wrapping/Typedefs") set(WRAP_ITK_LIB_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}") ############################################################################### # Setup test driver ############################################################################### set(ITK_TEST_DRIVER "itkTestDriver") ############################################################################### # The real work on wrappers ############################################################################### include(ConfigureWrapping.cmake) ############################################################################### # Configure specific wrapper modules ############################################################################### unset(WRAP_ITK_MODULES CACHE) file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/Modules/) if(ITK_SOURCE_DIR) foreach(_module_enabled ${ITK_CONFIG_MODULES_ENABLED}) if(EXISTS "${${_module_enabled}_SOURCE_DIR}/wrapping/CMakeLists.txt") list(APPEND WRAP_ITK_MODULES ${_module_enabled}) set(itk-module_SOURCE_DIR ${${_module_enabled}_SOURCE_DIR}) add_subdirectory("${${_module_enabled}_SOURCE_DIR}/wrapping" ${CMAKE_CURRENT_BINARY_DIR}/Modules/${_module_enabled}) unset(itk-module_SOURCE_DIR) endif() endforeach() else() # Building a module externally so itk-module variable must have been previously set if(EXISTS "${${itk-module}_SOURCE_DIR}/wrapping/CMakeLists.txt") foreach(_module_depend ${ITK_MODULE_${itk-module}_DEPENDS}) if(EXISTS ${WRAPPER_MASTER_INDEX_OUTPUT_DIR}/${_module_depend}.mdx) list(APPEND WRAP_ITK_MODULES ${_module_depend}) endif() endforeach() list(APPEND WRAP_ITK_MODULES ${itk-module}) add_subdirectory("${${itk-module}_SOURCE_DIR}/wrapping" ${CMAKE_CURRENT_BINARY_DIR}/Modules/${itk-module}) endif() endif() set(WRAP_ITK_MODULES ${WRAP_ITK_MODULES} CACHE INTERNAL "Internal library list.") ############################################################################### # let the different generators running some code after have parsed all the # modules ############################################################################### if(${module_prefix}_WRAP_PYTHON) # Wrap PyUtils if(NOT EXTERNAL_WRAP_ITK_PROJECT) add_subdirectory(${ITK_WRAP_PYTHON_SOURCE_DIR}/PyUtils) add_subdirectory(${ITK_WRAP_PYTHON_SOURCE_DIR}/PyBase) endif() endif() ############################################################################### # Generate Python typehints when wrapped ############################################################################### if(ITK_WRAP_PYTHON) # Generate .pyi files for each class # The intent is that the pyi_generator file is run after every occurrence of igenerator has ran. # The call to igenerator is contained within a macro that is called by each of the modules. # According to online documents CMAkE dependencies can only be created between # custom_targets and custom_commands contained within the same CMakeLists file. It is unknown if this # can be done since the macros are called from a variety of locations. # PYI_GENERATOR: The file location of the pyi_generator.py script # This script is responsible for merging all of the pickle files together and # generating the Template and Proxy files for each class. In addition this file # generates the __init__.pyi and _proxies.pyi files used to interface between # the individual .pyi files. set(PYI_GENERATOR "${CMAKE_CURRENT_SOURCE_DIR}/Generators/Python/itk/pyi_generator.py") configure_file(${CMAKE_CURRENT_SOURCE_DIR}/GlobalIdxFilesList.txt.in ${CMAKE_CURRENT_BINARY_DIR}/GlobalIdxFilesList.txt) # Run pyi_generator # ${GLOBAL_IdxFilesList}: is described within SwigInterface/CMakeLists.txt # The variable is passed to pyi_generator to make sure that the function only uses current index files # All index files found that are not in the given list are assumed to be outdated and are removed. add_custom_target( itk-stub-files ALL BYPRODUCTS "${ITK_STUB_DIR}/_proxies.pyi" "${ITK_STUB_DIR}/__init__.pyi" COMMAND ${Python3_EXECUTABLE} ${PYI_GENERATOR} --pyi_dir "${ITK_STUB_DIR}" --pkl_dir "${ITK_PKL_DIR}" --index_list_file "${CMAKE_CURRENT_BINARY_DIR}/GlobalIdxFilesList.txt" DEPENDS ${PYI_GENERATOR} ${GLOBAL_IdxFilesList} COMMENT "Generating .pyi files for Python wrapper interface" VERBATIM) # Add module dependencies to ensure .index.txt files have been generated unique(WRAPPED_MODULE_LIST "${WRAP_ITK_MODULES};ITKPyUtils") foreach(WRAPPER_LIBRARY_NAME ${WRAPPED_MODULE_LIST}) list(LENGTH ${WRAPPER_LIBRARY_NAME}PyiIdxFiles ${WRAPPER_LIBRARY_NAME}PyiIdxFiles_Len) if(${WRAPPER_LIBRARY_NAME}PyiIdxFiles_Len GREATER 0) # Swig custom targets build .index.txt files as byproducts add_dependencies(itk-stub-files ${WRAPPER_LIBRARY_NAME}Swig) endif() endforeach() unset(ITK_STUB_DIR CACHE) unset(ITK_PKL_DIR CACHE) endif()