hackrf/host/cmake/modules/FindFFTW.cmake
Jamie Smith d60fb83320 Cleanup of host software CMake build system (#664)
* Clean up the CMake build system and improve the FindFFTW3 module.

* Fixes for Linux build

* Include winsock.h to get struct timeval

* Couple more fixes for MSVC, also add new FindMath module

* Update host build README for new CMake changes (esp. Windows)

* Try to fix Travis OS X build error

* Add docs about pthread-win32

* Whoops, AppVeyor caught a bug in FindFFTW where the includes not being found weren't generating a fatal error.

* Travis rebuild bump

* One more fix: replace hardcoded include paths with a PATH_SUFFIX to standard include paths

* Invert Windows preprocessor flag so it's only needed when using a static build.  This preserves compatibility with the previous system.

* Fix copy-paste error

* Update cmake modules from amber-cmake upstream, incorporate TryLinkLibrary into FindUSB1

* Fix missing include
2021-12-03 14:11:04 -05:00

368 lines
12 KiB
CMake

# - Find FFTW
# Find the native FFTW includes and library
# Components:
# MPI Fortran SinglePrecision QuadPrecision
# FFTW_COMPILE_OPTIONS - Compile options to apply when using fftw
# FFTW_INCLUDES - where to find fftw3.h
# FFTW_LIBRARIES - List of libraries when using FFTW.
# FFTW_FOUND - True if FFTW found.
# FFTW_IS_SHARED - True if FFTW is being linked as a shared library
# FFTW_<Component>_FOUND - Whether the given component was found.
#
# Note that FFTW splits itself into multiple libraries,
# single precision (fftwf), double precision (fftw), and quad precision (fftwl).
# By default FindFFTW will find only the standard double precision variant.
# To guarantee that you get the other variants, request the relevant components.
#
# Why is there a "Fortran" component you ask? It's because some systems lack the Fortran headers (e.g. fftw3.f03)
#
# when using components:
# FFTW_INCLUDES_SERIAL - include path for FFTW serial
# FFTW_LIBRARIES_SERIAL - library for use of fftw from C and Fortran
# FFTW_INCLUDES_MPI - include path for FFTW MPI
# FFTW_LIBRARIES_MPI - extra FFTW library to use MPI
#
# This module also creates the following imported targets, if the relevant components are enabled:
# fftw::fftwl - Main (double precision) library
# fftw::fftwf - Single precision library
# fftw::fftwq - Quad precision library
# fftw::mpi_f - MPI single precision library
# fftw::mpi_l - MPI double precision library
# fftw::mpi_q - MPI quad precision library
# fftw::fftw - All enabled libraries
if (FFTW_FOUND)
# Already in cache, be silent
set (FFTW_FIND_QUIETLY TRUE)
endif()
include(CheckCSourceCompiles)
set(FFTW_REQUIRED_VARIABLES )
set(FFTW_COMPILE_OPTIONS )
set(FIND_FFTW_DEBUG FALSE)
# utility function for finding multiple precisions
macro(fftw_find_precision COMPONENT PREC LIBNAMES CHECK_FUNCTION TYPE)
if(FIND_FFTW_DEBUG)
message("Searching for split ${TYPE} FFTW library (${COMPONENT}) with names ${LIBNAMES}")
endif()
# first find the library
find_library(FFTW${PREC}_LIBRARY_${TYPE} NAMES ${LIBNAMES})
if(EXISTS "${FFTW${PREC}_LIBRARY_${TYPE}}")
if(FIND_FFTW_DEBUG)
message("Found ${COMPONENT} ${TYPE} FFTW library: ${FFTW${PREC}_LIBRARY_${TYPE}}")
endif()
# now check if it works
set(LIBS_TO_CHECK ${FFTW${PREC}_LIBRARY_${TYPE}})
if("${TYPE}" STREQUAL "SERIAL")
# only link serial FFTW
list(APPEND LIBS_TO_CHECK ${FFTW_LIBRARY_SERIAL})
else()
# link serial and parallel
list(APPEND LIBS_TO_CHECK ${FFTW_LIBRARY_MPI} ${FFTW_LIBRARY_SERIAL})
endif()
fftw_check_c_function(${CHECK_FUNCTION} FFTW${PREC}_${TYPE}_WORKS ${LIBS_TO_CHECK})
unset(LIBS_TO_CHECK)
else()
if(FIND_FFTW_DEBUG)
message("Could not find ${COMPONENT} ${TYPE} FFTW library: ${FFTW${PREC}_LIBRARY_${TYPE}}")
endif()
set(FFTW${PREC}_${TYPE}_WORKS FALSE)
endif()
if(FFTW${PREC}_${TYPE}_WORKS)
set(FFTW_LIBRARIES ${FFTW${PREC}_LIBRARY_SERIAL} ${FFTW_LIBRARIES})
set(FFTW_LIBRARIES_${TYPE} ${FFTW${PREC}_LIBRARY_SERIAL} ${FFTW_LIBRARIES_${TYPE}})
# if the component is already set to not found, then don't make it found
if(NOT (DEFINED FFTW_${COMPONENT}_FOUND AND NOT FFTW_${COMPONENT}_FOUND))
set(FFTW_${COMPONENT}_FOUND TRUE)
endif()
endif()
if(FFTW_FIND_REQUIRED_${COMPONENT})
list(APPEND FFTW_REQUIRED_VARIABLES FFTW${PREC}_LIBRARY_${TYPE} FFTW${PREC}_${TYPE}_WORKS)
endif()
endmacro(fftw_find_precision)
# Check if a given function can be found in a given library.
# Similar to CheckFunctionExists, but can handle DLL imports on Windows.
function(fftw_check_c_function FUNCTION RESULT_VARIABLE) # ARGN: LIBRARIES...
# mirror the logic in fftw3.h
if(FFTW_DLL_IMPORT)
set(FUNCTION_PREFIX "extern __declspec(dllimport)")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
set(FUNCTION_PREFIX "extern")
else()
set(FUNCTION_PREFIX "")
endif()
try_link_library(${RESULT_VARIABLE}
LANGUAGE C
FUNCTION ${FUNCTION}
FUNC_PREFIX ${FUNCTION_PREFIX}
LIBRARIES ${ARGN})
endfunction(fftw_check_c_function)
# headers
# --------------------------------------------------------------------
find_path (FFTW_INCLUDES_SERIAL fftw3.h)
set(FFTW_INCLUDES ${FFTW_INCLUDES_SERIAL})
list(APPEND FFTW_REQUIRED_VARIABLES FFTW_INCLUDES_SERIAL)
# serial libraries
# --------------------------------------------------------------------
find_library(FFTW_LIBRARY_SERIAL NAMES fftw3-3 fftw3 fftw)
set(FFTW_LIBRARIES ${FFTW_LIBRARY_SERIAL})
set(FFTW_LIBRARIES_SERIAL ${FFTW_LIBRARY_SERIAL})
if(FIND_FFTW_DEBUG AND EXISTS "${FFTW_LIBRARY_SERIAL}")
message("Found main FFTW library: ${FFTW_LIBRARY_SERIAL}")
endif()
# set up DLL compile flags (need to check type of library)
set(FFTW_IS_SHARED FALSE)
set(FFTW_DLL_IMPORT FALSE)
if(EXISTS "${FFTW_LIBRARY_SERIAL}")
get_lib_type(${FFTW_LIBRARY_SERIAL} FFTW_LIB_TYPE)
if(FIND_FFTW_DEBUG)
message("Lib type: ${FFTW_LIB_TYPE}")
endif()
if(FFTW_LIB_TYPE STREQUAL "SHARED" OR FFTW_LIB_TYPE STREQUAL "IMPORT")
set(FFTW_IS_SHARED TRUE)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Windows" AND FFTW_LIB_TYPE STREQUAL "IMPORT")
set(FFTW_DLL_IMPORT TRUE)
set(FFTW_COMPILE_OPTIONS -DFFTW_DLL)
endif()
endif()
if(EXISTS "${FFTW_LIBRARY_SERIAL}")
fftw_check_c_function(fftw_execute FFTW_WORKS ${FFTW_LIBRARY_SERIAL})
else()
set(FFTW_WORKS FALSE)
endif()
set(FFTW_REQUIRED_VARIABLES FFTW_LIBRARY_SERIAL FFTW_WORKS ${FFTW_REQUIRED_VARIABLES})
# search for precision libraries
if("${FFTW_FIND_COMPONENTS}" MATCHES "SinglePrecision")
fftw_find_precision(SinglePrecision F "fftw3f-3;fftw3f;fftwf" fftwf_execute SERIAL)
endif()
if("${FFTW_FIND_COMPONENTS}" MATCHES "QuadPrecision")
fftw_find_precision(QuadPrecision L "fftw3l-3;fftw3l;fftwl" fftwl_execute SERIAL)
endif()
# Fortran component
# --------------------------------------------------------------------
if("${FFTW_FIND_COMPONENTS}" MATCHES "Fortran")
# should exist if Fortran support is present
set(FFTW_FORTRAN_HEADER "${FFTW_INCLUDES_SERIAL}/fftw3.f03")
if(NOT EXISTS "${FFTW_INCLUDES_SERIAL}")
message(STATUS "Cannot search for FFTW Fortran headers because the serial headers were not found")
set(FFTW_Fortran_FOUND FALSE)
elseif(EXISTS "${FFTW_FORTRAN_HEADER}")
# check that the Fortran compiler can link fftw and that the manglings match
# Deal with annoying issue: sometimes /usr/include is removed from Fortran
# include directories since CMake incorrectly thinks it's part of the implcit
# include directories.
# We could try clearing "CMAKE_Fortran_IMPLICIT_INCLUDE_DIRECTORIES" but that won't
# work in try_link_library().
set(FFTW_INCLUDES_FORTRAN ${FFTW_INCLUDES_SERIAL})
if("${FFTW_INCLUDES_FORTRAN}" IN_LIST CMAKE_Fortran_IMPLICIT_INCLUDE_DIRECTORIES)
get_filename_component(FFTW_FORTRAN_INCLUDE_FOLDER ${FFTW_INCLUDES_FORTRAN} NAME )
set(FFTW_INCLUDES_FORTRAN ${FFTW_INCLUDES_FORTRAN}/../${FFTW_FORTRAN_INCLUDE_FOLDER})
endif()
try_link_library(FFTW_FORTRAN_WORKS
LANGUAGE Fortran
FUNCTION fftw_cleanup
LIBRARIES ${FFTW_LIBRARY_SERIAL}
INCLUDES ${FFTW_INCLUDES_FORTRAN}
FUNC_CALL "
use, intrinsic :: iso_c_binding
implicit none
include 'fftw3.f03'
call fftw_cleanup()")
if(FFTW_FORTRAN_WORKS)
set(FFTW_Fortran_FOUND TRUE)
list(APPEND FFTW_INCLUDES ${FFTW_INCLUDES_FORTRAN})
else()
set(FFTW_Fortran_FOUND FALSE)
endif()
else()
set(FFTW_Fortran_FOUND FALSE)
message(STATUS "Cannot find FFTW Fortran headers - ${FFTW_FORTRAN_HEADER} is missing.")
endif()
if(FFTW_FIND_REQUIRED_Fortran)
list(APPEND FFTW_REQUIRED_VARIABLES FFTW_FORTRAN_HEADER FFTW_FORTRAN_WORKS)
endif()
endif()
# MPI component
# --------------------------------------------------------------------
if("${FFTW_FIND_COMPONENTS}" MATCHES "MPI")
find_library(FFTW_LIBRARY_MPI NAMES fftw3_mpi fftw_mpi)
set(FFTW_LIBRARIES_MPI ${FFTW_LIBRARY_MPI})
find_path(FFTW_INCLUDES_MPI fftw3-mpi.h)
list(APPEND FFTW_INCLUDES ${FFTW_INCLUDES_MPI})
set(CMAKE_REQUIRED_LIBRARIES ${FFTW_LIBRARY_MPI})
if(EXISTS "${FFTW_LIBRARY_MPI}")
fftw_check_c_function(fftw_mpi_init FFTW_MPI_WORKS)
else()
set(FFTW_MPI_WORKS FALSE)
endif()
if(FFTW_MPI_WORKS)
set(FFTW_MPI_FOUND TRUE)
endif()
if(FFTW_FIND_REQUIRED_MPI)
list(APPEND FFTW_REQUIRED_VARIABLES FFTW_LIBRARY_MPI FFTW_INCLUDES_MPI FFTW_MPI_WORKS)
endif()
if("${FFTW_FIND_COMPONENTS}" MATCHES "SinglePrecision")
fftw_find_precision(SinglePrecision F "fftw3f_mpi-3;fftw3f_mpi;fftwf_mpi" fftwl_mpi_init MPI)
endif()
if("${FFTW_FIND_COMPONENTS}" MATCHES "QuadPrecision")
fftw_find_precision(QuadPrecision L "fftw3l_mpi-3;fftw3l_mpi;fftwl_mpi" fftwl_mpi_init MPI)
endif()
# also look for MPI fortran header if we requested fortran and MPI
if("${FFTW_FIND_COMPONENTS}" MATCHES "Fortran" AND FFTW_Fortran_FOUND)
set(FFTW_FORTRAN_MPI_HEADER "${FFTW_INCLUDES_MPI}/fftw3-mpi.f03")
# reevaluate our life choices
if(EXISTS "${FFTW_FORTRAN_MPI_HEADER}")
set(FFTW_Fortran_FOUND TRUE)
else()
set(FFTW_Fortran_FOUND FALSE)
message(STATUS "Cannot find FFTW Fortran headers - ${FFTW_FORTRAN_MPI_HEADER} is missing")
endif()
endif()
set(FFTW_LIBRARIES ${FFTW_LIBRARIES_MPI} ${FFTW_LIBRARIES})
mark_as_advanced (FFTW_LIBRARIES_MPI FFTW_INCLUDES_MPI)
endif()
# handle the QUIETLY and REQUIRED arguments and set FFTW_FOUND to TRUE if
# all listed variables are TRUE
include (FindPackageHandleStandardArgs)
find_package_handle_standard_args (FFTW REQUIRED_VARS ${FFTW_REQUIRED_VARIABLES})
mark_as_advanced(${FFTW_REQUIRED_VARIABLES})
# dump variables in debug mode
if(FIND_FFTW_DEBUG)
message("FFTW_COMPILE_OPTIONS: ${FFTW_COMPILE_OPTIONS}")
message("FFTW_INCLUDES: ${FFTW_INCLUDES}")
message("FFTW_LIBRARIES: ${FFTW_LIBRARIES}")
message("FFTW_FOUND: ${FFTW_FOUND}")
message("FFTW_IS_SHARED: ${FFTW_IS_SHARED}")
endif()
# import targets
if(FFTW_FOUND)
# main lib (double precision)
add_library(fftw::fftwl UNKNOWN IMPORTED)
set_property(TARGET fftw::fftwl PROPERTY IMPORTED_LOCATION ${FFTW_LIBRARY_SERIAL})
set_property(TARGET fftw::fftwl PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${FFTW_INCLUDES_SERIAL})
set_property(TARGET fftw::fftwl PROPERTY INTERFACE_COMPILE_OPTIONS ${FFTW_COMPILE_OPTIONS})
set(FFTW_ALL_IMPORTED_LIBRARIES fftw::fftwl)
if(FFTW_SinglePrecision_FOUND)
add_library(fftw::fftwf UNKNOWN IMPORTED)
set_property(TARGET fftw::fftwf PROPERTY IMPORTED_LOCATION ${FFTWF_LIBRARY_SERIAL})
set_property(TARGET fftw::fftwf PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${FFTW_INCLUDES_SERIAL})
set_property(TARGET fftw::fftwf PROPERTY INTERFACE_COMPILE_OPTIONS ${FFTW_COMPILE_OPTIONS})
list(APPEND FFTW_ALL_IMPORTED_LIBRARIES fftw::fftwf)
endif()
if(FFTW_QuadPrecision_FOUND)
add_library(fftw::fftwq UNKNOWN IMPORTED)
set_property(TARGET fftw::fftwq PROPERTY IMPORTED_LOCATION ${FFTWQ_LIBRARY_SERIAL})
set_property(TARGET fftw::fftwq PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${FFTW_INCLUDES_SERIAL})
set_property(TARGET fftw::fftwq PROPERTY INTERFACE_COMPILE_OPTIONS ${FFTW_COMPILE_OPTIONS})
list(APPEND FFTW_ALL_IMPORTED_LIBRARIES fftw::fftwq)
endif()
if(FFTW_MPI_FOUND)
add_library(fftw::mpi_l UNKNOWN IMPORTED)
set_property(TARGET fftw::mpi_l PROPERTY IMPORTED_LOCATION ${FFTW_LIBRARY_MPI})
set_property(TARGET fftw::mpi_l PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${FFTW_INCLUDES_MPI})
set_property(TARGET fftw::mpi_l PROPERTY INTERFACE_LINK_LIBRARIES fftw::fftwl)
list(APPEND FFTW_ALL_IMPORTED_LIBRARIES fftw::mpi_l)
if(FFTW_SinglePrecision_FOUND)
add_library(fftw::mpi_f UNKNOWN IMPORTED)
set_property(TARGET fftw::mpi_f PROPERTY IMPORTED_LOCATION ${FFTWF_LIBRARY_MPI})
set_property(TARGET fftw::mpi_f PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${FFTW_INCLUDES_MPI})
set_property(TARGET fftw::mpi_f PROPERTY INTERFACE_LINK_LIBRARIES fftw::fftwf)
list(APPEND FFTW_ALL_IMPORTED_LIBRARIES fftw::mpi_f)
endif()
if(FFTW_QuadPrecision_FOUND)
add_library(fftw::mpi_q UNKNOWN IMPORTED)
set_property(TARGET fftw::mpi_q PROPERTY IMPORTED_LOCATION ${FFTWQ_LIBRARY_MPI})
set_property(TARGET fftw::mpi_q PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${FFTW_INCLUDES_MPI})
set_property(TARGET fftw::mpi_q PROPERTY INTERFACE_LINK_LIBRARIES fftw::fftwq)
list(APPEND FFTW_ALL_IMPORTED_LIBRARIES fftw::mpi_q)
endif()
endif()
# add combined target
add_library(fftw::fftw INTERFACE IMPORTED)
set_property(TARGET fftw::fftw PROPERTY INTERFACE_LINK_LIBRARIES ${FFTW_ALL_IMPORTED_LIBRARIES})
set_property(TARGET fftw::fftw PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${FFTW_INCLUDES})
endif()
# don't leak required libraries
set(CMAKE_REQUIRED_LIBRARIES "")