Skip to content

Add qiskit.capi module#15711

Merged
Cryoris merged 5 commits intoQiskit:mainfrom
jakelishman:c/include-file
Mar 11, 2026
Merged

Add qiskit.capi module#15711
Cryoris merged 5 commits intoQiskit:mainfrom
jakelishman:c/include-file

Conversation

@jakelishman
Copy link
Copy Markdown
Member

@jakelishman jakelishman commented Feb 22, 2026

This adds a basic qiskit.capi module for Python-space interaction with the C API. The two initial functions included are get_include and get_lib, to get the package include directory and shared-object library containing the C-API exported symbols, respectively.

Note that while the included header files are complete information to build against the C API, the file returned from get_lib is not generally useful as part of a build system, but can be used to interact with the C API live through a Python session.

I hope to follow this patch with two more:

  • provide a second "mode" for the packaged header files that allows building safe Python extension modules against the C API. This would mean that all the C API function names will be #define'd to function pointers looked up in a static table stored inside a PyCapsule that is initialised as part of _accelerate's initialisation.

  • generate a ctypes wrapper file for the C API as part of the _accelerate (pyext) build script, which would expose all of the C API functions directly to Python space, potentially allowing them to be jitted through Numba, or allowing direct tests of C API functionality (without the manually-written file currently in our test suite).

Summary

Details and comments

Close #15609.

Currently built on #15679 and a PR to setuptools-rust (PyO3/setuptools-rust#574).

@jakelishman jakelishman added this to the 2.4.0 milestone Feb 22, 2026
@jakelishman jakelishman added the Changelog: Added Add an "Added" entry in the GitHub Release changelog. label Feb 22, 2026
@jakelishman jakelishman requested a review from a team as a code owner February 22, 2026 15:16
@jakelishman jakelishman added ci: test wheels Run the wheel-build scripts as an additional CI run for this PR Changelog: Build Add a "Build System" entry in the GitHub Release changelog. labels Feb 22, 2026
@qiskit-bot
Copy link
Copy Markdown
Collaborator

One or more of the following people are relevant to this code:

Copy link
Copy Markdown
Member

@mrossinek mrossinek left a comment

Choose a reason for hiding this comment

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

At a cursory glance this all makes sense to me thus far 👍

Will give a more thorough look next week!

Copy link
Copy Markdown
Member

@mrossinek mrossinek left a comment

Choose a reason for hiding this comment

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

I just reviewed 843b4bf to isolate the changes made by this PR from the current base.

This all seems great, I'm just adding some minor suggestions/questions.


I assume this is blocked by a working solution to get merged and released into setuptools-rust?

@jakelishman
Copy link
Copy Markdown
Member Author

I assume this is blocked by a working solution to get merged and released into setuptools-rust?

Yeah, basically. It's not 100% hard blocked on that because we could release using the build dependency on my branch of setuptools-rust, or I could release a forked version to PyPI with it. But that's hugely undesirable and an absolute last resort - I'd first see if there was a hackier way I could do it manually from within our setup.py before doing something like that.

(I think there is - I could patch the build_rust command from a known version of setuptools-rust to basically vendor in my PyO3/setuptools-rust#574 PR with some extra hacky logic to search for the target directory.)

This adds a basic `qiskit.capi` module for Python-space interaction with
the C API.  The two initial functions included are `get_include` and
`get_lib`, to get the package include directory and shared-object
library containing the C-API exported symbols, respectively.

Note that while the included header files _are_ complete information to
build against the C API, the file returned from `get_lib` is not
generally useful as part of a _build_ system, but can be used to
interact with the C API live through a Python session.

I hope to follow this patch with two more:

* provide a second "mode" for the packaged header files that allows
  building safe Python extension modules against the C API.  This would
  mean that all the C API function names will be `#define`'d to function
  pointers looked up in a static table stored inside a `PyCapsule` that
  is initialised as part of `_accelerate`'s initialisation.

* generate a `ctypes` wrapper file for the C API as part of the
  `_accelerate` (`pyext`) build script, which would expose all of the C
  API functions directly to Python space, potentially allowing them to
  be jitted through Numba, or allowing direct tests of C API
  functionality (without the manually-written file currently in our test
  suite).

Co-authored-by: Max Rossmannek <max@rossmannek.de>
@jakelishman
Copy link
Copy Markdown
Member Author

I think I'll have to revisit this and put in temporary infrastructure to do a git submodule and an in-tree build-system build of setuptools-rust, or something like that, because I don't think we can depend on a full release of setuptools-rust with my patch in time.

That's ok, I think - we can work around it.

We need PyO3/setuptools-rust#574 (or something
akin to it) to handle the movement of the generated files from the build
script to the output. This is not yet ready for merge, and is highly
unlikely to be ready in time for the Qiskit 2.4.0 release (or at least
2.4.0rc1), so to avoid blocking ourselves, we vendor in a
monkey-patching reimplementation of the code temporarily.

