Finding FFTW
FFTW does not ship CMake config files by default — you need either a custom find module or pkg-config integration. CMake has no built-in FindFFTW.cmake, so projects typically provide their own:
# Using pkg-config to find FFTW (simplest approach)
cmake_minimum_required(VERSION 3.20)
project(SignalApp LANGUAGES C CXX)
find_package(PkgConfig REQUIRED)
pkg_check_modules(FFTW3 REQUIRED IMPORTED_TARGET fftw3)
add_executable(signal_app main.cpp)
target_link_libraries(signal_app PRIVATE PkgConfig::FFTW3)
For systems without pkg-config (Windows), or for more control, use a manual search:
# Manual FFTW discovery
cmake_minimum_required(VERSION 3.20)
project(FFTApp LANGUAGES CXX)
# Search for FFTW header and libraries
find_path(FFTW3_INCLUDE_DIR fftw3.h
HINTS
${FFTW3_ROOT}/include
/usr/local/include
/opt/fftw/include
)
find_library(FFTW3_LIBRARY fftw3
HINTS
${FFTW3_ROOT}/lib
/usr/local/lib
/opt/fftw/lib
)
# Create imported target
if(FFTW3_INCLUDE_DIR AND FFTW3_LIBRARY)
add_library(FFTW3::fftw3 IMPORTED INTERFACE)
set_target_properties(FFTW3::fftw3 PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${FFTW3_INCLUDE_DIR}"
INTERFACE_LINK_LIBRARIES "${FFTW3_LIBRARY}"
)
endif()
add_executable(fft_app main.cpp)
target_link_libraries(fft_app PRIVATE FFTW3::fftw3)
libfftw3-dev. On these systems, find_package(FFTW3 CONFIG) may work directly without a custom find module.
Single, Double & Long Precision
FFTW3 provides separate libraries for each floating-point precision. The API is identical but prefixed differently:
# Finding all FFTW precision variants
find_library(FFTW3_DOUBLE_LIB fftw3) # double precision (default)
find_library(FFTW3_SINGLE_LIB fftw3f) # float (single precision)
find_library(FFTW3_LONG_LIB fftw3l) # long double precision
find_library(FFTW3_QUAD_LIB fftw3q) # __float128 (GCC only)
add_executable(multi_precision main.cpp)
target_link_libraries(multi_precision PRIVATE
${FFTW3_DOUBLE_LIB}
${FFTW3_SINGLE_LIB}
)
target_include_directories(multi_precision PRIVATE ${FFTW3_INCLUDE_DIR})
// main.cpp — FFTW3 multi-precision usage
#include <fftw3.h>
#include <cmath>
#include <iostream>
#include <vector>
int main() {
const int N = 1024;
// Double precision FFT
std::vector<double> in_d(N);
for (int i = 0; i < N; i++)
in_d[i] = std::sin(2.0 * M_PI * 50.0 * i / N);
fftw_complex* out_d = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * (N/2+1));
fftw_plan plan_d = fftw_plan_dft_r2c_1d(N, in_d.data(), out_d, FFTW_ESTIMATE);
fftw_execute(plan_d);
std::cout << "Double: DC component = " << out_d[0][0] << "\n";
fftw_destroy_plan(plan_d);
fftw_free(out_d);
// Single precision FFT (fftwf_ prefix)
std::vector<float> in_f(N);
for (int i = 0; i < N; i++)
in_f[i] = std::sin(2.0f * (float)M_PI * 50.0f * i / N);
fftwf_complex* out_f = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * (N/2+1));
fftwf_plan plan_f = fftwf_plan_dft_r2c_1d(N, in_f.data(), out_f, FFTW_ESTIMATE);
fftwf_execute(plan_f);
std::cout << "Single: DC component = " << out_f[0][0] << "\n";
fftwf_destroy_plan(plan_f);
fftwf_free(out_f);
return 0;
}
Threading Support
FFTW provides parallel execution via pthreads or OpenMP. Each requires linking the corresponding thread library:
# FFTW with threading (pthreads)
find_library(FFTW3_THREADS_LIB fftw3_threads)
find_package(Threads REQUIRED)
add_executable(fft_threaded threaded.cpp)
target_link_libraries(fft_threaded PRIVATE
${FFTW3_LIBRARY}
${FFTW3_THREADS_LIB}
Threads::Threads
m # math library on Linux
)
# Alternative: FFTW with OpenMP
find_library(FFTW3_OMP_LIB fftw3_omp)
find_package(OpenMP REQUIRED)
add_executable(fft_omp omp_fft.cpp)
target_link_libraries(fft_omp PRIVATE
${FFTW3_LIBRARY}
${FFTW3_OMP_LIB}
OpenMP::OpenMP_CXX
)
// threaded.cpp — Multi-threaded FFTW
#include <fftw3.h>
#include <iostream>
#include <vector>
#include <cmath>
int main() {
// Initialize threading (call once before any plan creation)
fftw_init_threads();
fftw_plan_with_nthreads(4); // Use 4 threads
const int N = 1048576; // 1M points — threading helps here
std::vector<double> signal(N);
for (int i = 0; i < N; i++)
signal[i] = std::sin(2.0 * M_PI * 440.0 * i / 44100.0);
fftw_complex* spectrum = (fftw_complex*)fftw_malloc(
sizeof(fftw_complex) * (N/2 + 1));
fftw_plan plan = fftw_plan_dft_r2c_1d(N, signal.data(), spectrum, FFTW_MEASURE);
fftw_execute(plan);
std::cout << "Computed " << N << "-point FFT with 4 threads\n";
fftw_destroy_plan(plan);
fftw_free(spectrum);
fftw_cleanup_threads();
return 0;
}
fftw_execute() is safe to call concurrently with different plans. Always initialize threads before creating the first plan.
Writing a FindFFTW Module
A reusable FindFFTW.cmake module that handles all precision variants and threading:
# cmake/FindFFTW.cmake — Reusable find module
# Usage: find_package(FFTW REQUIRED COMPONENTS DOUBLE FLOAT THREADS)
include(FindPackageHandleStandardArgs)
# Find include directory
find_path(FFTW_INCLUDE_DIR fftw3.h
HINTS ${FFTW_ROOT} ENV FFTW_ROOT
PATH_SUFFIXES include
)
# Component library map
set(_fftw_component_libs
DOUBLE fftw3
FLOAT fftw3f
LONG fftw3l
THREADS fftw3_threads
FLOAT_THREADS fftw3f_threads
OMP fftw3_omp
)
# Find requested component libraries
set(FFTW_LIBRARIES "")
foreach(_comp ${FFTW_FIND_COMPONENTS})
list(FIND _fftw_component_libs ${_comp} _idx)
if(_idx GREATER_EQUAL 0)
math(EXPR _lib_idx "${_idx} + 1")
list(GET _fftw_component_libs ${_lib_idx} _lib_name)
find_library(FFTW_${_comp}_LIBRARY ${_lib_name}
HINTS ${FFTW_ROOT} ENV FFTW_ROOT
PATH_SUFFIXES lib lib64
)
if(FFTW_${_comp}_LIBRARY)
list(APPEND FFTW_LIBRARIES ${FFTW_${_comp}_LIBRARY})
set(FFTW_${_comp}_FOUND TRUE)
endif()
endif()
endforeach()
find_package_handle_standard_args(FFTW
REQUIRED_VARS FFTW_INCLUDE_DIR FFTW_LIBRARIES
HANDLE_COMPONENTS
)
# Create imported targets
if(FFTW_FOUND)
if(NOT TARGET FFTW::FFTW)
add_library(FFTW::FFTW INTERFACE IMPORTED)
set_target_properties(FFTW::FFTW PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIR}"
INTERFACE_LINK_LIBRARIES "${FFTW_LIBRARIES}"
)
endif()
endif()
# Using the custom find module in your project
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
find_package(FFTW REQUIRED COMPONENTS DOUBLE FLOAT THREADS)
add_executable(spectral_app main.cpp)
target_link_libraries(spectral_app PRIVATE FFTW::FFTW)
Building FFTW from Source
FFTW supports CMake as a build system (since FFTW 3.3.5), making source builds straightforward:
# Build FFTW3 from source with CMake
git clone https://github.com/FFTW/fftw3.git
cd fftw3
git checkout fftw-3.3.10
# Double precision build
cmake -B build-double -G Ninja \
-DCMAKE_INSTALL_PREFIX=/opt/fftw3 \
-DCMAKE_BUILD_TYPE=Release \
-DENABLE_THREADS=ON \
-DENABLE_OPENMP=ON \
-DENABLE_AVX2=ON \
-DENABLE_SSE2=ON \
-DBUILD_SHARED_LIBS=ON \
-DBUILD_TESTS=OFF
cmake --build build-double --parallel 8
cmake --install build-double
# Single precision build (must be separate!)
cmake -B build-single -G Ninja \
-DCMAKE_INSTALL_PREFIX=/opt/fftw3 \
-DCMAKE_BUILD_TYPE=Release \
-DENABLE_FLOAT=ON \
-DENABLE_THREADS=ON \
-DENABLE_AVX2=ON \
-DENABLE_SSE2=ON \
-DBUILD_SHARED_LIBS=ON
cmake --build build-single --parallel 8
cmake --install build-single
libfftw3, libfftw3f, libfftw3l) but can be installed to the same prefix.
FFTW3 vs FFTW2 Migration
FFTW2 (legacy) and FFTW3 have incompatible APIs. If migrating from FFTW2:
# Detect FFTW version and adapt
find_path(FFTW_INCLUDE_DIR fftw3.h)
if(FFTW_INCLUDE_DIR)
message(STATUS "Found FFTW3 headers")
set(FFTW_VERSION 3)
else()
find_path(FFTW_INCLUDE_DIR fftw.h) # FFTW2 header
if(FFTW_INCLUDE_DIR)
message(WARNING "Found FFTW2 — consider upgrading to FFTW3")
set(FFTW_VERSION 2)
endif()
endif()
# Version-conditional compilation
target_compile_definitions(app PRIVATE FFTW_VERSION=${FFTW_VERSION})
// Abstraction layer for FFTW2/FFTW3 migration
#if FFTW_VERSION == 3
#include <fftw3.h>
#define FFT_PLAN fftw_plan
#define FFT_COMPLEX fftw_complex
#define FFT_MALLOC(n) fftw_malloc(n)
#define FFT_FREE(p) fftw_free(p)
#define FFT_DESTROY_PLAN(p) fftw_destroy_plan(p)
#define FFT_EXECUTE(p) fftw_execute(p)
#else
// FFTW2 compatibility (deprecated)
#include <fftw.h>
#define FFT_PLAN fftw_plan
#define FFT_COMPLEX fftw_complex
#define FFT_MALLOC(n) malloc(n)
#define FFT_FREE(p) free(p)
#define FFT_DESTROY_PLAN(p) fftw_destroy_plan(p)
#define FFT_EXECUTE(p) /* FFTW2 uses fftw_one() */
#endif
- Use pkg-config on Linux/macOS for the simplest FFTW discovery
- Write a custom
FindFFTW.cmakefor cross-platform portability - Always link precision-specific libraries (
fftw3ffor float) - Initialize threads before creating plans (
fftw_init_threads()) - Build each precision variant separately when compiling from source
- Enable
FFTW_MEASUREfor production —FFTW_ESTIMATEfor development