From c74f30f8da5b1a7f8ceb92975208f0fe0db070be Mon Sep 17 00:00:00 2001 From: Bradley Lowekamp Date: Tue, 24 Feb 2026 14:27:57 +0000 Subject: [PATCH] WIP: In the process of moving FFTW to thirdparty infrastructure Completed: - General structure of the ITKFFT module optionally depending on FFTW thirdpary module. - Using module interfaces FFTW, as opposed to custom CMake variables. - The FindFFTW3.cmake is working well. Not done: - OpenCL FFTW is remove, may need separate find package script - Intel MKL is removed, modern one MKL has a Cmake config package which can be found. - FFTW is attempted to be compile in two FetchContent. The paths taken to mostly use the existing CMakeLists.txt from FFTW does not seem productive. There are challenges with building and installing the same source code twice, additionally the current file is not using target properties fully. --- CMake/FindFFTW.cmake | 267 ------ CMake/ITKConfig.cmake.in | 13 - CMakeLists.txt | 105 +-- Modules/Filtering/FFT/CMakeLists.txt | 2 - Modules/Filtering/FFT/itk-module.cmake | 2 + Modules/Filtering/FFT/src/CMakeLists.txt | 23 - Modules/ThirdParty/FFTW/CMake/CMakeLists.txt | 758 ++++++++++++++++++ Modules/ThirdParty/FFTW/CMake/FindFFTW3.cmake | 144 ++++ .../FFTW/CMake/RemoveFirstLine.cmake | 61 ++ .../FFTW/CMake}/itkExternal_FFTW.cmake | 0 .../ThirdParty/FFTW/CMake/itkFetchFFTW.cmake | 106 +++ Modules/ThirdParty/FFTW/CMakeLists.txt | 152 ++++ Modules/ThirdParty/FFTW/itk-module-init.cmake | 36 + Modules/ThirdParty/FFTW/itk-module.cmake | 8 + Modules/ThirdParty/FFTW/src/itk_fftw.h.in | 44 + 15 files changed, 1312 insertions(+), 409 deletions(-) delete mode 100644 CMake/FindFFTW.cmake create mode 100644 Modules/ThirdParty/FFTW/CMake/CMakeLists.txt create mode 100644 Modules/ThirdParty/FFTW/CMake/FindFFTW3.cmake create mode 100644 Modules/ThirdParty/FFTW/CMake/RemoveFirstLine.cmake rename {CMake => Modules/ThirdParty/FFTW/CMake}/itkExternal_FFTW.cmake (100%) create mode 100644 Modules/ThirdParty/FFTW/CMake/itkFetchFFTW.cmake create mode 100644 Modules/ThirdParty/FFTW/CMakeLists.txt create mode 100644 Modules/ThirdParty/FFTW/itk-module-init.cmake create mode 100644 Modules/ThirdParty/FFTW/itk-module.cmake create mode 100644 Modules/ThirdParty/FFTW/src/itk_fftw.h.in diff --git a/CMake/FindFFTW.cmake b/CMake/FindFFTW.cmake deleted file mode 100644 index b92b418fcb0..00000000000 --- a/CMake/FindFFTW.cmake +++ /dev/null @@ -1,267 +0,0 @@ -## FFTW can be compiled and subsequently linked against -## various data types. -## There is a single set of include files, and then multiple libraries, -## One for each type. I.e. libfftw.a-->double, libfftwf.a-->float - -## The following logic belongs in the individual package -## mark_as_advanced(ITK_USE_FFTWD) -## option(ITK_USE_FFTWD "Use double precision FFTW if found" ON) -## mark_as_advanced(ITK_USE_FFTWF) -## option(ITK_USE_FFTWF "Use single precision FFTW if found" ON) - -## FFTW can be included from Intel MKL library (static). Both -## `ITK_USE_FFTWD` and `ITK_USE_FFTWF` will be turned ON. -## -## To use the MKL implementation, set `ITK_USE_MKL` to ON and set -## `MKLROOT` to the installation directory of the MKL library on -## your system and point to the `mkl` subdirectory: -## ** On Linux, the default install directory is: -## /opt/intel/compilers_and_libraries/linux/ -## ** On Windows, it is: -## `C:\Program Files (x86)\Intel\oneAPI\mkl\2021.4.0` -## ** On Mac, it is: -## `/opt/intel/compilers_and_libraries/mac/mkl` -## -## '''Disabled''': If the compiler supports it, `ITK_USE_TBB_WITH_MKL` is automatically -## set to ON and MKL is linked against `TBB`. Otherwise it is linked against -## `mkl_sequential`. -## -## Note: if the environment variable `MKLROOT` is set, its value will be used -## to set the initial value of the CMake variable `MKLROOT` (see -## https://software.intel.com/en-us/mkl-linux-developer-guide-scripts-to-set-environment-variables). - -if(ITK_USE_FFTWD OR ITK_USE_FFTWF) - if(ITK_USE_MKL) - # If the user has provided the MKL include path then search nearby for library files - if(FFTW_INCLUDE_PATH) - # mkl//include/fftw -> mkl/ - get_filename_component(MKLROOT ${FFTW_INCLUDE_PATH} DIRECTORY) - get_filename_component(MKLROOT ${MKLROOT} DIRECTORY) - elseif(DEFINED ENV{MKLROOT}) - set(MKLROOT_default $ENV{MKLROOT}) - elseif(WIN32) - set(MKLROOT_default "C:/Program Files (x86)/Intel/oneAPI/mkl/2021.4.0") - elseif(APPLE) - set(MKLROOT_default "/opt/intel/compilers_and_libraries/mac/mkl") - elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux") - set(MKLROOT_default "/opt/intel/compilers_and_libraries/linux/mkl") - else() - message(FATAL_ERROR "System not supported for MKL.") - endif() - set(MKLROOT ${MKLROOT_default} CACHE PATH "Intel path containing MKL") - set(FFTW_INC_SEARCHPATH ${MKLROOT}/include/fftw) - else() - set( - FFTW_INC_SEARCHPATH - ${FFTW3f_INCLUDE_DIRS} # Defined in fftwf local build - ${FFTW3_INCLUDE_DIRS} # Defined in fftwd local build - /sw/include - /usr/include - /usr/local/include - /usr/include/fftw - /usr/local/include/fftw - ) - endif() - - if(ITK_USE_CUFFTW) - find_path(CUFFTW_INCLUDE_PATH cufftw.h ${FFTW_INC_SEARCHPATH}) - else() - find_path(FFTW_INCLUDE_PATH fftw3.h ${FFTW_INC_SEARCHPATH}) - endif() - - if(FFTW_INCLUDE_PATH OR CUFFTW_INCLUDE_PATH) - if(ITK_USE_CUFFTW) - file(TO_CMAKE_PATH "${CUFFTW_INCLUDE_PATH}" CUFFTW_INCLUDE_PATH) - set(FFTW_INCLUDE ${CUFFTW_INCLUDE_PATH}) - else() - file(TO_CMAKE_PATH "${FFTW_INCLUDE_PATH}" FFTW_INCLUDE_PATH) - set(FFTW_INCLUDE ${FFTW_INCLUDE_PATH}) - endif() - endif() - - if(ITK_USE_CUFFTW) - find_library(CUFFTW_LIB cufftw ${FFTW_LIB_SEARCHPATH}) #Single Precision Lib - find_library(CUFFT_LIB cufft ${FFTW_LIB_SEARCHPATH}) #Single Precision Lib - unset(FFTWD_LIBRARIES CACHE) - unset(FFTWF_LIBRARIES CACHE) - unset(FFTWD_THREADS_LIB CACHE) - unset(FFTWF_THREADS_LIB CACHE) - set( - FFTWF_LIBRARIES - ${CUFFT_LIB} - ${CUFFTW_LIB} - ) - set( - FFTWD_LIBRARIES - ${CUFFT_LIB} - ${CUFFTW_LIB} - ) - elseif(ITK_USE_MKL) - # '''Disabled''': `ITK_USE_TBB_WITH_MKL`. To configure MKL with TBB, the TBB library - # has to be found. This is not currently taken care of as part of this file and may - # result in conflicts if `Module_ITKTBB` is ON. - # if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") - # # See MKL configuration help page: - # # https://software.intel.com/en-us/articles/intel-mkl-link-line-advisor - # message("TBB threading option not available with Clang compiler.") - # set(ITK_USE_TBB_WITH_MKL OFF CACHE BOOL "Use TBB threading in MKL" FORCE) - # else() - # option(ITK_USE_TBB_WITH_MKL "Use TBB threading in MKL" ON) - # mark_as_advanced(ITK_USE_TBB_WITH_MKL) - # endif() - - if(CMAKE_SIZEOF_VOID_P EQUAL "8") - if(APPLE) - set(FFTW_LIB_SEARCHPATH ${MKLROOT}/lib) - else() - set(FFTW_LIB_SEARCHPATH ${MKLROOT}/lib/intel64) - endif() - set(MKL_LIBRARY mkl_intel_ilp64) - if(WIN32) - set(MKL_OPTIONS /DMKL_ILP64) - else() - set( - MKL_OPTIONS - -DMKL_ILP64 - -m64 - ) - endif() - else() - set(FFTW_LIB_SEARCHPATH ${MKLROOT}/lib/ia32) - if(WIN) - set(MKL_LIBRARY mkl_intel_c) - else() - set(MKL_LIBRARY mkl_intel) - endif() - endif() - set(MKL_EXTRA_LIBRARIES mkl_core) - # Force to sequential for now. - list(APPEND MKL_EXTRA_LIBRARIES mkl_sequential) - # if(ITK_USE_TBB_WITH_MKL) - # list(APPEND MKL_EXTRA_LIBRARIES mkl_tbb_thread) - # else() - # list(APPEND MKL_EXTRA_LIBRARIES mkl_sequential) - # endif() - set( - FFTW_LIBRARY_NAMES - ${MKL_LIBRARY} - ${MKL_EXTRA_LIBRARIES} - ) - - macro(FFTWD_LIBRARIES_START) - unset(FFTWD_LIBRARIES CACHE) - unset(FFTWF_LIBRARIES CACHE) - unset(FFTWD_THREADS_LIB CACHE) - unset(FFTWF_THREADS_LIB CACHE) - if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") - set(FFTWD_LIBRARIES -Wl,--start-group) - endif() - endmacro() - - macro(FFTWD_LIBRARIES_END) - if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") - list( - APPEND - FFTWD_LIBRARIES - -Wl,--end-group - -lpthread - -lm - -ldl - ) - # Force to sequential for now. - # if(ITK_USE_TBB_WITH_MKL) - # list(APPEND FFTWD_LIBRARIES -ltbb -lstdc++) - # endif() - endif() - endmacro() - - # Because of circular dependencies between the libraries, we need to use - # --start-group and --end-group on UNIX. - fftwd_libraries_start() - foreach(LIB ${FFTW_LIBRARY_NAMES}) - string(TOUPPER ${LIB} LIB_UPPER) - mark_as_advanced(${LIB_UPPER}_LIB) - set( - LIB_NAME - ${CMAKE_STATIC_LIBRARY_PREFIX}${LIB}${CMAKE_STATIC_LIBRARY_SUFFIX} - ) - find_library(${LIB_UPPER}_LIB ${LIB_NAME} ${FFTW_LIB_SEARCHPATH}) - if(${LIB_UPPER}_LIB) - set(${LIB}_FOUND 1) - list(APPEND FFTWD_LIBRARIES ${${LIB_UPPER}_LIB}) - else() - message(FATAL_ERROR "${LIB_NAME} not found.") - endif() - endforeach() - fftwd_libraries_end() - add_compile_options(${MKL_OPTIONS}) - else() - get_filename_component(FFTW_INSTALL_BASE_PATH ${FFTW_INCLUDE_PATH} PATH) - set( - FFTW_LIB_SEARCHPATH - ${FFTW3f_LIBRARY_DIRS} # Defined in fftwf local build - ${FFTW3_LIBRARY_DIRS} # Defined in fftwd local build - ${FFTW_INSTALL_BASE_PATH}/lib - ${FFTW_INSTALL_BASE_PATH}/lib64 - /usr/lib/fftw - /usr/local/lib/fftw - ) - unset(FFTWD_FOUND) - if(ITK_USE_FFTWD) - mark_as_advanced( - FFTWD_BASE_LIB - FFTWD_THREADS_LIB - FFTWD_LIBRARIES - ) - find_library(FFTWD_BASE_LIB fftw3 ${FFTW_LIB_SEARCHPATH}) #Double Precision Lib - find_library(FFTWD_THREADS_LIB fftw3_threads ${FFTW_LIB_SEARCHPATH}) #Double Precision Lib only if compiled with threads support - - if(FFTWD_BASE_LIB) - set(FFTWD_FOUND 1) - get_filename_component(FFTW_LIBDIR ${FFTWD_BASE_LIB} PATH) #NOTE FFTWD_BASE_LIB and FFTWF_BASE_LIB must be installed in the same location - get_filename_component(FFTWD_BASE_LIB ${FFTWD_BASE_LIB} NAME) - get_filename_component(FFTWD_THREADS_LIB ${FFTWD_THREADS_LIB} NAME) - set(FFTWD_LIBRARIES ${FFTWD_BASE_LIB}) - if(FFTWD_THREADS_LIB) - set( - FFTWD_LIBRARIES - ${FFTWD_THREADS_LIB} - ${FFTWD_BASE_LIB} - ) - endif() - else() - message(FATAL_ERROR "fftw3 not found.") - endif() - endif() - - unset(FFTWF_FOUND) - if(ITK_USE_FFTWF) - mark_as_advanced( - FFTWF_BASE_LIB - FFTWF_THREADS_LIB - FFTWF_LIBRARIES - ) - find_library(FFTWF_BASE_LIB fftw3f ${FFTW_LIB_SEARCHPATH}) #Single Precision Lib - find_library(FFTWF_THREADS_LIB fftw3f_threads ${FFTW_LIB_SEARCHPATH}) #Single Precision Lib only if compiled with threads support - - if(FFTWF_BASE_LIB) - set(FFTWF_FOUND 1) - get_filename_component(FFTW_LIBDIR ${FFTWF_BASE_LIB} PATH) #NOTE FFTWD_BASE_LIB and FFTWF_BASE_LIB must be installed in the same location - get_filename_component(FFTWF_BASE_LIB ${FFTWF_BASE_LIB} NAME) - get_filename_component(FFTWF_THREADS_LIB ${FFTWF_THREADS_LIB} NAME) - set(FFTWF_LIBRARIES ${FFTWF_BASE_LIB}) - if(FFTWF_THREADS_LIB) - set( - FFTWF_LIBRARIES - ${FFTWF_THREADS_LIB} - ${FFTWF_BASE_LIB} - ) - endif() - else() - message(FATAL_ERROR "fftw3f not found.") - endif() - endif() - endif() - unset(FFTWD_THREADS_LIB) - unset(FFTWF_THREADS_LIB) -endif() diff --git a/CMake/ITKConfig.cmake.in b/CMake/ITKConfig.cmake.in index 367b1b096ae..4b145ed1082 100644 --- a/CMake/ITKConfig.cmake.in +++ b/CMake/ITKConfig.cmake.in @@ -98,19 +98,6 @@ endif() # Load factory registration manager functions include( "${ITK_CMAKE_DIR}/ITKFactoryRegistration.cmake" ) -# Add configuration with FFTW -set(ITK_USE_FFTWD "@ITK_USE_FFTWD@") -set(ITK_USE_FFTWF "@ITK_USE_FFTWF@") -set(ITK_USE_SYSTEM_FFTW "@ITK_USE_SYSTEM_FFTW@") -set(ITK_FFTW_INCLUDE_PATH "@FFTW_INCLUDE_PATH@") -set(ITK_FFTW_LIBDIR "@FFTW_LIBDIR@") - -# Add FFTW include and library directories -if (ITK_USE_FFTWF OR ITK_USE_FFTWD) - set(ITK_INCLUDE_DIRS ${ITK_INCLUDE_DIRS} "${ITK_FFTW_INCLUDE_PATH}") - set(ITK_LIBRARY_DIRS ${ITK_LIBRARY_DIRS} "${ITK_FFTW_LIBDIR}") -endif() - # Add configuration with GPU set(ITK_USE_GPU "@ITK_USE_GPU@") diff --git a/CMakeLists.txt b/CMakeLists.txt index be2e77af64a..8b5c9a6eb43 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -535,99 +535,6 @@ if(ITK_USE_GPU) include(itkOpenCL) endif() -#----------------------------------------------------------------------------- -# Manage FFT v3 Options -# -option( - ITK_USE_MKL - "Use system Intel Math Kernel Library (MKL) for FFT computation." - OFF -) -mark_as_advanced(ITK_USE_MKL) -if(ITK_USE_MKL) - # The following lines are only useful if one sets `ITK_USE_MKL` to ON in - # the command line. Otherwise, the first CMake run will always initialize - # these variables to false. The error message will help the user to set - # the appropriate values. - set(ITK_USE_FFTWD ON CACHE BOOL "Use double precision FFTW if found") - set(ITK_USE_FFTWF ON CACHE BOOL "Use single precision FFTW if found") - set(ITK_USE_SYSTEM_FFTW ON CACHE BOOL "Use an installed version of FFTW") - if(NOT ITK_USE_FFTWD OR NOT ITK_USE_FFTWF OR NOT ITK_USE_SYSTEM_FFTW) - message( - FATAL_ERROR - "ITK_USE_MKL is set to ON. ITK_USE_FFTWD, ITK_USE_FFTWF\ - and ITK_USE_SYSTEM_FFTW must be set to ON, too." - ) - endif() -endif() -option( - ITK_USE_CUFFTW - "Use NVidia CUDA cuFFT with its FFTW interface for FFT computation." - OFF -) -mark_as_advanced(ITK_USE_CUFFTW) -if(ITK_USE_CUFFTW) - # The following lines are only useful if one sets `ITK_USE_CUFFTW` to ON in - # the command line. Otherwise, the first CMake run will always initialize - # these variables to false. The error message will help the user to set - # the appropriate values. - set(ITK_USE_FFTWD ON CACHE BOOL "Use double precision FFTW if found") - set(ITK_USE_FFTWF ON CACHE BOOL "Use single precision FFTW if found") - set(ITK_USE_SYSTEM_FFTW ON CACHE BOOL "Use an installed version of FFTW") - if(NOT ITK_USE_FFTWD OR NOT ITK_USE_FFTWF OR NOT ITK_USE_SYSTEM_FFTW) - message( - FATAL_ERROR - "ITK_USE_CUFFTW is set to ON. ITK_USE_FFTWD, ITK_USE_FFTWF\ - and ITK_USE_SYSTEM_FFTW must be set to ON, too." - ) - endif() -endif() -# ITK_USE_FFTWD -- use double precision FFTW -if(DEFINED USE_FFTWD) - set(ITK_USE_FFTWD_DEFAULT ${USE_FFTWD}) -else() - set(ITK_USE_FFTWD_DEFAULT OFF) -endif() -option( - ITK_USE_FFTWD - "Use double precision FFTW if found" - ${ITK_USE_FFTWD_DEFAULT} -) -mark_as_advanced(ITK_USE_FFTWD) -# -# ITK_USE_FFTWF -- use single precision FFTW -if(DEFINED USE_FFTWF) - set(ITK_USE_FFTWF_DEFAULT ${USE_FFTWF}) -else() - set(ITK_USE_FFTWF_DEFAULT OFF) -endif() -option( - ITK_USE_FFTWF - "Use single precision FFTW if found" - ${ITK_USE_FFTWF_DEFAULT} -) -mark_as_advanced(ITK_USE_FFTWF) - -# ITK_USE_SYSTEM_FFTW -- locate a readybuilt FFTW installation -if(DEFINED USE_SYSTEM_FFTW) - set(ITK_USE_SYSTEM_FFTW_DEFAULT ${USE_SYSTEM_FFTW}) -else() - set(ITK_USE_SYSTEM_FFTW_DEFAULT ${ITK_USE_SYSTEM_LIBRARIES}) -endif() -option( - ITK_USE_SYSTEM_FFTW - "Use an installed version of FFTW" - ${ITK_USE_SYSTEM_FFTW_DEFAULT} -) -mark_as_advanced(ITK_USE_SYSTEM_FFTW) - -if(ITK_USE_FFTWD OR ITK_USE_FFTWF) - include(itkExternal_FFTW) - # This pollutes the global namespace, but is needed for backward compatibility - include_directories(${FFTW_INCLUDE}) - link_directories(${FFTW_LIBDIR}) -endif() - set(ITK_USE_64BITS_IDS_DEFAULT "OFF") # Note WIN32 is true when targeting any windows system if(CMAKE_SIZEOF_VOID_P EQUAL "8" AND WIN32) @@ -800,17 +707,7 @@ set( ITK_CONFIG_MODULE_API_FILE "\${ITK_INSTALL_PREFIX}/${ITK_INSTALL_PACKAGE_DIR}/ITKModuleAPI.cmake" ) -if(NOT ITK_USE_SYSTEM_FFTW) - # Location installed with the FFTW ExternalProject. - set( - FFTW_LIBDIR - "\${ITK_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/ITK-${ITK_VERSION_MAJOR}.${ITK_VERSION_MINOR}" - ) - set( - FFTW_INCLUDE_PATH - "\${ITK_INSTALL_PREFIX}/include/ITK-${ITK_VERSION_MAJOR}.${ITK_VERSION_MINOR}/Algorithms" - ) -endif() + configure_file(CMake/ITKConfig.cmake.in CMakeFiles/ITKConfig.cmake @ONLY) #----------------------------------------------------------------------------- diff --git a/Modules/Filtering/FFT/CMakeLists.txt b/Modules/Filtering/FFT/CMakeLists.txt index ac75b264d64..640e50051a7 100644 --- a/Modules/Filtering/FFT/CMakeLists.txt +++ b/Modules/Filtering/FFT/CMakeLists.txt @@ -9,7 +9,5 @@ if(ITK_USE_CUFFTW) else() set(ITKFFT_LIBRARIES ITKFFT) endif() -set(ITKFFT_SYSTEM_LIBRARY_DIRS ${FFTW_LIBDIR}) -set(ITKFFT_INCLUDE_DIRS "${FFTW_INCLUDE}") itk_module_impl() diff --git a/Modules/Filtering/FFT/itk-module.cmake b/Modules/Filtering/FFT/itk-module.cmake index da3ddc68b76..e533908b091 100644 --- a/Modules/Filtering/FFT/itk-module.cmake +++ b/Modules/Filtering/FFT/itk-module.cmake @@ -12,6 +12,7 @@ set(_fft_backends "FFTImageFilterInit::Vnl") if(ITK_USE_FFTWF OR ITK_USE_FFTWD) # Prepend so that FFTW constructor is preferred list(PREPEND _fft_backends "FFTImageFilterInit::FFTW") + set(ITK_USE_FFTW_MODULE ITKFFTW) endif() itk_module( @@ -19,6 +20,7 @@ itk_module( ENABLE_SHARED DEPENDS ITKCommon + ${ITK_USE_FFTW_MODULE} COMPILE_DEPENDS ITKImageGrid TEST_DEPENDS diff --git a/Modules/Filtering/FFT/src/CMakeLists.txt b/Modules/Filtering/FFT/src/CMakeLists.txt index 23aab4c9fba..39d8ce135d4 100644 --- a/Modules/Filtering/FFT/src/CMakeLists.txt +++ b/Modules/Filtering/FFT/src/CMakeLists.txt @@ -12,26 +12,3 @@ if(ITK_USE_FFTWF OR ITK_USE_FFTWD) endif() itk_module_add_library(ITKFFT ${ITKFFT_SRCS}) - -# this library is only needed if FFTW is used -if(ITK_USE_FFTWF OR ITK_USE_FFTWD AND NOT ITK_USE_CUFFTW) - if(ITK_USE_FFTWD) - if(NOT ITK_USE_SYSTEM_FFTW) - add_dependencies(ITKFFT fftwd) # Ensure that local FFTW is built before using - target_link_libraries(ITKFFT PUBLIC ${ITK_FFTWD_LIBRARIES_NAMES}) - else() - target_include_directories(ITKFFT PUBLIC ${FFTW_INCLUDE}) - target_link_libraries(ITKFFT PUBLIC ${FFTWD_LIBRARIES}) - endif() - endif() - - if(ITK_USE_FFTWF) - if(NOT ITK_USE_SYSTEM_FFTW) - add_dependencies(ITKFFT fftwf) # Esnsure that local FFTW is build before using - target_link_libraries(ITKFFT PUBLIC ${ITK_FFTWF_LIBRARIES_NAMES}) - else() - target_include_directories(ITKFFT PUBLIC ${FFTW_INCLUDE}) - target_link_libraries(ITKFFT PUBLIC ${FFTWF_LIBRARIES}) - endif() - endif() -endif() diff --git a/Modules/ThirdParty/FFTW/CMake/CMakeLists.txt b/Modules/ThirdParty/FFTW/CMake/CMakeLists.txt new file mode 100644 index 00000000000..91dfd10003a --- /dev/null +++ b/Modules/ThirdParty/FFTW/CMake/CMakeLists.txt @@ -0,0 +1,758 @@ +if(NOT DEFINED CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type") +endif() +project(fftw) +if(POLICY CMP0042) + cmake_policy(SET CMP0042 NEW) +endif() +option(BUILD_SHARED_LIBS "Build shared libraries" ON) +option(BUILD_TESTS "Build tests" ON) +option(ENABLE_OPENMP "Use OpenMP for multithreading" OFF) +option(ENABLE_THREADS "Use pthread for multithreading" OFF) +option(WITH_COMBINED_THREADS "Merge thread library" OFF) +option(ENABLE_FLOAT "single-precision" OFF) +option(ENABLE_LONG_DOUBLE "long-double precision" OFF) +option(ENABLE_QUAD_PRECISION "quadruple-precision" OFF) +option(ENABLE_SSE "Compile with SSE instruction set support" OFF) +option(ENABLE_SSE2 "Compile with SSE2 instruction set support" OFF) +option(ENABLE_AVX "Compile with AVX instruction set support" OFF) +option(ENABLE_AVX2 "Compile with AVX2 instruction set support" OFF) +option(DISABLE_FORTRAN "Disable Fortran wrapper routines" OFF) +include(GNUInstallDirs) +include(CheckIncludeFile) +check_include_file( + alloca.h + HAVE_ALLOCA_H +) +check_include_file( + altivec.h + HAVE_ALTIVEC_H +) +check_include_file( + c_asm.h + HAVE_C_ASM_H +) +check_include_file( + dlfcn.h + HAVE_DLFCN_H +) +check_include_file( + intrinsics.h + HAVE_INTRINSICS_H +) +check_include_file( + inttypes.h + HAVE_INTTYPES_H +) +check_include_file( + libintl.h + HAVE_LIBINTL_H +) +check_include_file( + limits.h + HAVE_LIMITS_H +) +check_include_file( + mach/mach_time.h + HAVE_MACH_MACH_TIME_H +) +check_include_file( + malloc.h + HAVE_MALLOC_H +) +check_include_file( + memory.h + HAVE_MEMORY_H +) +check_include_file( + stddef.h + HAVE_STDDEF_H +) +check_include_file( + stdint.h + HAVE_STDINT_H +) +check_include_file( + stdlib.h + HAVE_STDLIB_H +) +check_include_file( + string.h + HAVE_STRING_H +) +check_include_file( + strings.h + HAVE_STRINGS_H +) +check_include_file( + sys/types.h + HAVE_SYS_TYPES_H +) +check_include_file( + sys/time.h + HAVE_SYS_TIME_H +) +check_include_file( + sys/stat.h + HAVE_SYS_STAT_H +) +check_include_file( + sys/sysctl.h + HAVE_SYS_SYSCTL_H +) +check_include_file( + time.h + HAVE_TIME_H +) +check_include_file( + uintptr.h + HAVE_UINTPTR_H +) +check_include_file( + unistd.h + HAVE_UNISTD_H +) +if(HAVE_TIME_H AND HAVE_SYS_TIME_H) + set(TIME_WITH_SYS_TIME TRUE) +endif() +include(CheckPrototypeDefinition) +check_prototype_definition( + drand48 + "double drand48 (void)" + "0" + stdlib.h + HAVE_DECL_DRAND48 +) +check_prototype_definition( + srand48 + "void srand48(long int seedval)" + "0" + stdlib.h + HAVE_DECL_SRAND48 +) +check_prototype_definition( + cosl + "long double cosl( long double arg )" + "0" + math.h + HAVE_DECL_COSL +) +check_prototype_definition( + sinl + "long double sinl( long double arg )" + "0" + math.h + HAVE_DECL_SINL +) +check_prototype_definition( + memalign + "void *memalign(size_t alignment, size_t size)" + "0" + malloc.h + HAVE_DECL_MEMALIGN +) +check_prototype_definition( + posix_memalign + "int posix_memalign(void **memptr, size_t alignment, size_t size)" + "0" + stdlib.h + HAVE_DECL_POSIX_MEMALIGN +) +include(CheckSymbolExists) +check_symbol_exists( + clock_gettime + time.h + HAVE_CLOCK_GETTIME +) +check_symbol_exists( + gettimeofday + sys/time.h + HAVE_GETTIMEOFDAY +) +check_symbol_exists( + getpagesize + unistd.h + HAVE_GETPAGESIZE +) +check_symbol_exists( + drand48 + stdlib.h + HAVE_DRAND48 +) +check_symbol_exists( + srand48 + stdlib.h + HAVE_SRAND48 +) +check_symbol_exists( + memalign + malloc.h + HAVE_MEMALIGN +) +check_symbol_exists( + posix_memalign + stdlib.h + HAVE_POSIX_MEMALIGN +) +check_symbol_exists( + mach_absolute_time + mach/mach_time.h + HAVE_MACH_ABSOLUTE_TIME +) +check_symbol_exists( + alloca + alloca.h + HAVE_ALLOCA +) +if(NOT HAVE_ALLOCA) + unset(HAVE_ALLOCA CACHE) + check_symbol_exists( + alloca + malloc.h + HAVE_ALLOCA + ) +endif() +check_symbol_exists( + isnan + math.h + HAVE_ISNAN +) +check_symbol_exists( + snprintf + stdio.h + HAVE_SNPRINTF +) +check_symbol_exists( + strchr + string.h + HAVE_STRCHR +) +check_symbol_exists( + sysctl + unistd.h + HAVE_SYSCTL +) +if(UNIX) + set(CMAKE_REQUIRED_LIBRARIES m) +endif() +check_symbol_exists( + cosl + math.h + HAVE_COSL +) +check_symbol_exists( + sinl + math.h + HAVE_SINL +) +include(CheckTypeSize) +check_type_size( + "float" + SIZEOF_FLOAT +) +check_type_size( + "double" + SIZEOF_DOUBLE +) +check_type_size( + "int" + SIZEOF_INT +) +check_type_size( + "long" + SIZEOF_LONG +) +check_type_size( + "long long" + SIZEOF_LONG_LONG +) +check_type_size( + "unsigned int" + SIZEOF_UNSIGNED_INT +) +check_type_size( + "unsigned long" + SIZEOF_UNSIGNED_LONG +) +check_type_size( + "unsigned long long" + SIZEOF_UNSIGNED_LONG_LONG +) +check_type_size( + "size_t" + SIZEOF_SIZE_T +) +check_type_size( + "ptrdiff_t" + SIZEOF_PTRDIFF_T +) +math(EXPR SIZEOF_INT_BITS "8 * ${SIZEOF_INT}") +set(C_FFTW_R2R_KIND "C_INT${SIZEOF_INT_BITS}_T") +find_library(LIBM_LIBRARY NAMES m) +if(LIBM_LIBRARY) + set(HAVE_LIBM TRUE) +endif() +if(ENABLE_THREADS) + find_package(Threads) +endif() +if(Threads_FOUND) + if(CMAKE_USE_PTHREADS_INIT) + set(USING_POSIX_THREADS 1) + endif() + set(HAVE_THREADS TRUE) +endif() +if(ENABLE_OPENMP) + find_package(OpenMP) +endif() +if(OPENMP_FOUND) + set(HAVE_OPENMP TRUE) +endif() +include(CheckCCompilerFlag) +if(ENABLE_SSE) + foreach(FLAG "-msse" "/arch:SSE") + unset(HAVE_SSE CACHE) + unset(HAVE_SSE) + check_c_compiler_flag( + ${FLAG} + HAVE_SSE + ) + if(HAVE_SSE) + set(SSE_FLAG ${FLAG}) + break() + endif() + endforeach() +endif() +if(ENABLE_SSE2) + foreach(FLAG "-msse2" "/arch:SSE2") + unset(HAVE_SSE2 CACHE) + unset(HAVE_SSE2) + check_c_compiler_flag( + ${FLAG} + HAVE_SSE2 + ) + if(HAVE_SSE2) + set(SSE2_FLAG ${FLAG}) + break() + endif() + endforeach() +endif() +if(ENABLE_AVX) + foreach(FLAG "-mavx" "/arch:AVX") + unset(HAVE_AVX CACHE) + unset(HAVE_AVX) + check_c_compiler_flag( + ${FLAG} + HAVE_AVX + ) + if(HAVE_AVX) + set(AVX_FLAG ${FLAG}) + break() + endif() + endforeach() +endif() +if(ENABLE_AVX2) + foreach(FLAG "-mavx2" "/arch:AVX2") + unset(HAVE_AVX2 CACHE) + unset(HAVE_AVX2) + check_c_compiler_flag( + ${FLAG} + HAVE_AVX2 + ) + if(HAVE_AVX2) + set(AVX2_FLAG ${FLAG}) + break() + endif() + endforeach() +endif() +# AVX2 codelets require FMA support as well +if(ENABLE_AVX2) + foreach(FLAG "-mfma" "/arch:FMA") + unset(HAVE_FMA CACHE) + unset(HAVE_FMA) + check_c_compiler_flag( + ${FLAG} + HAVE_FMA + ) + if(HAVE_FMA) + set(FMA_FLAG ${FLAG}) + break() + endif() + endforeach() +endif() +if(HAVE_SSE2 OR HAVE_AVX) + set(HAVE_SIMD TRUE) +endif() +file( + GLOB fftw_api_SOURCE + api/*.c + api/*.h +) +file( + GLOB fftw_dft_SOURCE + dft/*.c + dft/*.h +) +file( + GLOB fftw_dft_scalar_SOURCE + dft/scalar/*.c + dft/scalar/*.h +) +file( + GLOB fftw_dft_scalar_codelets_SOURCE + dft/scalar/codelets/*.c + dft/scalar/codelets/*.h +) +file( + GLOB fftw_dft_simd_SOURCE + dft/simd/*.c + dft/simd/*.h +) +file( + GLOB fftw_dft_simd_sse2_SOURCE + dft/simd/sse2/*.c + dft/simd/sse2/*.h +) +file( + GLOB fftw_dft_simd_avx_SOURCE + dft/simd/avx/*.c + dft/simd/avx/*.h +) +file( + GLOB fftw_dft_simd_avx2_SOURCE + dft/simd/avx2/*.c + dft/simd/avx2/*.h + dft/simd/avx2-128/*.c + dft/simd/avx2-128/*.h +) +file( + GLOB fftw_kernel_SOURCE + kernel/*.c + kernel/*.h +) +file( + GLOB fftw_rdft_SOURCE + rdft/*.c + rdft/*.h +) +file( + GLOB fftw_rdft_scalar_SOURCE + rdft/scalar/*.c + rdft/scalar/*.h +) +file( + GLOB fftw_rdft_scalar_r2cb_SOURCE + rdft/scalar/r2cb/*.c + rdft/scalar/r2cb/*.h +) +file( + GLOB fftw_rdft_scalar_r2cf_SOURCE + rdft/scalar/r2cf/*.c + rdft/scalar/r2cf/*.h +) +file( + GLOB fftw_rdft_scalar_r2r_SOURCE + rdft/scalar/r2r/*.c + rdft/scalar/r2r/*.h +) +file( + GLOB fftw_rdft_simd_SOURCE + rdft/simd/*.c + rdft/simd/*.h +) +file( + GLOB fftw_rdft_simd_sse2_SOURCE + rdft/simd/sse2/*.c + rdft/simd/sse2/*.h +) +file( + GLOB fftw_rdft_simd_avx_SOURCE + rdft/simd/avx/*.c + rdft/simd/avx/*.h +) +file( + GLOB fftw_rdft_simd_avx2_SOURCE + rdft/simd/avx2/*.c + rdft/simd/avx2/*.h + rdft/simd/avx2-128/*.c + rdft/simd/avx2-128/*.h +) +file( + GLOB fftw_reodft_SOURCE + reodft/*.c + reodft/*.h +) +file( + GLOB fftw_simd_support_SOURCE + simd-support/*.c + simd-support/*.h +) +file( + GLOB fftw_libbench2_SOURCE + libbench2/*.c + libbench2/*.h +) +list( + REMOVE_ITEM + fftw_libbench2_SOURCE + ${CMAKE_CURRENT_SOURCE_DIR}/libbench2/useropt.c +) +set( + SOURCEFILES + ${fftw_api_SOURCE} + ${fftw_dft_SOURCE} + ${fftw_dft_scalar_SOURCE} + ${fftw_dft_scalar_codelets_SOURCE} + ${fftw_dft_simd_SOURCE} + ${fftw_kernel_SOURCE} + ${fftw_rdft_SOURCE} + ${fftw_rdft_scalar_SOURCE} + ${fftw_rdft_scalar_r2cb_SOURCE} + ${fftw_rdft_scalar_r2cf_SOURCE} + ${fftw_rdft_scalar_r2r_SOURCE} + ${fftw_rdft_simd_SOURCE} + ${fftw_reodft_SOURCE} + ${fftw_simd_support_SOURCE} + ${fftw_threads_SOURCE} +) +set( + fftw_par_SOURCE + threads/api.c + threads/conf.c + threads/ct.c + threads/dft-vrank-geq1.c + threads/f77api.c + threads/hc2hc.c + threads/rdft-vrank-geq1.c + threads/vrank-geq1-rdft2.c +) +set( + fftw_threads_SOURCE + ${fftw_par_SOURCE} + threads/threads.c +) +set( + fftw_omp_SOURCE + ${fftw_par_SOURCE} + threads/openmp.c +) +include_directories(.) +if(WITH_COMBINED_THREADS) + list(APPEND SOURCEFILES ${fftw_threads_SOURCE}) +endif() +if(HAVE_SSE2) + list( + APPEND + SOURCEFILES + ${fftw_dft_simd_sse2_SOURCE} + ${fftw_rdft_simd_sse2_SOURCE} + ) +endif() +if(HAVE_AVX) + list( + APPEND + SOURCEFILES + ${fftw_dft_simd_avx_SOURCE} + ${fftw_rdft_simd_avx_SOURCE} + ) +endif() +if(HAVE_AVX2) + list( + APPEND + SOURCEFILES + ${fftw_dft_simd_avx2_SOURCE} + ${fftw_rdft_simd_avx2_SOURCE} + ) +endif() +set(FFTW_VERSION 3.3.9) +set(PREC_SUFFIX) +if(ENABLE_FLOAT) + set(FFTW_SINGLE TRUE) + set(BENCHFFT_SINGLE TRUE) + set(PREC_SUFFIX f) +endif() +if(ENABLE_LONG_DOUBLE) + set(FFTW_LDOUBLE TRUE) + set(BENCHFFT_LDOUBLE TRUE) + set(PREC_SUFFIX l) +endif() +if(ENABLE_QUAD_PRECISION) + set(FFTW_QUAD TRUE) + set(BENCHFFT_QUAD TRUE) + set(PREC_SUFFIX q) +endif() +set(fftw3_lib fftw3${PREC_SUFFIX}) +configure_file(cmake.config.h.in config.h @ONLY) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) +if(BUILD_SHARED_LIBS) + add_definitions(-DFFTW_DLL) +endif() +add_library(${fftw3_lib} ${SOURCEFILES}) +target_include_directories(${fftw3_lib} INTERFACE $) +if(MSVC AND NOT (CMAKE_C_COMPILER_ID STREQUAL "Intel")) + target_compile_definitions(${fftw3_lib} PRIVATE /bigobj) +endif() +if(HAVE_SSE) + target_compile_options(${fftw3_lib} PRIVATE ${SSE_FLAG}) +endif() +if(HAVE_SSE2) + target_compile_options(${fftw3_lib} PRIVATE ${SSE2_FLAG}) +endif() +if(HAVE_AVX) + target_compile_options(${fftw3_lib} PRIVATE ${AVX_FLAG}) +endif() +if(HAVE_AVX2) + target_compile_options(${fftw3_lib} PRIVATE ${AVX2_FLAG}) +endif() +if(HAVE_FMA) + target_compile_options(${fftw3_lib} PRIVATE ${FMA_FLAG}) +endif() +if(HAVE_LIBM) + target_link_libraries(${fftw3_lib} m) +endif() +set(subtargets ${fftw3_lib}) +if(Threads_FOUND) + if(WITH_COMBINED_THREADS) + target_link_libraries(${fftw3_lib} ${CMAKE_THREAD_LIBS_INIT}) + else() + add_library(${fftw3_lib}_threads ${fftw_threads_SOURCE}) + target_include_directories( + ${fftw3_lib}_threads + INTERFACE + $ + ) + target_link_libraries(${fftw3_lib}_threads ${fftw3_lib}) + target_link_libraries(${fftw3_lib}_threads ${CMAKE_THREAD_LIBS_INIT}) + list(APPEND subtargets ${fftw3_lib}_threads) + endif() +endif() +if(OPENMP_FOUND) + add_library(${fftw3_lib}_omp ${fftw_omp_SOURCE}) + target_include_directories( + ${fftw3_lib}_omp + INTERFACE + $ + ) + target_link_libraries(${fftw3_lib}_omp ${fftw3_lib}) + target_link_libraries(${fftw3_lib}_omp ${CMAKE_THREAD_LIBS_INIT}) + list(APPEND subtargets ${fftw3_lib}_omp) + target_compile_options(${fftw3_lib}_omp PRIVATE ${OpenMP_C_FLAGS}) +endif() +foreach(subtarget ${subtargets}) + set_target_properties( + ${subtarget} + PROPERTIES + SOVERSION + 3.6.9 + VERSION + 3 + ) +endforeach() +install( + TARGETS + ${subtargets} + EXPORT FFTW3LibraryDepends${PREC_SUFFIX} + RUNTIME + DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY + DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE + DESTINATION ${CMAKE_INSTALL_LIBDIR} +) +install(FILES api/fftw3.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +if(EXISTS ${CMAKE_SOURCE_DIR}/api/fftw3.f) + install( + FILES + api/fftw3.f + api/fftw3l.f03 + api/fftw3q.f03 + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + ) +endif() +if(EXISTS ${CMAKE_SOURCE_DIR}/api/fftw3.f03.in) + file(READ api/fftw3.f03.in FFTW3_F03_IN OFFSET 42) + file( + WRITE + ${CMAKE_CURRENT_BINARY_DIR}/fftw3.f03 + "! Generated automatically. DO NOT EDIT!\n\n" + ) + file( + APPEND + ${CMAKE_CURRENT_BINARY_DIR}/fftw3.f03 + " integer, parameter :: C_FFTW_R2R_KIND = ${C_FFTW_R2R_KIND}\n\n" + ) + file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/fftw3.f03 "${FFTW3_F03_IN}") + install( + FILES + ${CMAKE_CURRENT_BINARY_DIR}/fftw3.f03 + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + ) +endif() +if(BUILD_TESTS) + add_executable( + bench + ${fftw_libbench2_SOURCE} + tests/bench.c + tests/hook.c + tests/fftw-bench.c + ) + if(ENABLE_THREADS AND NOT WITH_COMBINED_THREADS) + target_link_libraries(bench ${fftw3_lib}_threads) + else() + target_link_libraries(bench ${fftw3_lib}) + endif() + enable_testing() + if(Threads_FOUND) + macro(fftw_add_test problem) + add_test( + NAME ${problem} + COMMAND + bench -s ${problem} + ) + endmacro() + fftw_add_test(32x64) + fftw_add_test(ib256) + endif() +endif() +# pkgconfig file +set(prefix ${CMAKE_INSTALL_PREFIX}) +set(exec_prefix ${CMAKE_INSTALL_PREFIX}) +set(libdir ${CMAKE_INSTALL_FULL_LIBDIR}) +set(includedir ${CMAKE_INSTALL_FULL_INCLUDEDIR}) +set(VERSION ${FFTW_VERSION}) +configure_file(fftw.pc.in fftw3${PREC_SUFFIX}.pc @ONLY) +install( + FILES + ${CMAKE_CURRENT_BINARY_DIR}/fftw3${PREC_SUFFIX}.pc + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig + COMPONENT Development +) +# cmake file +set(FFTW3_LIBRARIES "") +foreach(_lib ${subtargets}) + list(APPEND FFTW3_LIBRARIES ${_lib}) +endforeach() +configure_file(FFTW3Config.cmake.in FFTW3${PREC_SUFFIX}Config.cmake @ONLY) +configure_file( + FFTW3ConfigVersion.cmake.in + FFTW3${PREC_SUFFIX}ConfigVersion.cmake + @ONLY +) +install( + FILES + ${CMAKE_CURRENT_BINARY_DIR}/FFTW3${PREC_SUFFIX}Config.cmake + ${CMAKE_CURRENT_BINARY_DIR}/FFTW3${PREC_SUFFIX}ConfigVersion.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/fftw3${PREC_SUFFIX} + COMPONENT Development +) +export( + TARGETS + ${subtargets} + NAMESPACE FFTW3:: + FILE ${PROJECT_BINARY_DIR}/FFTW3LibraryDepends${PREC_SUFFIX}.cmake +) +install( + EXPORT FFTW3LibraryDepends${PREC_SUFFIX} + NAMESPACE FFTW3:: + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/fftw3${PREC_SUFFIX} + COMPONENT Development +) diff --git a/Modules/ThirdParty/FFTW/CMake/FindFFTW3.cmake b/Modules/ThirdParty/FFTW/CMake/FindFFTW3.cmake new file mode 100644 index 00000000000..818dc4e2bae --- /dev/null +++ b/Modules/ThirdParty/FFTW/CMake/FindFFTW3.cmake @@ -0,0 +1,144 @@ +## FFTW can be compiled and subsequently linked against +## various data types. +## There is a single set of include files, and then multiple libraries, +## One for each type. I.e. libfftw3.a-->double, libfftw3f.a-->float + +## This FindFFTW3 module locates system-installed FFTW libraries. +## +## This module creates the following IMPORTED targets in the FFTW3:: namespace: +## FFTW3::fftw3 - Double precision FFTW library +## FFTW3::fftw3_threads - Double precision FFTW threads library +## FFTW3::fftw3f - Single precision FFTW library +## FFTW3::fftw3f_threads - Single precision FFTW threads library +## FFTW3::fftw3l - Long double precision FFTW library +## FFTW3::fftw3l_threads - Long double precision FFTW threads library +## FFTW3::fftw3q - Quad precision FFTW library +## FFTW3::fftw3q_threads - Quad precision FFTW threads library +## +## This module sets the following variables: +## FFTW3_FOUND - True if FFTW3 is found +## FFTW3_VERSION - Version of FFTW3 (e.g., "3.3.10") +## FFTW3_INCLUDE_DIRS - Include directories for FFTW3 +## FFTW3_LIBRARIES - Libraries to link for FFTW3 +## FFTW3_fftw3_FOUND - True if double precision library found +## FFTW3_fftw3f_FOUND - True if single precision library found +## FFTW3_fftw3l_FOUND - True if long double precision library found +## FFTW3_fftw3q_FOUND - True if quad precision library found + +include(FindPackageHandleStandardArgs) + +# Try to get version from pkg-config +find_package(PkgConfig QUIET) +if(PKG_CONFIG_FOUND) + pkg_check_modules(PC_FFTW3 QUIET fftw3) + set(FFTW3_VERSION ${PC_FFTW3_VERSION}) +endif() + +find_path( + FFTW3_INCLUDE_DIR + fftw3.h + PATH_SUFFIXES + fftw3 + fftw +) +mark_as_advanced(FFTW3_INCLUDE_DIR) + +# Determine which components to search for +# If FFTW3_FIND_COMPONENTS is set, only search for those components +# Otherwise, search for all precision types +if(FFTW3_FIND_COMPONENTS) + set(_FFTW3_components_to_search ${FFTW3_FIND_COMPONENTS}) + message( + STATUS + "FFTW3_FIND_COMPONENTS is set, searching for components: ${_FFTW3_components_to_search}" + ) +else() + set( + _FFTW3_components_to_search + fftw3 + fftw3f + fftw3l + fftw3q + ) + + set(_varients "") + foreach(_comp IN LISTS _FFTW3_components_to_search) + list( + APPEND + _varients + "${_comp}" + "${_comp}_threads" + ) + endforeach() + + list(APPEND _FFTW3_components_to_search ${_varients}) +endif() + +# Search for each component library +foreach(_comp IN LISTS _FFTW3_components_to_search) + find_library(FFTW3_${_comp}_LIBRARY NAMES ${_comp} NAMES_PER_DIR) + if(FFTW3_${_comp}_LIBRARY) + set(FFTW3_${_comp}_FOUND TRUE) + else() + set(FFTW3_${_comp}_FOUND FALSE) + endif() +endforeach() + +# Use find_package_handle_standard_args to set FFTW3_FOUND +# With HANDLE_COMPONENTS, this will: +# - Check that all required components (from COMPONENTS) have __FOUND=TRUE +# - Set FFTW3_FOUND=FALSE if any required component is missing +# - Report which components were found/missing +find_package_handle_standard_args( + FFTW3 + REQUIRED_VARS + FFTW3_INCLUDE_DIR + VERSION_VAR FFTW3_VERSION + HANDLE_COMPONENTS +) + +if(FFTW3_FOUND) + # Set standard output variables + set(FFTW3_INCLUDE_DIRS ${FFTW3_INCLUDE_DIR}) + set(FFTW3_LIBRARIES "") + + # Create IMPORTED targets for requested/found components + foreach(_comp IN LISTS _FFTW3_components_to_search) + if(FFTW3_${_comp}_LIBRARY) + if(NOT TARGET FFTW3::${_comp}) + add_library(FFTW3::${_comp} UNKNOWN IMPORTED) + set_target_properties( + FFTW3::${_comp} + PROPERTIES + IMPORTED_LOCATION + "${FFTW3_${_comp}_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES + "${FFTW3_INCLUDE_DIR}" + ) + if( + ( + CMAKE_SYSTEM_NAME + STREQUAL + "Linux" + ) + AND + ( + "${FFTW3_${_comp}_LIBRARY}" + MATCHES + "\\${CMAKE_STATIC_LIBRARY_SUFFIX}$" + ) + ) + set_property( + TARGET + FFTW3::${_comp} + APPEND + PROPERTY + INTERFACE_LINK_LIBRARIES + m + ) + endif() + endif() + endif() + list(APPEND FFTW3_LIBRARIES FFTW3::${_comp}) + endforeach() +endif() diff --git a/Modules/ThirdParty/FFTW/CMake/RemoveFirstLine.cmake b/Modules/ThirdParty/FFTW/CMake/RemoveFirstLine.cmake new file mode 100644 index 00000000000..73ce35e1add --- /dev/null +++ b/Modules/ThirdParty/FFTW/CMake/RemoveFirstLine.cmake @@ -0,0 +1,61 @@ +# Remove the first line from a file and patch EXPORT names +# This is used to: +# 1. Remove "cmake_minimum_required (VERSION 3.0)" from FFTW's CMakeLists.txt +# so that ITK's policy settings (via CMAKE_POLICY_DEFAULT_CMP0077) apply. +# 2. Change "EXPORT FFTW3LibraryDepends" to "EXPORT FFTW3LibraryDepends${PREC_SUFFIX}" +# to avoid conflicts when building both single and double precision. +# 3. Change export() FILE path from "FFTW3LibraryDepends.cmake" to "FFTW3LibraryDepends${PREC_SUFFIX}.cmake" +# to avoid conflicts when building both single and double precision. +# 4. Add "EXPORT FFTW3LibraryDepends${PREC_SUFFIX}" to the install(TARGETS ${subtarget}) in the foreach loop +# so all subtargets (threads, omp) are included in the export. + +if(NOT DEFINED INFILE) + message(FATAL_ERROR "INFILE not defined") +endif() + +# Read the file +file(READ "${INFILE}" CONTENT) + +# Split into lines +string(REGEX REPLACE "\n" ";" LINES "${CONTENT}") + +# Remove first line +list(REMOVE_AT LINES 0) + +# Join back together +string(REPLACE ";" "\n" NEW_CONTENT "${LINES}") + +# Replace EXPORT name to include precision suffix +string( + REPLACE + "EXPORT FFTW3LibraryDepends" + "EXPORT FFTW3LibraryDepends\${PREC_SUFFIX}" + NEW_CONTENT + "${NEW_CONTENT}" +) + +# Replace export() FILE name to include precision suffix +string( + REPLACE + "FILE \${PROJECT_BINARY_DIR}/FFTW3LibraryDepends.cmake" + "FILE \${PROJECT_BINARY_DIR}/FFTW3LibraryDepends\${PREC_SUFFIX}.cmake" + NEW_CONTENT + "${NEW_CONTENT}" +) + +# Add EXPORT clause to the install(TARGETS ${subtarget}) in foreach loop +string( + REPLACE + "install (TARGETS \${subtarget}\n" + "install (TARGETS \${subtarget}\n EXPORT FFTW3LibraryDepends\${PREC_SUFFIX}\n" + NEW_CONTENT + "${NEW_CONTENT}" +) + +# Write back +file(WRITE "${INFILE}" "${NEW_CONTENT}") + +message( + STATUS + "Patched ${INFILE}: removed first line, updated EXPORT names, fixed export() FILE path, and added EXPORT to foreach install" +) diff --git a/CMake/itkExternal_FFTW.cmake b/Modules/ThirdParty/FFTW/CMake/itkExternal_FFTW.cmake similarity index 100% rename from CMake/itkExternal_FFTW.cmake rename to Modules/ThirdParty/FFTW/CMake/itkExternal_FFTW.cmake diff --git a/Modules/ThirdParty/FFTW/CMake/itkFetchFFTW.cmake b/Modules/ThirdParty/FFTW/CMake/itkFetchFFTW.cmake new file mode 100644 index 00000000000..f145761d9e2 --- /dev/null +++ b/Modules/ThirdParty/FFTW/CMake/itkFetchFFTW.cmake @@ -0,0 +1,106 @@ +# +# Encapsulates building FFTW using FetchContent at configure time. +# +# NOTE: Internal building of FFTW is for convenience and testing. +# The version built here uses conservative settings for broad hardware compatibility. +# For production use where performance is critical, consider using ITK_USE_SYSTEM_FFTW +# with an optimized FFTW installation. +# +include(ITK_CheckCCompilerFlag) +include(FetchContent) + +# Find Threads package for threading support +find_package(Threads REQUIRED) + +# FFTW limitation: can't be built in a directory with whitespace in its name +if(${CMAKE_CURRENT_BINARY_DIR} MATCHES ".*[ \t].*") + message( + FATAL_ERROR + "Can't build FFTW in a directory with whitespace in its name" + ) +endif() + +set(_fftw_target_version 3.3.10) +set( + _fftw_url_hash + "2d34b5ccac7b08740dbdacc6ebe451d8a34cf9d9bfec85a5e776e87adf94abfd803c222412d8e10fbaa4ed46f504aa87180396af1b108666cde4314a55610b40" +) +set( + _fftw_url + "https://data.kitware.com/api/v1/file/hashsum/sha512/${_fftw_url_hash}/download" +) + +# Set policy CMP0077 to NEW so that option() respects normal variables +# This allows us to configure FFTW's build options without cache variables +set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) + +# Build single precision FFTW if requested +if(ITK_USE_FFTWF) + itk_download_attempt_check(FFTW) + + # Declare and fetch FFTW single precision + FetchContent_Declare( + fftw3f + URL + ${_fftw_url} + URL_HASH SHA512=${_fftw_url_hash} + DOWNLOAD_NAME "fftw-${_fftw_target_version}.tar.gz" + ) + + # Set FFTW options for single precision before populating + # With CMP0077=NEW, option() respects normal variables + set(BUILD_TESTS OFF) + set(DISABLE_FORTRAN ON) + set(ENABLE_AVX OFF) + set(ENABLE_AVX2 OFF) + set(ENABLE_FLOAT ON) + set(ENABLE_LONG_DOUBLE OFF) + set(ENABLE_OPENMP OFF) + set(ENABLE_QUAD_PRECISION OFF) + set(ENABLE_SSE OFF) + set(ENABLE_SSE2 OFF) + set(ENABLE_THREADS ON) + set(WITH_COMBINED_THREADS OFF) + + FetchContent_MakeAvailable(fftw3f) +endif() + +# Build double precision FFTW if requested +if(ITK_USE_FFTWD) + if(NOT ITK_USE_FFTWF) + itk_download_attempt_check(FFTW) + endif() + + # Declare and fetch FFTW double precision + + # Only declare if not already declared for single precision + FetchContent_Declare( + fftw3 + URL + ${_fftw_url} + URL_HASH SHA512=${_fftw_url_hash} + DOWNLOAD_NAME "fftw-${_fftw_target_version}.tar.gz" + PATCH_COMMAND + ${CMAKE_COMMAND} -E echo + "Removing cmake_minimum_required from FFTW CMakeLists.txt" COMMAND + ${CMAKE_COMMAND} -DINFILE=CMakeLists.txt -P + "${ITKFFTW_SOURCE_DIR}/CMake/RemoveFirstLine.cmake" + ) + + # Set FFTW options for double precision + # With CMP0077=NEW, option() respects normal variables + set(BUILD_TESTS OFF) + set(DISABLE_FORTRAN ON) + set(ENABLE_AVX OFF) + set(ENABLE_AVX2 OFF) + set(ENABLE_FLOAT OFF) + set(ENABLE_LONG_DOUBLE OFF) + set(ENABLE_OPENMP OFF) + set(ENABLE_QUAD_PRECISION OFF) + set(ENABLE_SSE OFF) + set(ENABLE_SSE2 OFF) + set(ENABLE_THREADS ON) + set(WITH_COMBINED_THREADS OFF) + + FetchContent_MakeAvailable(fftw3) +endif() diff --git a/Modules/ThirdParty/FFTW/CMakeLists.txt b/Modules/ThirdParty/FFTW/CMakeLists.txt new file mode 100644 index 00000000000..025f4835f98 --- /dev/null +++ b/Modules/ThirdParty/FFTW/CMakeLists.txt @@ -0,0 +1,152 @@ +project(ITKFFTW) +set(ITKFFTW_THIRD_PARTY 1) + +# ITK_USE_FFTWD -- use double precision FFTW +option(ITK_USE_FFTWD "Use double precision FFTW" ON) +mark_as_advanced(ITK_USE_FFTWD) + +# ITK_USE_FFTWF -- use single precision FFTW +option(ITK_USE_FFTWF "Use single precision FFTW" ON) +mark_as_advanced(ITK_USE_FFTWF) + +if(NOT ITK_USE_FFTWD AND NOT ITK_USE_FFTWF) + message( + FATAL_ERROR + "At least one of ITK_USE_FFTWD or ITK_USE_FFTWF must be ON" + ) +endif() + +set(msg "ATTENTION: You have enabled the use of FFTW.") +set(msg "${msg} This library is distributed under a GPL license.") +set(msg "${msg} By enabling this option, the ITK libraries binary") +set(msg "${msg} that is built will be covered by a GPL license") +set( + msg + "${msg} and so will any executable that is linked against these libraries." +) +message(STATUS "${msg}") + +set(ITKFFTW_LIBRARIES "") + +if(ITK_USE_SYSTEM_FFTW) + # When using system FFTW, find_package is called in itk-module-init.cmake + # The FindFFTW3.cmake module sets up FFTW3:: namespaced targets + set(ITKFFTW_INCLUDE_DIRS ${FFTW3_INCLUDE_DIRS}) + + # Create ITK:: namespace aliases for the FFTW3:: targets + if(ITK_USE_FFTWF) + if(TARGET FFTW3::fftw3f) + list(APPEND ITKFFTW_LIBRARIES FFTW3::fftw3f) + endif() + + if(TARGET FFTW3::fftw3f_threads) + list(APPEND ITKFFTW_LIBRARIES FFTW3::fftw3f_threads) + endif() + endif() + + if(ITK_USE_FFTWD) + if(TARGET FFTW3::fftw3) + list(APPEND ITKFFTW_LIBRARIES FFTW3::fftw3) + endif() + + if(TARGET FFTW3::fftw3_threads) + list(APPEND ITKFFTW_LIBRARIES FFTW3::fftw3_threads) + endif() + endif() + + set( + ITKFFTW_EXPORT_CODE_INSTALL + " +set(ITK_USE_FFTWD \"${ITK_USE_FFTWD}\") +set(ITK_USE_FFTWF \"${ITK_USE_FFTWF}\") +list(APPEND CMAKE_MODULE_PATH \"\${ITK_CMAKE_DIR}\") +find_package(FFTW3 REQUIRED) +" + ) + set( + ITKFFTW_EXPORT_CODE_BUILD + " +if(NOT ITK_BINARY_DIR) + set(ITK_USE_FFTWD \"${ITK_USE_FFTWD}\") + set(ITK_USE_FFTWF \"${ITK_USE_FFTWF}\") + list(APPEND CMAKE_MODULE_PATH \"${CMAKE_CURRENT_LIST_DIR}/CMake\") + find_package(FFTW3 REQUIRED) + list(REMOVE_AT CMAKE_MODULE_PATH 0) +endif() +" + ) + + set(ITKFFTW_NO_SRC 1) + + install( + FILES + CMake/FindFFTW3.cmake + DESTINATION ${ITK_INSTALL_PACKAGE_DIR} + COMPONENT Development + ) +else() + # Build FFTW using FetchContent + include(${ITKFFTW_SOURCE_DIR}/CMake/itkFetchFFTW.cmake) + + set(ITKFFTW_INCLUDE_DIRS ${ITKFFTW_BINARY_DIR}/src) + + # Create IMPORTED INTERFACE targets with FFTW3:: namespace for export compatibility + # IMPORTED targets (unlike ALIAS targets) can be exported in ITKTargets.cmake + if(ITK_USE_FFTWF) + list( + APPEND + ITKFFTW_LIBRARIES + FFTW3::fftw3f + FFTW3::fftw3f_threads + ) + add_library(FFTW3::fftw3f INTERFACE IMPORTED GLOBAL) + target_link_libraries(FFTW3::fftw3f INTERFACE fftw3f) + add_library(FFTW3::fftw3f_threads INTERFACE IMPORTED GLOBAL) + target_link_libraries(FFTW3::fftw3f_threads INTERFACE fftw3f_threads) + endif() + if(ITK_USE_FFTWD) + list( + APPEND + ITKFFTW_LIBRARIES + FFTW3::fftw3 + FFTW3::fftw3_threads + ) + add_library(FFTW3::fftw3 INTERFACE IMPORTED GLOBAL) + target_link_libraries(FFTW3::fftw3 INTERFACE fftw3) + add_library(FFTW3::fftw3_threads INTERFACE IMPORTED GLOBAL) + target_link_libraries(FFTW3::fftw3_threads INTERFACE fftw3_threads) + endif() + + set( + ITKFFTW_EXPORT_CODE_INSTALL + " +set(ITK_USE_FFTWD \"${ITK_USE_FFTWD}\") +set(ITK_USE_FFTWF \"${ITK_USE_FFTWF}\") +set(ITK_USE_SYSTEM_FFTW OFF) + +" + ) + set( + ITKFFTW_EXPORT_CODE_BUILD + " +if(NOT ITK_BINARY_DIR) + set(ITK_USE_FFTWD \"${ITK_USE_FFTWD}\") + set(ITK_USE_FFTWF \"${ITK_USE_FFTWF}\") + set(ITK_USE_SYSTEM_FFTW OFF) + +endif() +" + ) +endif() + +itk_module_impl() + +configure_file(src/itk_fftw.h.in src/itk_fftw.h) +install( + FILES + ${ITKFFTW_BINARY_DIR}/src/itk_fftw.h + DESTINATION ${ITKFFTW_INSTALL_INCLUDE_DIR} + COMPONENT Development +) + +message(STATUS "ITKFFTW_LIBRARIES: ${ITKFFTW_LIBRARIES}") diff --git a/Modules/ThirdParty/FFTW/itk-module-init.cmake b/Modules/ThirdParty/FFTW/itk-module-init.cmake new file mode 100644 index 00000000000..18ee7cee3ee --- /dev/null +++ b/Modules/ThirdParty/FFTW/itk-module-init.cmake @@ -0,0 +1,36 @@ +# ITK_USE_SYSTEM_FFTW -- locate a ready-built FFTW installation +option( + ITK_USE_SYSTEM_FFTW + "Use an installed version of FFTW" + ${ITK_USE_SYSTEM_LIBRARIES} +) +mark_as_advanced(ITK_USE_SYSTEM_FFTW) + +option(ITK_USE_FFTWD "Use double precision FFTW if found" OFF) +mark_as_advanced(ITK_USE_FFTWD) +option(ITK_USE_FFTWF "Use single precision FFTW if found" OFF) +mark_as_advanced(ITK_USE_FFTWF) + +if(ITK_USE_SYSTEM_FFTW) + set(_FFTW3_required_components "") + if(ITK_USE_FFTWD) + list( + APPEND + _FFTW3_required_components + fftw3 + fftw3_threads + ) + endif() + if(ITK_USE_FFTWF) + list( + APPEND + _FFTW3_required_components + fftw3f + fftw3f_threads + ) + endif() + + list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMake") + find_package(FFTW3 REQUIRED COMPONENTS ${_FFTW3_required_components}) + list(REMOVE_AT CMAKE_MODULE_PATH 0) +endif() diff --git a/Modules/ThirdParty/FFTW/itk-module.cmake b/Modules/ThirdParty/FFTW/itk-module.cmake new file mode 100644 index 00000000000..70f7ae7a71e --- /dev/null +++ b/Modules/ThirdParty/FFTW/itk-module.cmake @@ -0,0 +1,8 @@ +set( + DOCUMENTATION + "This module contains the third party FFTW library. +FFTW is a C library for computing the discrete Fourier transform (DFT) in one or more dimensions. +Note: FFTW is licensed under the GPL. By enabling this module, your ITK build will be covered by the GPL license." +) + +itk_module(ITKFFTW DEPENDS DESCRIPTION "${DOCUMENTATION}" EXCLUDE_FROM_DEFAULT) diff --git a/Modules/ThirdParty/FFTW/src/itk_fftw.h.in b/Modules/ThirdParty/FFTW/src/itk_fftw.h.in new file mode 100644 index 00000000000..65e728eacfb --- /dev/null +++ b/Modules/ThirdParty/FFTW/src/itk_fftw.h.in @@ -0,0 +1,44 @@ +/*========================================================================= + * + * Copyright NumFOCUS + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ + +#ifndef itk_fftw_h +#define itk_fftw_h + +/* This header provides access to FFTW headers for both system and internal builds. + * + * IMPORTANT: FFTW is licensed under the GPL license. + * By using FFTW, your code will be covered by the GPL license. + * + * Usage: + * #include "itk_fftw.h" + * Then use standard FFTW headers via + */ + +#cmakedefine01 ITK_USE_SYSTEM_FFTW +#cmakedefine01 ITK_USE_FFTWD +#cmakedefine01 ITK_USE_FFTWF + +#if ITK_USE_SYSTEM_FFTW + // Using system-installed FFTW + #include +#else + // Using ITK's internally built FFTW + #include +#endif + +#endif // itk_fftw_h