Skip to content

Fix free-threaded cross-compile builds by stating the Python ABI - #352

Merged
nsmith- merged 3 commits into
masterfrom
fix-freethreaded-cross-compile
Jul 31, 2026
Merged

Fix free-threaded cross-compile builds by stating the Python ABI#352
nsmith- merged 3 commits into
masterfrom
fix-freethreaded-cross-compile

Conversation

@nsmith-

@nsmith- nsmith- commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

Note

This description is agent-generated text, written by Claude Opus 5 via Claude Code.

The conda-forge cp314t (free-threaded 3.14) builds fail on exactly the three
cross-compiled targets — linux-aarch64, linux-ppc64le, osx-arm64 — with

CMake Error at $BUILD_PREFIX/share/cmake-4.4/Modules/FindPackageHandleStandardArgs.cmake:290 (message):
  Could NOT find Python (missing: Development.Module) (found suitable version
  "3.14.6", minimum required is "3.8")

See conda-forge/correctionlib-feedstock#37. Native cp314t builds pass, and so do
all the cross-compiled GIL-enabled variants, so it takes cross-compiling and
free-threading together.

Cause

  1. conda's CMAKE_ARGS passes -DCMAKE_SYSTEM_NAME=Linux, so CMAKE_CROSSCOMPILING is true.
  2. pybind11 3.0 honours CMP0190 (enabled here because our policy range reaches 4.1)
    and drops the Interpreter component when cross-compiling.
  3. CMake 4.4's FindPython deduces the free-threaded ABI from the interpreter. With
    no interpreter it falls back to GIL-enabled and rejects the python3.14t headers
    that scikit-build-core points it at — the version still gets read out of
    patchlevel.h, hence the "found suitable version 3.14.6" in the same message.

Nothing is wrong on the conda-forge side, and cibuildwheel is unaffected because it
never sets CMAKE_SYSTEM_NAME.

Worth noting that CMake <= 4.3 did not error here — it silently computed a SOABI
without the t flag (cpython-314-linux-aarch64), i.e. a mis-named extension
module. 4.4 turned that into a hard error.

Fix

State the ABI explicitly when the headers we were handed are free-threaded, before
pybind11 runs find_package(Python).

Testing

