From 2fb9c29ae77e74c2e34e73decc17e621c9a56841 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Feb 2026 10:50:36 +0000 Subject: [PATCH 1/4] Initial plan From a030818fee19bd4ed9a86f943e5458c35a88a1b0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Feb 2026 10:57:50 +0000 Subject: [PATCH 2/4] ENH: Fix INTERFACE_INCLUDE_DIRECTORIES error for source-prefixed paths When system include directories are within the source directory (e.g., .pixi/envs/python/include), they should only be added to BUILD_INTERFACE, not INSTALL_INTERFACE. CMake does not allow INTERFACE properties to contain paths prefixed in the source directory. This fix checks each system include directory using file(RELATIVE_PATH) and only adds it to INSTALL_INTERFACE if it is outside the source directory. The implementation: - Normalizes paths with REALPATH to handle symlinks consistently - Handles both Unix (/) and Windows (\) path separators - Checks for empty relative paths (directory equals source directory) - Identifies parent directory references (../) to detect external paths --- CMake/ITKModuleMacros.cmake | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/CMake/ITKModuleMacros.cmake b/CMake/ITKModuleMacros.cmake index f60c236d614..2c51b13c748 100644 --- a/CMake/ITKModuleMacros.cmake +++ b/CMake/ITKModuleMacros.cmake @@ -258,12 +258,32 @@ endif() set(${itk-module}_SYSTEM_GENEX_INCLUDE_DIRS "") if(${itk-module}_SYSTEM_INCLUDE_DIRS) foreach(_dir ${${itk-module}_SYSTEM_INCLUDE_DIRS}) + # Always add to BUILD_INTERFACE list( APPEND ${itk-module}_SYSTEM_GENEX_INCLUDE_DIRS "$" - "$" ) + # Only add to INSTALL_INTERFACE if the directory is not within the source directory + # CMake does not allow INTERFACE properties to contain paths prefixed in the source directory + # Normalize the path to handle symlinks consistently + get_filename_component(_dir_real "${_dir}" REALPATH) + file(RELATIVE_PATH _relpath "${CMAKE_SOURCE_DIR}" "${_dir_real}") + # Check if directory is outside source tree: + # - Empty _relpath means _dir equals CMAKE_SOURCE_DIR (inside source) + # - Path starting with ".." means outside source tree + # - Pattern matches ".." at start followed by path separator (/ or \) or end of string + if(_relpath AND (_relpath MATCHES "^\\.\\.([/\\\\]|$)")) + # Directory is outside source directory, safe to add to INSTALL_INTERFACE + list( + APPEND + ${itk-module}_SYSTEM_GENEX_INCLUDE_DIRS + "$" + ) + else() + # Directory is within source directory or equals source directory + # Skip adding to INSTALL_INTERFACE as it's a build-time only dependency + endif() endforeach() endif() From ff78d32eb5af82cd4bc1e849678e79a949b8cbfc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Feb 2026 15:52:55 +0000 Subject: [PATCH 3/4] ENH: Fix INTERFACE_INCLUDE_DIRECTORIES in ITKBridgeNumPy module Conditionally set SYSTEM_INCLUDE_DIRS based on Python location. When Python is in source directory (e.g., .pixi/envs), use include_directories() for build-time only instead of SYSTEM_INCLUDE_DIRS which would add to INSTALL_INTERFACE and violate CMake policy. This fixes the CMake error: Target 'ITKBridgeNumPyModule' INTERFACE_INCLUDE_DIRECTORIES property contains path which is prefixed in the source directory. The previous approach of modifying ITKModuleMacros.cmake was incorrect as it changed behavior for all modules. The fix should be localized to the ITKBridgeNumPy module where the issue originates. Handles edge cases: - Empty relative path (directory equals source directory) - Absolute paths on different drives (Windows-specific) - Parent directory references (../) --- Modules/Bridge/NumPy/CMakeLists.txt | 39 ++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/Modules/Bridge/NumPy/CMakeLists.txt b/Modules/Bridge/NumPy/CMakeLists.txt index 8807e4b6954..976a6d1b3b5 100644 --- a/Modules/Bridge/NumPy/CMakeLists.txt +++ b/Modules/Bridge/NumPy/CMakeLists.txt @@ -1,7 +1,44 @@ cmake_minimum_required(VERSION 3.16.3) project(ITKBridgeNumPy) -set(ITKBridgeNumPy_SYSTEM_INCLUDE_DIRS "${Python3_INCLUDE_DIRS}") +# Only set SYSTEM_INCLUDE_DIRS if Python is outside the source directory +# CMake does not allow INTERFACE properties to contain paths prefixed in the source directory +set(ITKBridgeNumPy_SYSTEM_INCLUDE_DIRS "") +if(Python3_INCLUDE_DIRS) + foreach(_py_inc_dir ${Python3_INCLUDE_DIRS}) + # Check if Python include directory is outside the source tree + get_filename_component(_py_inc_real "${_py_inc_dir}" REALPATH) + # Use CMAKE_SOURCE_DIR which is the ITK source directory when building as part of ITK + file(RELATIVE_PATH _relpath "${CMAKE_SOURCE_DIR}" "${_py_inc_real}") + + # Determine if directory is outside the source tree: + # 1. Empty _relpath means directory equals CMAKE_SOURCE_DIR (inside source) + # 2. If _relpath is still absolute (Windows: different drive), it's outside source + # 3. If _relpath starts with "..", it's outside the source tree + # Pattern matches: ".." at start, followed by "/" or "\" (path separator) or end of string + set(_is_outside_source FALSE) + if(_relpath) + if(IS_ABSOLUTE "${_relpath}") + # Path is on different drive/root (Windows-specific), outside source tree + set(_is_outside_source TRUE) + elseif(_relpath MATCHES "^\\.\\.([/\\\\]|$)") + # Path starts with "..", outside source tree + set(_is_outside_source TRUE) + endif() + endif() + + if(_is_outside_source) + # Directory is outside source directory, safe to add to SYSTEM_INCLUDE_DIRS + # This will be added to both BUILD_INTERFACE and INSTALL_INTERFACE + list(APPEND ITKBridgeNumPy_SYSTEM_INCLUDE_DIRS "${_py_inc_dir}") + else() + # Directory is within source directory or equals source directory (e.g., .pixi/envs) + # Use include_directories() to add for build-time compilation only + # This affects all targets in this module but won't propagate to INSTALL_INTERFACE + include_directories("${_py_inc_dir}") + endif() + endforeach() +endif() if(NOT ITK_SOURCE_DIR) find_package(ITK REQUIRED) From daebeaadf58495a0f8cc051ba8250fdbb061d8d5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Feb 2026 16:24:02 +0000 Subject: [PATCH 4/4] ENH: Use BUILD_INTERFACE generator expression for Python includes Add Python includes directly to ITKBridgeNumPyModule target using $ generator expression after itk_module_impl(). This prevents CMake errors about source-prefixed paths in INSTALL_INTERFACE while keeping the includes available during build. Reverts incorrect changes to ITKModuleMacros.cmake that affected all modules. Addresses reviewer request to use $ generator expressions. --- CMake/ITKModuleMacros.cmake | 22 +------------ Modules/Bridge/NumPy/CMakeLists.txt | 49 +++++++---------------------- 2 files changed, 13 insertions(+), 58 deletions(-) diff --git a/CMake/ITKModuleMacros.cmake b/CMake/ITKModuleMacros.cmake index 2c51b13c748..f60c236d614 100644 --- a/CMake/ITKModuleMacros.cmake +++ b/CMake/ITKModuleMacros.cmake @@ -258,32 +258,12 @@ endif() set(${itk-module}_SYSTEM_GENEX_INCLUDE_DIRS "") if(${itk-module}_SYSTEM_INCLUDE_DIRS) foreach(_dir ${${itk-module}_SYSTEM_INCLUDE_DIRS}) - # Always add to BUILD_INTERFACE list( APPEND ${itk-module}_SYSTEM_GENEX_INCLUDE_DIRS "$" + "$" ) - # Only add to INSTALL_INTERFACE if the directory is not within the source directory - # CMake does not allow INTERFACE properties to contain paths prefixed in the source directory - # Normalize the path to handle symlinks consistently - get_filename_component(_dir_real "${_dir}" REALPATH) - file(RELATIVE_PATH _relpath "${CMAKE_SOURCE_DIR}" "${_dir_real}") - # Check if directory is outside source tree: - # - Empty _relpath means _dir equals CMAKE_SOURCE_DIR (inside source) - # - Path starting with ".." means outside source tree - # - Pattern matches ".." at start followed by path separator (/ or \) or end of string - if(_relpath AND (_relpath MATCHES "^\\.\\.([/\\\\]|$)")) - # Directory is outside source directory, safe to add to INSTALL_INTERFACE - list( - APPEND - ${itk-module}_SYSTEM_GENEX_INCLUDE_DIRS - "$" - ) - else() - # Directory is within source directory or equals source directory - # Skip adding to INSTALL_INTERFACE as it's a build-time only dependency - endif() endforeach() endif() diff --git a/Modules/Bridge/NumPy/CMakeLists.txt b/Modules/Bridge/NumPy/CMakeLists.txt index 976a6d1b3b5..8f734fb8c67 100644 --- a/Modules/Bridge/NumPy/CMakeLists.txt +++ b/Modules/Bridge/NumPy/CMakeLists.txt @@ -1,44 +1,9 @@ cmake_minimum_required(VERSION 3.16.3) project(ITKBridgeNumPy) -# Only set SYSTEM_INCLUDE_DIRS if Python is outside the source directory -# CMake does not allow INTERFACE properties to contain paths prefixed in the source directory +# Don't set SYSTEM_INCLUDE_DIRS for Python - handle includes separately +# to avoid CMake errors about source-prefixed paths in INTERFACE properties set(ITKBridgeNumPy_SYSTEM_INCLUDE_DIRS "") -if(Python3_INCLUDE_DIRS) - foreach(_py_inc_dir ${Python3_INCLUDE_DIRS}) - # Check if Python include directory is outside the source tree - get_filename_component(_py_inc_real "${_py_inc_dir}" REALPATH) - # Use CMAKE_SOURCE_DIR which is the ITK source directory when building as part of ITK - file(RELATIVE_PATH _relpath "${CMAKE_SOURCE_DIR}" "${_py_inc_real}") - - # Determine if directory is outside the source tree: - # 1. Empty _relpath means directory equals CMAKE_SOURCE_DIR (inside source) - # 2. If _relpath is still absolute (Windows: different drive), it's outside source - # 3. If _relpath starts with "..", it's outside the source tree - # Pattern matches: ".." at start, followed by "/" or "\" (path separator) or end of string - set(_is_outside_source FALSE) - if(_relpath) - if(IS_ABSOLUTE "${_relpath}") - # Path is on different drive/root (Windows-specific), outside source tree - set(_is_outside_source TRUE) - elseif(_relpath MATCHES "^\\.\\.([/\\\\]|$)") - # Path starts with "..", outside source tree - set(_is_outside_source TRUE) - endif() - endif() - - if(_is_outside_source) - # Directory is outside source directory, safe to add to SYSTEM_INCLUDE_DIRS - # This will be added to both BUILD_INTERFACE and INSTALL_INTERFACE - list(APPEND ITKBridgeNumPy_SYSTEM_INCLUDE_DIRS "${_py_inc_dir}") - else() - # Directory is within source directory or equals source directory (e.g., .pixi/envs) - # Use include_directories() to add for build-time compilation only - # This affects all targets in this module but won't propagate to INSTALL_INTERFACE - include_directories("${_py_inc_dir}") - endif() - endforeach() -endif() if(NOT ITK_SOURCE_DIR) find_package(ITK REQUIRED) @@ -47,3 +12,13 @@ if(NOT ITK_SOURCE_DIR) else() itk_module_impl() endif() + +# Add Python includes using BUILD_INTERFACE generator expression +# This ensures they're only used during build, not in exports +if(Python3_INCLUDE_DIRS AND TARGET ITKBridgeNumPyModule) + target_include_directories(ITKBridgeNumPyModule + SYSTEM + INTERFACE + $ + ) +endif()