Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## Unreleased
### Changed
- Deprecate `py_limited_api` option to `RustExtension` in favour of always using `"auto"` to configure this from `bdist_wheel`. [#410](https://github.com/PyO3/setuptools-rust/pull/410)

## 1.8.1 (2023-10-30)
### Fixed
- Fix regression in `install_extension` crashing since 1.8.0. [#380](https://github.com/PyO3/setuptools-rust/pull/380)
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ target = "hello_world._lib" # The last part of the name (e.g. "_lib") has to ma
# but you can add a prefix to nest it inside of a Python package.
path = "Cargo.toml" # Default value, can be omitted
binding = "PyO3" # Default value, can be omitted
py-limited-api = "auto" # Default value, can be omitted
```

Each extension module should map directly into the corresponding `[lib]` table on the
Expand Down
33 changes: 25 additions & 8 deletions docs/building_wheels.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,36 @@ Because `setuptools-rust` is an extension to `setuptools`, the standard [`python
(or [`pip wheel --no-deps . --wheel-dir dist`](https://pip.pypa.io/en/stable/cli/pip_wheel/)) can be used to build distributable wheels.
These wheels can be uploaded to PyPI using standard tools such as [twine](https://github.com/pypa/twine).

`setuptools-rust` supports building for the [PEP 384](https://www.python.org/dev/peps/pep-0384/) "stable" (aka "limited") API when the `py_limited_api` option is set on the `[bdist_wheel]` section of `setup.cfg`.
If using PyO3 bindings for `RustExtension`, then the correct [`pyo3/abi3`](https://pyo3.rs/v0.14.5/features.html#abi3) sub-feature is automatically enabled.
In this way, abi3 wheels can be uploaded to make package distributors' roles easier, and package users installing from source with `pip install .` can use optimizations specific to their Python version.
A key choice to make is whether to upload [PEP 384](https://www.python.org/dev/peps/pep-0384/) "stable" (aka "limited") API wheels which support multiple Python versions in a single binary, or to build individual artifacts for each Python version. There is a longer discussion of this [in the PyO3 docs](https://pyo3.rs/latest/building_and_distribution#py_limited_apiabi3).

This chapter of the documentation explains two possible ways to build wheels for multiple Python versions below.
This chapter covers each of these options below.

## Using `cibuildwheel`
## Building for ABI3

`setuptools-rust` will automatically configure for the limited API when this is set in the `[bdist_wheel]` configuration section of [`setup.cfg`](https://setuptools.pypa.io/en/latest/deprecated/distutils/configfile.html#writing-the-setup-configuration-file):

```ini
[bdist_wheel]
py_limited_api=cp37 # replace with desired minimum Python version
```

If using a `pyproject.toml`-based build, then save the above in a file and use the `DIST_EXTRA_CONFIG` environment variable to instruct `setuptools` to pick up this extra configuration. (`DIST_EXTRA_CONFIG` is documented [on this page](https://setuptools.pypa.io/en/latest/deprecated/distutils/configfile.html#writing-the-setup-configuration-file) of the `setuptools` docs.)

It is also possible to pass this setting via the command line, e.g.

```
python -m build --config-settings=--build-option=--py-limited-api=cp37
```

## Building for multiple Python versions

### Using `cibuildwheel`

[`cibuildwheel`][cibuildwheel] is a tool to build wheels for multiple platforms using Github Actions.

The [`rtoml` package does this, for example](https://github.com/samuelcolvin/rtoml/blob/143ee0907bba616cbcd5cc58eefe9000fcc2b5f2/.github/workflows/ci.yml#L99-L195).

## Building manually
### Building manually

Place a script called `build-wheels.sh` with the following contents in your project root (next to the `setup.py` file):

Expand All @@ -27,7 +44,7 @@ Place a script called `build-wheels.sh` with the following contents in your proj

This script can be used to produce wheels for multiple Python versions.

### Binary wheels on linux
#### Binary wheels on linux

To build binary wheels on linux, you need to use the [manylinux docker container](https://github.com/pypa/manylinux). You will run the `build-wheels.sh` from above inside that container.

Expand All @@ -54,7 +71,7 @@ hello_rust-0.1.0-cp39-cp39-linux_x86_64.whl hello_rust-0.1.0-cp39-cp39

It is possible to use any of the `manylinux` docker images: `manylinux1`, `manylinux2010` or `manylinux2014`. (Just replace `manylinux2014` in the above instructions with the alternative version you wish to use.)

### Binary wheels on macOS
#### Binary wheels on macOS

For building wheels on macOS it is sufficient to use one of the default `python -m build` or `pip wheel --no-deps . --wheel-dir dist` commands.

Expand Down
1 change: 0 additions & 1 deletion examples/hello-world-setuppy/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
# in Cargo.toml and the function name in the `.rs` file,
# but you can add a prefix to nest it inside of a Python package.
path="Cargo.toml", # Default value, can be omitted
py_limited_api="auto", # Default value, can be omitted
binding=Binding.PyO3, # Default value, can be omitted
)
],
Expand Down
1 change: 0 additions & 1 deletion examples/hello-world/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ find = { where = ["python"] }
# Private Rust extension module to be nested into Python package
target = "hello_world._lib" # The last part of the name (e.g. "_lib") has to match lib.name in Cargo.toml,
# but you can add a prefix to nest it inside of a Python package.
py-limited-api = "auto" # Default value, can be omitted
binding = "PyO3" # Default value, can be omitted
# See reference for RustExtension in https://setuptools-rust.readthedocs.io/en/latest/reference.html

Expand Down
2 changes: 1 addition & 1 deletion examples/rust_with_cffi/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
packages=find_packages(where="python"),
package_dir={"": "python"},
rust_extensions=[
RustExtension("rust_with_cffi.rust", py_limited_api="auto"),
RustExtension("rust_with_cffi.rust"),
],
cffi_modules=["cffi_module.py:ffi"],
install_requires=["cffi"],
Expand Down
24 changes: 8 additions & 16 deletions setuptools_rust/extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,22 +107,7 @@ class RustExtension:
optional: If it is true, a build failure in the extension will not
abort the build process, and instead simply not install the failing
extension.
py_limited_api: Similar to ``py_limited_api`` on
``setuptools.Extension``, this controls whether the built extension
should be considered compatible with the PEP 384 "limited API".

- ``'auto'``: the ``py_limited_api`` option of
``bdist_wheel`` will control whether the extension is
built as a limited api extension. The corresponding
``pyo3/abi3-pyXY`` feature will be set accordingly.
This is the recommended setting, as it allows
to build a version-specific extension for best performance.

- ``True``: the extension is assumed to be compatible with the
limited abi. You must ensure this is the case (e.g. by setting
the ``pyo3/abi3`` feature).

- ``False``: the extension is version-specific.
py_limited_api: Deprecated.
"""

def __init__(
Expand Down Expand Up @@ -180,6 +165,13 @@ def __init__(
DeprecationWarning,
)

if self.py_limited_api != "auto":
warnings.warn(
"`RustExtension.py_limited_api` is deprecated, use [bdist_wheel] configuration "
"in `setup.cfg` or `DIST_EXTRA_CONFIG` to build abi3 wheels.",
DeprecationWarning,
)

def get_lib_name(self, *, quiet: bool) -> str:
"""Parse Cargo.toml to get the name of the shared library."""
metadata = self.metadata(quiet=quiet)
Expand Down