Skip to main content

Build and publish crates with pyo3, rust-cpython and cffi bindings as well as rust binaries as python packages

Project description

Maturin

formerly pyo3-pack

Actions Status FreeBSD Crates.io PyPI Maturin User Guide Chat on Gitter

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 or maturin upload.
  • maturin develop builds the crate and installs it as a python module directly in the current virtualenv. Note that while maturin develop is faster, it doesn't support all the feature that running pip install after maturin 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.13,<0.14"]
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.13,<0.14"]
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).

  1. 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.
  2. Delete target/test-cache to clear the cache (e.g. after changing a test crate) or remove test-crates/cargo-mock/target/release/cargo to deactivate it.
  3. By running the tests with the faster-tests feature, binaries are stripped and wheels are only stored and not compressed.

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

maturin-0.13.0_beta.3.tar.gz (157.4 kB view details)

Uploaded Source

Built Distributions

maturin-0.13.0_beta.3-py3-none-win_arm64.whl (5.2 MB view details)

Uploaded Python 3 Windows ARM64

maturin-0.13.0_beta.3-py3-none-win_amd64.whl (6.0 MB view details)

Uploaded Python 3 Windows x86-64

maturin-0.13.0_beta.3-py3-none-win32.whl (5.5 MB view details)

Uploaded Python 3 Windows x86

maturin-0.13.0_beta.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl (9.8 MB view details)

Uploaded Python 3 manylinux: glibc 2.17+ s390x

maturin-0.13.0_beta.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.musllinux_1_1_ppc64le.whl (8.4 MB view details)

Uploaded Python 3 manylinux: glibc 2.17+ ppc64le musllinux: musl 1.1+ ppc64le

maturin-0.13.0_beta.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl (9.2 MB view details)

Uploaded Python 3 manylinux: glibc 2.17+ ARMv7l musllinux: musl 1.1+ ARMv7l

maturin-0.13.0_beta.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl (9.2 MB view details)

Uploaded Python 3 manylinux: glibc 2.17+ ARM64 musllinux: musl 1.1+ ARM64

maturin-0.13.0_beta.3-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.musllinux_1_1_x86_64.whl (9.6 MB view details)

Uploaded Python 3 manylinux: glibc 2.12+ x86-64 musllinux: musl 1.1+ x86-64

maturin-0.13.0_beta.3-py3-none-manylinux_2_12_i686.manylinux2010_i686.musllinux_1_1_i686.whl (9.8 MB view details)

Uploaded Python 3 manylinux: glibc 2.12+ i686 musllinux: musl 1.1+ i686

maturin-0.13.0_beta.3-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl (13.0 MB view details)

Uploaded Python 3 macOS 10.9+ universal2 (ARM64, x86-64) macOS 10.9+ x86-64 macOS 11.0+ ARM64

maturin-0.13.0_beta.3-py3-none-macosx_10_7_x86_64.whl (6.7 MB view details)

Uploaded Python 3 macOS 10.7+ x86-64

File details

Details for the file maturin-0.13.0_beta.3.tar.gz.

File metadata

  • Download URL: maturin-0.13.0_beta.3.tar.gz
  • Upload date:
  • Size: 157.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: maturin/0.12.19

File hashes

Hashes for maturin-0.13.0_beta.3.tar.gz
Algorithm Hash digest
SHA256 c41d6e359567c29365138a1c4ae0159994704b2d3301453d79840a99e3bddc0a
MD5 1ecb857daa81959ef7890f581f6e2412
BLAKE2b-256 73276979adfa4181dbe9e50e23aeb93aa3bb681785e1b142dd4fab196366b628

See more details on using hashes here.

File details

Details for the file maturin-0.13.0_beta.3-py3-none-win_arm64.whl.

File metadata

File hashes

Hashes for maturin-0.13.0_beta.3-py3-none-win_arm64.whl
Algorithm Hash digest
SHA256 8808a4a085612772d8fa5c713a023761027b95b9997d4561a6760e3f89d1fc1a
MD5 ab398640a32267506260cf52fc246605
BLAKE2b-256 e74a20b082da3964973c4e2e7ee050529f4664131e54543e7af06aac55b8a59c

See more details on using hashes here.

File details

Details for the file maturin-0.13.0_beta.3-py3-none-win_amd64.whl.

File metadata

File hashes

Hashes for maturin-0.13.0_beta.3-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 0c83e53178aa9c06ee2f5a330cb1246d6d101aa2edde75a9f909a7f5026807aa
MD5 d4a853c135b256fa74462e410cf1012d
BLAKE2b-256 2bde046b7a6143d7ec7f285a07b9607cb964ee2955139f1d72ada803edde0979

See more details on using hashes here.

File details

Details for the file maturin-0.13.0_beta.3-py3-none-win32.whl.

File metadata

File hashes