The allowed range of `setuptools-rust` is _probably_ larger than the
hard pin, but the monkey-patch is so invasive and v1.12.0 is
sufficiently old (August 2025) that it's not worth the risk.

There are no meaningful licensing concerns since the vendored code here
was entirely written by me both here and in the `setuptools-rust` patch;
there is no cross-contamination from that repository and no code
inclusion from it.

This commit should be reverted as soon as we can swap to a safe released
version of `setuptools-rust`.
@jakelishman jakelishman removed the on hold Can not fix yet label Mar 10, 2026
@jakelishman
Copy link
Copy Markdown
Member Author

jakelishman commented Mar 10, 2026

It's unlikely that PyO3/setuptools-rust#574 will merge in time, so I've updated this PR to make a horrendous but self-contained monkeypatch to a known-good version of setuptools-rust as a temporary build system, until we can revert d3d2e54 and swap to a proper installed version of setuptools-rust.

Doing that unblocks this chain of work - if the setuptools-rust PR merges (and releases) before our 2.4.0rc1 we can swap back later, but there's no need to wait.

@Cryoris Cryoris self-assigned this Mar 10, 2026
Copy link
Copy Markdown
Collaborator

@Cryoris Cryoris left a comment

Choose a reason for hiding this comment

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

Essentially LGTM, I left some small comments below


LIB_PATH = qiskit._accelerate.__file__
LIB = ctypes.PyDLL(LIB_PATH)
LIB = ctypes.PyDLL(qiskit.capi.get_lib())
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nice - we should remember to update the guides with this

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Well not really - you basically should never be doing this. I do have to update the guide, but with how to build an actually safe C extension, and that doesn't involve qiskit.capi.get_lib() at all.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

(Using ctypes is like the one exception where it makes sense to use the _accelerate object loaded live.)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

No it isn't, at least not related to get_lib() - the guide is describing how to make a ctypes binding to you own correctly-exposed module. It's the "Build" section below that one that discusses _accelerate, where this method would be relevant, but that's the place that's wildly unsafe and needs to be completely rewritten.

@jakelishman
Copy link
Copy Markdown
Member Author

The wheel-build failures are unrelated and should be fixed by #15791.

Copy link
Copy Markdown
Member

@mrossinek mrossinek left a comment

Choose a reason for hiding this comment

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

Nice, Julien caught a lot more typos than I did 😅


Do you already want to open an issue to track the removal of the horrendous monkeypatch in setup.py once the setuptools-rust feature lands?

@jakelishman
Copy link
Copy Markdown
Member Author

Max: the "messsages" typo was only introduced after you reviewed haha.

I can open an issue after this merges, assuming it merges in this form. I'm not likely to forget, though - it's already my PR I'm waiting on, and I wrote it specifically for this purpose!

Copy link
Copy Markdown
Collaborator

@Cryoris Cryoris left a comment

Choose a reason for hiding this comment

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

LGTM thanks for the explanations, too!

@Cryoris Cryoris added this pull request to the merge queue Mar 11, 2026
Merged via the queue into Qiskit:main with commit 676863e Mar 11, 2026
27 of 30 checks passed
@github-project-automation github-project-automation bot moved this from Ready to Done in Qiskit 2.4 Mar 11, 2026
@jakelishman jakelishman deleted the c/include-file branch March 11, 2026 14:43
github-merge-queue bot pushed a commit to Qiskit/documentation that referenced this pull request Mar 16, 2026
frankharkins added a commit to Qiskit/documentation that referenced this pull request Mar 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

C API Related to the C API Changelog: Added Add an "Added" entry in the GitHub Release changelog. Changelog: Build Add a "Build System" entry in the GitHub Release changelog. ci: test wheels Run the wheel-build scripts as an additional CI run for this PR

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Bundle the C API header with Python wheels

4 participants