How to use FFTW library in cmake?
Asked Answered
H

2

5

I have C++ code which uses FFTW 3.3.4. Ubuntu 16.04, cmake version 3.7.2

$ locate *fftw*.so

/usr/lib/libsfftw.so
/usr/lib/libsfftw_mpi.so
/usr/lib/libsfftw_threads.so
/usr/lib/libsrfftw.so
/usr/lib/libsrfftw_mpi.so
/usr/lib/libsrfftw_threads.so
/usr/lib/x86_64-linux-gnu/libfftw3.so
/usr/lib/x86_64-linux-gnu/libfftw3_mpi.so
/usr/lib/x86_64-linux-gnu/libfftw3_omp.so
/usr/lib/x86_64-linux-gnu/libfftw3_threads.so
/usr/lib/x86_64-linux-gnu/libfftw3f.so
/usr/lib/x86_64-linux-gnu/libfftw3f_mpi.so
/usr/lib/x86_64-linux-gnu/libfftw3f_omp.so
/usr/lib/x86_64-linux-gnu/libfftw3f_threads.so
/usr/lib/x86_64-linux-gnu/libfftw3l.so
/usr/lib/x86_64-linux-gnu/libfftw3l_mpi.so
/usr/lib/x86_64-linux-gnu/libfftw3l_omp.so
/usr/lib/x86_64-linux-gnu/libfftw3l_threads.so
/usr/lib/x86_64-linux-gnu/libfftw3q.so
/usr/lib/x86_64-linux-gnu/libfftw3q_omp.so
/usr/lib/x86_64-linux-gnu/libfftw3q_threads.so


$ locate fftw3.h
/usr/include/fftw3.h

I can compile it in this way:

g++ main.cpp -o main -lfftw3

but I have a problem with cmake.

This is my CMakeLists.txt:

cmake_minimum_required(VERSION 3.5.1)
project (main)
SET(CMAKE_C_COMPILER gcc)
SET(CMAKE_CXX_COMPILER g++)
file(GLOB SOURCES "*.cpp") 
SET(CMAKE_CXX_FLAGS "-lm -lfftw3")
SET(CMAKE_C_FLAGS   "-lm -lfftw3")
INCLUDE_DIRECTORIES(/usr/include)
LINK_DIRECTORIES(/usr/lib/x86_64-linux-gnu)
add_library(fftw3 STATIC IMPORTED)
set(CMAKE_C_OUTPUT_EXTENSION_REPLACE 1) 
set(CMAKE_CXX_OUTPUT_EXTENSION_REPLACE 1)
add_executable(main ${SOURCES})

cmake . && make

gives

undefined reference to `fftw_malloc'

and the same for the other fftw functions.

Hatchment answered 31/5, 2017 at 6:21 Comment(2)
Possible duplicate of How to add "-l" (ell) compiler flag in CMakeBernadette
libm usually comes all the way at the end, so put it behind libfftw3.Coleville
N
4

We delegate this to pkg-config:

find_package(PkgConfig REQUIRED)
pkg_search_module(FFTW REQUIRED fftw3 IMPORTED_TARGET)
include_directories(PkgConfig::FFTW)
link_libraries(PkgConfig::FFTW)

This works with cmake 3.11 (at least, it may work with earlier versions too).


NOTE: This doesn't work with fftw3_thread component because they don't have a separate .pc file. (see https://github.com/FFTW/fftw3/issues/180).

This may work to add the component (not tested, doesn't work in Macs --see comments--):

link_libraries(PkgConfig::FFTW -lfftw3_thread)

NOTE 2: I am pasting here @OlafWilkocx solution to get the thread component as well

cmake_minimum_required(VERSION 3.20)
...
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -fno-math-errno -ffinite-math-only") # clang
find_package(OpenMP REQUIRED)

find_package(PkgConfig REQUIRED)     
pkg_check_modules(FFTW IMPORTED_TARGET REQUIRED fftw3)
          
if(NOT FFTW_ROOT AND DEFINED ENV{FFTWDIR})
    set(FFTW_ROOT $ENV{FFTWDIR})
endif()
          
find_library(
    FFTW_DOUBLE_THREADS_LIB
    NAMES "fftw3_threads"
    PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR}
)
          
if (FFTW_DOUBLE_THREADS_LIB)
    set(FFTW_DOUBLE_THREADS_LIB_FOUND TRUE)
    set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_DOUBLE_THREADS_LIB})
    add_library(FFTW::DoubleThreads INTERFACE IMPORTED)
    set_target_properties(FFTW::DoubleThreads
        PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}"
        INTERFACE_LINK_LIBRARIES "${FFTW_DOUBLE_THREADS_LIB}"
    )
else()
    set(FFTW_DOUBLE_THREADS_LIB_FOUND FALSE)
endif()
     
include_directories(PkgConfig::FFTW)
     
add_executable(solver_step src/solver_step.cc)
target_link_libraries(solver_step PRIVATE OpenMP::OpenMP_CXX ${VTK_LIBRARIES} PkgConfig::FFTW ${FFTW_DOUBLE_THREADS_LIB})

NOTE 3

I am told that the line include_directories(PkgConfig::FFTW) is always incorrect and suggested to either only use link_libraries(PkgConfig::FFTW) or target_link_libraries(target_name PRIVATE PkgConfig::FFTW).

See here: Avoid bad include paths in CMake's pkg-config fallback

Neubauer answered 2/7, 2021 at 6:14 Comment(14)
Any way to make this work with the other libraries, fftw3_threads, fftw3_omp, etc.?Clipping
@OlafWillocx can you try to see if they work with pkg-config in the first place?Neubauer
Seems like they don't, which is my problem hehe, and FFTW3's CMake issue persists.Clipping
@OlafWillocx, yes, that is sad. github.com/FFTW/fftw3/issues/180. Maybe what you can do is append (somehow) _threads to the library detected in PkgConfig::FFTW. I am not expert in CMake dark magic but perhaps it can be done. If so, feel welcome to edit my answer or post a new one. I am very interested. Worst case what you can do is just add -lfftw3_thread -lfftw3_omp and hope for the best, after all the library search directory should have been detected already. See my edit. Please test.Neubauer
@OlafWillocx, BTW, in my experience using the threaded version of FFTW doesn't pay off. I think the speed ups are only up to 50% and saturates very quickly at 2 or 3 threads. I think this is because the FFTW algorithm is mostly memory-access bound. But maybe it is worth in your case.Neubauer
Can't find the library it says. Staring right at it next to the fftw3.dylib. Whatever, nothing of value was lost; I've also heard FFTW is bad multithreaded. cuFFT it is.Clipping
@OlafWillocx, sorry, it should say -lfftw3_thread in the edit (not -lfftw_thread). Can you try again?Neubauer
It's -lfftw3_threads actually but it's fine, seems there's some other reason that doesn't work.Clipping
Can you post the generated compilation line (make VERBOSE=1) and the subsequent error? Also check that libfftw3_thread.so is installed (in the same directory as libfftw3.so)Neubauer
Sure. My dynamic libs are .dylib. But either way, I can compile with clang++ ... -lfftw3 -lfftw3_omp -lfftw3_threads. I also checked the pkg-config the install comes with, and only fftw3.pc, fftw3f.pc, and fftw3l.pc exist.Clipping
Ah, ok, I see what you mean. It seems that pkg-config in your Mac expands to the full filename, not -lfftw3.... Sorry, I am not familiar with pkg-config and CMake in Mac. Still, you best bet could be convince CMake to do a copy and replace of fftw3 -> fftw3_thread of the variable ${FFTW_LINK_LIBRARIES} generated by pkg_search_module. See here cmake.org/cmake/help/latest/module/FindPkgConfig.htmlNeubauer
Another option is use a third party CMake that supports threads variants. github.com/egpbos/findFFTW , you copy FindFFTW.cmake to your own project and do something like find_package(FFTW REQUIRED COMPONENTS DOUBLE_LIB DOUBLE_THREADS_LIB). You also have to hope that it is Mac-ready, I don't know.Neubauer
I got it to work by taking what I need from that FindFFTW.cmake implementation. Thanks! Here's what that looks like in case you want to update your answer; necessary stuff can probably be simplified to a few lines.Clipping
@OlafWillocx, thanks see NOTE 2. Also a recent update NOTE 3.Neubauer
K
12

The command add_library will create a library in your project (CMake - add_library). I assume that is not what you want.

The command: g++ main.cpp -o main -lfftw3 will link the executable to the fftw library. In CMake you can reproduce the linking with:

add_executable(main ${SOURCES})
target_link_libraries(main fftw3)

Docu: CMake - target_link_libraries
Notice: It is important that the add_executable command comes before the linking.
Have fun with FFTW :)

Krysta answered 31/5, 2017 at 7:42 Comment(4)
It works, thanks. Was it possible to do the same withHatchment
It works, thanks. Was it possible to do the same with find_package(FFTW)?Hatchment
Actual there is no FindFFTW Module in cmake. To use find_package(FFTW) you should write this by your own or find a good one in the internet. I would just leave it as it is.Krysta
I used this for MPI - find_package(MPI), that was the reason for the question. OK ;)Hatchment
N
4

We delegate this to pkg-config:

find_package(PkgConfig REQUIRED)
pkg_search_module(FFTW REQUIRED fftw3 IMPORTED_TARGET)
include_directories(PkgConfig::FFTW)
link_libraries(PkgConfig::FFTW)

This works with cmake 3.11 (at least, it may work with earlier versions too).


NOTE: This doesn't work with fftw3_thread component because they don't have a separate .pc file. (see https://github.com/FFTW/fftw3/issues/180).

This may work to add the component (not tested, doesn't work in Macs --see comments--):

link_libraries(PkgConfig::FFTW -lfftw3_thread)

NOTE 2: I am pasting here @OlafWilkocx solution to get the thread component as well

cmake_minimum_required(VERSION 3.20)
...
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -fno-math-errno -ffinite-math-only") # clang
find_package(OpenMP REQUIRED)

find_package(PkgConfig REQUIRED)     
pkg_check_modules(FFTW IMPORTED_TARGET REQUIRED fftw3)
          
if(NOT FFTW_ROOT AND DEFINED ENV{FFTWDIR})
    set(FFTW_ROOT $ENV{FFTWDIR})
endif()
          
find_library(
    FFTW_DOUBLE_THREADS_LIB
    NAMES "fftw3_threads"
    PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR}
)
          
if (FFTW_DOUBLE_THREADS_LIB)
    set(FFTW_DOUBLE_THREADS_LIB_FOUND TRUE)
    set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_DOUBLE_THREADS_LIB})
    add_library(FFTW::DoubleThreads INTERFACE IMPORTED)
    set_target_properties(FFTW::DoubleThreads
        PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}"
        INTERFACE_LINK_LIBRARIES "${FFTW_DOUBLE_THREADS_LIB}"
    )
else()
    set(FFTW_DOUBLE_THREADS_LIB_FOUND FALSE)
endif()
     
include_directories(PkgConfig::FFTW)
     
add_executable(solver_step src/solver_step.cc)
target_link_libraries(solver_step PRIVATE OpenMP::OpenMP_CXX ${VTK_LIBRARIES} PkgConfig::FFTW ${FFTW_DOUBLE_THREADS_LIB})

NOTE 3

I am told that the line include_directories(PkgConfig::FFTW) is always incorrect and suggested to either only use link_libraries(PkgConfig::FFTW) or target_link_libraries(target_name PRIVATE PkgConfig::FFTW).

See here: Avoid bad include paths in CMake's pkg-config fallback

Neubauer answered 2/7, 2021 at 6:14 Comment(14)
Any way to make this work with the other libraries, fftw3_threads, fftw3_omp, etc.?Clipping
@OlafWillocx can you try to see if they work with pkg-config in the first place?Neubauer
Seems like they don't, which is my problem hehe, and FFTW3's CMake issue persists.Clipping
@OlafWillocx, yes, that is sad. github.com/FFTW/fftw3/issues/180. Maybe what you can do is append (somehow) _threads to the library detected in PkgConfig::FFTW. I am not expert in CMake dark magic but perhaps it can be done. If so, feel welcome to edit my answer or post a new one. I am very interested. Worst case what you can do is just add -lfftw3_thread -lfftw3_omp and hope for the best, after all the library search directory should have been detected already. See my edit. Please test.Neubauer
@OlafWillocx, BTW, in my experience using the threaded version of FFTW doesn't pay off. I think the speed ups are only up to 50% and saturates very quickly at 2 or 3 threads. I think this is because the FFTW algorithm is mostly memory-access bound. But maybe it is worth in your case.Neubauer
Can't find the library it says. Staring right at it next to the fftw3.dylib. Whatever, nothing of value was lost; I've also heard FFTW is bad multithreaded. cuFFT it is.Clipping
@OlafWillocx, sorry, it should say -lfftw3_thread in the edit (not -lfftw_thread). Can you try again?Neubauer
It's -lfftw3_threads actually but it's fine, seems there's some other reason that doesn't work.Clipping
Can you post the generated compilation line (make VERBOSE=1) and the subsequent error? Also check that libfftw3_thread.so is installed (in the same directory as libfftw3.so)Neubauer
Sure. My dynamic libs are .dylib. But either way, I can compile with clang++ ... -lfftw3 -lfftw3_omp -lfftw3_threads. I also checked the pkg-config the install comes with, and only fftw3.pc, fftw3f.pc, and fftw3l.pc exist.Clipping
Ah, ok, I see what you mean. It seems that pkg-config in your Mac expands to the full filename, not -lfftw3.... Sorry, I am not familiar with pkg-config and CMake in Mac. Still, you best bet could be convince CMake to do a copy and replace of fftw3 -> fftw3_thread of the variable ${FFTW_LINK_LIBRARIES} generated by pkg_search_module. See here cmake.org/cmake/help/latest/module/FindPkgConfig.htmlNeubauer
Another option is use a third party CMake that supports threads variants. github.com/egpbos/findFFTW , you copy FindFFTW.cmake to your own project and do something like find_package(FFTW REQUIRED COMPONENTS DOUBLE_LIB DOUBLE_THREADS_LIB). You also have to hope that it is Mac-ready, I don't know.Neubauer
I got it to work by taking what I need from that FindFFTW.cmake implementation. Thanks! Here's what that looks like in case you want to update your answer; necessary stuff can probably be simplified to a few lines.Clipping
@OlafWillocx, thanks see NOTE 2. Also a recent update NOTE 3.Neubauer

© 2022 - 2024 — McMap. All rights reserved.