Fix build-tree export references for superproject builds#150
Conversation
The build-tree DCMTKTargets.cmake is written by export(TARGETS ... NAMESPACE DCMTK::), which prefixes DCMTK:: onto every in-build target referenced by the exported link interfaces, including targets owned by a superproject that vendors DCMTK via add_subdirectory() or FetchContent() (e.g. a codec target supplied through ZLIB_LIBRARIES). The export then records nonexistent targets such as DCMTK::ITK::ITKZLIBModule or DCMTK::super_zlibwrap, and any external consumer of the superproject's build tree that imports DCMTKConfig fails at CMake generate with 'target ... not found'. The install-tree export is written by install(EXPORT) and resolves the same references correctly. All genuine DCMTK:: targets are defined once DCMTKConfig.cmake has included DCMTKTargets.cmake, so strip the mis-applied prefix from any DCMTK::-prefixed link-interface reference that is not an existing target. For the install tree and for standalone builds the loop is a no-op.
a867c7c to
6d69495
Compare
|
Here is a self-contained minimal failing test case (no ITK required) — four small files, CMake ≥ 3.24, configure-only. It uses a dependency provider, the standard mechanism for a superproject to satisfy a vendored project's
cmake_minimum_required(VERSION 3.24)
project(super C CXX)
add_library(super_zlibwrap INTERFACE)
add_library(Super::zlibwrap ALIAS super_zlibwrap)
install(TARGETS super_zlibwrap EXPORT SuperTargets)
install(EXPORT SuperTargets NAMESPACE Super:: DESTINATION lib/cmake/super)
set(BUILD_APPS OFF)
add_subdirectory(${DCMTK_SOURCE} dcmtk)
macro(super_provide_dependency method dep_name)
if("${dep_name}" STREQUAL "ZLIB")
find_package(ZLIB BYPASS_PROVIDER)
set(ZLIB_LIBRARIES Super::zlibwrap)
endif()
endmacro()
cmake_language(SET_DEPENDENCY_PROVIDER super_provide_dependency SUPPORTED_METHODS FIND_PACKAGE)
cmake_minimum_required(VERSION 3.24)
project(consumer C CXX)
find_package(DCMTK REQUIRED CONFIG)
add_executable(t main.cxx)
target_link_libraries(t DCMTK::dcmdata)( Run: cmake -S super -B super-b -G Ninja \
-DDCMTK_SOURCE=/path/to/dcmtk \
-DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=$PWD/super/provider.cmake \
-DDCMTK_WITH_ZLIB=ON
# superproject configures and generates with no errors, but:
grep 'DCMTK::super_zlibwrap' super-b/DCMTKTargets.cmake # the mis-prefixed reference
cmake -S consumer -B consumer-b -G Ninja -DDCMTK_DIR=$PWD/super-bResult on current master — the consumer fails at generate: With this PR applied, the same consumer configures and generates cleanly, and the superproject's own Note the test case surfaced a second shape of the same defect: when the superproject's value is a plain ALIAS, CMake records the de-aliased real name ( |
When DCMTK is vendored inside a superproject (
add_subdirectory()/FetchContent()) and the superproject supplies its own imported codec targets (e.g.ZLIB_LIBRARIES=ITK::ITKZLIBModule), the build-treeDCMTKTargets.cmakewritten byexport(TARGETS ... NAMESPACE DCMTK::)records nonexistent double-namespaced targets likeDCMTK::ITK::ITKZLIBModule. This patch hasDCMTKConfig.cmakestrip the mis-applied prefix from anyDCMTK::-prefixed link-interface reference that does not name an existing target afterDCMTKTargets.cmakehas been imported (all genuineDCMTK::targets exist at that point) — a no-op for the install tree and for standalone builds.Failure this fixes
ITK vendors DCMTK via FetchContent and points external consumers of ITK's build tree at the generated
DCMTKConfig.cmake. Such a consumer (e.g. an ANTs SuperBuild) fails at CMake generate:The root cause is
export(TARGETS)semantics: it namespace-prefixes every in-build target referenced by the exported link interfaces, including targets owned by the superproject rather than by DCMTK. The install-tree export, written byinstall(EXPORT), resolves the same references to their real names and is unaffected. Two shapes occur: ITK's FetchContent setup records the namespaced name (DCMTK::ITK::ITKZLIBModule), while a plain ALIAS supplied by a superproject is recorded de-aliased (DCMTK::super_zlibwrap). Checking target existence after import handles both without ever touching genuine DCMTK targets. A self-contained minimal failing test case (no ITK needed) is in the first PR comment.Downstream context: InsightSoftwareConsortium/ITK#6548 carries the same repair on the ITK side; with this patch in DCMTK, that consumer-side workaround becomes unnecessary. Related in spirit to #145, which handled external imported targets in
DCMTKConfig.cmakefor standalone builds.Verification
Reproduced and validated against ITK's FetchContent vendoring of DCMTK (Linux, CMake 3.28, Ninja):
Module_ITKIODCMTK=ON(vendored DCMTK);grep 'DCMTK::ITK::' <build>/DCMTKTargets.cmakeshows the mis-prefixed entries.find_package(ITK COMPONENTS ITKIODCMTK)+ link + run): fails at generate with the error above.DCMTKConfig.cmake.inchange applied to the vendored DCMTK source and ITK reconfigured, the same consumer configures, generates, links, and runs.install(EXPORT)output is unchanged).