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.

Mike Kinghan
  • 55,740
  • 12
  • 153
  • 182
Maxim
  • 75
  • 1
  • 1
  • 8
  • 2
    Possible duplicate of [How to add "-l" (ell) compiler flag in CMake](https://stackoverflow.com/questions/43136418/how-to-add-l-ell-compiler-flag-in-cmake) – Tsyvarev May 31 '17 at 08:21
  • `libm` usually comes all the way at the end, so put it behind `libfftw3`. – Victor Eijkhout Nov 25 '21 at 10:31

2 Answers2

11

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 :)

Soeren
  • 1,725
  • 1
  • 16
  • 30
  • It works, thanks. Was it possible to do the same with – Maxim May 31 '17 at 07:52
  • It works, thanks. Was it possible to do the same with find_package(FFTW)? – Maxim May 31 '17 at 07:52
  • 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. – Soeren May 31 '17 at 08:03
  • I used this for MPI - find_package(MPI), that was the reason for the question. OK ;) – Maxim May 31 '17 at 08:07
3

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

Anton Kesy
  • 119
  • 7
alfC
  • 14,261
  • 4
  • 67
  • 118
  • Any way to make this work with the other libraries, fftw3_threads, fftw3_omp, etc.? – Olaf Willocx Nov 25 '21 at 09:22
  • @OlafWillocx can you try to see if they work with pkg-config in the first place? – alfC Nov 25 '21 at 09:23
  • Seems like they don't, which is my problem hehe, and FFTW3's CMake issue persists. – Olaf Willocx Nov 25 '21 at 09:27
  • @OlafWillocx, yes, that is sad. https://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. – alfC Nov 25 '21 at 09:40
  • @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. – alfC Nov 25 '21 at 09:42
  • 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. – Olaf Willocx Nov 25 '21 at 10:07
  • @OlafWillocx, sorry, it should say `-lfftw3_thread` in the edit (not `-lfftw_thread`). Can you try again? – alfC Nov 25 '21 at 10:19
  • It's `-lfftw3_threads` actually but it's fine, seems there's some other reason that doesn't work. – Olaf Willocx Nov 25 '21 at 10:21
  • 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`) – alfC Nov 25 '21 at 10:24
  • 1
    [Sure](https://0bin.net/paste/epwC4GwV#omAeDtPBsiQcg8NVvWC2e0HvOf4ARGFj67UUFnGD+S8). 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. – Olaf Willocx Nov 25 '21 at 11:20
  • 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 https://cmake.org/cmake/help/latest/module/FindPkgConfig.html – alfC Nov 25 '21 at 21:20
  • Another option is use a third party CMake that supports threads variants. https://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. – alfC Nov 25 '21 at 21:24
  • 1
    I got it to work by taking what I need from that FindFFTW.cmake implementation. Thanks! [Here](https://0bin.net/paste/z0w5Wroi#jzxyOz8hVG8fh9lYKjF8XUqj2QiMEXNAd+kOwl0+Dbk)'s what that looks like in case you want to update your answer; necessary stuff can probably be simplified to a few lines. – Olaf Willocx Nov 26 '21 at 11:49
  • @OlafWillocx, thanks see NOTE 2. Also a recent update NOTE 3. – alfC Apr 23 '22 at 18:31