Skip to content

feat(wheels)!: ✨ publish MPI-enabled wheels across MPI ABI families - #426

Draft
robertodr wants to merge 15 commits into
feat/scikit-build-config-settingsfrom
feat/mpi-wheels
Draft

robertodr wants to merge 15 commits into
feat/scikit-build-config-settingsfrom
feat/mpi-wheels

Conversation

@robertodr

Copy link
Copy Markdown
Member

🤖 AI text below 🤖

Summary

This PR publishes MPI-enabled monoprop wheels that work with the MPI library already installed on the user's machine. They don't bundle MPI, and they don't require the MPI-5 standard ABI. The approach follows mpi4py's wheels (cibw/, _mpiabi.py). We build one extension per MPI ABI family, identified by the library's soname:

  • mpich (libmpi.so.12): MPICH, Intel MPI, MVAPICH and Cray MPICH.
  • openmpi (libmpi.so.40).
  • mpiabi (libmpi_abi.so.1): built and tested locally, not shipped yet. It is waiting for an mpi4py release that uses it.

monoprop loads the variant matching the family mpi4py is using.

How it works at runtime. Every build ships a serial monoprop._core. MPI builds add monoprop._core_mpi.<abi>, in a separate nanobind domain.

  • A propagator built with comm=None always runs serially. Importing monoprop never imports mpi4py or initializes MPI.
  • Passing an mpi4py communicator loads the matching MPI module on first use. Before loading, monoprop checks the ABI family (from mpi4py's wheel file name, or from the library otherwise) and the MPI version.
  • Each implementation has a minimum version: Open MPI 4.1, MPICH 4.0, Intel MPI 2021.0, MVAPICH 3.0, Cray MPICH 8.1. Configure-time and runtime checks both enforce it. An implementation not in that list only gets a warning.

C++ SDK. The SDK in the wheel gains libmonoprop_mpi_<abi>. find_package(monoprop CONFIG COMPONENTS MPI) selects it to match the consumer's MPI.

Design spec and implementation plan: docs/superpowers/specs/2026-10-23-mpi-wheels-design.md and docs/superpowers/plans/2026-10-23-mpi-wheels.md. They are not part of this PR and can be shared on request.

Stacked on #421. The base branch is feat/scikit-build-config-settings.

Breaking changes:

  • monoprop.has_mpi is removed. Use bool(monoprop.MPI_ABIS).
  • comm=None now always runs serially. MPI builds used to fall back to MPI_COMM_WORLD.
  • monoprop::monoprop is serial in every build. MPI C++ consumers use COMPONENTS MPI and monoprop::monoprop_mpi.

Changes

  • CMake
    • Core sources are compiled once per variant (cmake/custom/monopropCore.cmake).
    • cmake/custom/monopropMPIABI.cmake reads the ABI family and vendor version from the mpi.h macros (-E -dM) and enforces the minimum versions. It is installed for consumers too.
    • cmake/custom/monopropMPI.cmake finds MPI either with FindMPI (dev builds) or from monoprop.mpi-abis <abi>=<prefix> entries (wheel builds).
    • Under CIBUILDWHEEL=1, the wheel keeps no RPATHs from the build machine.
  • Bindings: the comm bridge is split into comm_serial.cpp and comm_mpi.cpp, so bindings.cpp.in no longer needs #ifdefs. monoprop_add_python_core builds _core and _core_mpi.<abi>.
  • Python
    • New monoprop._backend (core_module, detect_mpi4py_abi, check_mpi_version) and the public monoprop.MPI_ABIS.
    • New errors: MPIUnavailableError, MPIAbiMismatchError, MPIVersionError.
    • Dispatch now goes through core_module(comm).
  • Wheels
    • tools/cibw/install-mpi.sh installs PyPI mpich==5.0.2 and openmpi==5.0.11 to build against.
    • repair-wheel.sh excludes MPI from auditwheel/delocate, then runs check_wheel.py. The audit checks MPI linkage per variant, RPATHs (including empty entries), that no MPI library is bundled, and that _mpi_abis.py lists exactly the shipped modules.
    • run-tests.sh / test-wheel-mpi.sh run the serial suite, then the MPI suite against each MPI from PyPI.
  • CI
    • New test-wheels deploy job, which also gates publishing. It covers:
      • the version floors: Ubuntu 22.04's Open MPI 4.1.2 and MPICH 4.0, each with source-built and PyPI mpi4py, and impi-rt==2021.1.1;
      • the latest Intel MPI;
      • Homebrew Open MPI, including the C++ consumer.
    • Deploy PR triggers now also cover the wheel-only files.
    • The setup action gains mpi: mpich and build-deps inputs.
  • Dev:
    • New recipes just test-wheel and just inspect-mpi.
    • just test-find-package adds an MPI leg and a check that an ABI mismatch fails at configure time.
    • The Nix dev shell puts Open MPI on the loader path.
  • Docs: README, getting-started, building (COMPONENTS MPI migration, release-wheel reproduction), parallelism (backend selection, supported versions), and testing (testing release wheels).

Verification so far

  • Locally (Nix, Open MPI 5.0.11):
    • serial and MPI Python and C++ suites;
    • the mpi marker suite at 1, 2 and 4 ranks;
    • the find_package consumer, serial and MPI on 2 ranks.
  • Local docker cibuildwheel (cp312, manylinux x86_64):
    • both variants built and the audit found 0 issues;
    • the serial suite and both PyPI-MPI suites passed.
  • Only this PR's CI can show: macOS (delocate and @rpath), linux-arm, abi3audit, and the test-wheels floor jobs.

Checklist

  • Tests added or updated to cover the changes
  • Documentation updated (docstrings, docs/, CONTRIBUTING.md) if needed
  • CHANGELOG / release notes updated if applicable (breaking changes are in the commit footers, for the release notes)

AI/LLM disclosure

  • I did not use LLM tooling, or used it only privately for ideation
  • I used the following tool to help write this PR description: Pi (claude-opus-5-5)
  • I used the following tool to generate or modify code: Pi (claude-opus-5-5 orchestrating claude-sonnet-5-5 / claude-haiku-5-5 subagents). Every commit carries an Assisted-by trailer.

Important

By opening this PR I confirm that I have read CONTRIBUTING.md and I agree to the terms of the Contributor License Agreement.

Warning

If you're contributing on behalf of your employer, contact cla@algorithmiq.fi to arrange a Corporate CLA.

…y helper

Core sources are registered once and compiled into an OBJECT library per variant, which later lets one configure build a serial core and one MPI core per ABI family.

Assisted-by: Pi:claude-opus-5-5
comm_serial.cpp and comm_mpi.cpp define get_mpi_comm and init_comm_bridge; each module compiles one, so the template needs no MPI guards.

Assisted-by: Pi:claude-opus-5-5
monoprop.MPI_ABIS lists the MPI ABI families the installation was built for, classified from the preprocessed mpi.h at configure time, which also rejects MPI implementations below monoprop's version floors (Open MPI 4.1, MPICH 4.0, Intel MPI 2021.0, MVAPICH 3.0, Cray MPICH 8.1). The MPI-2 C++ bindings are disabled.

BREAKING CHANGE: monoprop.has_mpi is removed; use bool(monoprop.MPI_ABIS).

Assisted-by: Pi:claude-opus-5-5
…mmunicator

Every build ships a serial _core; MPI builds add _core_mpi.<abi> in a separate nanobind domain. monoprop._backend serves comm=None from _core and loads the MPI module matching mpi4py's ABI family on first use, after checking mpi4py.MPI.get_vendor() against monoprop's version floors. libmonoprop is serial in every build.

BREAKING CHANGE: comm=None now always runs serially; MPI builds no longer fall back to MPI_COMM_WORLD. In MPI builds, monoprop::monoprop is serial until the MPI component lands.

Assisted-by: Pi:claude-opus-5-5
…omponent

Each MPI ABI family gets libmonoprop_mpi_<abi>; find_package(monoprop COMPONENTS MPI) classifies the consumer's mpi.h and provides monoprop::monoprop_mpi, or fails naming the ABI.

BREAKING CHANGE: monoprop::monoprop is serial in every build; MPI consumers use COMPONENTS MPI and monoprop::monoprop_mpi.

Assisted-by: Pi:claude-opus-5-5
monoprop.mpi-abis takes <abi>=<prefix> entries and builds each variant against that prefix without compiler wrappers, checking the prefix's mpi.h matches the declared ABI. Under cibuildwheel the extensions drop build-machine RPATHs; macOS MPI binaries search the usual MPI prefixes.

Assisted-by: Pi:claude-opus-5-5
cibuildwheel builds _core_mpi.mpich and _core_mpi.openmpi against the PyPI mpich 5.0.2 and openmpi 5.0.11 packages, keeps MPI out of the repaired wheel, audits it with check_wheel.py, and runs the MPI suite against each PyPI MPI.

Assisted-by: Pi:claude-opus-5-5
…w MPI

A test-wheels job installs the wheels next to the supported version floors (Ubuntu 22.04's Open MPI 4.1.2 and MPICH 4.0 with source-built and PyPI mpi4py, Intel MPI 2021.1.1), the latest Intel MPI and Homebrew Open MPI, runs configure's MPI inspection on the floor headers, the MPI suite and a C++ consumer, and gates publishing.

Assisted-by: Pi:claude-opus-5-5
… wheel build on wheel-only changes

Assisted-by: Pi:claude-opus-5-5
@coderabbitai

coderabbitai Bot commented Oct 24, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added documentation Improvements or additions to documentation dependencies Pull requests that update a dependency file python cpp ci tools labels Oct 24, 2026
@robertodr
robertodr added this pull request to stack #427 October 24, 2026 12:13
@github-actions

Copy link
Copy Markdown

Docs preview: https://pr-426.monoprop-docs.pages.dev

@codecov

codecov Bot commented Oct 24, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.30435% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 97.45%. Comparing base (3cbd80b) to head (57c36e4).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/monoprop/_backend.py 90.47% 5 Missing and 1 partial ⚠️
Additional details and impacted files
@@                          Coverage Diff                          @@
##           feat/scikit-build-config-settings     #426      +/-   ##
=====================================================================
- Coverage                              97.99%   97.45%   -0.54%     
=====================================================================
  Files                                     14       15       +1     
  Lines                                    797      865      +68     
  Branches                                 111      120       +9     
=====================================================================
+ Hits                                     781      843      +62     
- Misses                                    11       16       +5     
- Partials                                   5        6       +1     
Flag Coverage Δ
cpp 97.45% <91.30%> (-0.54%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

@sonarqubecloud

Copy link
Copy Markdown

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci cpp dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation python tools

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant