diff --git a/CMake/ElastixITKDeps.cmake b/CMake/ElastixITKDeps.cmake new file mode 100644 index 000000000..3c38b5fa8 --- /dev/null +++ b/CMake/ElastixITKDeps.cmake @@ -0,0 +1,102 @@ +# +# ElastixITKDeps.cmake +# +# Provides a helper macro and convenience variables for linking ITK dependencies +# using modern CMake interface library targets (ITK 6+) or the legacy +# ${ITK_LIBRARIES} variable (ITK 5.x), maintaining backward compatibility. +# +# Must be included AFTER find_package(ITK ...) and, for ITK 6+, after +# itk_generate_factory_registration() has been called so that factory +# meta-module target properties are properly configured. +# +# Variables set by this file +# -------------------------- +# +# ELASTIX_ITK_EXECUTABLE_LIBRARIES +# For executables that already carry ITK processing module dependencies +# transitively via elxCommon (e.g. elastix_exe, transformix_exe, GTest targets). +# ITK 6+: IO factory meta-module targets (ITK::ITKImageIO, etc.) that provide +# the factory registration include directories and compile definitions. +# ITK 5.x: ${ITK_LIBRARIES} (factory registration handled globally by UseITK.cmake). +# +# ELASTIX_ITK_ALL_LIBRARIES +# For standalone executables that do NOT link elxCommon/elxCore and therefore +# need explicit ITK processing module dependencies as well as IO factories +# (e.g. elxComputeOverlap, elxImageCompare, external project examples). +# ITK 6+: ${ITK_INTERFACE_LIBRARIES} (all requested module interface libs) +# plus IO factory meta-module targets. +# ITK 5.x: ${ITK_LIBRARIES}. +# +# Macro provided +# -------------- +# +# elastix_link_itk( [PUBLIC|PRIVATE|INTERFACE] MODULES [ ...]) +# +# Links to specific ITK modules using: +# ITK 6+: ITK::Module interface library targets +# ITK 5.x: ${ITK_LIBRARIES} (all loaded modules) +# +# The optional scope keyword (PUBLIC / PRIVATE / INTERFACE) controls CMake +# link visibility and may be omitted for old-style plain linkage. +# +# Example (library that exposes ITK types in its public headers): +# elastix_link_itk(elxCommon PUBLIC MODULES +# ITKCommon ITKTransform ITKOptimizers ITKRegistrationCommon) +# +# Example (internal library with no public ITK API): +# elastix_link_itk(param MODULES ITKCommon) +# + +if(ITK_VERSION_MAJOR GREATER_EQUAL 6) + # Collect IO factory meta-module targets configured by itk_generate_factory_registration(). + # These carry INTERFACE_INCLUDE_DIRECTORIES pointing to the generated factory + # registration headers and INTERFACE_COMPILE_DEFINITIONS enabling the managers. + set(ELASTIX_ITK_EXECUTABLE_LIBRARIES "") + foreach(_elx_meta ITKImageIO ITKTransformIO ITKMeshIO) + if(TARGET ITK::${_elx_meta}) + list(APPEND ELASTIX_ITK_EXECUTABLE_LIBRARIES ITK::${_elx_meta}) + endif() + endforeach() + unset(_elx_meta) + + # ITKTestKernel provides test utilities (itkTestingComparisonImageFilter.h, etc.). + # Linked only to test targets; not added to production libraries. + if(TARGET ITK::ITKTestKernelModule) + set(ELASTIX_ITK_TEST_LIBRARIES ITK::ITKTestKernelModule) + else() + set(ELASTIX_ITK_TEST_LIBRARIES "") + endif() + + # Full ITK: all requested module interface libraries + IO factory meta-modules. + # ITK_INTERFACE_LIBRARIES is set by itk_module_config() in ITKConfig.cmake + # and contains one ITK::Module target per loaded ITK module. + set(ELASTIX_ITK_ALL_LIBRARIES ${ITK_INTERFACE_LIBRARIES} ${ELASTIX_ITK_EXECUTABLE_LIBRARIES}) + +else() + # ITK 5.x: the single ${ITK_LIBRARIES} variable covers all requested modules + # and IO factories (factory registration is done globally by UseITK.cmake). + set(ELASTIX_ITK_EXECUTABLE_LIBRARIES ${ITK_LIBRARIES}) + set(ELASTIX_ITK_TEST_LIBRARIES "") + set(ELASTIX_ITK_ALL_LIBRARIES ${ITK_LIBRARIES}) +endif() + +# +# elastix_link_itk( [PUBLIC|PRIVATE|INTERFACE] MODULES [ ...]) +# +macro(elastix_link_itk _elt_target) + cmake_parse_arguments(_elt "" "" "MODULES" ${ARGN}) + # _elt_UNPARSED_ARGUMENTS holds an optional scope keyword (PUBLIC/PRIVATE/INTERFACE). + if(ITK_VERSION_MAJOR GREATER_EQUAL 6) + set(_elt_itk_link_targets "") + foreach(_elt_mod ${_elt_MODULES}) + list(APPEND _elt_itk_link_targets ITK::${_elt_mod}Module) + endforeach() + target_link_libraries(${_elt_target} ${_elt_UNPARSED_ARGUMENTS} ${_elt_itk_link_targets}) + unset(_elt_itk_link_targets) + unset(_elt_mod) + else() + target_link_libraries(${_elt_target} ${_elt_UNPARSED_ARGUMENTS} ${ITK_LIBRARIES}) + endif() + unset(_elt_MODULES) + unset(_elt_UNPARSED_ARGUMENTS) +endmacro() diff --git a/CMakeLists.txt b/CMakeLists.txt index 541a76248..5c4bbe3f8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,7 +86,20 @@ find_package(ITK 5.4.1 REQUIRED COMPONENTS ${_GPU_depends} ${_ITK_io_depends} ) -include(${ITK_USE_FILE}) + +if(ITK_VERSION_MAJOR GREATER_EQUAL 6) + # ITK 6+: use modern interface library targets. + # itk_generate_factory_registration() configures the factory registration + # headers and sets INTERFACE properties on the factory meta-module targets + # (ITK::ITKImageIO, ITK::ITKTransformIO, ITK::ITKMeshIO). + # Must be called before any add_subdirectory() so the target properties are + # ready when subdirectory CMakeLists.txt files reference them. + itk_generate_factory_registration() +else() + # ITK 5.x: UseITK.cmake sets global include/link directories and calls + # itk_generate_factory_registration() internally. + include(${ITK_USE_FILE}) +endif() #--------------------------------------------------------------------- # Add the CMake dir as an additional module path, @@ -100,6 +113,10 @@ include(elastixVersion) # Function for exporting targets include(elastixExportTarget) +# ITK dependency helper: provides elastix_link_itk() macro and +# ELASTIX_ITK_EXECUTABLE_LIBRARIES / ELASTIX_ITK_ALL_LIBRARIES variables. +include(ElastixITKDeps) + if (MSVC) add_compile_options(/W3) else() diff --git a/Common/CMakeLists.txt b/Common/CMakeLists.txt index 007545d5e..1d16e7d9a 100644 --- a/Common/CMakeLists.txt +++ b/Common/CMakeLists.txt @@ -214,8 +214,32 @@ endif() #--------------------------------------------------------------------- # Link against other libraries. -target_link_libraries(elxCommon - ${ITK_LIBRARIES} +elastix_link_itk(elxCommon PUBLIC MODULES + ITKCommon + ITKDisplacementField + ITKDistanceMap + ITKImageCompose + ITKImageFilterBase + ITKImageFunction + ITKImageGradient + ITKImageGrid + ITKImageIntensity + ITKImageStatistics + ITKIOImageBase + ITKIOMeshBase + ITKIOMeta + ITKIOTransformBase + ITKIOXML + ITKMathematicalMorphology + ITKMesh + ITKOptimizers + ITKRegistrationCommon + ITKSmoothing + ITKSpatialObjects + ITKStatistics + ITKThresholding + ITKTransform + ITKTransformFactory ) target_include_directories(elxCommon PUBLIC diff --git a/Common/GTesting/CMakeLists.txt b/Common/GTesting/CMakeLists.txt index d10d1bbc8..641d3206b 100644 --- a/Common/GTesting/CMakeLists.txt +++ b/Common/GTesting/CMakeLists.txt @@ -39,14 +39,14 @@ if (ITK_VERSION VERSION_LESS_EQUAL 5.4.5) target_link_libraries(CommonGTest GTest::GTest GTest::Main - ${ITK_LIBRARIES} + ${ELASTIX_ITK_EXECUTABLE_LIBRARIES} elastix_lib ) else() target_link_libraries(CommonGTest GTest::gtest GTest::gtest_main - ${ITK_LIBRARIES} + ${ELASTIX_ITK_EXECUTABLE_LIBRARIES} elastix_lib ) endif() diff --git a/Common/MevisDicomTiff/CMakeLists.txt b/Common/MevisDicomTiff/CMakeLists.txt index bc8fa4124..acbd5c800 100644 --- a/Common/MevisDicomTiff/CMakeLists.txt +++ b/Common/MevisDicomTiff/CMakeLists.txt @@ -24,7 +24,11 @@ if(NOT ELASTIX_NO_INSTALL_DEVELOPMENT) COMPONENT Development) endif() -target_link_libraries(mevisdcmtiff ${ITK_LIBRARIES}) +elastix_link_itk(mevisdcmtiff MODULES + ITKCommon + ITKGDCM + ITKIOImageBase +) target_include_directories(mevisdcmtiff PUBLIC $ $) diff --git a/Common/OpenCL/CMakeLists.txt b/Common/OpenCL/CMakeLists.txt index b3b49e2e3..a10ed3edc 100644 --- a/Common/OpenCL/CMakeLists.txt +++ b/Common/OpenCL/CMakeLists.txt @@ -56,10 +56,15 @@ set(OpenCL_Files add_library(elxOpenCL STATIC ${OpenCL_Files}) # Link it against the necessary libraries. -target_link_libraries(elxOpenCL - ${ITK_LIBRARIES} - ${OPENCL_LIBRARIES} +elastix_link_itk(elxOpenCL MODULES + ITKCommon + ITKGPUCommon + ITKTransform + ITKImageGrid + ITKSmoothing + ITKImageFunction ) +target_link_libraries(elxOpenCL ${OPENCL_LIBRARIES}) target_include_directories(elxOpenCL PUBLIC ${OPENCL_INCLUDE_DIRS}) target_compile_definitions(elxOpenCL PUBLIC ELASTIX_USE_OPENCL) diff --git a/Common/ParameterFileParser/CMakeLists.txt b/Common/ParameterFileParser/CMakeLists.txt index 202620576..2a9dd7cb8 100644 --- a/Common/ParameterFileParser/CMakeLists.txt +++ b/Common/ParameterFileParser/CMakeLists.txt @@ -17,7 +17,9 @@ if(NOT ELASTIX_NO_INSTALL_DEVELOPMENT) COMPONENT Development) endif() -target_link_libraries(param ${ITK_LIBRARIES}) +elastix_link_itk(param MODULES + ITKCommon +) target_include_directories(param PUBLIC $ $) diff --git a/Components/CMakeLists.txt b/Components/CMakeLists.txt index bf6d242b1..1f202dcd0 100644 --- a/Components/CMakeLists.txt +++ b/Components/CMakeLists.txt @@ -5,10 +5,22 @@ project(elxComponents) #--------------------------------------------------------------------- # Set the libraries to be linked. - -set(elxLinkLibs - elxCore - ${ITK_LIBRARIES}) +# +# For ITK 6+, component libraries inherit all ITK processing module dependencies +# transitively via elxCore -> elxCommon (PUBLIC link). No additional direct +# ITK module link is needed here. +# For ITK 5.x, ${ITK_LIBRARIES} provides full coverage (factory registration +# is handled globally by UseITK.cmake). +if(ITK_VERSION_MAJOR GREATER_EQUAL 6) + set(elxLinkLibs + elxCore + ) +else() + set(elxLinkLibs + elxCore + ${ITK_LIBRARIES} + ) +endif() #-------------------------------------------------------------------- # Prepare elxInstallComponentFunctionDeclarations.h and diff --git a/Components/Metrics/KNNGraphAlphaMutualInformation/KNN/CMakeLists.txt b/Components/Metrics/KNNGraphAlphaMutualInformation/KNN/CMakeLists.txt index 69345cce1..0b04c800b 100644 --- a/Components/Metrics/KNNGraphAlphaMutualInformation/KNN/CMakeLists.txt +++ b/Components/Metrics/KNNGraphAlphaMutualInformation/KNN/CMakeLists.txt @@ -36,7 +36,12 @@ add_subdirectory(ann_1.1) add_library(KNNlib STATIC ${KNN_Files}) # Link it against the necessary libraries. -target_link_libraries(KNNlib ANNlib ${ITK_LIBRARIES}) +elastix_link_itk(KNNlib MODULES + ITKCommon + ITKStatistics + ITKSpatialObjects +) +target_link_libraries(KNNlib ANNlib) # Group in IDE's like Visual Studio set_property(TARGET KNNlib PROPERTY FOLDER "libraries") diff --git a/Core/CMakeLists.txt b/Core/CMakeLists.txt index 4cf201804..4faa2789f 100644 --- a/Core/CMakeLists.txt +++ b/Core/CMakeLists.txt @@ -185,13 +185,20 @@ elastix_export_target(param) # Define the mevis dcm tiff lib to which we should link. set(mevisdcmtifflib mevisdcmtiff) +# For ITK 6+: executables link to the IO factory meta-module targets which carry +# INTERFACE_INCLUDE_DIRECTORIES pointing to the generated factory registration +# headers (itkImageIOFactoryRegisterManager.h, etc.) and INTERFACE_COMPILE_DEFINITIONS +# enabling the registration managers. ELASTIX_ITK_EXECUTABLE_LIBRARIES is set +# by CMake/ElastixITKDeps.cmake (included from the top-level CMakeLists.txt). +# For ITK 5.x: ${ITK_LIBRARIES} is used (factory registration handled globally +# by UseITK.cmake via directory-scoped COMPILE_DEFINITIONS). set(ELASTIX_TARGET_LINK_LIBRARIES param elxCommon elxCore ${mevisdcmtifflib} ${AllComponentLibs} - ${ITK_LIBRARIES} + ${ELASTIX_ITK_EXECUTABLE_LIBRARIES} ) if(ELASTIX_USE_OPENCL) set(ELASTIX_TARGET_LINK_LIBRARIES ${ELASTIX_TARGET_LINK_LIBRARIES} elxOpenCL) diff --git a/Core/Main/GTesting/CMakeLists.txt b/Core/Main/GTesting/CMakeLists.txt index f2bd9d210..bfba876a0 100644 --- a/Core/Main/GTesting/CMakeLists.txt +++ b/Core/Main/GTesting/CMakeLists.txt @@ -18,7 +18,7 @@ if (ITK_VERSION VERSION_LESS_EQUAL 5.4.5) GTest::Main elastix_lib transformix_lib - ${ITK_LIBRARIES} + ${ELASTIX_ITK_EXECUTABLE_LIBRARIES} ) else() target_link_libraries(ElastixLibGTest @@ -26,7 +26,7 @@ else() GTest::gtest_main elastix_lib transformix_lib - ${ITK_LIBRARIES} + ${ELASTIX_ITK_EXECUTABLE_LIBRARIES} ) endif() diff --git a/ElastixConfig.cmake.in b/ElastixConfig.cmake.in index 3b084d4cd..c9246b985 100644 --- a/ElastixConfig.cmake.in +++ b/ElastixConfig.cmake.in @@ -25,6 +25,16 @@ if(NOT ITK_CONFIG_TARGETS_FILE) find_package(ITK "@ITK_VERSION@" EXACT REQUIRED) endif() +# For ITK 6+: generate factory registration headers and configure factory +# meta-module target properties in the downstream project's build scope. +# Guards against double-invocation if the downstream project also calls this. +if(NOT ELASTIX_ITK_FACTORY_REGISTRATION_DONE) + set(ELASTIX_ITK_FACTORY_REGISTRATION_DONE TRUE) + if(ITK_VERSION_MAJOR GREATER_EQUAL 6 AND COMMAND itk_generate_factory_registration) + itk_generate_factory_registration() + endif() +endif() + # Import ELASTIX targets. set( ELASTIX_CONFIG_TARGETS_FILE "${_ELASTIXConfig_DIR}/ElastixTargets.cmake") diff --git a/Testing/CMakeLists.txt b/Testing/CMakeLists.txt index ea58367e5..4471ffce5 100644 --- a/Testing/CMakeLists.txt +++ b/Testing/CMakeLists.txt @@ -73,7 +73,8 @@ macro(elx_add_test_core executable_name source_name test_name group) param # some test use the CommandLineArgumentParser elxCommon # provides Common headers (Transforms, CostFunctions, etc.) ${mevisdcmtifflib} # is empty if not selected in CMake - ${ITK_LIBRARIES} + ${ELASTIX_ITK_EXECUTABLE_LIBRARIES} + ${ELASTIX_ITK_TEST_LIBRARIES} ) if(ELASTIX_USE_OPENCL) @@ -420,22 +421,22 @@ endmacro() # Create elxComputeOverlap add_executable(elxComputeOverlap elxComputeOverlap.cxx itkCommandLineArgumentParser.cxx) -target_link_libraries(elxComputeOverlap ${ITK_LIBRARIES}) +target_link_libraries(elxComputeOverlap ${ELASTIX_ITK_ALL_LIBRARIES}) set_property(TARGET elxComputeOverlap PROPERTY FOLDER "tests/Executable") # Create elxImageCompare add_executable(elxImageCompare elxImageCompare.cxx itkCommandLineArgumentParser.cxx) -target_link_libraries(elxImageCompare ${ITK_LIBRARIES}) +target_link_libraries(elxImageCompare ${ELASTIX_ITK_ALL_LIBRARIES}) set_property(TARGET elxImageCompare PROPERTY FOLDER "tests/Executable") # Create elxTransformParametersCompare add_executable(elxTransformParametersCompare elxTransformParametersCompare.cxx itkCommandLineArgumentParser.cxx) -target_link_libraries(elxTransformParametersCompare elxCore param ${ITK_LIBRARIES}) +target_link_libraries(elxTransformParametersCompare elxCore param ${ELASTIX_ITK_EXECUTABLE_LIBRARIES}) set_property(TARGET elxTransformParametersCompare PROPERTY FOLDER "tests/Executable") # Create elxInvertTransform add_executable(elxInvertTransform elxInvertTransform.cxx itkCommandLineArgumentParser.cxx) -target_link_libraries(elxInvertTransform elxCore param ${ITK_LIBRARIES}) +target_link_libraries(elxInvertTransform elxCore param ${ELASTIX_ITK_EXECUTABLE_LIBRARIES}) set_property(TARGET elxInvertTransform PROPERTY FOLDER "tests/Executable") #--------------------------------------------------------------------- diff --git a/UseElastix.cmake.in b/UseElastix.cmake.in index c486d8975..dcdddfdc2 100644 --- a/UseElastix.cmake.in +++ b/UseElastix.cmake.in @@ -6,6 +6,12 @@ # find_package( Elastix REQUIRED ) # include( ${ELASTIX_USE_FILE} ) # +# Note: for ITK 6+, prefer linking directly to the 'elastix_lib' or +# 'transformix_lib' CMake targets instead of using this file. Modern +# targets carry include directories, compile definitions, and all ITK +# interface library dependencies as transitive INTERFACE properties, +# so include_directories() and link_directories() are no longer needed. +# # Add include dirs include_directories( ${ELASTIX_INCLUDE_DIRS} ) diff --git a/dox/externalproject/CMakeLists.txt b/dox/externalproject/CMakeLists.txt index 051738530..611c4722e 100644 --- a/dox/externalproject/CMakeLists.txt +++ b/dox/externalproject/CMakeLists.txt @@ -12,6 +12,13 @@ if ( DEFINED ELASTIX_ITK_DIR) endif() find_package(ITK REQUIRED) +# For ITK 6+: call itk_generate_factory_registration() to configure the factory +# registration headers and set INTERFACE properties on factory meta-module targets +# (ITK::ITKImageIO, etc.) before any add_executable() calls. +if(ITK_VERSION_MAJOR GREATER_EQUAL 6) + itk_generate_factory_registration() +endif() + # Use the version of Torch from Elastix. if ( DEFINED ELASTIX_Torch_DIR) set(Torch_DIR "${ELASTIX_Torch_DIR}" CACHE PATH "Torch_DIR from Elastix" FORCE) @@ -28,22 +35,33 @@ add_executable(elastix_translation_example ElastixTranslationExample.cxx) set_property(TARGET elastix_translation_example PROPERTY CXX_STANDARD 17) -target_include_directories(elastix_translation_example - PRIVATE ${ELASTIX_INCLUDE_DIRS} ${ITK_INCLUDE_DIRS}) - -target_link_libraries(elastix_translation_example - PRIVATE ${ITK_LIBRARIES} elastix_lib) +if(ITK_VERSION_MAJOR GREATER_EQUAL 6) + # ITK 6+: elastix_lib carries all ITK module dependencies and include paths + # transitively via its INTERFACE_LINK_LIBRARIES. No explicit ${ITK_INCLUDE_DIRS} + # or ${ITK_LIBRARIES} needed. + target_link_libraries(elastix_translation_example + PRIVATE elastix_lib) +else() + target_include_directories(elastix_translation_example + PRIVATE ${ELASTIX_INCLUDE_DIRS} ${ITK_INCLUDE_DIRS}) + target_link_libraries(elastix_translation_example + PRIVATE ${ITK_LIBRARIES} elastix_lib) +endif() # Build the example executable using Impact metric add_executable(elastix_impact_metric_example ElastixImpactMetricExample.cxx) set_property(TARGET elastix_impact_metric_example PROPERTY CXX_STANDARD 17) -target_include_directories(elastix_impact_metric_example - PRIVATE ${ELASTIX_INCLUDE_DIRS} ${ITK_INCLUDE_DIRS}) - -target_link_libraries(elastix_impact_metric_example - PRIVATE ${ITK_LIBRARIES} elastix_lib) +if(ITK_VERSION_MAJOR GREATER_EQUAL 6) + target_link_libraries(elastix_impact_metric_example + PRIVATE elastix_lib) +else() + target_include_directories(elastix_impact_metric_example + PRIVATE ${ELASTIX_INCLUDE_DIRS} ${ITK_INCLUDE_DIRS}) + target_link_libraries(elastix_impact_metric_example + PRIVATE ${ITK_LIBRARIES} elastix_lib) +endif() file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/Conv2D_ChannelReplicator.pt