Maturin User Guide
Welcome to the maturin user guide! It contains examples and documentation to explain all of maturin's use cases in detail.
Please choose from the chapters on the left to jump to individual topics, or continue below to start with maturin's README.
Maturin
formerly pyo3-pack
Build and publish crates with pyo3, rust-cpython and cffi bindings as well as rust binaries as python packages.
This project is meant as a zero configuration replacement for setuptools-rust and milksnake. It supports building wheels for python 3.5+ on windows, linux, mac and freebsd, can upload them to pypi and has basic pypy support.
Check out the User Guide!
Usage
You can either download binaries from the latest release or install it with pip:
pip install maturin
There are four main commands:
maturin new
creates a new cargo project with maturin configured.maturin publish
builds the crate into python packages and publishes them to pypi.maturin build
builds the wheels and stores them in a folder (target/wheels
by default), but doesn't upload them. It's possible to upload those with twine ormaturin upload
.maturin develop
builds the crate and installs it as a python module directly in the current virtualenv. Note that whilematurin develop
is faster, it doesn't support all the feature that runningpip install
aftermaturin build
supports.
pyo3
and rust-cpython
bindings are automatically detected, for cffi or binaries you need to pass -b cffi
or -b bin
.
maturin doesn't need extra configuration files and doesn't clash with an existing setuptools-rust or milksnake configuration.
You can even integrate it with testing tools such as tox.
There are examples for the different bindings in the test-crates
folder.
The name of the package will be the name of the cargo project, i.e. the name field in the [package]
section of Cargo.toml
.
The name of the module, which you are using when importing, will be the name
value in the [lib]
section (which defaults to the name of the package). For binaries, it's simply the name of the binary generated by cargo.
Python packaging basics
Python packages come in two formats: A built form called wheel and source distributions (sdist), both of which are archives. A wheel can be compatible with any python version, interpreter (cpython and pypy, mainly), operating system and hardware architecture (for pure python wheels), can be limited to a specific platform and architecture (e.g. when using ctypes or cffi) or to a specific python interpreter and version on a specific architecture and operating system (e.g. with pyo3 and rust-cpython).
When using pip install
on a package, pip tries to find a matching wheel and install that. If it doesn't find one, it downloads the source distribution and builds a wheel for the current platform,
which requires the right compilers to be installed. Installing a wheel is much faster than installing a source distribution as building wheels is generally slow.
When you publish a package to be installable with pip install
, you upload it to pypi, the official package repository.
For testing, you can use test pypi instead, which you can use with pip install --index-url https://test.pypi.org/simple/
.
Note that for publishing for linux, you need to use the manylinux docker container, while for publishing from your repository you can use the messense/maturin-action github action.
pyo3 and rust-cpython
For pyo3 and rust-cpython, maturin can only build packages for installed python versions. On linux and mac, all python versions in PATH
are used.
If you don't set your own interpreters with -i
, a heuristic is used to search for python installations.
On windows all versions from the python launcher (which is installed by default by the python.org installer) and all conda environments except base are used. You can check which versions are picked up with the list-python
subcommand.
pyo3 will set the used python interpreter in the environment variable PYTHON_SYS_EXECUTABLE
, which can be used from custom build scripts. Maturin can build and upload wheels for pypy with pyo3, even though only pypy3.7-7.3 on linux is tested.
Cffi
Cffi wheels are compatible with all python versions including pypy. If cffi
isn't installed and python is running inside a virtualenv, maturin will install it, otherwise you have to install it yourself (pip install cffi
).
maturin uses cbindgen to generate a header file, which can be customized by configuring cbindgen through a cbindgen.toml
file inside your project root. Alternatively you can use a build script that writes a header file to $PROJECT_ROOT/target/header.h
.
Based on the header file maturin generates a module which exports an ffi
and a lib
object.
Example of a custom build script
use cbindgen; use std::env; use std::path::Path; fn main() { let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); let bindings = cbindgen::Builder::new() .with_no_includes() .with_language(cbindgen::Language::C) .with_crate(crate_dir) .generate() .unwrap(); bindings.write_to_file(Path::new("target").join("header.h")); }
Mixed rust/python projects
To create a mixed rust/python project, create a folder with your module name (i.e. lib.name
in Cargo.toml) next to your Cargo.toml and add your python sources there:
my-project
├── Cargo.toml
├── my_project
│ ├── __init__.py
│ └── bar.py
├── pyproject.toml
├── Readme.md
└── src
└── lib.rs
You can specify a different python source directory in Cargo.toml
by setting package.metadata.maturin.python-source
, for example
[package.metadata.maturin]
python-source = "python"
then the project structure would look like this:
my-project
├── Cargo.toml
├── python
│ └── my_project
│ ├── __init__.py
│ └── bar.py
├── pyproject.toml
├── Readme.md
└── src
└── lib.rs
maturin will add the native extension as a module in your python folder. When using develop, maturin will copy the native library and for cffi also the glue code to your python folder. You should add those files to your gitignore.
With cffi you can do from .my_project import lib
and then use lib.my_native_function
, with pyo3/rust-cpython you can directly from .my_project import my_native_function
.
Example layout with pyo3 after maturin develop
:
my-project
├── Cargo.toml
├── my_project
│ ├── __init__.py
│ ├── bar.py
│ └── my_project.cpython-36m-x86_64-linux-gnu.so
├── Readme.md
└── src
└── lib.rs
Python metadata
maturin supports PEP 621, you can specify python package metadata in pyproject.toml
.
maturin merges metadata from Cargo.toml
and pyproject.toml
, pyproject.toml
take precedence over Cargo.toml
.
To specify python dependencies, add a list dependencies
in a [project]
section in the pyproject.toml
. This list is equivalent to install_requires
in setuptools:
[project]
name = "my-project"
dependencies = ["flask~=1.1.0", "toml==0.10.0"]
Pip allows adding so called console scripts, which are shell commands that execute some function in you program. You can add console scripts in a section [project.scripts]
.
The keys are the script names while the values are the path to the function in the format some.module.path:class.function
, where the class
part is optional. The function is called with no arguments. Example:
[project.scripts]
get_42 = "my_project:DummyClass.get_42"
You can also specify trove classifiers in your Cargo.toml under project.classifiers
:
[project]
name = "my-project"
classifiers = ["Programming Language :: Python"]
Source distribution
maturin supports building through pyproject.toml
. To use it, create a pyproject.toml
next to your Cargo.toml
with the following content:
[build-system]
requires = ["maturin>=0.12,<0.13"]
build-backend = "maturin"
If a pyproject.toml
with a [build-system]
entry is present, maturin will build a source distribution of your package, unless --no-sdist
is specified.
The source distribution will contain the same files as cargo package
. To only build a source distribution, pass --interpreter
without any values.
You can then e.g. install your package with pip install .
. With pip install . -v
you can see the output of cargo and maturin.
You can use the options compatibility
, skip-auditwheel
, bindings
, strip
, cargo-extra-args
and rustc-extra-args
under [tool.maturin]
the same way you would when running maturin directly.
The bindings
key is required for cffi and bin projects as those can't be automatically detected. Currently, all builds are in release mode (see this thread for details).
For a non-manylinux build with cffi bindings you could use the following:
[build-system]
requires = ["maturin>=0.12,<0.13"]
build-backend = "maturin"
[tool.maturin]
bindings = "cffi"
compatibility = "linux"
manylinux
option is also accepted as an alias of compatibility
for backward compatibility with old version of maturin.
To include arbitrary files in the sdist for use during compilation specify sdist-include
as an array of globs:
[tool.maturin]
sdist-include = ["path/**/*"]
There's a maturin sdist
command for only building a source distribution as workaround for pypa/pip#6041.
Manylinux and auditwheel
For portability reasons, native python modules on linux must only dynamically link a set of very few libraries which are installed basically everywhere, hence the name manylinux. The pypa offers special docker images and a tool called auditwheel to ensure compliance with the manylinux rules. If you want to publish widely usable wheels for linux pypi, you need to use a manylinux docker image.
The Rust compiler since version 1.47 requires at least glibc 2.11, so you need to use at least manylinux2010.
For publishing, we recommend enforcing the same manylinux version as the image with the manylinux flag, e.g. use --manylinux 2014
if you are building in quay.io/pypa/manylinux2014_x86_64
.
The messense/maturin-action github action already takes care of this if you set e.g. manylinux: 2014
.
maturin contains a reimplementation of auditwheel automatically checks the generated library and gives the wheel the proper.
If your system's glibc is too new or you link other shared libraries, it will assign the linux
tag.
You can also manually disable those checks and directly use native linux target with --manylinux off
.
For full manylinux compliance you need to compile in a CentOS docker container. The pyo3/maturin image is based on the manylinux2010 image,
and passes arguments to the maturin
binary. You can use it like this:
docker run --rm -v $(pwd):/io ghcr.io/pyo3/maturin build --release # or other maturin arguments
Note that this image is very basic and only contains python, maturin and stable rust. If you need additional tools, you can run commands inside the manylinux container. See konstin/complex-manylinux-maturin-docker for a small educational example or nanoporetech/fast-ctc-decode for a real world setup.
maturin itself is manylinux compliant when compiled for the musl target.
Code
The main part is the maturin library, which is completely documented and should be well integrable. The accompanying main.rs
takes care username and password for the pypi upload and otherwise calls into the library.
The sysconfig
folder contains the output of python -m sysconfig
for different python versions and platform, which is helpful during development.
You need to install cffi
and virtualenv
(pip install cffi virtualenv
) to run the tests.
There are some optional hacks that can speed up the tests (over 80s to 17s on my machine).
- By running
cargo build --release --manifest-path test-crates/cargo-mock/Cargo.toml
you can activate a cargo cache avoiding to rebuild the pyo3 test crates with every python version. - Delete
target/test-cache
to clear the cache (e.g. after changing a test crate) or removetest-crates/cargo-mock/target/release/cargo
to deactivate it. - By running the tests with the
faster-tests
feature, binaries are stripped and wheels are only stored and not compressed.
Installation
Install from package managers
PyPI
maturin is published as Python binary wheel to PyPI, you can install it using pip:
pip install maturin
There are some extra dependencies for certain scenarios:
zig
: use zig as linker for easier cross compiling and manylinux compliance.patchelf
: repair wheels that links other shared libraries.
For example, to install patchelf dependencies: pip install maturin[patchelf]
.
Homebrew
On macOS maturin is in Homebrew and you can install maturin from Homebrew:
brew install maturin
conda
Installing from the conda-forge
channel can be achieved by adding conda-forge
to your conda channels with:
conda config --add channels conda-forge
conda config --set channel_priority strict
Once the conda-forge
channel has been enabled, maturin
can be installed with:
conda install maturin
Alpine Linux
On Alpine Linux, maturin is in community repository
and can be installed with apk
after enabling the community repository:
apk add maturin
Download from GitHub Releases
You can download precompiled maturin binaries from the latest GitHub Releases.
Build from source
crates.io
You can install maturin from crates.io using cargo:
cargo install maturin
Git repository
cargo install --git https://github.com/PyO3/maturin.git maturin
Tutorial
In this tutorial we will wrap a version of the guessing game from The Rust Book to run in Python using pyo3.
Create a new Rust project
First, create a new Rust library project using cargo new --lib --edition 2018 guessing-game
. This will create a directory with the following structure.
guessing-game/
├── Cargo.toml
└── src
└── lib.rs
Edit Cargo.toml
to configure the project and module name, and add the
dependencies (rand
and pyo3
). Configure pyo3
with additional features to
make an extension module compatible with multiple Python versions using the
stable ABI (abi3
).
[package]
name = "guessing-game"
version = "0.1.0"
edition = "2018"
[lib]
name = "guessing_game"
# "cdylib" is necessary to produce a shared library for Python to import from.
crate-type = ["cdylib"]
[dependencies]
rand = "0.8.4"
[dependencies.pyo3]
version = "0.16.1"
# "extension-module" tells pyo3 we want to build an extension module (skips linking against libpython.so)
# "abi3-py37" tells pyo3 (and maturin) to build using the stable ABI with minimum Python version 3.7
features = ["extension-module", "abi3-py37"]
Use maturin new
New projects can also be quickly created using the maturin new
command:
USAGE:
maturin new [FLAGS] [OPTIONS] <path>
FLAGS:
-h, --help Prints help information
--mixed Use mixed Rust/Python project layout
-V, --version Prints version information
OPTIONS:
-b, --bindings <bindings> Which kind of bindings to use [possible values: pyo3, rust-cpython, cffi, bin]
--name <name> Set the resulting package name, defaults to the directory name
ARGS:
<path> Project path
The above process can be achieved by running maturin new -b pyo3 guessing_game
then edit Cargo.toml
to add abi3-py37
feature.
Install and configure maturin (in a virtual environment)
Create a virtual environment and install maturin. Note maturin has minimal dependencies!
ferris@rustbox [~/src/rust/guessing-game] % python3 -m venv .venv
ferris@rustbox [~/src/rust/guessing-game] % source .venv/bin/activate
(.venv) ferris@rustbox [~/src/rust/guessing-game] % pip install -U pip maturin
(.venv) ferris@rustbox [~/src/rust/guessing-game] % pip freeze
maturin==0.12.10
tomli==2.0.1
maturin is configured in pyproject.toml
as introduced by PEP
518. This file lives in the root
of your project tree:
guessing-game/
├── Cargo.toml
├── pyproject.toml # <<< add this file
└── src
└── lib.rs
Configuration in this file is quite simple for most projects. You just need to indicate maturin as a requirement (and restrict the version) and as the build-backend (Python supports a number of build-backends since PEP 517).
[build-system]
requires = ["maturin>=0.12,<0.13"]
build-backend = "maturin"
Various other tools may also be configured in pyproject.toml
and the Python
community seems to be consolidating declarative configuration in this file.
Program the guessing game in Rust
When you create a lib
project with cargo new
it creates a file
src/lib.rs
with some default code. Edit that file and replace the default
code with the code below. As mentioned, we will implement a slightly
modified version of the guessing game from The Rust
Book.
Instead of implementing as a bin
crate, we're using a lib
and will expose
the main logic as a Python function.
#![allow(unused)] fn main() { use pyo3::prelude::*; use rand::Rng; use std::cmp::Ordering; use std::io; #[pyfunction] fn guess_the_number() { println!("Guess the number!"); let secret_number = rand::thread_rng().gen_range(1..101); loop { println!("Please input your guess."); let mut guess = String::new(); io::stdin() .read_line(&mut guess) .expect("Failed to read line"); let guess: u32 = match guess.trim().parse() { Ok(num) => num, Err(_) => continue, }; println!("You guessed: {}", guess); match guess.cmp(&secret_number) { Ordering::Less => println!("Too small!"), Ordering::Greater => println!("Too big!"), Ordering::Equal => { println!("You win!"); break; } } } } /// A Python module implemented in Rust. The name of this function must match /// the `lib.name` setting in the `Cargo.toml`, else Python will not be able to /// import the module. #[pymodule] fn guessing_game(_py: Python, m: &PyModule) -> PyResult<()> { m.add_function(wrap_pyfunction!(guess_the_number, m)?)?; Ok(()) } }
Thanks to pyo3, there's very little difference between this and the example in The Rust Book. All we had to do was:
- Include the pyo3 prelude
- Add
#[pyfunction]
to our function - Add the
#[pymodule]
block to expose the function as part of a Python module
Refer to the pyo3 User Guide for more information on using pyo3. It can do a lot more!
Build and install the module with maturin develop
Note that this is just a Rust project at this point, and with few exceptions
you can build it as you'd expect using cargo build
. maturin helps with this,
however, adding some platform-specific build configuration and ultimately
packaging the binary results as a wheel (a .whl
file, which is an archive of
compiled components suitable for installation with pip
, the Python package
manager).
So let's use maturin to build and install in our current environment.
(.venv) ferris@rustbox [~/src/rust/guessing-game] % maturin develop
🔗 Found pyo3 bindings with abi3 support for Python ≥ 3.7
🐍 Not using a specific python interpreter (With abi3, an interpreter is only required on windows)
Compiling pyo3-build-config v0.16.1
Compiling libc v0.2.119
Compiling once_cell v1.10.0
Compiling cfg-if v1.0.0
Compiling proc-macro2 v1.0.36
Compiling unicode-xid v0.2.2
Compiling syn v1.0.86
Compiling parking_lot_core v0.8.5
Compiling smallvec v1.8.0
Compiling scopeguard v1.1.0
Compiling unindent v0.1.8
Compiling ppv-lite86 v0.2.16
Compiling instant v0.1.12
Compiling lock_api v0.4.6
Compiling indoc v1.0.4
Compiling getrandom v0.2.5
Compiling rand_core v0.6.3
Compiling parking_lot v0.11.2
Compiling rand_chacha v0.3.1
Compiling rand v0.8.5
Compiling quote v1.0.15
Compiling pyo3-ffi v0.16.1
Compiling pyo3 v0.16.1
Compiling pyo3-macros-backend v0.16.1
Compiling pyo3-macros v0.16.1
Compiling guessing-game v0.1.0 (/Users/ferris/src/rust/guessing-game)
Finished dev [unoptimized + debuginfo] target(s) in 13.31s
Your guessing_game
module should now be available in your current virtual
environment. Go ahead and play a few games!
(.venv) ferris@rustbox [~/src/rust/guessing-game] % python
Python 3.9.6 (default, Aug 25 2021, 16:04:27)
[Clang 12.0.5 (clang-1205.0.22.9)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import guessing_game
>>> guessing_game.guess_the_number()
Guess the number!
Please input your guess.
42
You guessed: 42
Too small!
Please input your guess.
80
You guessed: 80
Too big!
Please input your guess.
50
You guessed: 50
Too small!
Please input your guess.
60
You guessed: 60
Too big!
Please input your guess.
55
You guessed: 55
You win!
Create a wheel for distribution
maturin develop
actually skips the wheel generation part and installs
directly in the current environment. maturin build
on the other hand will
produce a wheel you can distribute. Note the wheel contains "tags" in its
filename that correspond to supported Python versions, platforms, and/or
architectures, so yours might look a little different. If you want to
distribute broadly, you may need to build on multiple platforms and use a
manylinux
Docker container to build
wheels compatible with a wide range of Linux distros.
(.venv) ferris@rustbox [~/src/rust/guessing-game] % maturin build
🔗 Found pyo3 bindings with abi3 support for Python ≥ 3.7
🐍 Not using a specific python interpreter (With abi3, an interpreter is only required on windows)
📦 Built source distribution to /Users/ferris/src/rust/guessing-game/target/wheels/guessing_game-0.1.0.tar.gz
Finished dev [unoptimized + debuginfo] target(s) in 7.32s
📦 Built wheel for abi3 Python ≥ 3.6 to /Users/ferris/src/rust/guessing-game/target/wheels/guessing_game-0.1.0-cp37-abi3-macosx_10_7_x86_64.whl
maturin can even publish wheels directly to PyPI with
maturin publish
!
Summary
Congratulations! You successfully created a Python module implemented entirely in Rust thanks to pyo3 and maturin.
This demonstrates how easy it is to get started with maturin, but keep reading to learn more about all the additional features.
Project Layout
Maturin expects a particular project layout depending on the contents of the package.
Pure Rust project
For a pure Rust project, the structure is as expected and what you get from cargo new
:
my-rust-project/
├── Cargo.toml
├── pyproject.toml # required for maturin configuration
└── src
├── lib.rs # default for library crates
└── main.rs # default for binary crates
Maturin will add a necessary __init__.py
to the package when building the
wheel. For convenience, this file includes the following:
from .my_project import *
__doc__ = my_project.__doc__
if hasattr(my_project, "__all__"):
__all__ = my_project.__all__
such that the module functions may be called directly with:
import my_project
my_project.foo()
rather than:
from my_project import my_project
Note: there is currently no way to tell maturin to include extra data (e.g.
package_data
in setuptools) for a pure Rust project. Instead, consider using the layout described below for the mixed Rust/Python project.
Mixed Rust/Python project
To create a mixed Rust/Python project, add a directory with your package name
(i.e. matching lib.name
in your Cargo.toml
) to contain the Python source:
my-rust-and-python-project
├── Cargo.toml
├── my_project # <<< add this directory and put Python code in here
│ ├── __init__.py
│ └── bar.py
├── pyproject.toml
├── Readme.md
└── src
└── lib.rs
Note that in a mixed Rust/Python project, maturin does not modify the
existing __init__.py
in the root package, so now to import the rust module in
Python you must use:
from my_project import my_project
You can modify __init__.py
yourself (see above) if you would like to import
functions Rust functions from a higher-level namespace.
Alternate Python source directory (src layout)
Having a directory with package_name
in the root of the project can
occasionally cause confusion as Python allows importing local packages and
modules. A popular way to avoid this is with the src
-layout, where the Python
package is nested within a src
directory. Unfortunately this interferes with
the structure of a typical Rust project. Fortunately, Python is nor particular
about the name of the parent source directory. You tell maturin to use a
different Python source directory in Cargo.toml
by setting
package.metadata.maturin.python-source
. For example:
[package.metadata.maturin]
python-source = "python"
then the project structure would look like this:
my-rust-and-python-project
├── Cargo.toml
├── python
│ └── my_project
│ ├── __init__.py
│ └── bar.py
├── pyproject.toml
├── README.md
└── src
└── lib.rs
Adding Python type information
To distribute typing information, you need to add:
- an empty marker file called
py.typed
in the root of the Python package - inline types in Python files and/or
.pyi
"stub" files
In a pure Rust project, add type stubs in a <module_name>.pyi
file in the
project root. Maturin will automatically include this file along with the
required py.typed
file for you.
my-rust-project/
├── Cargo.toml
├── my_project.pyi # <<< add type stubs for Rust functions in the my_project module here
├── pyproject.toml
└── src
└── lib.rs
In a mixed Rust/Python project, additional files in the Python source dir (but
not in .gitignore
) will be automatically included in the build outputs
(source distribution and/or wheel). Type information can be therefore added to
the root Python package directory as you might do in a pure Python package.
This requires you to add the py.typed
marker file yourself.
my-project
├── Cargo.toml
├── python
│ └── my_project
│ ├── __init__.py
│ ├── py.typed # <<< add this empty file
│ ├── my_project.pyi # <<< add type stubs for Rust functions in the my_project module here
│ ├── bar.pyi # <<< add type stubs for bar.py here OR type bar.py inline
│ └── bar.py
├── pyproject.toml
├── README.md
└── src
└── lib.rs
Data
You can add wheel data by creating a <module_name>.data
folder or setting its location as data
in pyproject.toml under [tool.maturin]
or in Cargo.toml under [project.metadata.maturin]
.
The data folder may have the following subfolder:
data
: The contents of this folder will simply be unpacked into the virtualenvscripts
: Treated similar to entry points, files in there are installed as standalone executableheaders
: For.h
C header filespurelib
: This also exists, but seems to be barely usedplatlib
: This also exists, but seems to be barely used
If you add a symlink in the data directory, we'll include the actual file so you more flexibility
Bindings
Maturin supports several kinds of bindings, some of which are automatically
detected. You can also pass -b
/ --bindings
command line option to manually
specify which bindings to use.
pyo3
pyo3 is Rust bindings for Python, including tools for creating native Python extension modules. It supports both CPython and PyPy.
maturin automatically detects pyo3 bindings when it's added as a dependency in Cargo.toml
.
Py_LIMITED_API
/abi3
pyo3 bindings has Py_LIMITED_API
/abi3 support, enable the abi3
feature of the pyo3
crate to use it:
pyo3 = { version = "0.14", features = ["abi3"] }
You may additionally specify a minimum Python version by using the abi3-pyXX
format for the pyo3 features, where XX
is corresponds to a Python version.
For example abi3-py37
will indicate a minimum Python version of 3.7.
Note: Read more about abi3 support in pyo3's documentation.
Cross Compiling
pyo3 bindings has decent cross compilation support. For manylinux support the manylinux-cross docker images can be used.
Note: Read more about cross compiling in pyo3's documentation.
cffi
Cffi wheels are compatible with all python versions including pypy. If cffi
isn't installed and python is running inside a virtualenv, maturin will install
it, otherwise you have to install it yourself (pip install cffi
).
Maturin uses cbindgen to generate a header file for supported Rust
types.
The header file can be customized by configuring cbindgen through a
cbindgen.toml
file inside your project root. Aternatively you can use a build
script that writes a header file to $PROJECT_ROOT/target/header.h
, like so:
use cbindgen; use std::env; use std::path::Path; fn main() { let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); let bindings = cbindgen::Builder::new() .with_no_includes() .with_language(cbindgen::Language::C) .with_crate(crate_dir) .generate() .unwrap(); bindings.write_to_file(Path::new("target").join("header.h")); }
Maturin uses the cbindgen-generated header to create a module that exposes ffi
and
lib
objects as attributes. See the cffi docs
for more information on using these ffi
/lib
objects to call the Rust code
from Python.
Note: Maturin does not automatically detect
cffi
bindings. You must specify them via either command line with-b cffi
or inpyproject.toml
.
rust-cpython
rust-cpython is Rust bindings for the Python interpreter. Currently it only supports CPython.
Maturin automatically detects rust-cpython bindings when it's added as a
dependency in Cargo.toml
.
bin
Maturin also supports distributing binary applications written in Rust as
Python packages using the bin
bindings. Binaries are packaged into the wheel
as "scripts" and are available on the user's PATH
(e.g. in the bin
directory of a virtual environment) once installed.
Note: Maturin does not automatically detect
bin
bindings. You must specify them via either command line with-b bin
or inpyproject.toml
.
Python Project Metadata
maturin supports PEP 621,
you can specify python package metadata in pyproject.toml
.
maturin merges metadata from Cargo.toml
and pyproject.toml
, pyproject.toml
take precedence over Cargo.toml
.
Here is a pyproject.toml
example from PEP 621 for reference purpose:
[project]
name = "spam"
version = "2020.0.0"
description = "Lovely Spam! Wonderful Spam!"
readme = "README.rst"
requires-python = ">=3.8"
license = {file = "LICENSE.txt"}
keywords = ["egg", "bacon", "sausage", "tomatoes", "Lobster Thermidor"]
authors = [
{email = "hi@pradyunsg.me"},
{name = "Tzu-Ping Chung"}
]
maintainers = [
{name = "Brett Cannon", email = "brett@python.org"}
]
classifiers = [
"Development Status :: 4 - Beta",
"Programming Language :: Python"
]
dependencies = [
"httpx",
"gidgethub[httpx]>4.0.0",
"django>2.1; os_name != 'nt'",
"django>2.0; os_name == 'nt'"
]
[project.optional-dependencies]
test = [
"pytest < 5.0.0",
"pytest-cov[all]"
]
[project.urls]
homepage = "example.com"
documentation = "readthedocs.org"
repository = "github.com"
changelog = "github.com/me/spam/blob/master/CHANGELOG.md"
[project.scripts]
spam-cli = "spam:main_cli"
[project.gui-scripts]
spam-gui = "spam:main_gui"
[project.entry-points."spam.magical"]
tomatoes = "spam:main_tomatoes"
Add Python dependencies
To specify python dependencies, add a list dependencies
in a [project]
section in the pyproject.toml
. This list is equivalent to install_requires
in setuptools:
[project]
name = "my-project"
dependencies = ["flask~=1.1.0", "toml==0.10.0"]
Add console scripts
Pip allows adding so called console scripts, which are shell commands that execute some function in you program. You can add console scripts in a section [project.scripts]
.
The keys are the script names while the values are the path to the function in the format some.module.path:class.function
, where the class
part is optional. The function is called with no arguments. Example:
[project.scripts]
get_42 = "my_project:DummyClass.get_42"
Add trove classifiers
You can also specify trove classifiers under project.classifiers
:
[project]
name = "my-project"
classifiers = ["Programming Language :: Python"]
Add SPDX license expressions
A practical string value for the license key has been purposefully left out by PEP 621 to allow for a future PEP to specify support for SPDX expressions.
To use SPDX license expressions, you can specify it in Cargo.toml
instead:
[package]
name = "my-project"
license = "MIT OR Apache-2.0"
Add maturin build
options
Some of the maturin build
command line options can also be specified
in the tool.maturin
section of pyproject.toml
.
[tool.maturin]
# Cargo manifest path
manifest-path = "Cargo.toml"
# Include arbitrary files in the sdist
sdist-include = []
# Bindings type
bindings = "pyo3"
# Control the platform tag on linux
compatibility = "manylinux2014"
# Don't check for manylinux compliance
skip-auditwheel = false
# Strip the library for minimum file size
strip = true
# Extra arguments that will be passed to cargo as `cargo rustc [...] [arg1] [arg2] -- [...]`
cargo-extra-args = ""
# Extra arguments that will be passed to rustc as `cargo rustc [...] -- [...] [arg1] [arg2]`
rustc-extra-args = ""
Local Development
maturin develop
command
For local development, the maturin develop
command can be used to quickly
build a package in debug mode by default and install it to virtualenv.
USAGE:
maturin develop [OPTIONS]
OPTIONS:
-b, --bindings <BINDINGS>
Which kind of bindings to use. Possible values are pyo3, rust-cpython, cffi and bin
--cargo-extra-args <CARGO_EXTRA_ARGS>
Extra arguments that will be passed to cargo as `cargo rustc [...] [arg1] [arg2] --`
Use as `--cargo-extra-args="--my-arg"`
-E, --extras <EXTRAS>
Install extra requires aka. optional dependencies
Use as `--extras=extra1,extra2`
-h, --help
Print help information
-m, --manifest-path <MANIFEST_PATH>
The path to the Cargo.toml
[default: Cargo.toml]
--release
Pass --release to cargo
--rustc-extra-args <RUSTC_EXTRA_ARGS>
Extra arguments that will be passed to rustc as `cargo rustc [...] -- [arg1] [arg2]`
Use as `--rustc-extra-args="--my-arg"`
--strip
Strip the library for minimum file size
PEP 660 Editable Installs
Maturin supports PEP 660 editable installs since v0.12.0.
You need to add maturin
to build-system
section of pyproject.toml
to use it:
[build-system]
requires = ["maturin>=0.12,<0.13"]
build-backend = "maturin"
Editable installs right now is only useful in mixed Rust/Python project so you don't have to recompile and reinstall when only Python source code changes. For example when using pip you can make an editable installation with
pip install -e .
Then Python source code changes will take effect immediately.
Import Hook
Starting from v0.12.4, the Python maturin package provides a Python import hook to allow quickly build and load a Rust module into Python.
It supports pure Rust and mixed Rust/Python project layout as well as a
standalone .rs
file.
from maturin import import_hook
# install the import hook with default settings
import_hook.install()
# or you can specify bindings
import_hook.install(bindings="pyo3")
# and build in release mode instead of the default debug mode
import_hook.install(release=True)
# now you can start importing your Rust module
import pyo3_pure
Distribution
Source Distribution
Maturin supports building through pyproject.toml
. To use it, create a pyproject.toml
next to your Cargo.toml
with the following content:
[build-system]
requires = ["maturin>=0.12,<0.13"]
build-backend = "maturin"
If a pyproject.toml
with a [build-system]
entry is present, maturin will build a source distribution of your package, unless --no-sdist
is specified.
The source distribution will contain the same files as cargo package
. To only build a source distribution, use the maturin sdist
command.
You can then e.g. install your package with pip install .
. With pip install . -v
you can see the output of cargo and maturin.
You can use the options compatibility
, skip-auditwheel
, bindings
, strip
, cargo-extra-args
and rustc-extra-args
under [tool.maturin]
the same way you would when running maturin directly.
The bindings
key is required for cffi and bin projects as those can't be automatically detected. Currently, all builds are in release mode (see this thread for details).
For a non-manylinux build with cffi bindings you could use the following:
[build-system]
requires = ["maturin>=0.12,<0.13"]
build-backend = "maturin"
[tool.maturin]
bindings = "cffi"
compatibility = "linux"
manylinux
option is also accepted as an alias of compatibility
for backward compatibility with old version of maturin.
To include arbitrary files in the sdist for use during compilation specify sdist-include
as an array of globs:
[tool.maturin]
sdist-include = ["path/**/*"]
Build Wheels
For portability reasons, native python modules on linux must only dynamically link a set of very few libraries which are installed basically everywhere, hence the name manylinux. The pypa offers special docker images and a tool called auditwheel to ensure compliance with the manylinux rules. If you want to publish widely usable wheels for linux pypi, you need to use a manylinux docker image or build with zig.
The Rust compiler since version 1.47 requires at least glibc 2.11, so you need to use at least manylinux2010.
For publishing, we recommend enforcing the same manylinux version as the image with the manylinux flag, e.g. use --manylinux 2014
if you are building in quay.io/pypa/manylinux2014_x86_64
.
The messense/maturin-action github action already takes care of this if you set e.g. manylinux: 2014
.
maturin contains a reimplementation of auditwheel automatically checks the generated library and gives the wheel the proper platform tag.
- If your system's glibc is too new, it will assign the
linux
tag. - If you link other shared libraries, maturin will try to bundle them within the wheel, note that this requires patchelf,
it can be installed along with maturin from PyPI:
pip install maturin[patchelf]
.
You can also manually disable those checks and directly use native linux target with --manylinux off
.
For full manylinux compliance you need to compile in a CentOS docker container. The pyo3/maturin image is based on the manylinux2010 image,
and passes arguments to the maturin
binary. You can use it like this:
docker run --rm -v $(pwd):/io ghcr.io/pyo3/maturin build --release # or other maturin arguments
Note that this image is very basic and only contains python, maturin and stable Rust. If you need additional tools, you can run commands inside the manylinux container. See konstin/complex-manylinux-maturin-docker for a small educational example or nanoporetech/fast-ctc-decode for a real world setup.
USAGE:
maturin build [OPTIONS]
OPTIONS:
-b, --bindings <BINDINGS>
Which kind of bindings to use. Possible values are pyo3, rust-cpython, cffi and bin
--cargo-extra-args <CARGO_EXTRA_ARGS>
Extra arguments that will be passed to cargo as `cargo rustc [...] [arg1] [arg2] --
[...]`
Use as `--cargo-extra-args="--my-arg"`
Note that maturin invokes cargo twice: Once as `cargo metadata` and then as `cargo
rustc`. maturin tries to pass only the shared subset of options to cargo metadata, but
this is may be a bit flaky.
--compatibility <compatibility>
Control the platform tag on linux.
Options are `manylinux` tags (for example `manylinux2014`/`manylinux_2_24`) or
`musllinux` tags (for example `musllinux_1_2`) and `linux` for the native linux tag.
Note that `manylinux1` is unsupported by the rust compiler. Wheels with the native
`linux` tag will be rejected by pypi, unless they are separately validated by
`auditwheel`.
The default is the lowest compatible `manylinux` tag, or plain `linux` if nothing
matched
This option is ignored on all non-linux platforms
-h, --help
Print help information
-i, --interpreter <INTERPRETER>
The python versions to build wheels for, given as the names of the interpreters. Uses
autodiscovery if not explicitly set
-m, --manifest-path <PATH>
The path to the Cargo.toml
--no-sdist
Don't build a source distribution
-o, --out <OUT>
The directory to store the built wheels in. Defaults to a new "wheels" directory in the
project's target directory
--release
Pass --release to cargo
--rustc-extra-args <RUSTC_EXTRA_ARGS>
Extra arguments that will be passed to rustc as `cargo rustc [...] -- [...] [arg1]
[arg2]`
Use as `--rustc-extra-args="--my-arg"`
--skip-auditwheel
Don't check for manylinux compliance
--strip
Strip the library for minimum file size
--target <TRIPLE>
The --target option for cargo
[env: CARGO_BUILD_TARGET=]
--universal2
Control whether to build universal2 wheel for macOS or not. Only applies to macOS
targets, do nothing otherwise
--zig
For manylinux targets, use zig to ensure compliance for the chosen manylinux version
Default to manylinux2010/manylinux_2_12 if you do not specify an `--compatibility`
Make sure you installed zig with `pip install maturin[zig]`
Cross Compiling
Maturin has decent cross compilation support for pyo3
and bin
bindings,
other kind of bindings may work but aren't tested regularly.
Use Docker
For manylinux support the manylinux-cross docker images can be used. And maturin-action makes it easy to do cross compilation on GitHub Actions.
Use Zig
Since v0.12.7 maturin added support for linking with zig cc
,
compile for Linux works and is regularly tested on CI, other platforms may also work but aren't tested regularly.
You can install zig following the official documentation, or install it from PyPI via pip install ziglang
.
Then pass --zig
to maturin build
or publish
commands to use it, for example
maturin build --release --target aarch64-unknown-linux-gnu --zig
Sphinx Documentation Integration
Sphinx is a popular documentation generator in Python community. It's commonly used together with services like Read The Docs which automates documentation building, versioning, and hosting for you.
Usually in a pure Python project setting up Sphinx is easy, just follow the quick start of Sphinx documentation is enough. But it can get complicated when Rust based Python extension modules are involved.
With maturin, first you need to make sure you have added a pyproject.toml
and
properly configured it to build source distributions, for example a minimal configuration below:
[build-system]
requires = ["maturin>=0.12,<0.13"]
build-backend = "maturin"
With this pip install .
should work when invoked in the project directory.
Read The Docs Integration
To build documentation on Read The Docs, you need
to tell it to install the Rust compiler and Python interpreter in its build environment,
you can do it by adding a .readthedocs.yaml
in your project root:
# https://docs.readthedocs.io/en/stable/config-file/v2.html#supported-settings
version: 2
sphinx:
builder: html
build:
os: "ubuntu-20.04"
tools:
python: "3.9"
rust: "1.55"
python:
install:
- method: pip
path: .
If you're using a mixed Rust/Python project layout, make sure you didn't add the
Python project path to sys.path
in conf.py
of Sphinx. Read The Docs
doesn't install your project in editable mode, adding it to sys.path
will make
your project fail to import which breaks documentation generation.
If you need to install a specific version of Sphinx or adding Sphinx
themes/extensions, you can change the python.install
section a bit to add an
extra installation step, for example:
python:
install:
- requirements: docs/requirements.txt
- method: pip
path: .
In docs/requirements.txt
you can add some Python package requirements you
needs build the documentation.
Netlify Integration
Netlify is another popular automated site hosting service that can be used with Sphinx and other documentation tools.
Netlify configuration can be specified in a .netlify.toml
file. Assuming your
Sphinx documentation files are placed in docs/
directory, a minimal
configurationfor maturin based project can be:
[build]
base = "docs"
publish = "_build/html"
command = "maturin develop -m ../Cargo.toml && make html"
You also need to add a rust-toolchain
file at docs/rust-toolchain
which netlify
will use to install the specified Rust toolchain that maturin needs to compile
your project.
For Sphinx which is written in Python to run you need to add a runtime.txt
at
docs/runtime.txt
, its content should be a Python interpreter version for
example 3.8
. Then a requirements.txt
file at docs/requirements.txt
is
needed to install Sphinx and its dependencies, you can generate one by:
python3 -m venv venv
source venv/bin/activate
python3 -m pip install sphinx
python3 -m pip freeze > docs/requirements.txt
Contributing
Contributions are welcome, and they are greatly appreciated!
You can contribute in many ways:
Types of Contributions
Report Bugs
Report bugs at https://github.com/PyO3/maturin/issues.
Fix Bugs
Look through the GitHub issues for bugs. Anything tagged with bug
and help wanted
is open to whoever wants to implement it.
Implement Features
Look through the GitHub issues for features.
Write Documentation
Maturin could always use more documentation, whether as part of the official guide, in docstrings or even on the web in blog posts, articles and such.
Submit Feedback
The best way to send feedback is to start a new discussion at https://github.com/PyO3/maturin/discussions.
Get Started!
Ready to contribute? Here's how to setup maturin for local development.
- Fork the maturin repository on GitHub.
- Clone your fork locally:
$ git clone git@github.com:your_name_here/maturin.git
- Install a stable Rust toolchain and of course Python 3.6 or later is also required.
- Create a branch for local development:
Now you can make your changes locally.$ cd maturin $ git checkout -b branch-name
- When you're done making changes, format your changes with
cargo fmt
, then lint withcargo clippy
and test them withcargo test
:
Note that in order to run tests you need to install$ cargo fmt $ cargo clippy $ cargo test
virtualenv
andcffi
(pip3 install cffi virtualenv
). - Commit your changes and push your branch to GitHub:
$ git add . $ git Commit $ git push origin branch-name
- Submit a pull request through the GitHub website.
Pull Request Guidelines
Before you submit a pull request, check that it meets these guidelines:
- The pull request should include tests if it adds or changes functionalities.
- Add a changelog entry.
- When command line interface changes, run
python3 test-crates/update_readme.py
to update related documentation.
Platform Support
Being built on cargo and rustc, maturin is limited by rust's platform support.
Automated tests
On GitHub actions, windows, macOS and linux are tested, all on 64-bit x86. FreeBSD is also tested though Cirrus CI, but might get removed at some point. Since CI is very time intensive to maintain, I'd like to stick to GitHub action and these three platforms.
Releases
The following targets are built into wheels and downloadable binaries:
- windows: 32-bit and 64-bit x86
- linux 32-bit and 64-bit x86 as well as armv7 and aarch64 (musl)
- macOS: 64-bit and aarch64
Other Operating Systems
It should be possible to build maturin and for maturin to build wheels on other platforms supported by rust.
To add a new os, add it in target.rs and, if it doesn't behave like the other unixes, in
PythonInterpreter::get_tag
. Please also submit the output of python -m sysconfig
as a file in the sysconfig
folder.
It's ok to edit setup.py to deactivate default features so pip install
works, but new platforms should not
require complex workaround in compile.rs
.
Architectures
All architectures included in manylinux (aarch64, armv7l, ppc64le, ppc64, i686, x86_64, s390x) are supported. I'm not sure whether it makes sense to allow architectures that aren't even supported by manylinux.
Python Support
CPython 3.7 to 3.10 are supported and tested on CI, though the entire 3.x series should work. This will be changed as new python versions are released and others have their end of life.
PyPy 3.6 and later also works.
Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning (for the cli, not for the crate).
Unreleased
- Add Linux armv7l python sysconfig in #901
- Add NetBSD python sysconfig in #903
- Update 'replace_needed' to reduce total calls to 'patchelf' in #905
- Add wheel data support in #906
- Allow use python interpreters from bundled sysconfig when not cross compiling in #907
- Use setuptools-rust for bootstrapping in #909
- Allow setting the publish repository URL via
MATURIN_REPOSITORY_URL
in #913 - Allow stubs-only mixed project layout in #914
- Allow setting the publish user name via
MATURIN_USERNAME
in #915 - Add Windows python sysconfig in #917
0.12.15 - 2022-05-07
- Re-export
__all__
for pure Rust projects in #886 - Stop setting
RUSTFLAGS
environment variable to an empty string in #887 - Add hardcoded well-known sysconfigs for effortless cross compiling in #896
- Add support for
PYO3_CONFIG_FILE
in #899
0.12.14 - 2022-04-25
- Fix PyPy pep517 build when abi3 feature is enabled in #883
0.12.13 - 2022-04-25
- Stop setting
PYO3_NO_PYTHON
environment variable for pyo3 0.16.4 and later in #875 - Build Windows abi3 wheels for
pyo3
0.16.4 and later versions withgenerate-abi3-import-lib
feature enabled no longer require a Python interpreter in #879
0.12.12 - 2022-04-07
- Migrate docker image to GitHub container registry in #845
- Change mixed rust/python template project layout for new projects in #855
- Automatically include license files in
.dist-info/license_files
following PEP 639 in #862 - Bring back multiple values support for
--interpreter
option in #873 - Update the default edition to 2021 for new projects by sa- in #874
- Drop
python3.6
fromghcr.io/pyo3/maturin
docker image.
0.12.11 - 2022-03-15
- Package license files in
.dist-info/license_files
following PEP 639 in #837 - Stop testing Python 3.6 on CI since it's already EOL in #840
- Update workspace members for sdist local dependencies in #844
- Migrate docker image to github container registry in #845
- Remove
PYO3_NO_PYTHON
hack for Windows in #848 - Remove Windows abi3 python lib link hack in #851
- Add
-r
option as a short alias for--release
in #854
0.12.10 - 2022-03-09
- Add support for
pyo3-ffi
by ijl in #804 - Defaults to
musllinux_1_2
for musl target if it's not bin bindings in #808 - Remove support for building only sdist via
maturin build -i
in #813, usematurin sdist
instead. - Add macOS target support for
--zig
in #817 - Migrate Python dependency
toml
totomllib
/tomli
by Contextualist in #821 - Disable auditwheel for PEP 517 build wheel process in #823
- Lookup existing cffi
header.h
in workspace target directory in #833 - Fix license line ending in wheel metadata for Windows in #836
0.12.9 - 2022-02-09
- Don't require
pyproject.toml
when cargo manifest is not specified in #806
0.12.8 - 2022-02-08
- Add missing
--version
flag from clap 3.0 upgrade
0.12.7 - 2022-02-08
- Add support for using
zig cc
as linker for easier cross compiling and manylinux compliance in #756 - Switch from reqwest to ureq to reduce dependencies in #767
- Fix missing Python submodule in wheel in #772
- Add support for specifying cargo manifest path in pyproject.toml in #781
- Add support for passing arguments to pep517 command via
MATURIN_PEP517_ARGS
env var in #786 - Fix auditwheel
No such file or directory
error whenLD_LIBRARY_PATH
contains non-existent paths in #794
0.12.6 - 2021-12-31
- Add support for repairing cross compiled linux wheels in #754
- Add support for
manylinux_2_28
andmanylinux_2_31
in #755 - Remove existing so file first in
maturin develop
command to avoid triggering SIGSEV in running process in #760
0.12.5 - 2021-12-20
- Fix docs for
new
andinit
commands inmaturin --help
in #734 - Add support for x86_64 Haiku in #735
- Fix undefined auditwheel policy panic in #740
- Fix sdist upload for packages where the pkgname contains multiple underscores in #741
- Implement auditwheel repair with patchelf in #742
- Add
Cargo.lock
to sdist when--locked
or--frozen
specified in #749 - Infer readme file if not specified in #751
0.12.4 - 2021-12-06
- Add a
maturin init
command as a companion tomaturin new
in #719 - Don't package non-path-dep crates in sdist for workspaces in #720
- Build release packages with
password-storage
feature in #725 - Add support for x86_64 DargonFly BSD in #727
- Add a Python import hook in #729
- Allow pip warnings in
maturin develop
command in #732
0.12.3 - 2021-11-29
- Use platform tag from
sysconfig.platform
on non-portable Linux in #709 - Consider current machine architecture when generating platform tags for abi3 wheels on linux in #709
- Revert back to Rust 2018 edition in #710
- Warn missing
cffi
package dependency in #711 - Add support for Illumos in #712
- Account for
MACOSX_DEPLOYMENT_TARGET
env var in wheel platform tag in #716
0.12.2 - 2021-11-26
- Add support for excluding files from wheels by
.gitignore
in #695 - Fix
pip install maturin
on OpenBSD 6.8 in #697 - Add support for x86, x86_64 and aarch64 on NetBSD in #704
- Add a
maturin new
command for bootstrapping new projects in #705
0.12.1 - 2021-11-21
- Add support for cross compiling PyPy wheels in #687
- Fix
sysconfig.get_platform
parsing for macOS in #690
0.12.0 - 2021-11-19
- Add support for PEP 660 editable installs in #648
- Publish musllinux_1_1 wheels for maturin in #651
- Refactor
develop
command to act identical to PEP 660 editable wheels in #653 - Upgrade to Rust 2021 edition in #655
- Add support for powerpc64 and powerpc64le on FreeBSD by pkubaj in #656
- Fix false positive missing pyinit warning on arm64 macOS in #673
- Build without rustls on arm64 Windows by nsait-linaro in #674
- Publish Windows arm64 wheels to PyPI by nsait-linaro in #675
- Add support for building on Windows mingw platforms in #677
- Allow building for non-abi3 pypy wheels when the abi3 feature is enabled in #678
- Add support for cross compiling to different operating systems in #680
0.11.5 - 2021-10-13
- Fixed module documentation missing bug of pyo3 bindings in #639
- Fix musllinux auditwheel wrongly detects libc forbidden link in #643
- Fix finding conda Python interpreters on Windows by RobertColton in #644
- Fix Unicode metadata when uploading to PyPI in #645
- Fix incorrectly folded long
Summary
metadata - Fix cross compilation for Python 3.10 in #646
0.11.4 - 2021-09-28
- Autodetect PyPy executables in #617
- auditwheel: add
libz.so.1
to whitelisted libraries in #625 - auditwheel: detect musl libc in #629
- Fixed Python 3.10 and later versions detection on Windows in #630
- Install entrypoint scripts in
maturin develop
command in #633 and #634 - Add support for installing optional dependencies in
maturin develop
command in #635 - Fixed build error when
manylinux
/compatibility
options is specified inpyproject.toml
in #637
0.11.3 - 2021-08-25
- Add path option for Python source in #584
- Add auditwheel support for musllinux in #597
[tool.maturin]
options frompyproject.toml
will be used automatically in #605- Skip unavailable Python interpreters from pyenv in #609
0.11.2 - 2021-07-20
- Use UTF-8 encoding when reading
pyproject.toml
by domdfcoding in #588 - Use Cargo's
repository
field asSource Code
in project URL in #590 - Fold long header fields in Python metadata in #594
- Fix
maturin develop
for PyPy on Unix in #596
0.11.1 - 2021-07-10
- Fix sdist error when VCS has uncommitted renamed files in #585
- Add
maturin completions <shell>
command to generate shell completions in #586
0.11.0 - 2021-07-04
- Add support for reading metadata from PEP 621 project table in
pyproject.toml
in #555 - Users should migrate away from the old
[package.metadata.maturin]
table ofCargo.toml
to this new[project]
table ofpyproject.toml
- Add PEP 656 musllinux support in #543
--manylinux
is now called--compatibility
and supports musllinux- The pure rust install layout changed from just the shared library to a python module that reexports the shared library. This should have now observable consequences for users of the created wheel expect that
my_project.my_project
is now also importable (and equal to justmy_project
) - Add support for packaging type stubs in pure Rust project layout in #567
- Support i386 on OpenBSD in #568
- Support Aarch64 on OpenBSD in #570
- Support Aarch64 on FreeBSD in #571
Cargo.toml
'sauthors
field is now optional per Rust RFC 3052 in #573- Allow dotted keys in
Cargo.toml
by switch fromtoml_edit
totoml
crate in #577 - Fix source distribution with local path dependencies on Windows in #580
0.10.6 - 2021-05-21
- Fix corrupted macOS binary release in #547
- Fix build with the "upload" feature disabled by ravenexp in #548
0.10.5 - 2021-05-21
- Add
manylinux_2_27
support in #521 - Add support for Windows arm64 target in #524
- Always output PEP 600 platform tags in #525
- Fix missing
PyInit_<module_name>
warning with Rust submodule in #528 - Better cross compiling support for PyO3 binding on Unix in #454
- Fix s390x architecture support in #530
- Fix auditwheel panic with s390x wheels in #532
- Support uploading heterogeneous wheels by ravenexp in #544
- Warn about
pyproject.toml
missing maturin version constraint in #545
0.10.4 - 2021-04-28
- Interpreter search now uses python 3.6 to 3.12 in #495
- Consider requires-python when searching for interpreters in #495
- Support Rust extension as a submodule in mixed Python/Rust projects in #489
0.10.3 - 2021-04-13
- The
upload
command is now implemented, it is mostly similar totwine upload
. #484 - Interpreter search now uses python 3.6 to 3.12
- Add basic support for OpenBSD in #496
- Fix the PowerPC platform by messense in #503
0.10.2 - 2021-04-03
- Fix
--target
being silently ignored
0.10.1 - 2021-04-03
- Fix a regression in 0.10.0 that would incorrectly assume we're building for musl instead of gnu by messense in #487
- Basic s390x support
0.10.0 - 2021-04-02
- Change manylinux default version based on target arch by messense in #424
- Support local path dependencies in source distribution (i.e. you can now package a workspace into an sdist)
- Set a more reasonable LC_ID_DYLIB entry on macOS by messense #433
- Add
--skip-existing
option to publish by messense #444 - maturn develop install dependencies automatically by messense #443
- Load credential from pypirc using repository name instead of package name by messense #445
- Add
manylinux_2_24
support in #451 - Improve error message when auditwheel failed to find versioned offending symbols in #452
- Add auditwheel test to CI in #455
- Fix sdist transitive path dependencies.
- auditwheel choose higher priority tag when possible in #456, dropped
auditwheel
Cargo feature. - develop now writes an INSTALLER file
- develop removes an old .dist-info directory if it exists before installing the new one
- Fix wheels for PyPy on windows containing extension modules with incorrect names. #482
0.9.4 - 2021-02-18
- Fix building a bin with musl
0.9.3
- CI failure
0.9.2 - 2021-02-17
- Escape version in wheel metadata by messense in #420
- Set executable bit on shared library by messense in #421
- Rename
classifier
toclassifiers
for pypi compatibility. The oldclassifier
is still available and now also works with pypi - Fix building for musl by automatically setting
-C target-feature=-crt-static
0.9.1 - 2021-01-13
- Error when the
abi3
feature is selected but no minimum version - Support building universal2 wheels (x86 and aarch64 in a single file) by messense in #403
- Recognize
PYO3_CROSS_LIB_DIR
for cross compiling with abi3 targeting windows. package.metadata.maturin.classifier
is renamed toclassifiers
by kngwyu in #416- Added more instructions to building complex manylinux setups
0.9.0 - 2021-01-10
- Added support for building abi3 wheels with pyo3 0.13.1
- Python 3.9 is supported (it should have worked before, but it is now tested on ci)
- There are 64-bit and aarch64 binary builds for linux and 64-bit builds for windows, mac and freebsd-12-1
- The auditwheel options have changed to
--manylinux=[off|2010|2014]
with manylinux2010 as default, and optionally--skip-auditwheel
. - Removed Python 3.5 since it is unsupported
- The default and minimum manylinux version is now manylinux2010
- restructured text (rst) readmes are now supported, by clbarnes in #360
- Allow python 3 interpreter with debuginfo use maturin by inevity in #370
- pypirc is checked for credentials by houqp in #374
- Added support for PowerPC by mzpqnxow and programmerjake in #366
project-url
is now a toml dictionary instead of a toml list to conform to the standard- No more retry loop when the password was wrong
- When bootstrapping, also search for
cargo.exe
ifcargo
was not found
0.8.3 - 2020-08-17
Added
- tox is now supported due to a bugfix in the latest version of tox
[tool.maturin]
now supportssdist-include = ["path/**/*"]
to include arbitrary files in source distributions (#296).- Add support for PyO3
0.12
'sPYO3_PYTHON
environment variable. #331
Fixed
- Fix incorrectly returning full path (not basename) from PEP 517
build_sdist
hook. This fixes tox support from maturin's side - Packages installed with
maturin develop
are now visible to pip and can be uninstalled with pip
0.8.2 - 2020-06-29
Added
- Python 3.8 was added to PATH in the docker image by oconnor663 in #302
0.8.1 - 2020-04-30
Added
- cffi is installed if it's missing and python is running inside a virtualenv.
0.8.0 - 2020-04-03
Added
- There is now a binary wheel for aarch64
- Warn if there are local dependencies
Fixed
- Omit author_email if
@
is not found in authors by evandrocoan in #290
0.7.9 - 2020-03-06
Fixed
- This release includes binary wheels for mac os
0.7.8 - 2020-03-06
Added
- Added support from arm, specifically arm7l, aarch64 by ijl in #273
- Added support for manylinux2014 by ijl in #273
Fixed
- Remove python 2 from tags by ijl in #254
- 32-bit wheels didn't work on linux. This has been fixed by dae in #250
- The path of the RECORD file on windows used a backward slash instead of a forward slash
0.7.7 - 2019-11-12
Added
- The setup.py installer for bootstrapping maturin now checks for cargo instead of failing with a complex error message.
- Upload errors now show the filesize
Changed
- maturin's metadata now lists a requirement of python3.5 or later to install.
0.7.6 - 2019-09-28
Changed
- Only
--features
,--no-default-features
and--all-features
in--cargo-extra-args
are passed tocargo metadata
when determining the bindings, fixing problems in the previous release with arguments supported bycargo build
but bycargo metadata
.
0.7.5 - 2019-09-24
Fixed
- Fix clippy error to fix publishing from ci
0.7.4 - 2019-09-22
Fixed
- Fix tests
0.7.3 - 2019-09-22
Fixed
- Fix building when the bindings crate is behind a feature flag
0.7.3 - 2019-09-22
Removed
- The manylinux docker container doesn't contain musl anymore. If you're targeting musl, there's no need to use manylinux.
0.7.2 - 2019-09-05
Added
- Allow cross compilation with cffi and a python interpreter with the host target
Fixed
- Renamed a folder to maturin so PEP 517 backend works again.
0.7.1 - 2019-08-31
Added
maturin build --interpreter
/maturin publish --interpreter
builds only a source distribution.
0.7.0 - 2019-08-30
With this release, the name of this project changes from pyo3-pack to maturin.
Added
- Mixed rust/python layout
- Added PEP 517 support
- Added a
maturin sdist
command as workaround for pypa/pip#6041 - Support settings all applicable fields from the python core metadata specification in Cargo.toml
- Support for FreeBSD by kxepal #173
0.6.1
Fixed
- Downgraded to structopt 0.2.16 to avoid the yanked 0.2.17
0.6.0
Added
- Basic pypy support by ijl #105
Removed
- Python 2 support
- The custom progress bar was removed and cargo's output is shown instead
0.5.0
Added
- Support for conda environments on windows by paddyhoran #52
- maturin will generate a header for cffi crates using cbinding, which means you don't need a
build.rs
anymore. The option to provide your own header file using abuild.rs
still exists. - The konstin2/maturin docker image makes it easy to build fully manylinux compliant wheels. See the readme for usage details.
- Support for manylinux2010 by ijl #70
- The
--manxlinux=[1|1-unchecked|2010|2010-unchecked|off]
option allows to build for manylinux1 and manylinux2010, both with audithweel (1
or2010
) and without (1-unchecked
or2010-unchecked
), but also for the native linux tag withoff
.
Changed
- The
--skip-auditwheel
flag has been deprecated in favor of--manxlinux=[1|1-unchecked|2010|2010-unchecked|off]
. - Switched to rustls. This means the upload feature can be used from the docker container and builds of maturin itself are manylinux compliant when compiled with the musl target.
0.4.2 - 2018-12-15
Fixup release because the appveyor failed to release artifacts for windows for 0.4.1.
0.4.1 - 2018-12-15
Added
- You can now specify trove classifiers in your Cargo.toml with
package.metadata.maturin.classifier
. Implemented by ijl in #48. Example:
[package.metadata.maturin]
classifier = ["Programming Language :: Python"]
0.4.0 - 2018-11-20
Changed
- publish defaults to release and strip, unless
--debug
or--no-strip
are given.
Added
- New ci script based on hyperfine which also builds debian packages.
0.3.10 - 2018-11-16
Fixed
- Fix rust-cpython detection and compilation
0.3.9
Changed
- Update reqwest to 0.9.4 which has seanmonstar/reqwest#374 fixed
0.3.8
Fixed
- Pin reqwest to 0.9.2 to work around seanmonstar/reqwest#374
0.3.7
Fixed
- Added cargo lock to project #9
0.3.6
With deflate and the strip options, the wheels get about 25x smaller:
wheel | baseline | deflate | strip + deflate |
---|---|---|---|
get_fourtytwo-2.0.1-cp36-cp36m-manylinux1_x86_64.whl | 2,8M | 771K | 102K |
hello_world-0.1.0-py2.py3-none-manylinux1_x86_64.whl | 3,9M | 1,1M | 180K |
points-0.1.0-py2.py3-none-manylinux1_x86_64.whl | 2,8M | 752K | 85K |
Added
--strip
by ijl #7
Changed
- Renamed
--bindings-crate
to--bindings
- Use deflate compression for zips by ijl #6
Fixed
--target
is now actually used for the wheel compatibility tag
0.3.5 - 2018-09-20
Changed
- Upgraded to reqwest 0.9
Fixed
- "Broken Pipe" with musl builds (through the reqwest upgrade)
0.3.4 - 2018-09-18
Added
- A
--target
option which behaves like cargo option of the same name
Changed
- Musl and auditwheel compliance: Using the new
musl
feature combined with the musl target, you can build completely static binaries. Thepassword-storage
, which enables keyring integration, is now disabled by default. The Pypi packages are now statically linked with musl so that they are audtiwheel compliant. - Replaced
--debug
with--release
. All builds are now debug by default
0.3.3 - 2018-09-17
Added
- Builds for i686 linux and mac
- Builds for maturin as wheel
Fixed
- Usage with stable
- Wrong tags in WHEEL file on non-linux platforms
- Uploading on windows
0.3.1 - 2017-09-14
Fixed
- Windows compilation
0.3.0 - 2017-09-14
Added
- Packaging binaries
- Published on pypi. You can now
pip install maturin
- A Dockerfile based on manylinux1
Fixed
- Travis ci setup builds all types of wheels for linux and mac
--no-default-features --features auditwheel
creates a manylinux compliant binary for maturin
Changed
- Replaced elfkit with goblin
0.2.0 - 2018-09-03
Added
- Cffi support
- A
develop
subcommand - A tox example
Changed
- Show a progress bar for cargo's compile progress
0.1.0 - 2018-08-22
- Initial Release