Reproduced locally with CMake 4.4.0 (conda-forge uses 4.4.1), a free-threaded
CPython 3.14.3, and a toolchain file setting only CMAKE_SYSTEM_NAME/
CMAKE_SYSTEM_PROCESSOR to trip CMAKE_CROSSCOMPILING:

  • before: Could NOT find Python (missing: Development.Module), same as CI
  • after: found components: Development.Module Development.Embed,
    Python_SOABI: cpython-314t-darwin, and _core.cpython-314t-darwin.so builds
    and links
  • unchanged: native free-threaded builds, and plain 3.14 with no hints (the
    pyconfig.h guard doesn't fire)

Follow-up

The cpp-peglib suppression here is a workaround, not a fix; #354 tracks bumping the
submodule and migrating off the removed parser.log API.

nsmith- added 3 commits July 31, 2026 09:33
When cross-compiling, pybind11 3.0 (via CMP0190) asks FindPython for
Development.Module without the Interpreter component. CMake 4.4 deduces
the free-threaded ABI from the interpreter, so with none available it
defaults to GIL-enabled, rejects the python3.14t headers, and fails with

  Could NOT find Python (missing: Development.Module)

Older CMake accepted the headers but derived a SOABI missing the "t"
flag. Both are fixed by setting Python_FIND_ABI when the headers we were
pointed at are free-threaded.

This is what breaks the conda-forge cp314t builds for linux-aarch64,
linux-ppc64le and osx-arm64, which cross-compile; cibuildwheel is
unaffected because it never sets CMAKE_SYSTEM_NAME.

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
numpy's stubs now use PEP 695 "type" statements, and mypy refuses to parse those
while python_version targets 3.9, so the format job fails before it checks any of
our code:

  numpy/__init__.pyi:737: error: Type statement is only supported in Python 3.12
  and greater  [syntax]
  Found 1 error in 1 file (errors prevented further checking)

Skip numpy rather than raise python_version, so we keep type checking against the
oldest interpreter we ship wheels for. follow_imports alone does not cover .pyi
files, hence follow_imports_for_stubs; both are needed.

Bumping mypy does not help on its own -- v2.3.0 reports the same error, and it
additionally refuses python_version 3.9 outright ("must be 3.10 or higher"), so
taking that route would mean giving up 3.9 checking as well.

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
cpp-peglib declares operator"" _ with the whitespace C++23 deprecates. The clang
now on macos-latest diagnoses that by default, and our -Werror makes it fatal, so
every macOS job fails on one line buried in Eigen's warning output:

  cpp-peglib/peglib.h:451:42: error: identifier '_' preceded by whitespace in a
  literal operator declaration is deprecated [-Werror,-Wdeprecated-literal-operator]

Bumping cpp-peglib does not get us out of it. The fix landed upstream in v1.14.0,
released four weeks ago, and every release carrying it has also dropped the
parser.log member that formula_ast.cc assigns to -- v1.15.1 fails with "no member
named 'log' in 'peg::parser'". No version both fixes the warning and builds against
our source, so migrating to set_logger is a deliberate change for after the release
rather than something to rush in now.

The check probes the positive form of the warning: compilers accept unknown -Wno-*
options silently, so probing -Wno-deprecated-literal-operator would succeed
everywhere and tell us nothing, including on gcc, which has no such warning.

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

CVMFS benchmarks

Top 25 slowest-loading corrections, sorted by mean time:

Benchmark Mean (ms) Stddev (ms) Rounds
test_load[JME/Run2-2017-UL-NanoAODv9/latest/jet_jerc.json.gz] 1000.930 6.182 5
test_load[JME/Run2-2017-UL-NanoAODv9/latest/fatJet_jerc.json.gz] 841.203 4.584 5
test_load[JME/Run3-24Prompt-Winter24-NanoAODv14/latest/jet_jerc.json.gz] 690.332 3.610 5
test_load[JME/Run3-24CDEReprocessingFGHIPrompt-Summer24-NanoAODv15/latest/fatJet_jerc.json.gz] 487.935 1.821 5
test_load[JME/Run3-24CDEReprocessingFGHIPrompt-Summer24-NanoAODv15/latest/jet_jerc.json.gz] 486.725 1.962 5
test_load[JME/Run3-25Prompt-Winter25-NanoAODv15/latest/fatJet_jerc.json.gz] 416.894 6.103 5
test_load[JME/Run3-25Prompt-Winter25-NanoAODv15/latest/jet_jerc.json.gz] 412.737 1.526 5
test_load[JME/Run3-25Prompt-Summer24-NanoAODv15/latest/jet_jerc.json.gz] 356.838 10.475 5
test_load[JME/Run3-25Prompt-Summer24-NanoAODv15/latest/fatJet_jerc.json.gz] 351.422 0.901 5
test_load[JME/Run2-2018-UL-NanoAODv9/latest/jet_jerc.json.gz] 333.537 2.351 5
test_load[JME/Run3-26Prompt-Summer24-NanoAODv15/latest/jet_jerc.json.gz] 333.348 2.096 5
test_load[JME/Run3-23CSep23-Summer23-NanoAODv12/latest/jet_jerc.json.gz] 332.904 2.086 5
test_load[JME/Run3-26Prompt-Summer24-NanoAODv15/latest/fatJet_jerc.json.gz] 332.207 0.675 5
test_load[JME/Run3-23CSep23-Summer23-NanoAODv12/latest/fatJet_jerc.json.gz] 330.680 0.873 5
test_load[JME/Run2-2016preVFP-UL-NanoAODv9/latest/jet_jerc.json.gz] 273.788 2.176 5
test_load[JME/Run2-2018-UL-NanoAODv9/latest/fatJet_jerc.json.gz] 261.386 0.971 5
test_load[JME/Run3-22EFGSep23-Summer22EE-NanoAODv12/latest/fatJet_jerc.json.gz] 256.873 1.425 5
test_load[JME/Run3-22EFGSep23-Summer22EE-NanoAODv12/latest/jet_jerc.json.gz] 256.502 1.277 5
test_load[JME/Run2-2016postVFP-UL-NanoAODv9/latest/jet_jerc.json.gz] 253.006 0.782 5
test_load[JME/Run3-23DSep23-Summer23BPix-NanoAODv12/latest/jet_jerc.json.gz] 240.104 0.353 5
test_load[JME/Run3-23DSep23-Summer23BPix-NanoAODv12/latest/fatJet_jerc.json.gz] 240.043 0.535 5
test_load[JME/Run2-2016preVFP-UL-NanoAODv9/latest/fatJet_jerc.json.gz] 235.803 0.906 5
test_load[JME/Run2-2017-UL-NanoAODv15/latest/jet_jerc.json.gz] 231.438 0.732 5
test_load[JME/Run2-2017-UL-NanoAODv15/latest/fatJet_jerc.json.gz] 231.200 1.139 5
test_load[JME/Run2-2016postVFP-UL-NanoAODv9/latest/fatJet_jerc.json.gz] 223.185 1.345 5

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses CMake cross-compilation failures for free-threaded CPython 3.14 (cp314t) by explicitly setting the Python ABI so FindPython can resolve Development.Module correctly when no interpreter is available (as happens under cross-compiling). It also adjusts build warning handling and type-checking configuration.

Changes:

  • Set Python_FIND_ABI based on Py_GIL_DISABLED detected from pyconfig.h to fix CMake 4.4+ free-threaded cross-compilation discovery.
  • Conditionally suppress -Wdeprecated-literal-operator for cpp-peglib under -Werror builds (non-MSVC).
  • Update mypy configuration to follow imports for stubs and skip numpy stubs to avoid parsing issues while targeting Python 3.9.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
CMakeLists.txt Adds free-threaded ABI hinting for cross-compiling and gates a clang warning suppression for cpp-peglib.
pyproject.toml Updates mypy behavior for stub imports and skips numpy stubs under the current python_version target.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pyproject.toml
@nsmith-
nsmith- added this pull request to the merge queue Jul 31, 2026
Merged via the queue into master with commit 269ea97 Jul 31, 2026
28 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants