Skip to content

Conversation

@blowekamp
Copy link
Member

@blowekamp blowekamp commented Jan 7, 2026

This PR introduces modern CMake interface libraries for ITK modules, enabling clean target-based linking and proper transitive dependency propagation.

Key Changes

  1. CMake Interface Libraries - Created ${ModuleName}Module interface library for each ITK module with:

    • Module-specific include directories using generator expressions
    • Automatic transitive dependency linking
  2. Target-Based Includes - Replaced directory-level include_directories() with target properties:

    • Uses target_include_directories() with BUILD_INTERFACE/INSTALL_INTERFACE
    • Proper PUBLIC propagation of includes and dependencies
    • Fixed header-only module compilation
  3. Example Modernization - Updated examples to use specific module targets:

    target_link_libraries(MyExample
      PRIVATE
        ITK::ITKImageGradientModule
        ITK::ITKImageIO
    )
  4. Enhanced Tooling - Improved WhatModulesITK.py with --link option to generate updated target_link_libraries commands

  5. Factory Registration - Properties part of factory meta-modules

Interface meta-modules for factories: ITKImageIO, ITKMeshIO, ITKTransformIO and FFTImageFilterInit factories. Factory modules will be added as dependencies to these meta-module. When itk_generate_factory_registration() is called, it adds the include directory containing the generated FactoryRegisterManager header file.

Example Usage:

find_package(ITK REQUIRED)
itk_generate_factory_registration()
 target_link_libraries(MyExample
     PRIVATE
       ITK::ITKCommonModule
       ITK::ITKImageIO
)

or

find_package(ITK REQUIRED)
itk_generate_factory_registration()
 target_link_libraries(MyExample
     PRIVATE
       ${ITK_INTERFACE_LIBRARIES}
)

Benefits

  • Cleaner, more maintainable CMake code
  • Explicit module dependencies (no more monolithic ${ITK_LIBRARIES})
  • Faster builds with minimal linking
  • Modern CMake best practices

Compatibility

  • External modules should use itk_module_add_library() for automatic target properties
  • Directory level include may need to be added for some External ITK Modules
  • Legacy ${ITK_LIBRARIES} pattern still supported

@github-actions github-actions bot added type:Infrastructure Infrastructure/ecosystem related changes, such as CMake or buildbots area:Examples Demonstration of the use of classes area:Python wrapping Python bindings for a class area:IO Issues affecting the IO module area:ThirdParty Issues affecting the ThirdParty module labels Jan 7, 2026
@dzenanz
Copy link
Member

dzenanz commented Jan 7, 2026

PR description sounds amazing! Now diving into the review.

Copy link
Member

@dzenanz dzenanz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am glad you are working on this! Does this work? What else is needed, besides changing the rest of the examples?

Copy link
Member

@hjmjohnson hjmjohnson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@blowekamp AMAZING! Thank you for tackling this. It is long overdue!

@dzenanz
Copy link
Member

dzenanz commented Jan 8, 2026

f8488a7 configures and builds locally, in Debug and RelWithDebInfo modes, including examples. CMake 4.2.1, VS 2022. Tests in RelWithDebInfo mode succeed.

@dzenanz dzenanz requested a review from thewtex January 8, 2026 15:49
@blowekamp blowekamp force-pushed the cmake_interface_module branch from f8488a7 to e648c27 Compare January 8, 2026 17:13
@github-actions github-actions bot removed the area:IO Issues affecting the IO module label Jan 8, 2026
@thewtex thewtex requested a review from Copilot January 8, 2026 19:26
@thewtex
Copy link
Member

thewtex commented Jan 8, 2026

Woohoo!

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR modernizes the ITK module system by introducing CMake interface libraries (${ModuleName}Module) that provide target-based dependency management and proper transitive propagation of include directories and dependencies. This replaces the legacy directory-level include_directories() approach with modern target-specific target_include_directories() calls using generator expressions.

Key Changes:

  • Created interface libraries for each ITK module with automatic transitive dependency linking
  • Migrated from directory-level includes to target-based includes using BUILD_INTERFACE/INSTALL_INTERFACE generator expressions
  • Updated 60+ filtering examples to explicitly link against specific module targets instead of the monolithic ${ITK_LIBRARIES}

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
Utilities/Maintenance/WhatModulesITK.py Enhanced script with argparse and new --link option to generate target_link_libraries commands; improved regex pattern for module detection
CMake/ITKModuleMacros.cmake Added interface library creation for modules, migrated to target-based include directories with generator expressions, added transitive dependency linking
CMake/ITKModuleInfo.cmake.in Added INCLUDE2_DIRS variable to support generator expression-based include directories
CMake/ITKModuleHeaderTest.cmake Updated header tests to use target-based include directories
CMake/ITKModuleEnablement.cmake Created factory meta-module interface libraries (ITKImageIO, ITKMeshIO, ITKTransformIO)
CMake/ITKModuleAPI.cmake Added INCLUDE2_DIRS propagation through module configuration
Modules/ThirdParty/MetaIO/src/CMakeLists.txt Added directory-level includes as compatibility workaround for third-party modules
Modules/ThirdParty/HDF5/CMakeLists.txt Added directory-level includes as compatibility workaround for third-party modules
Examples/Filtering/CMakeLists.txt Converted all examples from ${ITK_LIBRARIES} to explicit module targets with Module suffix and factory meta-modules

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@blowekamp blowekamp force-pushed the cmake_interface_module branch from e648c27 to 4b20ef5 Compare January 8, 2026 20:35
@blowekamp
Copy link
Member Author

blowekamp commented Jan 8, 2026

Thank you @Copilot for the thorough review! I've addressed the actionable feedback in the latest commit:

Fixed:

  • ✅ Removed the commented-out include_directories() and link_directories() blocks
  • ✅ Removed the if(TRUE) conditional wrapper around the ${itk-module}Module creation
  • ✅ Removed trailing space in itk_module_target_install(${itk-module}Module)
  • ✅ Removed commented-out debug messages
  • ✅ Fixed the module count bug in WhatModulesITK.py where len(allModules) was reported after base modules were discarded in --link mode

Regarding directory-level includes in third-party modules (MetaIO/HDF5):
These include_directories() calls are intentional compatibility exceptions for third-party code that doesn't use modern CMake target-based practices. Adding explanatory comments is a good suggestion - I can add those in a follow-up commit if the maintainers would like, though they're not critical to this PR's main goal.

@blowekamp
Copy link
Member Author

In SimpleITK the PR SimpleITK/SimpleITK#2475 is using this branch along with cmake FetchContent with ITK. Additionally it is build ITK in a super build and separate build are using ITK from the source or from the build tree. They seem to be working.

The one exception is the build with Elastic, which is encountering a Sobel filter related error 😸

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 22 out of 22 changed files in this pull request and generated 13 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@blowekamp blowekamp force-pushed the cmake_interface_module branch from 4b20ef5 to ea12c51 Compare January 9, 2026 00:10
@blowekamp
Copy link
Member Author

@bradking Would you be able to provide feedback on this PR?

Copy link
Contributor

