PocketFFT (3rd/pocketfft, vendored 2018 version) cannot be compiled with -fno-exceptions, which PIP uses on all non-Windows/non-Android targets. This adds the proposed upstream patch adding a POCKETFFT_NO_EXCEPTIONS option (error paths abort with a diagnostic instead of throwing), plus the PR description for submission to mreineck/pocketfft. Verified: PIP builds with current upstream master + this patch and '-fno-exceptions -DPOCKETFFT_NO_EXCEPTIONS -DPOCKETFFT_NO_MULTITHREADING' and passes the FFT functional test suite. After the upstream PR is merged, bump the vendored header and drop the local workarounds.
3.9 KiB
PR: Add POCKETFFT_NO_EXCEPTIONS option for builds without exception handling
Repo: https://github.com/mreineck/pocketfft
Branch base: cpp (upstream master)
Motivation
pocketfft currently reports all errors via C++ exceptions (invalid arguments,
allocation failures, internal consistency checks). This makes the header
unusable in projects that are compiled without exception handling, e.g. with
GCC/Clang -fno-exceptions — a common setting in embedded,
safety-focused and performance-oriented code bases.
With -fno-exceptions the header fails to compile at every throw site:
pocketfft_hdronly.h: In function 'void* pocketfft::detail::aligned_alloc(...)':
error: exception handling disabled, use '-fexceptions' to enable
and additionally at the catch clauses in the thread pool (GCC rejects
catch under -fno-exceptions even with an empty body).
The only workaround today is to sed-patch the vendored header in every downstream project. This PR adds an opt-in upstream option instead.
What the PR adds
A new configuration macro POCKETFFT_NO_EXCEPTIONS, following the existing
POCKETFFT_NO_VECTORS / POCKETFFT_NO_MULTITHREADING naming convention:
#define POCKETFFT_NO_EXCEPTIONS // optionally + POCKETFFT_NO_MULTITHREADING
#include "pocketfft_hdronly.h"
// build with -fno-exceptions as usual
Semantics: error conditions that would normally throw an exception instead
print a diagnostic to stderr and call abort():
pocketfft: bad axis number
Aborted (core dumped)
Design
- Every
throw std::...;site (26 of them) is wrapped in aPOCKETFFT_THROW(exception)macro:- undefined (default): expands to
throw exception— behavior is 100% unchanged, exceptions are still catchable as before; - defined: calls
POCKETFFT_NAMESPACE::detail::handle_fatal_error(e), which printspocketfft: <what()>to stderr andstd::abort().
- undefined (default): expands to
- The two
try/catchregions of the thread pool are#if-guarded, sincecatchitself is a compile error under-fno-exceptions:thread_pool::create_threads(): without exception handling the worker thread is created directly — a failingstd::threadconstructor already results instd::terminate()per the standard, so nothing is lost;threading::thread_map(): the worker lambda simply callsf()without the exception-capture plumbing.
- Why
abort(): all error sites are unrecoverable (programmer errors such as invalid size/stride/axis, or OOM). In a no-exception program there is no meaningful recovery path, and abort-with-diagnostic is the customary behavior. A user-configurable fatal handler could be a follow-up if desired.
Verification
pocketfft_demo.cc was built and run with GCC 15 and Clang (latest) in the
following configurations, with identical numerical output in all of them:
- default (exceptions enabled) — unchanged behavior; additionally verified
that an out-of-range axis still throws a catchable
std::invalid_argument; -DPOCKETFFT_NO_EXCEPTIONSwith exceptions enabled (mixed mode);-fno-exceptions -DPOCKETFFT_NO_EXCEPTIONS -DPOCKETFFT_NO_MULTITHREADING;-fno-exceptions -DPOCKETFFT_NO_EXCEPTIONS(thread pool compiled in).
Error-path check: with the macro defined (configurations 2–4), requesting a
transform with an out-of-range axis prints pocketfft: bad axis number and
aborts with SIGABRT.
Multithreaded check: with the macro defined and the thread pool enabled, a
1024-point transform with nthreads=4 is bit-identical to the
single-threaded reference, across repeated pool runs.
Files changed
pocketfft_hdronly.h— the option (macro +handle_fatal_error, guarded thread pool code);README.md— documentation entry in "Configuration options".
Note for downstream users
This is what allows downstream projects that vendor the header and build with
-fno-exceptions (e.g. the PIP library) to drop their local header patches
and/or move to a current upstream release.