From a4e306e4a7c3ae8dce9658f3a3b9218487cb33d8 Mon Sep 17 00:00:00 2001 From: "Hans J. Johnson" Date: Sun, 20 Sep 2026 12:50:31 -0500 Subject: [PATCH 1/7] ENH: Install the module build files an external module includes An external module starts with include(ITKModuleExternal), but that file and the ones it reaches are not installed, so configuring a module against an installed ITK fails immediately. Adds the transitive closure of that entry point over ITK-owned CMake files, the templates they configure, and BuildHeaderTest.py, which the header test runs by a path that only resolves in a source tree. About 115 KB. --- CMake/ITKModuleHeaderTest.cmake | 13 +++++++++++-- CMakeLists.txt | 23 +++++++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/CMake/ITKModuleHeaderTest.cmake b/CMake/ITKModuleHeaderTest.cmake index 22745f5c78b..cb7a1d04873 100644 --- a/CMake/ITKModuleHeaderTest.cmake +++ b/CMake/ITKModuleHeaderTest.cmake @@ -4,6 +4,16 @@ # primary purpose of this test is to make sure there are not missing module # dependencies. +# /CMake in a build tree, the installed package directory otherwise. +if(EXISTS "${ITK_CMAKE_DIR}/../Utilities/Maintenance/BuildHeaderTest.py") + set( + ITK_BUILD_HEADER_TEST_SCRIPT + "${ITK_CMAKE_DIR}/../Utilities/Maintenance/BuildHeaderTest.py" + ) +else() + set(ITK_BUILD_HEADER_TEST_SCRIPT "${ITK_CMAKE_DIR}/BuildHeaderTest.py") +endif() + # Improve performance of MSVC GUI, by reducing number of header tests. set(MAXIMUM_NUMBER_OF_HEADERS_default 35) if(MSVC) @@ -114,8 +124,7 @@ macro(itk_module_headertest _name) OUTPUT ${_header_test_src} COMMAND - ${Python3_EXECUTABLE} - ${ITK_CMAKE_DIR}/../Utilities/Maintenance/BuildHeaderTest.py ${_name} + ${Python3_EXECUTABLE} ${ITK_BUILD_HEADER_TEST_SCRIPT} ${_name} ${${_name}_SOURCE_DIR} ${${_name}_BINARY_DIR} ${MAXIMUM_NUMBER_OF_HEADERS} ${_test_num} ) diff --git a/CMakeLists.txt b/CMakeLists.txt index facd73eddf6..4d13d3455ca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -896,6 +896,29 @@ install( CMake/itkTransformIOFactoryRegisterManager.h.in CMake/itkMeshIOFactoryRegisterManager.h.in CMake/ITKInitializeCXXStandard.cmake + # The transitive closure of include(ITKModuleExternal). + CMake/ITKModuleExternal.cmake + CMake/ITKModuleMacros.cmake + CMake/ITKModuleTest.cmake + CMake/ITKModuleInfo.cmake.in + CMake/ITKSetPython3Vars.cmake + CMake/ITKInitializeBuildType.cmake + CMake/ITKWindowsUtf8.cmake + CMake/ITKExternalData.cmake + CMake/ITKDownloadSetup.cmake + CMake/ExternalData.cmake + CMake/ExternalData_config.cmake.in + CMake/WrappingConfigCommon.cmake + CMake/itkRemoveTestFiles.cmake + CMake/ITKModuleDoxygen.cmake + CMake/ITKModuleHeaderTest.cmake + CMake/ITKModuleKWStyleTest.cmake + CMake/ITKModuleCPPCheckTest.cmake + CMake/CppcheckTargets.cmake + # Remote modules include it through ITK_CMAKE_DIR for their version strings. + CMake/GetGitRevisionDescription.cmake + CMake/itkVersion.cmake + Utilities/Maintenance/BuildHeaderTest.py DESTINATION ${ITK_INSTALL_PACKAGE_DIR} COMPONENT Development ) From 58ecf3b604b89519946e670e4174e10006ba55d6 Mon Sep 17 00:00:00 2001 From: "Hans J. Johnson" Date: Sun, 20 Sep 2026 12:50:48 -0500 Subject: [PATCH 2/7] ENH: Allow wrapping an external module against an installed ITK The wrapping infrastructure and the generated SWIG type indices exist only in a build tree, so an installed ITK cannot wrap an external module. ITK_INSTALL_WRAPPING_DEVELOPMENT_FILES=ON installs both under the package directory, where ITK_CMAKE_DIR and ITK_DIR already point for an installed consumer. It defaults to OFF because the indices are tens of megabytes. Also repairs the install-tree branch in ITKModuleExternal.cmake: it read EXISTS"${ITK_CMAKE_DIR}/..." with no space, which CMake evaluates as false even when the file is present, so the branch was unreachable. --- CMake/ITKModuleExternal.cmake | 27 +++--- .../docs/contributing/module_workflows.md | 35 ++++++++ Wrapping/CMakeLists.txt | 82 +++++++++++++++++++ .../Generators/SwigInterface/CMakeLists.txt | 14 ++-- Wrapping/WrappingOptions.cmake | 10 +++ 5 files changed, 148 insertions(+), 20 deletions(-) diff --git a/CMake/ITKModuleExternal.cmake b/CMake/ITKModuleExternal.cmake index 84eef38cd24..d2f15dcf0a9 100644 --- a/CMake/ITKModuleExternal.cmake +++ b/CMake/ITKModuleExternal.cmake @@ -273,23 +273,22 @@ if(ITK_WRAPPING) "${CMAKE_CURRENT_SOURCE_DIR}/wrapping/CMakeLists.txt" ) set(EXTERNAL_WRAP_ITK_PROJECT ON) - set(WRAP_ITK_CMAKE_DIR "${ITK_CMAKE_DIR}/../Wrapping") - include("${WRAP_ITK_CMAKE_DIR}/TypedefMacros.cmake") - # Build tree + # /CMake in a build tree, the installed package directory otherwise. if(EXISTS "${ITK_CMAKE_DIR}/../Wrapping/CMakeLists.txt") - add_subdirectory( - "${ITK_CMAKE_DIR}/../Wrapping" - ${CMAKE_CURRENT_BINARY_DIR}/Wrapping - ) - # Install tree - elseif(EXISTS"${ITK_CMAKE_DIR}/Wrapping/CMakeLists.txt") - add_subdirectory( - "${ITK_CMAKE_DIR}/Wrapping" - ${CMAKE_CURRENT_BINARY_DIR}/Wrapping - ) + set(WRAP_ITK_CMAKE_DIR "${ITK_CMAKE_DIR}/../Wrapping") + elseif(EXISTS "${ITK_CMAKE_DIR}/Wrapping/CMakeLists.txt") + set(WRAP_ITK_CMAKE_DIR "${ITK_CMAKE_DIR}/Wrapping") else() - message(FATAL_ERROR "Could not find wrapping infrastructure.") + message( + FATAL_ERROR + "Could not find wrapping infrastructure at ${ITK_CMAKE_DIR}. To wrap a module against an installed ITK, that ITK must be reconfigured with ITK_INSTALL_WRAPPING_DEVELOPMENT_FILES=ON, then rebuilt and reinstalled." + ) endif() + include("${WRAP_ITK_CMAKE_DIR}/TypedefMacros.cmake") + add_subdirectory( + "${WRAP_ITK_CMAKE_DIR}" + ${CMAKE_CURRENT_BINARY_DIR}/Wrapping + ) endif() endif() # Create target to download data from the ITKData group. This must come after diff --git a/Documentation/docs/contributing/module_workflows.md b/Documentation/docs/contributing/module_workflows.md index e4bdf98c7cc..a90e4db4769 100644 --- a/Documentation/docs/contributing/module_workflows.md +++ b/Documentation/docs/contributing/module_workflows.md @@ -36,6 +36,41 @@ jobs: pypi_password: ${{ secrets.pypi_password }} ``` +## Building an external module against an installed ITK + +An external module can be configured, built, and Python-wrapped against an +installed ITK prefix rather than an ITK build tree. Point `ITK_DIR` at the +installed package directory, for example +`/lib/cmake/ITK-6.0`, and configure the module as usual. + +Wrapping additionally requires the SWIG type indices and the wrapping CMake +infrastructure, which ITK installs only on request because the payload is +tens of megabytes. To make an installed prefix usable as a wrapping SDK, the +ITK being installed must be configured with: + +```bash +cmake -DITK_WRAP_PYTHON:BOOL=ON \ + -DITK_INSTALL_WRAPPING_DEVELOPMENT_FILES:BOOL=ON +``` + +then rebuilt and reinstalled. Configuring a module with `ITK_WRAP_PYTHON=ON` +against a prefix that lacks these files fails with "Could not find wrapping +infrastructure"; the remedy is to reconfigure, rebuild, and reinstall the ITK +the module points at, not to change anything in the module. + +A module that extends another module's SWIG templates, as RTK extends +`ITKBridgeNumPy`'s `PyBuffer.i.init`, finds them in a build tree under that +module's source `wrapping/` directory and in an install tree under +`${WRAP_ITK_CMAKE_DIR}/Modules//`: + +```cmake +set(_numpy_wrapping "${WRAP_ITK_CMAKE_DIR}/Modules/ITKBridgeNumPy") +if(NOT EXISTS "${_numpy_wrapping}/PyBuffer.i.init") + list(GET ITKBridgeNumPy_INCLUDE_DIRS 0 _numpy_include) + set(_numpy_wrapping "${_numpy_include}/../wrapping") +endif() +``` + ## Further Reading For more information visit README documentation at the [ITKRemoteModuleBuildTestPackageAction](https://github.com/InsightSoftwareConsortium/ITKRemoteModuleBuildTestPackageAction/blob/main/README.md#itkremotemodulebuildtestpackageaction) project. diff --git a/Wrapping/CMakeLists.txt b/Wrapping/CMakeLists.txt index 1f4d8c95cd3..18a5e018cb7 100644 --- a/Wrapping/CMakeLists.txt +++ b/Wrapping/CMakeLists.txt @@ -267,3 +267,85 @@ if(ITK_WRAP_PYTHON) unset(ITK_STUB_DIR CACHE) unset(ITK_PKL_DIR CACHE) endif() + +# Lands under the package directory, where an installed consumer's ITK_DIR already points. +if(ITK_INSTALL_WRAPPING_DEVELOPMENT_FILES) + set(_itk_wrapping_install_dir "${ITK_INSTALL_PACKAGE_DIR}/Wrapping") + + macro(_itk_install_wrapping_development _source_dir _destination) + install( + DIRECTORY + "${_source_dir}/" + DESTINATION "${_destination}" + COMPONENT ${WRAP_ITK_INSTALL_COMPONENT_IDENTIFIER}WrappingDevelopment + FILES_MATCHING + ${ARGN} + ) + endmacro() + + _itk_install_wrapping_development( + "${WrapITK_SOURCE_DIR}" + "${_itk_wrapping_install_dir}" + PATTERN + "*.cmake" + PATTERN + "CMakeLists.txt" + PATTERN + "*.i" + PATTERN + "*.in" + PATTERN + "*.py" + PATTERN + "*.h" + PATTERN + "images" + EXCLUDE + PATTERN + "Tests" + EXCLUDE + ) + + _itk_install_wrapping_development( + "${WRAP_ITK_TYPEDEFS_DIRECTORY}" + "${_itk_wrapping_install_dir}/Typedefs" + PATTERN + "*.i" + PATTERN + "*.idx" + PATTERN + "*.mdx" + PATTERN + "*.h" + ) + + _itk_install_wrapping_development( + "${ITK_SOURCE_DIR}/Modules/ThirdParty/pygccxml/src/pygccxml" + "${_itk_wrapping_install_dir}/ThirdParty/pygccxml/pygccxml" + PATTERN + "*.py" + PATTERN + "__pycache__" + EXCLUDE + ) + + # SWIG templates other modules extend, such as ITKBridgeNumPy's PyBuffer.i.init. + foreach(_module ${WRAP_ITK_MODULES}) + _itk_install_wrapping_development( + "${${_module}_SOURCE_DIR}/wrapping" + "${_itk_wrapping_install_dir}/Modules/${_module}" + PATTERN + "*.i" + PATTERN + "*.i.in" + PATTERN + "*.i.init" + PATTERN + "test" + EXCLUDE + ) + endforeach() + unset(_module) + + unset(_itk_wrapping_install_dir) +endif() diff --git a/Wrapping/Generators/SwigInterface/CMakeLists.txt b/Wrapping/Generators/SwigInterface/CMakeLists.txt index af8526463b6..12525f5e98b 100644 --- a/Wrapping/Generators/SwigInterface/CMakeLists.txt +++ b/Wrapping/Generators/SwigInterface/CMakeLists.txt @@ -362,12 +362,14 @@ else() mark_as_advanced(SWIG_EXECUTABLE) endif() -set( - PYGCCXML_DIR - ${ITK_CMAKE_DIR}/../Modules/ThirdParty/pygccxml/src - CACHE INTERNAL - "pygccxml path" -) +# The source tree's copy, or the one installed with the wrapping development files. +if(EXISTS "${ITK_CMAKE_DIR}/../Modules/ThirdParty/pygccxml/src/pygccxml") + set(_pygccxml_dir "${ITK_CMAKE_DIR}/../Modules/ThirdParty/pygccxml/src") +else() + set(_pygccxml_dir "${WRAP_ITK_CMAKE_DIR}/ThirdParty/pygccxml") +endif() +set(PYGCCXML_DIR "${_pygccxml_dir}" CACHE INTERNAL "pygccxml path") +unset(_pygccxml_dir) ############################################################################### # store the current dir, so it can be reused later diff --git a/Wrapping/WrappingOptions.cmake b/Wrapping/WrappingOptions.cmake index 8b1fd7d71a4..cd4ff6817fe 100644 --- a/Wrapping/WrappingOptions.cmake +++ b/Wrapping/WrappingOptions.cmake @@ -13,6 +13,16 @@ else() set(ITK_WRAPPING OFF CACHE INTERNAL "Build external languages support" FORCE) endif() +# Opt-in: the SWIG type indices are tens of MB. +cmake_dependent_option( + ITK_INSTALL_WRAPPING_DEVELOPMENT_FILES + "Install the wrapping infrastructure and SWIG type indices so that external modules can be wrapped against an installed ITK" + OFF + "ITK_WRAPPING" + OFF +) +mark_as_advanced(ITK_INSTALL_WRAPPING_DEVELOPMENT_FILES) + cmake_dependent_option( ITK_PYTHON_RELEASE_GIL "Release Python Global Interpreter Lock (GIL) during ITK operations" From 022bb7e3218bddc0ed2a0a9f8e2ba1db52e8375c Mon Sep 17 00:00:00 2001 From: "Hans J. Johnson" Date: Mon, 21 Sep 2026 07:17:50 -0500 Subject: [PATCH 3/7] COMP: Give castxml ITK's include directories Wrapping an external module against an installed ITK failed in castxml with "'itkCommand.h' file not found" although the header was installed: the generated response file carried only the module's own include directories. In a build tree the dependency targets supply ITK's; from an install tree they contribute nothing. ITKConfig.cmake sets ITK_INCLUDE_DIRS in both trees, so it covers the installed case. It is not empty in a build tree: it accumulates the include directories of every module find_package requested, so the response file widens there too. --- Wrapping/macro_files/itk_auto_load_submodules.cmake | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Wrapping/macro_files/itk_auto_load_submodules.cmake b/Wrapping/macro_files/itk_auto_load_submodules.cmake index 4ca246ebc1e..d825aa51472 100644 --- a/Wrapping/macro_files/itk_auto_load_submodules.cmake +++ b/Wrapping/macro_files/itk_auto_load_submodules.cmake @@ -105,6 +105,14 @@ function(generate_castxml_commandline_flags) # create the files used to pass the file to include to castxml set(include_dir_list ${WRAPPER_LIBRARY_INCLUDE_DIRECTORIES}) + # From an install tree the dependency targets carry no ITK include dirs. + if(ITK_INCLUDE_DIRS) + list(APPEND include_dir_list ${ITK_INCLUDE_DIRS}) + endif() + # ITKBridgeNumPy exports Python.h's directory for the build tree only. + if(EXTERNAL_WRAP_ITK_PROJECT AND Python3_INCLUDE_DIRS) + list(APPEND include_dir_list ${Python3_INCLUDE_DIRS}) + endif() list(REMOVE_DUPLICATES include_dir_list) # CONFIG_CASTXML_INC_CONTENTS - variable used for building contents to write with file(GENERATE) From 637022883581b8ef4774f68eed678b5810df87ea Mon Sep 17 00:00:00 2001 From: "Hans J. Johnson" Date: Tue, 22 Sep 2026 09:58:13 -0500 Subject: [PATCH 4/7] COMP: Wrap external modules without the IO factory register manager A consumer tree that includes UseITK gets ITK__FACTORY_REGISTER_MANAGER on every target, including an external module's Python wrapping library. Wrapped classes that include itkImageFileReader.h then reference the register function of every IO factory the installed ITK enables, and the wrapping library, which links only its module's dependencies, fails to load with unresolved symbols. Python registers the factories at import, so ITKModuleExternal asks the wrapping directory to drop them and itk_wrap_module removes the ones ITK_FACTORY_LIST names. The request uses a variable only itk_wrap_module reads, so a scope added after the wrapping directory, such as a module's examples, cannot lose its factory registration. ITK's own build never includes UseITK, so in-tree wrapping is unchanged, and a module's library, tests, and examples keep their managers. --- CMake/ITKModuleExternal.cmake | 2 ++ Wrapping/TypedefMacros.cmake | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/CMake/ITKModuleExternal.cmake b/CMake/ITKModuleExternal.cmake index d2f15dcf0a9..01caaf4fe0e 100644 --- a/CMake/ITKModuleExternal.cmake +++ b/CMake/ITKModuleExternal.cmake @@ -285,6 +285,8 @@ if(ITK_WRAPPING) ) endif() include("${WRAP_ITK_CMAKE_DIR}/TypedefMacros.cmake") + # Python registers the factories at import; the wrapping library must not. + set(ITK_WRAPPING_NO_FACTORY_REGISTER_MANAGER ON) add_subdirectory( "${WRAP_ITK_CMAKE_DIR}" ${CMAKE_CURRENT_BINARY_DIR}/Wrapping diff --git a/Wrapping/TypedefMacros.cmake b/Wrapping/TypedefMacros.cmake index 4d034eab42d..71a74ba01e0 100644 --- a/Wrapping/TypedefMacros.cmake +++ b/Wrapping/TypedefMacros.cmake @@ -133,6 +133,15 @@ macro(itk_wrap_module library_name) set(WRAPPER_LIBRARY_NAME "${library_name}") message(STATUS "${WRAPPER_LIBRARY_NAME}: Creating module.") + # Drop the register managers the consumer tree's UseITK put on this directory. + if(ITK_WRAPPING_NO_FACTORY_REGISTER_MANAGER) + foreach(_factory_name ${ITK_FACTORY_LIST}) + string(TOUPPER ${_factory_name} _factory_uc) + remove_definitions(-DITK_${_factory_uc}_FACTORY_REGISTER_MANAGER) + endforeach() + unset(_factory_uc) + endif() + # Mark the current source dir for inclusion because it may contain header files. include_directories(BEFORE "${CMAKE_CURRENT_SOURCE_DIR}") include_directories(BEFORE ${WRAPPER_LIBRARY_INCLUDE_DIRECTORIES}) From 4346fa1a7e5f1ebea8845bd1fda4d9d10758b2ce Mon Sep 17 00:00:00 2001 From: "Hans J. Johnson" Date: Tue, 22 Sep 2026 13:17:14 -0500 Subject: [PATCH 5/7] COMP: Build external module tests against an installed ITK With BUILD_TESTING=ON, ITK_USE_KWSTYLE defaults on, and when no KWStyle is found the module build includes Utilities/KWStyle/BuildKWStyle.cmake to build one, which exists only in a source tree; an external module then fails to configure against an installed ITK. Build KWStyle only when the source tree provides it, so an install-tree consumer falls through to the existing branch that turns ITK_USE_KWSTYLE off. The InDoxygenGroup test ran Utilities/Doxygen/mcdoc.py by a source-relative path. Install the script into the package directory and resolve it the way BuildHeaderTest.py is resolved. The header test and the test driver pick up UseITK's IO factory register manager through itkImageFileReader.h, which references every IO factory the ITK enables. The header test linked only the module, and the test driver linked the module's test dependencies and ITKTestKernel, which covers the default IO modules but not the ones an ITK built with extra IO modules enables; both failed with unresolved symbols. Link ITK_LIBRARIES for external modules, as any consumer executable must. --- CMake/ITKModuleDoxygen.cmake | 9 ++++++++- CMake/ITKModuleHeaderTest.cmake | 4 ++++ CMake/ITKModuleKWStyleTest.cmake | 4 ++++ CMake/ITKModuleTest.cmake | 4 ++++ CMakeLists.txt | 1 + 5 files changed, 21 insertions(+), 1 deletion(-) diff --git a/CMake/ITKModuleDoxygen.cmake b/CMake/ITKModuleDoxygen.cmake index 7a1ca952840..3af92802f76 100644 --- a/CMake/ITKModuleDoxygen.cmake +++ b/CMake/ITKModuleDoxygen.cmake @@ -3,6 +3,13 @@ # ${_name}.dot file which defines the local dependency as graph # which will be then processed by dot +# /CMake in a build tree, the installed package directory otherwise. +if(EXISTS "${ITK_CMAKE_DIR}/../Utilities/Doxygen/mcdoc.py") + set(ITK_MCDOC_SCRIPT "${ITK_CMAKE_DIR}/../Utilities/Doxygen/mcdoc.py") +else() + set(ITK_MCDOC_SCRIPT "${ITK_CMAKE_DIR}/mcdoc.py") +endif() + macro(itk_module_doxygen _name) # _content defines the content of the ${_name}.dox file set(_content "/**\n") @@ -49,7 +56,7 @@ macro(itk_module_doxygen _name) NAME ${_name}InDoxygenGroup COMMAND ${Python3_EXECUTABLE} - "${ITK_CMAKE_DIR}/../Utilities/Doxygen/mcdoc.py" + "${ITK_MCDOC_SCRIPT}" check ${_name} ${${_name}_SOURCE_DIR}/include diff --git a/CMake/ITKModuleHeaderTest.cmake b/CMake/ITKModuleHeaderTest.cmake index cb7a1d04873..d9570f7cd90 100644 --- a/CMake/ITKModuleHeaderTest.cmake +++ b/CMake/ITKModuleHeaderTest.cmake @@ -135,6 +135,10 @@ macro(itk_module_headertest _name) ${ITK_MODULE_${_name}_TARGETS_NAMESPACE}${_name}Module ${ITK_MODULE_${_name}_TARGETS_NAMESPACE}ITKKWSysModule ) + # UseITK's register manager references every IO factory the ITK enables. + if(NOT ITK_SOURCE_DIR) + target_link_libraries(${_test_name} PRIVATE ${ITK_LIBRARIES}) + endif() target_link_options( ${_test_name} diff --git a/CMake/ITKModuleKWStyleTest.cmake b/CMake/ITKModuleKWStyleTest.cmake index 69a5060303a..bc5abbca804 100644 --- a/CMake/ITKModuleKWStyleTest.cmake +++ b/CMake/ITKModuleKWStyleTest.cmake @@ -32,7 +32,11 @@ if( AND NOT CMAKE_CROSSCOMPILING + AND + EXISTS + "${ITK_CMAKE_DIR}/../Utilities/KWStyle/BuildKWStyle.cmake" ) + # Only an ITK source tree carries BuildKWStyle.cmake; an install tree does not. include(${ITK_CMAKE_DIR}/../Utilities/KWStyle/BuildKWStyle.cmake) elseif(NOT KWSTYLE_FOUND) set(ITK_USE_KWSTYLE OFF) diff --git a/CMake/ITKModuleTest.cmake b/CMake/ITKModuleTest.cmake index 86aefd6c49b..720f4a4409a 100644 --- a/CMake/ITKModuleTest.cmake +++ b/CMake/ITKModuleTest.cmake @@ -87,6 +87,10 @@ EM_ASM( ${KIT_LIBS} ${ITKTestKernel_LIBRARIES} ) + # UseITK's register manager references every IO factory the ITK enables. + if(NOT ITK_SOURCE_DIR) + target_link_libraries(${KIT}TestDriver PRIVATE ${ITK_LIBRARIES}) + endif() target_link_options( ${KIT}TestDriver PRIVATE diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d13d3455ca..e65955eb028 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -919,6 +919,7 @@ install( CMake/GetGitRevisionDescription.cmake CMake/itkVersion.cmake Utilities/Maintenance/BuildHeaderTest.py + Utilities/Doxygen/mcdoc.py DESTINATION ${ITK_INSTALL_PACKAGE_DIR} COMPONENT Development ) From 760d069dbefd19bd5702f85e53aca28ca37d1cb8 Mon Sep 17 00:00:00 2001 From: "Hans J. Johnson" Date: Tue, 6 Oct 2026 19:51:32 -0500 Subject: [PATCH 6/7] DOC: Say where installed Python bindings go and how to redirect them The bindings install into PY_SITE_PACKAGES_PATH, which defaults to the interpreter's platlib. On a system Python that directory is often not writable, and the install step fails with "Permission denied" on itkConfig.py before any of the wrapping development files are copied. --- Documentation/docs/contributing/module_workflows.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Documentation/docs/contributing/module_workflows.md b/Documentation/docs/contributing/module_workflows.md index a90e4db4769..3ac61f9f4f9 100644 --- a/Documentation/docs/contributing/module_workflows.md +++ b/Documentation/docs/contributing/module_workflows.md @@ -53,7 +53,13 @@ cmake -DITK_WRAP_PYTHON:BOOL=ON \ -DITK_INSTALL_WRAPPING_DEVELOPMENT_FILES:BOOL=ON ``` -then rebuilt and reinstalled. Configuring a module with `ITK_WRAP_PYTHON=ON` +then rebuilt and reinstalled. The Python bindings install into +`PY_SITE_PACKAGES_PATH`, which defaults to the interpreter's own +`site-packages`; when that directory is not writable, or the bindings should +stay inside the prefix, set it explicitly, for example +`-DPY_SITE_PACKAGES_PATH=/lib/python/site-packages`. + +Configuring a module with `ITK_WRAP_PYTHON=ON` against a prefix that lacks these files fails with "Could not find wrapping infrastructure"; the remedy is to reconfigure, rebuild, and reinstall the ITK the module points at, not to change anything in the module. From 5ec71e15d4ad1bbc53d36d82740fe93f33641ba9 Mon Sep 17 00:00:00 2001 From: "Hans J. Johnson" Date: Wed, 7 Oct 2026 09:18:09 -0500 Subject: [PATCH 7/7] COMP: Install the UTF-8 manifest the installed test macros attach ITKWindowsUtf8.cmake resolves Windows-utf8-codepage.manifest next to itself, so on MSVC every module test driver configured against an installed ITK failed with a missing source file. --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index e65955eb028..0849166292b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -904,6 +904,7 @@ install( CMake/ITKSetPython3Vars.cmake CMake/ITKInitializeBuildType.cmake CMake/ITKWindowsUtf8.cmake + CMake/Windows-utf8-codepage.manifest CMake/ITKExternalData.cmake CMake/ITKDownloadSetup.cmake CMake/ExternalData.cmake