Hashes for maturin-0.13.0_beta.3-py3-none-win32.whl
Algorithm Hash digest
SHA256 3c23216b98a97ea121a3ecf5560bc1c658ece5f59372c280f64f584eaefbb566
MD5 061f620d192fdec2a3ae44c55d28dd97
BLAKE2b-256 20b08bbfd7944d68f408ca2b2839c34cb23111955ebbb1c4022d9a9f4561f9f1

See more details on using hashes here.

File details

Details for the file maturin-0.13.0_beta.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl.

File metadata

File hashes

Hashes for maturin-0.13.0_beta.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl
Algorithm Hash digest
SHA256 a95924dacc11654cde5f32f788862c871d7a86a958662ffe6122f90be6e0ad29
MD5 c4b17aecd83f8bc2e583e53680d40625
BLAKE2b-256 da3ba418f6431ad7e6ca7cfd99176309d46a56ab2740779870c43fedea005c60

See more details on using hashes here.

File details

Details for the file maturin-0.13.0_beta.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.musllinux_1_1_ppc64le.whl.

File metadata

File hashes

Hashes for maturin-0.13.0_beta.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.musllinux_1_1_ppc64le.whl
Algorithm Hash digest
SHA256 34a589f0f14619e9eb46cde9ff30c81a5150a8066e904857d29addd74973888f
MD5 a9905f027bfadf5993ba7cf53bc6e792
BLAKE2b-256 9a489c7b29d8f24bbdad2bd209a537be225ac81c3b64a6759fabc644e2acfcee

See more details on using hashes here.

File details

Details for the file maturin-0.13.0_beta.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl.

File metadata

File hashes

Hashes for maturin-0.13.0_beta.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl
Algorithm Hash digest
SHA256 44983f52131e60c79315efd88810464df5e1eaabe76a21f26c8f01eaa5693ad8
MD5 c4ac12773080ad9319a2872f4817fa39
BLAKE2b-256 ed4334ef4b4d9ee7cbe3dcf8ff031ca6cdef1d95c973e43ab073a771c219fe20

See more details on using hashes here.

File details

Details for the file maturin-0.13.0_beta.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl.

File metadata

File hashes

Hashes for maturin-0.13.0_beta.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl
Algorithm Hash digest
SHA256 25ff9f44ec5bb9a2d295c02bac97807ee90e9a7ad67c8b054cfd607fd8c45723
MD5 66da4b987fbcc8394f6ec467e93e809c
BLAKE2b-256 3a759f5d35ee0a3be4dcde42e979012e5348fa1120d2f51fe69555c10b3ae25e

See more details on using hashes here.

File details

Details for the file maturin-0.13.0_beta.3-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.musllinux_1_1_x86_64.whl.

File metadata

File hashes

Hashes for maturin-0.13.0_beta.3-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.musllinux_1_1_x86_64.whl
Algorithm Hash digest
SHA256 f5da74975628e0d122ed215349e31bf7202447fbc28cb28104842fc89c5dc38e
MD5 b1293e114b3cd3625a60956429cacf0d
BLAKE2b-256 9b270fe7312c32ac2c550c1b515d14b21acbd86835c9aed105b953f61a5edf6c

See more details on using hashes here.

File details

Details for the file maturin-0.13.0_beta.3-py3-none-manylinux_2_12_i686.manylinux2010_i686.musllinux_1_1_i686.whl.

File metadata

File hashes

Hashes for maturin-0.13.0_beta.3-py3-none-manylinux_2_12_i686.manylinux2010_i686.musllinux_1_1_i686.whl
Algorithm Hash digest
SHA256 1d849af63908f498401d73fd3105989113bb8dcabfa1d71ef0df2dfcd8f48064
MD5 6e9d68238b60fd364d370419bb6d7cbc
BLAKE2b-256 586c126fce706e052253a924e63ce1a9028fab76dcbc2a634317d12c053d9a66

See more details on using hashes here.

File details

Details for the file maturin-0.13.0_beta.3-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl.

File metadata

File hashes

Hashes for maturin-0.13.0_beta.3-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl
Algorithm Hash digest
SHA256 0737a49f12281327d4c673049068f3eeba41d386973bc2921aac7e8a5803560b
MD5 dc3c945e6d5321b854e253e1bb8a56fa
BLAKE2b-256 4f0b276df332971b7c24f0f1fc981380d5e755646135076b484f5caeb00ec418

See more details on using hashes here.

File details

Details for the file maturin-0.13.0_beta.3-py3-none-macosx_10_7_x86_64.whl.

File metadata

File hashes

Hashes for maturin-0.13.0_beta.3-py3-none-macosx_10_7_x86_64.whl
Algorithm Hash digest
SHA256 cc5eb9a7974647ae2f2c58f49a5c19219afcfe1a59987d4f8e2912bc488b3869
MD5 0e1585af86045eb722967ee831947468
BLAKE2b-256 35665e56435a07995badcdacbcbb7a0f94eaca471bb5fbce959b47e153399f27

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page