@mathstuf mathstuf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some high-level recommendations based on VTK module experience:

  • add alias targets for all targets that match what find_package(ITK) users see
  • highly recommend exporting with ITK:: namespace (it will help with CPS support in the future)
  • use EXPORT_NAME property to name the post-:: install target rather than the core target name (a mistake from VTK's module system because I was unaware of the property)
  • use FILE_SET source listings so that you don't even need target_include_directories and header installation Just Works™ even with subdirectories (VTK opportunistically does it, but still supports even CMake 3.12(!))

Comment on lines 469 to 472
set(
itk-module-RUNTIME_LIBRARY_DIRS-install2
"$<INSTALL_INTERFACE:\${ITK_INSTALL_PREFIX}/${ITK_INSTALL_RUNTIME_DIR}>"
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's an open CMake feature request for runtime usage requirements like this. But it's not implemented yet.

@mathstuf
Copy link
Contributor

mathstuf commented Jan 9, 2026

Some of those recommendations might be out-of-scope for this PR.

@blowekamp blowekamp force-pushed the cmake_interface_module branch from ea12c51 to 5f1281c Compare January 9, 2026 19:41
Introduce ITK_INTERFACE_LIBRARIES variable to allow users to link to
the interface libraries with properties.

Add ITK_LIBRARY_NAMESPACE configuration (defaults to 'ITK') that enables
namespaced targets for all ITK modules (e.g., ITK::ITKCommonModule).

Introduce LIBRARIES_DEPRECATED variable alongside LIBRARIES to maintain
backward compatibility. Create INTERFACE IMPORTED wrappers for old target
names that link to new namespaced targets with DEPRECATION property set.

Update module system to use ${module-targets-namespace} throughout:
- itk_module_impl builds both deprecated and namespaced library lists
- itk_module_link_dependencies uses namespaced targets
- itk_module_test uses namespaced targets
- Factory meta-modules use namespaced targets

Update external itk_modile_config api to use ITK interface module
libraries.

Add init_module_vars() macro to set per-module namespace configuration.

Add documentation for itk_module_target_export() explaining export
mechanism and namespace handling for library targets.
@blowekamp blowekamp force-pushed the cmake_interface_module branch from 074d9c4 to 5c53e2b Compare January 21, 2026 21:23
@github-actions github-actions bot removed area:Core Issues affecting the Core module area:IO Issues affecting the IO module area:ThirdParty Issues affecting the ThirdParty module labels Jan 21, 2026
@blowekamp
Copy link
Member Author

blowekamp commented Jan 22, 2026

This is very close a couple choices made:

  • The ITK_LIBRARY_NAMESPACE is the one CMake variable which can be used to configure the CMake Library namespaces. It can be explicitly set to an empty string for special compatibility cases. It will be the same for all internal and remote modules (not a configuration variable in the ModuleInfo).
  • The COMPILE_DEPENS is treated the same as DEPENDS, introduce INTERFACE_DEPENDS following the CMake option, which can be used when the library does not need a dependency but other headers do.
  • A new INTERFACE_LIBRARIES is creating in the API which is accumulation of all the requested modules interface libraries.

Options:

  • From the ModuleAPI/ConfigITK, make the ITK_LIBRARIES the list of interface libraries replacing the compiled libraries.
  • Remove the ModuleInfo files, and related variables produced.

TODO:

  • Need to build application which use the olde factory registration system to verify still works with out changes.
  • Verify code documentation is consistent with the current implementation.

This PR is just about complete is unless there are additional major requests for features, compatibility or other changes that must go in the PR and not a follow up.

Additional testing and feedback is welcome.

P.S. Testing ITKMontage against a ITK build, and ITKRLEImage remote as an enable module during the build and others, all working.

@dzenanz
Copy link
Member

dzenanz commented Jan 22, 2026

I am building locally.

@dzenanz
Copy link
Member

dzenanz commented Jan 22, 2026

Builds and tests fine locally. Let's see when I start building some applications against it.

@dzenanz
Copy link
Member

dzenanz commented Jan 22, 2026

One small application builds and works.

@seanm
Copy link
Contributor

seanm commented Jan 22, 2026

Is this PR something I should test my app against before it's merged?

@blowekamp
Copy link
Member Author

Is this PR something I should test my app against before it's merged?

Yes, that will be helpful if you have time. Also feedback on the options, and compatibility would be appriciated.

Does your applications current use the "UseITK.cmake" approach with global properties and the ITK_LIBRARIES? Can it be easily update to use the for modular interface approach in the PR description?

@thewtex
Copy link
Member

thewtex commented Jan 22, 2026

the CMake Library namespaces

I wonder if @jcfr has thoughts on this.

@blowekamp can we update ITK/Examples/Installation/CMakeLists.txt?

@seanm
Copy link
Contributor

seanm commented Jan 22, 2026

Yes, that will be helpful if you have time. Also feedback on the options, and compatibility would be appriciated.

Does your applications current use the "UseITK.cmake" approach with global properties and the ITK_LIBRARIES? Can it be easily update to use the for modular interface approach in the PR description?

I build ITK with cmake, generating static libraries. My application I build with Xcode, not CMake. I just link to the static libraries.

I'll clone this and give it a try....

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 24 out of 24 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@jcfr
Copy link
Contributor

jcfr commented Jan 22, 2026

I will have a look later this weekend.

@seanm
Copy link
Contributor

seanm commented Jan 22, 2026

I tried rebuilding an existing ITK bin directory I have, but it failed to build (so didn't get as far as trying with my app):

CMake Error at /Users/sean/external/ITK-BS-ASan-bin/lib/cmake/ITK-6.0/Modules/ITKZLIB.cmake:17 (add_library):
  The target name
  "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/lib/libz.tbd"
  is reserved or not valid for certain CMake features, such as generator
  expressions, and may result in undefined behavior.
Call Stack (most recent call first):
  CMake/ITKModuleAPI.cmake:85 (include)
  CMake/ITKModuleAPI.cmake:7 (itk_module_load)
  CMake/ITKModuleAPI.cmake:181 (_itk_module_use_recurse)
  CMake/ITKModuleMacros.cmake:177 (itk_module_use)
  Modules/ThirdParty/MetaIO/CMakeLists.txt:10 (itk_module_impl)

I tried with a fresh bin directory and that did build; not yet sure what setting difference is relevant...

@seanm
Copy link
Contributor

seanm commented Jan 22, 2026

Actually, didn't take long to find... just setting ITK_USE_SYSTEM_ZLIB to YES seems to break the build.

@mathstuf
Copy link
Contributor

It looks like something ends up treating a path like a target. I think following the VTK pattern of always representing third party deps as a consistent target is the way to go here. It can then be backed by the vendored target or the imported target pretty easily.

Note that I found it extremely precarious to try and support a target-centric world and the variable-centric world at the same time. VTK's use of generator expressions made it nigh impossible (it could probably have been done, but may have extended the development period considerably). I don't know if ITK is using them to the same extent, but if not, a compatibility bridge might be feasible.

For a Module's Libraries, detect non-target library file with an
"EXISTS" check. This will detect full paths, but not library only
filenames with library search path usages.
Update the example usage of ITK to remove "UseITK" to use the
ITK's module interface libraries with the library properties.
@blowekamp
Copy link
Member Author

blowekamp commented Jan 23, 2026

Actually, didn't take long to find... just setting ITK_USE_SYSTEM_ZLIB to YES seems to break the build.

Thank you for testing! I have updated the PR with a fix which enabled building on Ubuntu 24.04 with system libraries include lib, expact, fifth,hdf5,jpeg,png,tif.

It looks like something ends up treating a path like a target. I think following the VTK pattern of always representing third party deps as a consistent target is the way to go here. It can then be backed by the vendored target or the imported target pretty easily.

Note that I found it extremely precarious to try and support a target-centric world and the variable-centric world at the same time. VTK's use of generator expressions made it nigh impossible (it could probably have been done, but may have extended the development period considerably). I don't know if ITK is using them to the same extent, but if not, a compatibility bridge might be feasible.

That sounds like an ideal solution. What I implemented was just detecting if a library was a file that existed. This approach will not work when library names/flags with LIBRARY_PATH are used. Using the name and path approach for libraries has been problematic with getting the correct library before, it should be reasonable to stop supporting it.

P.S. Also update the installation example.

@seanm
Copy link
Contributor

seanm commented Jan 23, 2026

I have updated the PR with a fix which enabled building on Ubuntu 24.04 with system libraries include lib, expact, fifth,hdf5,jpeg,png,tif.

That seemed to fix that, great!

Next thing I hit:

/Users/sean/external/ITK/Modules/IO/PhilipsREC/src/itkPhilipsRECImageIOFactory.cxx:20:10: fatal error: 'itkPhilipsRECImageIOFactory.h' file not found
   20 | #include "itkPhilipsRECImageIOFactory.h"
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

@github-actions github-actions bot added the area:IO Issues affecting the IO module label Jan 23, 2026
@blowekamp
Copy link
Member Author

I fixed the PhilipsREC module issues. Tested with additional internal modules successfully. Tested many level 2 remote models, and encountered and issue with the IO ones and the factories that will need further work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:Examples Demonstration of the use of classes area:IO Issues affecting the IO module area:Python wrapping Python bindings for a class type:Infrastructure Infrastructure/ecosystem related changes, such as CMake or buildbots

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants