Files
pip/3rd/pocketfft/pr-description.md
andrey ba897e0911 Add pending upstream pocketfft patch: POCKETFFT_NO_EXCEPTIONS option
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.
2026-10-18 18:46:59 +00:00

3.9 KiB
Raw Permalink Blame History

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 a POCKETFFT_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 prints pocketfft: <what()> to stderr and std::abort().
  • The two try/catch regions of the thread pool are #if-guarded, since catch itself is a compile error under -fno-exceptions:
    • thread_pool::create_threads(): without exception handling the worker thread is created directly — a failing std::thread constructor already results in std::terminate() per the standard, so nothing is lost;
    • threading::thread_map(): the worker lambda simply calls f() 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:

  1. default (exceptions enabled) — unchanged behavior; additionally verified that an out-of-range axis still throws a catchable std::invalid_argument;
  2. -DPOCKETFFT_NO_EXCEPTIONS with exceptions enabled (mixed mode);
  3. -fno-exceptions -DPOCKETFFT_NO_EXCEPTIONS -DPOCKETFFT_NO_MULTITHREADING;
  4. -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.