Skip to content

Factory registration include directory collides between targets in one project #6860

Description

@hjmjohnson

itk_generate_factory_registration() stores the generated header's include directory on the shared ITK::ITKImageIO target, so in a project with more than one target requesting different IO components the last call wins and the other targets compile against the wrong registration header.

Reproducer

# CMakeLists.txt
cmake_minimum_required(VERSION 3.22.1)
project(FactoryRegistrationCollision CXX)
find_package(ITK 6 REQUIRED)       # aggregate project finds ITK once
add_subdirectory(png_example)
add_subdirectory(meta_example)
# png_example/CMakeLists.txt   (meta_example is identical with ITKIOMeta)
project(png_example CXX)
find_package(ITK REQUIRED COMPONENTS ITKCommon ITKIOImageBase ITKIOPNG)
itk_generate_factory_registration()
add_executable(png_example prog.cxx)
target_link_libraries(png_example PRIVATE ITK::ITKCommonModule ITK::ITKImageIO)

prog.cxx writes a 4x4 image to argv[1] with itk::WriteImage.

Observed

target components requested factories in binary runtime
png_example ITKIOPNG Meta fails to write .png
meta_example ITKIOMeta Meta writes .mha

png_example fails with Could not create IO object for writing file, because it was compiled against meta_example's registration header.

Expected

Each target registers the factories for the components it requested.

Cause

_itk_configure_FactoryRegisterManager in CMake/ITKFactoryRegistration.cmake writes the header to ${CMAKE_CURRENT_BINARY_DIR}/ITKFactoryRegistration and then points the meta-module target at it:

set_property(
  TARGET ${_meta_module}
  PROPERTY INTERFACE_INCLUDE_DIRECTORIES
    "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/ITKFactoryRegistration>"
)

The property is overwritten on each call. Two sibling subdirectories that each call find_package(ITK) themselves are unaffected, because each gets its own imported target; the collision appears once a parent scope calls find_package(ITK) and the subdirectories inherit that target.

Impact

Per-target narrowing of IO components is not usable in a single-project build. In ITKSphinxExamples, narrowing each example to the formats it reads reduces the built examples from 5.26 GB to 0.72 GB, but only works when each example is configured as its own project; in the aggregate build 62 of 558 tests fail this way.

Verified against ITK main (6.0.0) on macOS with AppleClang.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions